From 2f21e55514e5e8d8e8bd5b7b121fac8a92d39ed6 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 9 Jul 2019 16:50:08 +0200 Subject: [PATCH] Remove legacy InstantSend code (#3020) * Remove ppszTypeName from protocol.cpp and reimplement GetCommand This removes the need to carefully maintain ppszTypeName, which required correct order and also did not allow to permanently remove old message types. To get the command name for an INV type, GetCommandInternal uses a switch which needs to be maintained from now on. The way this is implemented also resembles the way it is implemented in Bitcoin today, but it's not identical. The original PR that introduced the switch case in Bitcoin was part of the Segwit changes and thus never got backported. I decided to implement it in a slightly different way that avoids throwing exceptions when an unknown INV type is encountered. IsKnownType will now also leverage GetCommandInternal() to figure out if the INV type is known locally. This has the side effect of old/legacy message types to return false from now on. We will depend on this side effect in later commits when we remove legacy InstantSend code. * Stop handling/relaying legacy IX messages When we receive an IX message, we simply treat it as a regular TX and relay it as such. We'll however still request IX messages when they are announced to us. We can't simply revert to requesting TX messages in this case as it might result in the other peer not answering due to the TX not being in mapRelay yet. We should at some point in the future completely drop handling of IX messages instead. * Remove IsNewInstantSendEnabled() and only use IsInstantSendEnabled() * Remove legacy InstantSend from GUI * Remove InstantSend from Bitcoin/Dash URIs * Remove legacy InstantSend from RPC commands * Remove legacy InstantSend from wallet * Remove legacy instantsend.h include * Remove legacy InstantSend from validation code * Completely remove remaining legacy InstantSend code * Remove now unused spork * Fix InstantSend related test failures * Remove now obsolete auto IS tests * Make spork2 and spork3 disabled by default This should have no influence on mainnet as these sporks are actually set there. This will however affect regtest, which shouldn't have LLMQ based InstantSend enabled by default. * Remove instantsend tests from dip3-deterministicmns.py These were only testing legacy InstantSend * Fix .QCheckBox#checkUsePrivateSend styling a bit * s/TXLEGACYLOCKREQUEST/LEGACYTXLOCKREQUEST/ * Revert "verified via InstantSend" back to "verified via LLMQ based InstantSend" * Use cmd == nullptr instead of !cmd * Remove last parameter from AvailableCoins call This was for fUseInstantSend which is not present anymore since rebase --- doc/files.md | 1 - src/Makefile.am | 2 - src/chainparams.cpp | 8 - src/consensus/params.h | 2 - src/dsnotificationinterface.cpp | 16 - src/init.cpp | 27 +- src/instantsend.cpp | 1264 ----------------- src/instantsend.h | 392 ----- src/llmq/quorums_chainlocks.cpp | 4 +- src/llmq/quorums_instantsend.cpp | 51 +- src/llmq/quorums_instantsend.h | 7 - src/net.cpp | 13 +- src/net_processing.cpp | 75 +- src/protocol.cpp | 102 +- src/protocol.h | 13 +- src/qt/coincontroldialog.cpp | 8 - src/qt/forms/receivecoinsdialog.ui | 14 +- src/qt/forms/sendcoinsdialog.ui | 16 - src/qt/guiutil.cpp | 11 +- src/qt/overviewpage.cpp | 1 - src/qt/receivecoinsdialog.cpp | 1 - src/qt/receiverequestdialog.cpp | 1 - src/qt/res/css/crownium.css | 10 - src/qt/res/css/drkblue.css | 10 - src/qt/res/css/light-hires-retro.css | 10 - src/qt/res/css/light-hires.css | 10 - src/qt/res/css/light-retro.css | 10 - src/qt/res/css/light.css | 10 - src/qt/res/css/trad.css | 5 - src/qt/sendcoinsdialog.cpp | 31 +- src/qt/sendcoinsdialog.h | 1 - src/qt/test/uritests.cpp | 17 +- src/qt/transactiondesc.cpp | 20 +- src/qt/walletmodel.cpp | 33 +- src/qt/walletmodel.h | 3 - src/rpc/blockchain.cpp | 5 +- src/rpc/governance.cpp | 8 +- src/rpc/rawtransaction.cpp | 17 +- src/rpc/rpcevo.cpp | 2 +- src/spork.cpp | 5 +- src/spork.h | 1 - src/txmempool.cpp | 13 +- src/txmempool.h | 2 - src/validation.cpp | 43 - src/wallet/coincontrol.h | 2 - src/wallet/rpcwallet.cpp | 103 +- src/wallet/wallet.cpp | 108 +- src/wallet/wallet.h | 15 +- src/zmq/zmqconfig.h | 2 - test/functional/autois-mempool.py | 123 -- test/functional/dip3-deterministicmns.py | 57 - test/functional/llmq-chainlocks.py | 7 +- test/functional/llmq-is-cl-conflicts.py | 3 +- test/functional/multikeysporks.py | 2 +- test/functional/p2p-autoinstantsend.py | 99 -- test/functional/p2p-instantsend.py | 15 +- test/functional/sporks.py | 16 +- .../test_framework/test_framework.py | 85 -- test/functional/test_runner.py | 2 - 59 files changed, 159 insertions(+), 2775 deletions(-) delete mode 100644 src/instantsend.cpp delete mode 100644 src/instantsend.h delete mode 100755 test/functional/autois-mempool.py delete mode 100755 test/functional/p2p-autoinstantsend.py diff --git a/doc/files.md b/doc/files.md index c295581569..0995b43b98 100644 --- a/doc/files.md +++ b/doc/files.md @@ -12,7 +12,6 @@ * evodb/*: special txes and quorums database * fee_estimates.dat: stores statistics used to estimate minimum transaction fees and priorities required for confirmation * governance.dat: stores data for governance obgects -* instantsend.dat: stores data for instantsend locks * llmq/*: quorum signatures database * mempool.dat: dump of the mempool's transactions * mncache.dat: stores data for masternode list diff --git a/src/Makefile.am b/src/Makefile.am index d2c842e00e..57b9ccc4a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -153,7 +153,6 @@ BITCOIN_CORE_H = \ httpserver.h \ indirectmap.h \ init.h \ - instantsend.h \ key.h \ keepass.h \ keystore.h \ @@ -273,7 +272,6 @@ libdash_server_a_SOURCES = \ httprpc.cpp \ httpserver.cpp \ init.cpp \ - instantsend.cpp \ dbwrapper.cpp \ governance/governance.cpp \ governance/governance-classes.cpp \ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index cc0752dec4..de4a2fa3bb 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -227,8 +227,6 @@ public: consensus.nMasternodePaymentsIncreasePeriod = 576*30; // 17280 - actual historical value consensus.nInstantSendConfirmationsRequired = 6; consensus.nInstantSendKeepLock = 24; - consensus.nInstantSendSigsRequired = 6; - consensus.nInstantSendSigsTotal = 10; consensus.nBudgetPaymentsStartBlock = 328008; // actual historical value consensus.nBudgetPaymentsCycleBlocks = 16616; // ~(60*24*30)/2.6, actual number of blocks per month is 200700 / 12 = 16725 consensus.nBudgetPaymentsWindowBlocks = 100; @@ -409,8 +407,6 @@ public: consensus.nMasternodePaymentsIncreasePeriod = 10; consensus.nInstantSendConfirmationsRequired = 2; consensus.nInstantSendKeepLock = 6; - consensus.nInstantSendSigsRequired = 6; - consensus.nInstantSendSigsTotal = 10; consensus.nBudgetPaymentsStartBlock = 4100; consensus.nBudgetPaymentsCycleBlocks = 50; consensus.nBudgetPaymentsWindowBlocks = 10; @@ -568,8 +564,6 @@ public: consensus.nMasternodePaymentsIncreasePeriod = 10; consensus.nInstantSendConfirmationsRequired = 2; consensus.nInstantSendKeepLock = 6; - consensus.nInstantSendSigsRequired = 6; - consensus.nInstantSendSigsTotal = 10; consensus.nBudgetPaymentsStartBlock = 4100; consensus.nBudgetPaymentsCycleBlocks = 50; consensus.nBudgetPaymentsWindowBlocks = 10; @@ -734,8 +728,6 @@ public: consensus.nMasternodePaymentsIncreasePeriod = 10; consensus.nInstantSendConfirmationsRequired = 2; consensus.nInstantSendKeepLock = 6; - consensus.nInstantSendSigsRequired = 3; - consensus.nInstantSendSigsTotal = 5; consensus.nBudgetPaymentsStartBlock = 1000; consensus.nBudgetPaymentsCycleBlocks = 50; consensus.nBudgetPaymentsWindowBlocks = 10; diff --git a/src/consensus/params.h b/src/consensus/params.h index 7a589165a5..0e330e1fa2 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -125,8 +125,6 @@ struct Params { int nMasternodePaymentsIncreasePeriod; // in blocks int nInstantSendConfirmationsRequired; // in blocks int nInstantSendKeepLock; // in blocks - int nInstantSendSigsRequired; - int nInstantSendSigsTotal; int nBudgetPaymentsStartBlock; int nBudgetPaymentsCycleBlocks; int nBudgetPaymentsWindowBlocks; diff --git a/src/dsnotificationinterface.cpp b/src/dsnotificationinterface.cpp index 6113f5976e..2ff951afba 100644 --- a/src/dsnotificationinterface.cpp +++ b/src/dsnotificationinterface.cpp @@ -4,7 +4,6 @@ #include "chainparams.h" #include "dsnotificationinterface.h" -#include "instantsend.h" #include "governance/governance.h" #include "masternode/masternode-payments.h" #include "masternode/masternode-sync.h" @@ -50,8 +49,6 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con // Update global DIP0001 activation status fDIP0001ActiveAtTip = pindexNew->nHeight >= Params().GetConsensus().DIP0001Height; - // update instantsend autolock activation flag (we reuse the DIP3 deployment) - instantsend.isAutoLockBip9Active = pindexNew->nHeight + 1 >= Params().GetConsensus().DIP0003Height; if (fInitialDownload) return; @@ -67,7 +64,6 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con llmq::quorumInstantSendManager->UpdatedBlockTip(pindexNew); llmq::chainLocksHandler->UpdatedBlockTip(pindexNew); - instantsend.UpdatedBlockTip(pindexNew); governance.UpdatedBlockTip(pindexNew, connman); llmq::quorumManager->UpdatedBlockTip(pindexNew, fInitialDownload); llmq::quorumDKGSessionManager->UpdatedBlockTip(pindexNew, fInitialDownload); @@ -78,7 +74,6 @@ void CDSNotificationInterface::TransactionAddedToMempool(const CTransactionRef& llmq::quorumInstantSendManager->TransactionAddedToMempool(ptx); llmq::chainLocksHandler->TransactionAddedToMempool(ptx); CPrivateSend::TransactionAddedToMempool(ptx); - instantsend.SyncTransaction(ptx); } void CDSNotificationInterface::BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindex, const std::vector& vtxConflicted) @@ -94,13 +89,6 @@ void CDSNotificationInterface::BlockConnected(const std::shared_ptrBlockConnected(pblock, pindex, vtxConflicted); llmq::chainLocksHandler->BlockConnected(pblock, pindex, vtxConflicted); CPrivateSend::BlockConnected(pblock, pindex, vtxConflicted); - - for (const CTransactionRef& ptx : vtxConflicted) { - instantsend.SyncTransaction(ptx); - } - for (size_t i = 0; i < pblock->vtx.size(); i++) { - instantsend.SyncTransaction(pblock->vtx[i], pindex, i); - } } void CDSNotificationInterface::BlockDisconnected(const std::shared_ptr& pblock, const CBlockIndex* pindexDisconnected) @@ -108,10 +96,6 @@ void CDSNotificationInterface::BlockDisconnected(const std::shared_ptrBlockDisconnected(pblock, pindexDisconnected); llmq::chainLocksHandler->BlockDisconnected(pblock, pindexDisconnected); CPrivateSend::BlockDisconnected(pblock, pindexDisconnected); - - for (const CTransactionRef& ptx : pblock->vtx) { - instantsend.SyncTransaction(ptx, pindexDisconnected->pprev, -1); - } } void CDSNotificationInterface::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff) diff --git a/src/init.cpp b/src/init.cpp index 9b96d849da..242be40639 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -52,7 +52,6 @@ #include "dsnotificationinterface.h" #include "flat-database.h" #include "governance/governance.h" -#include "instantsend.h" #ifdef ENABLE_WALLET #include "keepass.h" #endif @@ -267,11 +266,6 @@ void PrepareShutdown() flatdb3.Dump(governance); CFlatDB flatdb4("netfulfilled.dat", "magicFulfilledCache"); flatdb4.Dump(netfulfilledman); - if(fEnableInstantSend) - { - CFlatDB flatdb5("instantsend.dat", "magicInstantSendCache"); - flatdb5.Dump(instantsend); - } CFlatDB flatdb6("sporks.dat", "magicSporkCache"); flatdb6.Dump(sporkManager); } @@ -616,7 +610,6 @@ std::string HelpMessage(HelpMessageMode mode) #endif // ENABLE_WALLET strUsage += HelpMessageGroup(_("InstantSend options:")); - strUsage += HelpMessageOpt("-enableinstantsend", strprintf(_("Enable InstantSend, show confirmations for locked transactions (0-1, default: %u)"), 1)); strUsage += HelpMessageOpt("-instantsendnotify=", _("Execute command when a wallet InstantSend transaction is successfully locked (%s in cmd is replaced by TxID)")); @@ -2029,11 +2022,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) CPrivateSend::InitStandardDenominations(); - // ********************************************************* Step 10b: setup InstantSend - - fEnableInstantSend = gArgs.GetBoolArg("-enableinstantsend", 1); - - // ********************************************************* Step 10c: Load cache data + // ********************************************************* Step 10b: Load cache data // LOAD SERIALIZED DAT FILES INTO DATA CACHES FOR INTERNAL USE @@ -2063,27 +2052,15 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) if(!flatdb4.Load(netfulfilledman)) { return InitError(_("Failed to load fulfilled requests cache from") + "\n" + (pathDB / strDBName).string()); } - - if(fEnableInstantSend) - { - strDBName = "instantsend.dat"; - uiInterface.InitMessage(_("Loading InstantSend data cache...")); - CFlatDB flatdb5(strDBName, "magicInstantSendCache"); - if(!flatdb5.Load(instantsend)) { - return InitError(_("Failed to load InstantSend data cache from") + "\n" + (pathDB / strDBName).string()); - } - } } - // ********************************************************* Step 10d: schedule Dash-specific tasks + // ********************************************************* Step 10c: schedule Dash-specific tasks if (!fLiteMode) { scheduler.scheduleEvery(boost::bind(&CNetFulfilledRequestManager::DoMaintenance, boost::ref(netfulfilledman)), 60 * 1000); scheduler.scheduleEvery(boost::bind(&CMasternodeSync::DoMaintenance, boost::ref(masternodeSync), boost::ref(*g_connman)), 1 * 1000); scheduler.scheduleEvery(boost::bind(&CGovernanceManager::DoMaintenance, boost::ref(governance), boost::ref(*g_connman)), 60 * 5 * 1000); - - scheduler.scheduleEvery(boost::bind(&CInstantSend::DoMaintenance, boost::ref(instantsend)), 60 * 1000); } scheduler.scheduleEvery(boost::bind(&CMasternodeUtils::DoMaintenance, boost::ref(*g_connman)), 1 * 1000); diff --git a/src/instantsend.cpp b/src/instantsend.cpp deleted file mode 100644 index d8129659b4..0000000000 --- a/src/instantsend.cpp +++ /dev/null @@ -1,1264 +0,0 @@ -// Copyright (c) 2014-2019 The Dash Core developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "masternode/activemasternode.h" -#include "init.h" -#include "instantsend.h" -#include "key.h" -#include "validation.h" -#include "masternode/masternode-payments.h" -#include "masternode/masternode-sync.h" -#include "masternode/masternode-utils.h" -#include "messagesigner.h" -#include "net.h" -#include "netmessagemaker.h" -#include "protocol.h" -#include "spork.h" -#include "sync.h" -#include "txmempool.h" -#include "util.h" -#include "consensus/validation.h" -#include "validationinterface.h" -#include "warnings.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet.h" -#endif // ENABLE_WALLET - -#include "llmq/quorums_instantsend.h" - -#include -#include - -#ifdef ENABLE_WALLET -extern CWallet* pwalletMain; -#endif // ENABLE_WALLET -extern CTxMemPool mempool; - -bool fEnableInstantSend = true; - -std::atomic CInstantSend::isAutoLockBip9Active{false}; -const double CInstantSend::AUTO_IX_MEMPOOL_THRESHOLD = 0.1; - -CInstantSend instantsend; -const std::string CInstantSend::SERIALIZATION_VERSION_STRING = "CInstantSend-Version-1"; - -// Transaction Locks -// -// step 1) Some node announces intention to lock transaction inputs via "txlockrequest" message (ix) -// step 2) Top nInstantSendSigsTotal masternodes per each spent outpoint push "txlockvote" message (txlvote) -// step 3) Once there are nInstantSendSigsRequired valid "txlockvote" messages (txlvote) per each spent outpoint -// for a corresponding "txlockrequest" message (ix), all outpoints from that tx are treated as locked - -// -// CInstantSend -// - -void CInstantSend::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) -{ - if (fLiteMode) return; // disable all Dash specific functionality - if (!llmq::IsOldInstantSendEnabled()) return; - - // NOTE: NetMsgType::TXLOCKREQUEST is handled via ProcessMessage() in net_processing.cpp - - if (strCommand == NetMsgType::TXLOCKVOTE) { // InstantSend Transaction Lock Consensus Votes - if(pfrom->nVersion < MIN_INSTANTSEND_PROTO_VERSION) { - LogPrint(BCLog::INSTANTSEND, "TXLOCKVOTE -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion); - connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, - strprintf("Version must be %d or greater", MIN_INSTANTSEND_PROTO_VERSION))); - return; - } - - CTxLockVote vote; - vRecv >> vote; - - - uint256 nVoteHash = vote.GetHash(); - - { - LOCK(cs_main); - connman.RemoveAskFor(nVoteHash); - } - - // Ignore any InstantSend messages until blockchain is synced - if (!masternodeSync.IsBlockchainSynced()) return; - - { - LOCK(cs_instantsend); - auto ret = mapTxLockVotes.emplace(nVoteHash, vote); - if (!ret.second) return; - } - - ProcessNewTxLockVote(pfrom, vote, connman); - - return; - } -} - -bool CInstantSend::ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CConnman& connman) -{ - LOCK(cs_main); -#ifdef ENABLE_WALLET - LOCK(pwalletMain ? &pwalletMain->cs_wallet : NULL); -#endif - LOCK2(mempool.cs, cs_instantsend); - - uint256 txHash = txLockRequest.GetHash(); - - // Check to see if we conflict with existing completed lock - for (const auto& txin : txLockRequest.tx->vin) { - std::map::iterator it = mapLockedOutpoints.find(txin.prevout); - if (it != mapLockedOutpoints.end() && it->second != txLockRequest.GetHash()) { - // Conflicting with complete lock, proceed to see if we should cancel them both - LogPrintf("CInstantSend::ProcessTxLockRequest -- WARNING: Found conflicting completed Transaction Lock, txid=%s, completed lock txid=%s\n", - txLockRequest.GetHash().ToString(), it->second.ToString()); - } - } - - // Check to see if there are votes for conflicting request, - // if so - do not fail, just warn user - for (const auto& txin : txLockRequest.tx->vin) { - std::map >::iterator it = mapVotedOutpoints.find(txin.prevout); - if (it != mapVotedOutpoints.end()) { - for (const auto& hash : it->second) { - if (hash != txLockRequest.GetHash()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::ProcessTxLockRequest -- Double spend attempt! %s\n", txin.prevout.ToStringShort()); - // do not fail here, let it go and see which one will get the votes to be locked - // NOTIFY ZMQ - CTransaction txCurrent = *txLockRequest.tx; // currently processed tx - auto itPrevious = mapTxLockCandidates.find(hash); - if (itPrevious != mapTxLockCandidates.end() && itPrevious->second.txLockRequest) { - CTransaction txPrevious = *itPrevious->second.txLockRequest.tx; // previously locked one - GetMainSignals().NotifyInstantSendDoubleSpendAttempt(txCurrent, txPrevious); - } - } - } - } - } - - if (!CreateTxLockCandidate(txLockRequest)) { - // smth is not right - LogPrintf("CInstantSend::ProcessTxLockRequest -- CreateTxLockCandidate failed, txid=%s\n", txHash.ToString()); - return false; - } - LogPrintf("CInstantSend::ProcessTxLockRequest -- accepted, txid=%s\n", txHash.ToString()); - - // Masternodes will sometimes propagate votes before the transaction is known to the client. - // If this just happened - process orphan votes, lock inputs, resolve conflicting locks, - // update transaction status forcing external script/zmq notifications. - ProcessOrphanTxLockVotes(); - std::map::iterator itLockCandidate = mapTxLockCandidates.find(txHash); - TryToFinalizeLockCandidate(itLockCandidate->second); - - return true; -} - -bool CInstantSend::CreateTxLockCandidate(const CTxLockRequest& txLockRequest) -{ - if (!txLockRequest.IsValid()) return false; - - LOCK(cs_instantsend); - - uint256 txHash = txLockRequest.GetHash(); - - std::map::iterator itLockCandidate = mapTxLockCandidates.find(txHash); - if (itLockCandidate == mapTxLockCandidates.end()) { - LogPrintf("CInstantSend::CreateTxLockCandidate -- new, txid=%s\n", txHash.ToString()); - - CTxLockCandidate txLockCandidate(txLockRequest); - // all inputs should already be checked by txLockRequest.IsValid() above, just use them now - for (const auto& txin : txLockRequest.tx->vin) { - txLockCandidate.AddOutPointLock(txin.prevout); - } - mapTxLockCandidates.insert(std::make_pair(txHash, txLockCandidate)); - } else if (!itLockCandidate->second.txLockRequest) { - // i.e. empty Transaction Lock Candidate was created earlier, let's update it with actual data - itLockCandidate->second.txLockRequest = txLockRequest; - if (itLockCandidate->second.IsTimedOut()) { - LogPrintf("CInstantSend::CreateTxLockCandidate -- timed out, txid=%s\n", txHash.ToString()); - return false; - } - LogPrintf("CInstantSend::CreateTxLockCandidate -- update empty, txid=%s\n", txHash.ToString()); - - // all inputs should already be checked by txLockRequest.IsValid() above, just use them now - for (const auto& txin : txLockRequest.tx->vin) { - itLockCandidate->second.AddOutPointLock(txin.prevout); - } - } else { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::CreateTxLockCandidate -- seen, txid=%s\n", txHash.ToString()); - } - - return true; -} - -void CInstantSend::CreateEmptyTxLockCandidate(const uint256& txHash) -{ - if (mapTxLockCandidates.find(txHash) != mapTxLockCandidates.end()) - return; - LogPrintf("CInstantSend::CreateEmptyTxLockCandidate -- new, txid=%s\n", txHash.ToString()); - const CTxLockRequest txLockRequest = CTxLockRequest(); - mapTxLockCandidates.insert(std::make_pair(txHash, CTxLockCandidate(txLockRequest))); -} - -void CInstantSend::Vote(const uint256& txHash, CConnman& connman) -{ - AssertLockHeld(cs_main); -#ifdef ENABLE_WALLET - LOCK(pwalletMain ? &pwalletMain->cs_wallet : NULL); -#endif - - CTxLockRequest dummyRequest; - CTxLockCandidate txLockCandidate(dummyRequest); - { - LOCK(cs_instantsend); - auto itLockCandidate = mapTxLockCandidates.find(txHash); - if (itLockCandidate == mapTxLockCandidates.end()) return; - txLockCandidate = itLockCandidate->second; - Vote(txLockCandidate, connman); - } - - // Let's see if our vote changed smth - LOCK2(mempool.cs, cs_instantsend); - TryToFinalizeLockCandidate(txLockCandidate); -} - -void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman) -{ - if (!fMasternodeMode) return; - if (!llmq::IsOldInstantSendEnabled()) return; - - AssertLockHeld(cs_main); - AssertLockHeld(cs_instantsend); - - uint256 txHash = txLockCandidate.GetHash(); - // We should never vote on a Transaction Lock Request that was not (yet) accepted by the mempool - if (mapLockRequestAccepted.find(txHash) == mapLockRequestAccepted.end()) return; - // check if we need to vote on this candidate's outpoints, - // it's possible that we need to vote for several of them - for (auto& outpointLockPair : txLockCandidate.mapOutPointLocks) { - int nPrevoutHeight = GetUTXOHeight(outpointLockPair.first); - if (nPrevoutHeight == -1) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::Vote -- Failed to find UTXO %s\n", outpointLockPair.first.ToStringShort()); - return; - } - - int nLockInputHeight = nPrevoutHeight + Params().GetConsensus().nInstantSendConfirmationsRequired - 2; - - int nRank; - uint256 quorumModifierHash; - if (!CMasternodeUtils::GetMasternodeRank(activeMasternodeInfo.outpoint, nRank, quorumModifierHash, nLockInputHeight)) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::Vote -- Can't calculate rank for masternode %s\n", activeMasternodeInfo.outpoint.ToStringShort()); - continue; - } - - int nSignaturesTotal = Params().GetConsensus().nInstantSendSigsTotal; - if (nRank > nSignaturesTotal) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::Vote -- Masternode not in the top %d (%d)\n", nSignaturesTotal, nRank); - continue; - } - - LogPrint(BCLog::INSTANTSEND, "CInstantSend::Vote -- In the top %d (%d)\n", nSignaturesTotal, nRank); - - std::map >::iterator itVoted = mapVotedOutpoints.find(outpointLockPair.first); - - // Check to see if we already voted for this outpoint, - // refuse to vote twice or to include the same outpoint in another tx - bool fAlreadyVoted = false; - if (itVoted != mapVotedOutpoints.end()) { - for (const auto& hash : itVoted->second) { - std::map::iterator it2 = mapTxLockCandidates.find(hash); - if (it2->second.HasMasternodeVoted(outpointLockPair.first, activeMasternodeInfo.outpoint)) { - // we already voted for this outpoint to be included either in the same tx or in a competing one, - // skip it anyway - fAlreadyVoted = true; - LogPrintf("CInstantSend::Vote -- WARNING: We already voted for this outpoint, skipping: txHash=%s, outpoint=%s\n", - txHash.ToString(), outpointLockPair.first.ToStringShort()); - break; - } - } - } - if (fAlreadyVoted) { - continue; // skip to the next outpoint - } - - // we haven't voted for this outpoint yet, let's try to do this now - // Please note that activeMasternodeInfo.proTxHash is only valid after spork15 activation - CTxLockVote vote(txHash, outpointLockPair.first, activeMasternodeInfo.outpoint, quorumModifierHash, activeMasternodeInfo.proTxHash); - - if (!vote.Sign()) { - LogPrintf("CInstantSend::Vote -- Failed to sign consensus vote\n"); - return; - } - if (!vote.CheckSignature()) { - LogPrintf("CInstantSend::Vote -- Signature invalid\n"); - return; - } - - // vote constructed sucessfully, let's store and relay it - uint256 nVoteHash = vote.GetHash(); - mapTxLockVotes.insert(std::make_pair(nVoteHash, vote)); - if (outpointLockPair.second.AddVote(vote)) { - LogPrintf("CInstantSend::Vote -- Vote created successfully, relaying: txHash=%s, outpoint=%s, vote=%s\n", - txHash.ToString(), outpointLockPair.first.ToStringShort(), nVoteHash.ToString()); - - if (itVoted == mapVotedOutpoints.end()) { - std::set setHashes; - setHashes.insert(txHash); - mapVotedOutpoints.insert(std::make_pair(outpointLockPair.first, setHashes)); - } else { - mapVotedOutpoints[outpointLockPair.first].insert(txHash); - if (mapVotedOutpoints[outpointLockPair.first].size() > 1) { - // it's ok to continue, just warn user - LogPrintf("CInstantSend::Vote -- WARNING: Vote conflicts with some existing votes: txHash=%s, outpoint=%s, vote=%s\n", - txHash.ToString(), outpointLockPair.first.ToStringShort(), nVoteHash.ToString()); - } - } - - vote.Relay(connman); - } - } -} - -bool CInstantSend::ProcessNewTxLockVote(CNode* pfrom, const CTxLockVote& vote, CConnman& connman) -{ - uint256 txHash = vote.GetTxHash(); - uint256 nVoteHash = vote.GetHash(); - - if (!vote.IsValid(pfrom, connman)) { - // could be because of missing MN - LogPrint(BCLog::INSTANTSEND, "CInstantSend::%s -- Vote is invalid, txid=%s\n", __func__, txHash.ToString()); - return false; - } - - // relay valid vote asap - vote.Relay(connman); - - LOCK(cs_main); -#ifdef ENABLE_WALLET - LOCK(pwalletMain ? &pwalletMain->cs_wallet : NULL); -#endif - LOCK2(mempool.cs, cs_instantsend); - - // Masternodes will sometimes propagate votes before the transaction is known to the client, - // will actually process only after the lock request itself has arrived - - std::map::iterator it = mapTxLockCandidates.find(txHash); - if (it == mapTxLockCandidates.end() || !it->second.txLockRequest) { - // no or empty tx lock candidate - if (it == mapTxLockCandidates.end()) { - // start timeout countdown after the very first vote - CreateEmptyTxLockCandidate(txHash); - } - bool fInserted = mapTxLockVotesOrphan.emplace(nVoteHash, vote).second; - LogPrint(BCLog::INSTANTSEND, "CInstantSend::%s -- Orphan vote: txid=%s masternode=%s %s\n", - __func__, txHash.ToString(), vote.GetMasternodeOutpoint().ToStringShort(), fInserted ? "new" : "seen"); - - // This tracks those messages and allows only the same rate as of the rest of the network - // TODO: make sure this works good enough for multi-quorum - - int nMasternodeOrphanExpireTime = GetTime() + 60*10; // keep time data for 10 minutes - auto itMnOV = mapMasternodeOrphanVotes.find(vote.GetMasternodeOutpoint()); - if (itMnOV == mapMasternodeOrphanVotes.end()) { - mapMasternodeOrphanVotes.emplace(vote.GetMasternodeOutpoint(), nMasternodeOrphanExpireTime); - } else { - if (itMnOV->second > GetTime() && itMnOV->second > GetAverageMasternodeOrphanVoteTime()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::%s -- masternode is spamming orphan Transaction Lock Votes: txid=%s masternode=%s\n", - __func__, txHash.ToString(), vote.GetMasternodeOutpoint().ToStringShort()); - // Misbehaving(pfrom->GetId(), 1); - return false; - } - // not spamming, refresh - itMnOV->second = nMasternodeOrphanExpireTime; - } - - return true; - } - - // We have a valid (non-empty) tx lock candidate - CTxLockCandidate& txLockCandidate = it->second; - - if (txLockCandidate.IsTimedOut()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::%s -- too late, Transaction Lock timed out, txid=%s\n", __func__, txHash.ToString()); - return false; - } - - LogPrint(BCLog::INSTANTSEND, "CInstantSend::%s -- Transaction Lock Vote, txid=%s\n", __func__, txHash.ToString()); - - UpdateVotedOutpoints(vote, txLockCandidate); - - if (!txLockCandidate.AddVote(vote)) { - // this should never happen - return false; - } - - int nSignatures = txLockCandidate.CountVotes(); - int nSignaturesMax = txLockCandidate.txLockRequest.GetMaxSignatures(); - LogPrint(BCLog::INSTANTSEND, "CInstantSend::%s -- Transaction Lock signatures count: %d/%d, vote hash=%s\n", __func__, - nSignatures, nSignaturesMax, nVoteHash.ToString()); - - TryToFinalizeLockCandidate(txLockCandidate); - - return true; -} - -bool CInstantSend::ProcessOrphanTxLockVote(const CTxLockVote& vote) -{ - // cs_main, cs_wallet and cs_instantsend should be already locked - AssertLockHeld(cs_main); -#ifdef ENABLE_WALLET - if (pwalletMain) - AssertLockHeld(pwalletMain->cs_wallet); -#endif - AssertLockHeld(cs_instantsend); - - uint256 txHash = vote.GetTxHash(); - - // We shouldn't process orphan votes without a valid tx lock candidate - std::map::iterator it = mapTxLockCandidates.find(txHash); - if (it == mapTxLockCandidates.end() || !it->second.txLockRequest) - return false; // this shouldn never happen - - CTxLockCandidate& txLockCandidate = it->second; - - if (txLockCandidate.IsTimedOut()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::%s -- too late, Transaction Lock timed out, txid=%s\n", __func__, txHash.ToString()); - return false; - } - - LogPrint(BCLog::INSTANTSEND, "CInstantSend::%s -- Transaction Lock Vote, txid=%s\n", __func__, txHash.ToString()); - - UpdateVotedOutpoints(vote, txLockCandidate); - - if (!txLockCandidate.AddVote(vote)) { - // this should never happen - return false; - } - - int nSignatures = txLockCandidate.CountVotes(); - int nSignaturesMax = txLockCandidate.txLockRequest.GetMaxSignatures(); - LogPrint(BCLog::INSTANTSEND, "CInstantSend::%s -- Transaction Lock signatures count: %d/%d, vote hash=%s\n", - __func__, nSignatures, nSignaturesMax, vote.GetHash().ToString()); - - return true; -} - -void CInstantSend::UpdateVotedOutpoints(const CTxLockVote& vote, CTxLockCandidate& txLockCandidate) -{ - AssertLockHeld(cs_instantsend); - - uint256 txHash = vote.GetTxHash(); - - std::map >::iterator it1 = mapVotedOutpoints.find(vote.GetOutpoint()); - if (it1 != mapVotedOutpoints.end()) { - for (const auto& hash : it1->second) { - if (hash != txHash) { - // same outpoint was already voted to be locked by another tx lock request, - // let's see if it was the same masternode who voted on this outpoint - // for another tx lock request - std::map::iterator it2 = mapTxLockCandidates.find(hash); - if (it2 !=mapTxLockCandidates.end() && it2->second.HasMasternodeVoted(vote.GetOutpoint(), vote.GetMasternodeOutpoint())) { - // yes, it was the same masternode - LogPrintf("CInstantSend::%s -- masternode sent conflicting votes! %s\n", __func__, vote.GetMasternodeOutpoint().ToStringShort()); - // mark both Lock Candidates as attacked, none of them should complete, - // or at least the new (current) one shouldn't even - // if the second one was already completed earlier - txLockCandidate.MarkOutpointAsAttacked(vote.GetOutpoint()); - it2->second.MarkOutpointAsAttacked(vote.GetOutpoint()); - // apply maximum PoSe ban score to this masternode i.e. PoSe-ban it instantly - // TODO Call new PoSe system when it's ready - //mnodeman.PoSeBan(vote.GetMasternodeOutpoint()); - // NOTE: This vote must be relayed further to let all other nodes know about such - // misbehaviour of this masternode. This way they should also be able to construct - // conflicting lock and PoSe-ban this masternode. - } - } - } - // store all votes, regardless of them being sent by malicious masternode or not - it1->second.insert(txHash); - } else { - mapVotedOutpoints.emplace(vote.GetOutpoint(), std::set({txHash})); - } -} - -void CInstantSend::ProcessOrphanTxLockVotes() -{ - AssertLockHeld(cs_main); - AssertLockHeld(cs_instantsend); - - std::map::iterator it = mapTxLockVotesOrphan.begin(); - while (it != mapTxLockVotesOrphan.end()) { - if (ProcessOrphanTxLockVote(it->second)) { - mapTxLockVotesOrphan.erase(it++); - } else { - ++it; - } - } -} - -void CInstantSend::TryToFinalizeLockCandidate(const CTxLockCandidate& txLockCandidate) -{ - if (!llmq::IsOldInstantSendEnabled()) return; - - AssertLockHeld(cs_main); - AssertLockHeld(cs_instantsend); - - uint256 txHash = txLockCandidate.txLockRequest.tx->GetHash(); - if (txLockCandidate.IsAllOutPointsReady() && !IsLockedInstantSendTransaction(txHash)) { - // we have enough votes now - LogPrint(BCLog::INSTANTSEND, "CInstantSend::TryToFinalizeLockCandidate -- Transaction Lock is ready to complete, txid=%s\n", txHash.ToString()); - if (ResolveConflicts(txLockCandidate)) { - LockTransactionInputs(txLockCandidate); - UpdateLockedTransaction(txLockCandidate); - } - } -} - -void CInstantSend::UpdateLockedTransaction(const CTxLockCandidate& txLockCandidate) -{ - // cs_main, cs_wallet and cs_instantsend should be already locked - AssertLockHeld(cs_main); -#ifdef ENABLE_WALLET - if (pwalletMain) { - AssertLockHeld(pwalletMain->cs_wallet); - } -#endif - AssertLockHeld(cs_instantsend); - - uint256 txHash = txLockCandidate.GetHash(); - - if (!IsLockedInstantSendTransaction(txHash)) return; // not a locked tx, do not update/notify - - llmq::CInstantSendLock islock; - GetMainSignals().NotifyTransactionLock(*txLockCandidate.txLockRequest.tx, islock); - - LogPrint(BCLog::INSTANTSEND, "CInstantSend::UpdateLockedTransaction -- done, txid=%s\n", txHash.ToString()); -} - -void CInstantSend::LockTransactionInputs(const CTxLockCandidate& txLockCandidate) -{ - if (!llmq::IsOldInstantSendEnabled()) return; - - LOCK(cs_instantsend); - - uint256 txHash = txLockCandidate.GetHash(); - - if (!txLockCandidate.IsAllOutPointsReady()) return; - - for (const auto& pair : txLockCandidate.mapOutPointLocks) { - mapLockedOutpoints.insert(std::make_pair(pair.first, txHash)); - } - LogPrint(BCLog::INSTANTSEND, "CInstantSend::LockTransactionInputs -- done, txid=%s\n", txHash.ToString()); -} - -bool CInstantSend::GetLockedOutPointTxHash(const COutPoint& outpoint, uint256& hashRet) -{ - LOCK(cs_instantsend); - std::map::iterator it = mapLockedOutpoints.find(outpoint); - if (it == mapLockedOutpoints.end()) return false; - hashRet = it->second; - return true; -} - -bool CInstantSend::ResolveConflicts(const CTxLockCandidate& txLockCandidate) -{ - AssertLockHeld(cs_main); - AssertLockHeld(cs_instantsend); - - uint256 txHash = txLockCandidate.GetHash(); - - // make sure the lock is ready - if (!txLockCandidate.IsAllOutPointsReady()) return false; - - AssertLockHeld(mempool.cs); // protect mempool.mapNextTx - - for (const auto& txin : txLockCandidate.txLockRequest.tx->vin) { - uint256 hashConflicting; - if (GetLockedOutPointTxHash(txin.prevout, hashConflicting) && txHash != hashConflicting) { - // completed lock which conflicts with another completed one? - // this means that majority of MNs in the quorum for this specific tx input are malicious! - std::map::iterator itLockCandidate = mapTxLockCandidates.find(txHash); - std::map::iterator itLockCandidateConflicting = mapTxLockCandidates.find(hashConflicting); - if (itLockCandidate == mapTxLockCandidates.end() || itLockCandidateConflicting == mapTxLockCandidates.end()) { - // safety check, should never really happen - LogPrintf("CInstantSend::ResolveConflicts -- ERROR: Found conflicting completed Transaction Lock, but one of txLockCandidate-s is missing, txid=%s, conflicting txid=%s\n", - txHash.ToString(), hashConflicting.ToString()); - return false; - } - LogPrintf("CInstantSend::ResolveConflicts -- WARNING: Found conflicting completed Transaction Lock, dropping both, txid=%s, conflicting txid=%s\n", - txHash.ToString(), hashConflicting.ToString()); - CTxLockRequest txLockRequest = itLockCandidate->second.txLockRequest; - CTxLockRequest txLockRequestConflicting = itLockCandidateConflicting->second.txLockRequest; - itLockCandidate->second.SetConfirmedHeight(0); // expired - itLockCandidateConflicting->second.SetConfirmedHeight(0); // expired - CheckAndRemove(); // clean up - // AlreadyHave should still return "true" for both of them - mapLockRequestRejected.insert(std::make_pair(txHash, txLockRequest)); - mapLockRequestRejected.insert(std::make_pair(hashConflicting, txLockRequestConflicting)); - - // TODO: clean up mapLockRequestRejected later somehow - // (not a big issue since we already PoSe ban malicious masternodes - // and they won't be able to spam) - // TODO: ban all malicious masternodes permanently, do not accept anything from them, ever - - // TODO: notify zmq+script about this double-spend attempt - // and let merchant cancel/hold the order if it's not too late... - - // can't do anything else, fallback to regular txes - return false; - } else if (mempool.mapNextTx.count(txin.prevout)) { - // check if it's in mempool - hashConflicting = mempool.mapNextTx.find(txin.prevout)->second->GetHash(); - if (txHash == hashConflicting) continue; // matches current, not a conflict, skip to next txin - // conflicts with tx in mempool - LogPrintf("CInstantSend::ResolveConflicts -- ERROR: Failed to complete Transaction Lock, conflicts with mempool, txid=%s\n", txHash.ToString()); - return false; - } - } // FOREACH - // No conflicts were found so far, check to see if it was already included in block - CTransactionRef txTmp; - uint256 hashBlock; - if (GetTransaction(txHash, txTmp, Params().GetConsensus(), hashBlock, true) && hashBlock != uint256()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::ResolveConflicts -- Done, %s is included in block %s\n", txHash.ToString(), hashBlock.ToString()); - return true; - } - // Not in block yet, make sure all its inputs are still unspent - for (const auto& txin : txLockCandidate.txLockRequest.tx->vin) { - Coin coin; - if (!GetUTXOCoin(txin.prevout, coin)) { - // Not in UTXO anymore? A conflicting tx was mined while we were waiting for votes. - LogPrintf("CInstantSend::ResolveConflicts -- ERROR: Failed to find UTXO %s, can't complete Transaction Lock\n", txin.prevout.ToStringShort()); - return false; - } - } - LogPrint(BCLog::INSTANTSEND, "CInstantSend::ResolveConflicts -- Done, txid=%s\n", txHash.ToString()); - - return true; -} - -int64_t CInstantSend::GetAverageMasternodeOrphanVoteTime() -{ - LOCK(cs_instantsend); - // NOTE: should never actually call this function when mapMasternodeOrphanVotes is empty - if (mapMasternodeOrphanVotes.empty()) return 0; - - int64_t total = 0; - for (const auto& pair : mapMasternodeOrphanVotes) { - total += pair.second; - } - - return total / mapMasternodeOrphanVotes.size(); -} - -void CInstantSend::CheckAndRemove() -{ - if (!masternodeSync.IsBlockchainSynced()) return; - - LOCK(cs_instantsend); - - std::map::iterator itLockCandidate = mapTxLockCandidates.begin(); - - // remove expired candidates - while (itLockCandidate != mapTxLockCandidates.end()) { - CTxLockCandidate &txLockCandidate = itLockCandidate->second; - uint256 txHash = txLockCandidate.GetHash(); - if (txLockCandidate.IsExpired(nCachedBlockHeight)) { - LogPrintf("CInstantSend::CheckAndRemove -- Removing expired Transaction Lock Candidate: txid=%s\n", txHash.ToString()); - - for (const auto& pair : txLockCandidate.mapOutPointLocks) { - mapLockedOutpoints.erase(pair.first); - mapVotedOutpoints.erase(pair.first); - } - mapLockRequestAccepted.erase(txHash); - mapLockRequestRejected.erase(txHash); - mapTxLockCandidates.erase(itLockCandidate++); - } else { - ++itLockCandidate; - } - } - - // remove expired votes - std::map::iterator itVote = mapTxLockVotes.begin(); - while (itVote != mapTxLockVotes.end()) { - if (itVote->second.IsExpired(nCachedBlockHeight)) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::CheckAndRemove -- Removing expired vote: txid=%s masternode=%s\n", - itVote->second.GetTxHash().ToString(), itVote->second.GetMasternodeOutpoint().ToStringShort()); - mapTxLockVotes.erase(itVote++); - } else { - ++itVote; - } - } - - // remove timed out orphan votes - std::map::iterator itOrphanVote = mapTxLockVotesOrphan.begin(); - while (itOrphanVote != mapTxLockVotesOrphan.end()) { - if (itOrphanVote->second.IsTimedOut()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::CheckAndRemove -- Removing timed out orphan vote: txid=%s masternode=%s\n", - itOrphanVote->second.GetTxHash().ToString(), itOrphanVote->second.GetMasternodeOutpoint().ToStringShort()); - mapTxLockVotes.erase(itOrphanVote->first); - mapTxLockVotesOrphan.erase(itOrphanVote++); - } else { - ++itOrphanVote; - } - } - - // remove invalid votes and votes for failed lock attempts - itVote = mapTxLockVotes.begin(); - while (itVote != mapTxLockVotes.end()) { - if (itVote->second.IsFailed()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::CheckAndRemove -- Removing vote for failed lock attempt: txid=%s masternode=%s\n", - itVote->second.GetTxHash().ToString(), itVote->second.GetMasternodeOutpoint().ToStringShort()); - mapTxLockVotes.erase(itVote++); - } else { - ++itVote; - } - } - - // remove timed out masternode orphan votes (DOS protection) - std::map::iterator itMasternodeOrphan = mapMasternodeOrphanVotes.begin(); - while (itMasternodeOrphan != mapMasternodeOrphanVotes.end()) { - if (itMasternodeOrphan->second < GetTime()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::CheckAndRemove -- Removing timed out orphan masternode vote: masternode=%s\n", - itMasternodeOrphan->first.ToStringShort()); - mapMasternodeOrphanVotes.erase(itMasternodeOrphan++); - } else { - ++itMasternodeOrphan; - } - } - LogPrintf("CInstantSend::CheckAndRemove -- %s\n", ToString()); -} - -bool CInstantSend::AlreadyHave(const uint256& hash) -{ - if (!llmq::IsOldInstantSendEnabled()) { - return true; - } - - LOCK(cs_instantsend); - return mapLockRequestAccepted.count(hash) || - mapLockRequestRejected.count(hash) || - mapTxLockVotes.count(hash); -} - -void CInstantSend::AcceptLockRequest(const CTxLockRequest& txLockRequest) -{ - LOCK(cs_instantsend); - mapLockRequestAccepted.insert(std::make_pair(txLockRequest.GetHash(), txLockRequest)); -} - -void CInstantSend::RejectLockRequest(const CTxLockRequest& txLockRequest) -{ - LOCK(cs_instantsend); - mapLockRequestRejected.insert(std::make_pair(txLockRequest.GetHash(), txLockRequest)); -} - -bool CInstantSend::HasTxLockRequest(const uint256& txHash) -{ - CTxLockRequest txLockRequestTmp; - return GetTxLockRequest(txHash, txLockRequestTmp); -} - -bool CInstantSend::GetTxLockRequest(const uint256& txHash, CTxLockRequest& txLockRequestRet) -{ - if (!llmq::IsOldInstantSendEnabled()) { - return false; - } - - LOCK(cs_instantsend); - - std::map::iterator it = mapTxLockCandidates.find(txHash); - if (it == mapTxLockCandidates.end() || !it->second.txLockRequest) return false; - txLockRequestRet = it->second.txLockRequest; - - return true; -} - -bool CInstantSend::GetTxLockVote(const uint256& hash, CTxLockVote& txLockVoteRet) -{ - if (!llmq::IsOldInstantSendEnabled()) { - return false; - } - - LOCK(cs_instantsend); - - std::map::iterator it = mapTxLockVotes.find(hash); - if (it == mapTxLockVotes.end()) return false; - txLockVoteRet = it->second; - - return true; -} - -void CInstantSend::Clear() -{ - LOCK(cs_instantsend); - - mapLockRequestAccepted.clear(); - mapLockRequestRejected.clear(); - mapTxLockVotes.clear(); - mapTxLockVotesOrphan.clear(); - mapTxLockCandidates.clear(); - mapVotedOutpoints.clear(); - mapLockedOutpoints.clear(); - mapMasternodeOrphanVotes.clear(); - nCachedBlockHeight = 0; -} - -bool CInstantSend::IsLockedInstantSendTransaction(const uint256& txHash) -{ - if (!fEnableInstantSend || GetfLargeWorkForkFound() || GetfLargeWorkInvalidChainFound() || - !sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) return false; - - LOCK(cs_instantsend); - - // there must be a lock candidate - std::map::iterator itLockCandidate = mapTxLockCandidates.find(txHash); - if (itLockCandidate == mapTxLockCandidates.end()) return false; - - // which should have outpoints - if (itLockCandidate->second.mapOutPointLocks.empty()) return false; - - // and all of these outputs must be included in mapLockedOutpoints with correct hash - for (const auto& pair : itLockCandidate->second.mapOutPointLocks) { - uint256 hashLocked; - if (!GetLockedOutPointTxHash(pair.first, hashLocked) || hashLocked != txHash) return false; - } - - return true; -} - -int CInstantSend::GetTransactionLockSignatures(const uint256& txHash) -{ - if (!fEnableInstantSend) return -1; - if (GetfLargeWorkForkFound() || GetfLargeWorkInvalidChainFound()) return -2; - if (!llmq::IsOldInstantSendEnabled()) return -3; - - LOCK(cs_instantsend); - - std::map::iterator itLockCandidate = mapTxLockCandidates.find(txHash); - if (itLockCandidate != mapTxLockCandidates.end()) { - return itLockCandidate->second.CountVotes(); - } - - return -1; -} - -bool CInstantSend::IsTxLockCandidateTimedOut(const uint256& txHash) -{ - if (!fEnableInstantSend) return false; - - LOCK(cs_instantsend); - - std::map::iterator itLockCandidate = mapTxLockCandidates.find(txHash); - if (itLockCandidate != mapTxLockCandidates.end()) { - return !itLockCandidate->second.IsAllOutPointsReady() && - itLockCandidate->second.IsTimedOut(); - } - - return false; -} - -void CInstantSend::Relay(const uint256& txHash, CConnman& connman) -{ - LOCK(cs_instantsend); - - std::map::const_iterator itLockCandidate = mapTxLockCandidates.find(txHash); - if (itLockCandidate != mapTxLockCandidates.end()) { - itLockCandidate->second.Relay(connman); - } -} - -void CInstantSend::UpdatedBlockTip(const CBlockIndex *pindex) -{ - nCachedBlockHeight = pindex->nHeight; -} - -void CInstantSend::SyncTransaction(const CTransactionRef& tx, const CBlockIndex* pindex, int posInBlock) -{ - // Update lock candidates and votes if corresponding tx confirmed - // or went from confirmed to 0-confirmed or conflicted. - - if (tx->IsCoinBase()) return; - - LOCK2(cs_main, cs_instantsend); - - uint256 txHash = tx->GetHash(); - - // When tx is 0-confirmed or conflicted, posInBlock is -1 and nHeightNew should be set to -1 - int nHeightNew = (posInBlock == -1 || pindex == nullptr) ? -1 : pindex->nHeight; - - LogPrint(BCLog::INSTANTSEND, "CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d\n", txHash.ToString(), nHeightNew); - - // Check lock candidates - std::map::iterator itLockCandidate = mapTxLockCandidates.find(txHash); - if (itLockCandidate != mapTxLockCandidates.end()) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d lock candidate updated\n", - txHash.ToString(), nHeightNew); - itLockCandidate->second.SetConfirmedHeight(nHeightNew); - // Loop through outpoint locks - for (const auto& pair : itLockCandidate->second.mapOutPointLocks) { - // Check corresponding lock votes - for (const auto& vote : pair.second.GetVotes()) { - uint256 nVoteHash = vote.GetHash(); - LogPrint(BCLog::INSTANTSEND, "CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d vote %s updated\n", - txHash.ToString(), nHeightNew, nVoteHash.ToString()); - const auto& it = mapTxLockVotes.find(nVoteHash); - if (it != mapTxLockVotes.end()) { - it->second.SetConfirmedHeight(nHeightNew); - } - } - } - } - - // check orphan votes - for (const auto& pair : mapTxLockVotesOrphan) { - if (pair.second.GetTxHash() == txHash) { - LogPrint(BCLog::INSTANTSEND, "CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d vote %s updated\n", - txHash.ToString(), nHeightNew, pair.first.ToString()); - mapTxLockVotes[pair.first].SetConfirmedHeight(nHeightNew); - } - } -} - -std::string CInstantSend::ToString() const -{ - LOCK(cs_instantsend); - return strprintf("Lock Candidates: %llu, Votes %llu", mapTxLockCandidates.size(), mapTxLockVotes.size()); -} - -void CInstantSend::DoMaintenance() -{ - if (ShutdownRequested()) return; - - CheckAndRemove(); -} - -bool CInstantSend::CanAutoLock() -{ - if (!isAutoLockBip9Active || !llmq::IsOldInstantSendEnabled()) { - return false; - } - if (!sporkManager.IsSporkActive(SPORK_16_INSTANTSEND_AUTOLOCKS)) { - return false; - } - return (mempool.UsedMemoryShare() < AUTO_IX_MEMPOOL_THRESHOLD); -} - -// -// CTxLockRequest -// - -bool CTxLockRequest::IsValid() const -{ - if (tx->vout.size() < 1) return false; - - if (tx->vin.size() > WARN_MANY_INPUTS) { - LogPrint(BCLog::INSTANTSEND, "CTxLockRequest::IsValid -- WARNING: Too many inputs: tx=%s", ToString()); - } - - AssertLockHeld(cs_main); - if (!CheckFinalTx(*tx)) { - LogPrint(BCLog::INSTANTSEND, "CTxLockRequest::IsValid -- Transaction is not final: tx=%s", ToString()); - return false; - } - - CAmount nValueIn = 0; - - int nInstantSendConfirmationsRequired = Params().GetConsensus().nInstantSendConfirmationsRequired; - - for (const auto& txin : tx->vin) { - - Coin coin; - - if (!GetUTXOCoin(txin.prevout, coin)) { - LogPrint(BCLog::INSTANTSEND, "CTxLockRequest::IsValid -- Failed to find UTXO %s\n", txin.prevout.ToStringShort()); - return false; - } - - int nTxAge = chainActive.Height() - coin.nHeight + 1; - // 1 less than the "send IX" gui requires, in case of a block propagating the network at the time - int nConfirmationsRequired = nInstantSendConfirmationsRequired - 1; - - if (nTxAge < nConfirmationsRequired) { - LogPrint(BCLog::INSTANTSEND, "CTxLockRequest::IsValid -- outpoint %s too new: nTxAge=%d, nConfirmationsRequired=%d, txid=%s\n", - txin.prevout.ToStringShort(), nTxAge, nConfirmationsRequired, GetHash().ToString()); - return false; - } - - nValueIn += coin.out.nValue; - } - - if (nValueIn > sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)*COIN) { - LogPrint(BCLog::INSTANTSEND, "CTxLockRequest::IsValid -- Transaction value too high: nValueIn=%d, tx=%s", nValueIn, ToString()); - return false; - } - - CAmount nValueOut = tx->GetValueOut(); - - if (nValueIn - nValueOut < GetMinFee(false)) { - LogPrint(BCLog::INSTANTSEND, "CTxLockRequest::IsValid -- did not include enough fees in transaction: fees=%d, tx=%s", nValueOut - nValueIn, ToString()); - return false; - } - - return true; -} - -CAmount CTxLockRequest::GetMinFee(bool fForceMinFee) const -{ - if (!fForceMinFee && CInstantSend::CanAutoLock() && IsSimple()) { - return CAmount(); - } - CAmount nMinFee = MIN_FEE; - return std::max(nMinFee, CAmount(tx->vin.size() * nMinFee)); -} - -int CTxLockRequest::GetMaxSignatures() const -{ - return tx->vin.size() * Params().GetConsensus().nInstantSendSigsTotal; -} - -bool CTxLockRequest::IsSimple() const -{ - return (tx->vin.size() <= MAX_INPUTS_FOR_AUTO_IX); -} - -// -// CTxLockVote -// - -bool CTxLockVote::IsValid(CNode* pnode, CConnman& connman) const -{ - auto mnList = deterministicMNManager->GetListAtChainTip(); - - if (!mnList.HasValidMNByCollateral(outpointMasternode)) { - LogPrint(BCLog::INSTANTSEND, "CTxLockVote::IsValid -- Unknown masternode %s\n", outpointMasternode.ToStringShort()); - return false; - } - - // Verify that masternodeProTxHash belongs to the same MN referred by the collateral - // This is a leftover from the legacy non-deterministic MN list where we used the collateral to identify MNs - // TODO eventually remove the collateral from CTxLockVote - if (!masternodeProTxHash.IsNull()) { - auto dmn = mnList.GetValidMN(masternodeProTxHash); - if (!dmn || dmn->collateralOutpoint != outpointMasternode) { - LogPrint(BCLog::INSTANTSEND, "CTxLockVote::IsValid -- invalid masternodeProTxHash %s\n", masternodeProTxHash.ToString()); - return false; - } - } else { - LogPrint(BCLog::INSTANTSEND, "CTxLockVote::IsValid -- missing masternodeProTxHash\n"); - return false; - } - - Coin coin; - if (!GetUTXOCoin(outpoint, coin)) { - LogPrint(BCLog::INSTANTSEND, "CTxLockVote::IsValid -- Failed to find UTXO %s\n", outpoint.ToStringShort()); - return false; - } - - int nLockInputHeight = coin.nHeight + Params().GetConsensus().nInstantSendConfirmationsRequired - 2; - - int nRank; - uint256 expectedQuorumModifierHash; - if (!CMasternodeUtils::GetMasternodeRank(outpointMasternode, nRank, expectedQuorumModifierHash, nLockInputHeight)) { - //can be caused by past versions trying to vote with an invalid protocol - LogPrint(BCLog::INSTANTSEND, "CTxLockVote::IsValid -- Can't calculate rank for masternode %s\n", outpointMasternode.ToStringShort()); - return false; - } - if (!quorumModifierHash.IsNull()) { - if (quorumModifierHash != expectedQuorumModifierHash) { - LogPrint(BCLog::INSTANTSEND, "CTxLockVote::IsValid -- invalid quorumModifierHash %s, expected %s\n", quorumModifierHash.ToString(), expectedQuorumModifierHash.ToString()); - return false; - } - } else { - LogPrint(BCLog::INSTANTSEND, "CTxLockVote::IsValid -- missing quorumModifierHash\n"); - return false; - } - - LogPrint(BCLog::INSTANTSEND, "CTxLockVote::IsValid -- Masternode %s, rank=%d\n", outpointMasternode.ToStringShort(), nRank); - - int nSignaturesTotal = Params().GetConsensus().nInstantSendSigsTotal; - if (nRank > nSignaturesTotal) { - LogPrint(BCLog::INSTANTSEND, "CTxLockVote::IsValid -- Masternode %s is not in the top %d (%d), vote hash=%s\n", - outpointMasternode.ToStringShort(), nSignaturesTotal, nRank, GetHash().ToString()); - return false; - } - - if (!CheckSignature()) { - LogPrintf("CTxLockVote::IsValid -- Signature invalid\n"); - return false; - } - - return true; -} - -uint256 CTxLockVote::GetHash() const -{ - return SerializeHash(*this); -} - -uint256 CTxLockVote::GetSignatureHash() const -{ - return GetHash(); -} - -bool CTxLockVote::CheckSignature() const -{ - std::string strError; - - auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMN(masternodeProTxHash); - if (!dmn) { - LogPrintf("CTxLockVote::CheckSignature -- Unknown Masternode: masternode=%s\n", masternodeProTxHash.ToString()); - return false; - } - - uint256 hash = GetSignatureHash(); - - CBLSSignature sig; - sig.SetBuf(vchMasternodeSignature); - if (!sig.IsValid() || !sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), hash)) { - LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n"); - return false; - } - return true; -} - -bool CTxLockVote::Sign() -{ - - uint256 hash = GetSignatureHash(); - - CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash); - if (!sig.IsValid()) { - return false; - } - sig.GetBuf(vchMasternodeSignature); - return true; -} - -void CTxLockVote::Relay(CConnman& connman) const -{ - CInv inv(MSG_TXLOCK_VOTE, GetHash()); - CTxLockRequest request; - if (instantsend.GetTxLockRequest(txHash, request) && request) { - connman.RelayInvFiltered(inv, *request.tx); - } else { - connman.RelayInvFiltered(inv, txHash); - } -} - -bool CTxLockVote::IsExpired(int nHeight) const -{ - // Locks and votes expire nInstantSendKeepLock blocks after the block corresponding tx was included into. - return (nConfirmedHeight != -1) && (nHeight - nConfirmedHeight > Params().GetConsensus().nInstantSendKeepLock); -} - -bool CTxLockVote::IsTimedOut() const -{ - return GetTime() - nTimeCreated > INSTANTSEND_LOCK_TIMEOUT_SECONDS; -} - -bool CTxLockVote::IsFailed() const -{ - return (GetTime() - nTimeCreated > INSTANTSEND_FAILED_TIMEOUT_SECONDS) && !instantsend.IsLockedInstantSendTransaction(GetTxHash()); -} - -// -// COutPointLock -// - -bool COutPointLock::AddVote(const CTxLockVote& vote) -{ - return mapMasternodeVotes.emplace(vote.GetMasternodeOutpoint(), vote).second; -} - -std::vector COutPointLock::GetVotes() const -{ - std::vector vRet; - for (const auto& pair : mapMasternodeVotes) { - vRet.push_back(pair.second); - } - return vRet; -} - -bool COutPointLock::HasMasternodeVoted(const COutPoint& outpointMasternodeIn) const -{ - return mapMasternodeVotes.count(outpointMasternodeIn); -} - -bool COutPointLock::IsReady() const -{ - return !fAttacked && CountVotes() >= Params().GetConsensus().nInstantSendSigsRequired; -} - -void COutPointLock::Relay(CConnman& connman) const -{ - for (const auto& pair : mapMasternodeVotes) { - pair.second.Relay(connman); - } -} - -// -// CTxLockCandidate -// - -void CTxLockCandidate::AddOutPointLock(const COutPoint& outpoint) -{ - mapOutPointLocks.insert(std::make_pair(outpoint, COutPointLock(outpoint))); -} - -void CTxLockCandidate::MarkOutpointAsAttacked(const COutPoint& outpoint) -{ - std::map::iterator it = mapOutPointLocks.find(outpoint); - if (it != mapOutPointLocks.end()) - it->second.MarkAsAttacked(); -} - -bool CTxLockCandidate::AddVote(const CTxLockVote& vote) -{ - std::map::iterator it = mapOutPointLocks.find(vote.GetOutpoint()); - if (it == mapOutPointLocks.end()) return false; - return it->second.AddVote(vote); -} - -bool CTxLockCandidate::IsAllOutPointsReady() const -{ - if (mapOutPointLocks.empty()) return false; - - for (const auto& pair : mapOutPointLocks) { - if (!pair.second.IsReady()) return false; - } - return true; -} - -bool CTxLockCandidate::HasMasternodeVoted(const COutPoint& outpointIn, const COutPoint& outpointMasternodeIn) -{ - std::map::iterator it = mapOutPointLocks.find(outpointIn); - return it !=mapOutPointLocks.end() && it->second.HasMasternodeVoted(outpointMasternodeIn); -} - -int CTxLockCandidate::CountVotes() const -{ - // Note: do NOT use vote count to figure out if tx is locked, use IsAllOutPointsReady() instead - int nCountVotes = 0; - for (const auto& pair : mapOutPointLocks) { - nCountVotes += pair.second.CountVotes(); - } - return nCountVotes; -} - -bool CTxLockCandidate::IsExpired(int nHeight) const -{ - // Locks and votes expire nInstantSendKeepLock blocks after the block corresponding tx was included into. - return (nConfirmedHeight != -1) && (nHeight - nConfirmedHeight > Params().GetConsensus().nInstantSendKeepLock); -} - -bool CTxLockCandidate::IsTimedOut() const -{ - return GetTime() - nTimeCreated > INSTANTSEND_LOCK_TIMEOUT_SECONDS; -} - -void CTxLockCandidate::Relay(CConnman& connman) const -{ - connman.RelayTransaction(*txLockRequest.tx); - for (const auto& pair : mapOutPointLocks) { - pair.second.Relay(connman); - } -} diff --git a/src/instantsend.h b/src/instantsend.h deleted file mode 100644 index 49006ce4e2..0000000000 --- a/src/instantsend.h +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright (c) 2014-2019 The Dash Core developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef INSTANTX_H -#define INSTANTX_H - -#include "chain.h" -#include "net.h" -#include "primitives/transaction.h" - -#include "evo/deterministicmns.h" - -class CTxLockVote; -class COutPointLock; -class CTxLockRequest; -class CTxLockCandidate; -class CInstantSend; - -extern CInstantSend instantsend; - -/* - At 15 signatures, 1/2 of the masternode network can be owned by - one party without compromising the security of InstantSend - (1000/2150.0)**10 = 0.00047382219560689856 - (1000/2900.0)**10 = 2.3769498616783657e-05 - - ### getting 5 of 10 signatures w/ 1000 nodes of 2900 - (1000/2900.0)**5 = 0.004875397277841433 -*/ - -static const int MIN_INSTANTSEND_PROTO_VERSION = 70213; - -/// For how long we are going to accept votes/locks -/// after we saw the first one for a specific transaction -static const int INSTANTSEND_LOCK_TIMEOUT_SECONDS = 15; -/// For how long we are going to keep invalid votes and votes for failed lock attempts, -/// must be greater than INSTANTSEND_LOCK_TIMEOUT_SECONDS -static const int INSTANTSEND_FAILED_TIMEOUT_SECONDS = 60; - -extern bool fEnableInstantSend; - -/** - * Manages InstantSend. Processes lock requests, candidates, and votes. - */ -class CInstantSend -{ -public: - /// Automatic locks of "simple" transactions are only allowed - /// when mempool usage is lower than this threshold - static const double AUTO_IX_MEMPOOL_THRESHOLD; -private: - static const std::string SERIALIZATION_VERSION_STRING; - - // Keep track of current block height - int nCachedBlockHeight; - - // maps for AlreadyHave - std::map mapLockRequestAccepted; ///< Tx hash - Tx - std::map mapLockRequestRejected; ///< Tx hash - Tx - std::map mapTxLockVotes; ///< Vote hash - Vote - std::map mapTxLockVotesOrphan; ///< Vote hash - Vote - - std::map mapTxLockCandidates; ///< Tx hash - Lock candidate - - std::map > mapVotedOutpoints; ///< UTXO - Tx hash set - std::map mapLockedOutpoints; ///< UTXO - Tx hash - - /// Track masternodes who voted with no txlockrequest (for DOS protection) - std::map mapMasternodeOrphanVotes; ///< MN outpoint - Time - - bool CreateTxLockCandidate(const CTxLockRequest& txLockRequest); - void CreateEmptyTxLockCandidate(const uint256& txHash); - void Vote(CTxLockCandidate& txLockCandidate, CConnman& connman); - - /// Process consensus vote message - bool ProcessNewTxLockVote(CNode* pfrom, const CTxLockVote& vote, CConnman& connman); - - void UpdateVotedOutpoints(const CTxLockVote& vote, CTxLockCandidate& txLockCandidate); - bool ProcessOrphanTxLockVote(const CTxLockVote& vote); - void ProcessOrphanTxLockVotes(); - int64_t GetAverageMasternodeOrphanVoteTime(); - - void TryToFinalizeLockCandidate(const CTxLockCandidate& txLockCandidate); - void LockTransactionInputs(const CTxLockCandidate& txLockCandidate); - /// Update UI and notify external script if any - void UpdateLockedTransaction(const CTxLockCandidate& txLockCandidate); - bool ResolveConflicts(const CTxLockCandidate& txLockCandidate); - -public: - mutable CCriticalSection cs_instantsend; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - std::string strVersion; - if(ser_action.ForRead()) { - READWRITE(strVersion); - } - else { - strVersion = SERIALIZATION_VERSION_STRING; - READWRITE(strVersion); - } - - READWRITE(mapLockRequestAccepted); - READWRITE(mapLockRequestRejected); - READWRITE(mapTxLockVotes); - READWRITE(mapTxLockVotesOrphan); - READWRITE(mapTxLockCandidates); - READWRITE(mapVotedOutpoints); - READWRITE(mapLockedOutpoints); - READWRITE(mapMasternodeOrphanVotes); - READWRITE(nCachedBlockHeight); - - if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) { - Clear(); - } - } - - void Clear(); - - void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); - - bool ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CConnman& connman); - void Vote(const uint256& txHash, CConnman& connman); - - bool AlreadyHave(const uint256& hash); - - void AcceptLockRequest(const CTxLockRequest& txLockRequest); - void RejectLockRequest(const CTxLockRequest& txLockRequest); - bool HasTxLockRequest(const uint256& txHash); - bool GetTxLockRequest(const uint256& txHash, CTxLockRequest& txLockRequestRet); - - bool GetTxLockVote(const uint256& hash, CTxLockVote& txLockVoteRet); - - bool GetLockedOutPointTxHash(const COutPoint& outpoint, uint256& hashRet); - - /// Verify if transaction is currently locked - bool IsLockedInstantSendTransaction(const uint256& txHash); - /// Get the actual number of accepted lock signatures - int GetTransactionLockSignatures(const uint256& txHash); - - /// Remove expired entries from maps - void CheckAndRemove(); - /// Verify if transaction lock timed out - bool IsTxLockCandidateTimedOut(const uint256& txHash); - - void Relay(const uint256& txHash, CConnman& connman); - - void UpdatedBlockTip(const CBlockIndex *pindex); - void SyncTransaction(const CTransactionRef& tx, const CBlockIndex* pindex = nullptr, int posInBlock = 0); - - std::string ToString() const; - - void DoMaintenance(); - - /// checks if we can automatically lock "simple" transactions - static bool CanAutoLock(); - - /// flag of the AutoLock Bip9 activation - static std::atomic isAutoLockBip9Active; -}; - -/** - * An InstantSend transaction lock request. - */ -class CTxLockRequest -{ -private: - static const CAmount MIN_FEE = 0.0001 * COIN; - /// If transaction has less or equal inputs than MAX_INPUTS_FOR_AUTO_IX, - /// it will be automatically locked - static const int MAX_INPUTS_FOR_AUTO_IX = 4; - -public: - /// Warn for a large number of inputs to an IS tx - fees could be substantial - /// and the number txlvote responses requested large (10 * # of inputs) - static const int WARN_MANY_INPUTS = 100; - - CTransactionRef tx; - - CTxLockRequest() : tx(MakeTransactionRef()) {} - CTxLockRequest(const CTransaction& _tx) : tx(MakeTransactionRef(_tx)) {}; - CTxLockRequest(const CTransactionRef& _tx) : tx(_tx) {}; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(tx); - } - - bool IsValid() const; - CAmount GetMinFee(bool fForceMinFee) const; - int GetMaxSignatures() const; - - // checks if related transaction is "simple" to lock it automatically - bool IsSimple() const; - - const uint256 &GetHash() const { - return tx->GetHash(); - } - - std::string ToString() const { - return tx->ToString(); - } - - friend bool operator==(const CTxLockRequest& a, const CTxLockRequest& b) - { - return *a.tx == *b.tx; - } - - friend bool operator!=(const CTxLockRequest& a, const CTxLockRequest& b) - { - return *a.tx != *b.tx; - } - - explicit operator bool() const - { - return *this != CTxLockRequest(); - } -}; - -/** - * An InstantSend transaction lock vote. Sent by a masternode in response to a - * transaction lock request (ix message) to indicate the transaction input can - * be locked. Contains the proposed transaction's hash and the outpoint being - * locked along with the masternodes outpoint and signature. - * @see CTxLockRequest - */ -class CTxLockVote -{ -private: - uint256 txHash; - COutPoint outpoint; - // TODO remove this member (not needed anymore after DIP3 has been deployed) - COutPoint outpointMasternode; - uint256 quorumModifierHash; - uint256 masternodeProTxHash; - std::vector vchMasternodeSignature; - // local memory only - int nConfirmedHeight; ///< When corresponding tx is 0-confirmed or conflicted, nConfirmedHeight is -1 - int64_t nTimeCreated; - -public: - CTxLockVote() : - txHash(), - outpoint(), - outpointMasternode(), - quorumModifierHash(), - masternodeProTxHash(), - vchMasternodeSignature(), - nConfirmedHeight(-1), - nTimeCreated(GetTime()) - {} - - CTxLockVote(const uint256& txHashIn, const COutPoint& outpointIn, const COutPoint& outpointMasternodeIn, const uint256& quorumModifierHashIn, const uint256& masternodeProTxHashIn) : - txHash(txHashIn), - outpoint(outpointIn), - outpointMasternode(outpointMasternodeIn), - quorumModifierHash(quorumModifierHashIn), - masternodeProTxHash(masternodeProTxHashIn), - vchMasternodeSignature(), - nConfirmedHeight(-1), - nTimeCreated(GetTime()) - {} - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(txHash); - READWRITE(outpoint); - READWRITE(outpointMasternode); - READWRITE(quorumModifierHash); - READWRITE(masternodeProTxHash); - if (!(s.GetType() & SER_GETHASH)) { - READWRITE(vchMasternodeSignature); - } - } - - uint256 GetHash() const; - uint256 GetSignatureHash() const; - - uint256 GetTxHash() const { return txHash; } - COutPoint GetOutpoint() const { return outpoint; } - COutPoint GetMasternodeOutpoint() const { return outpointMasternode; } - - bool IsValid(CNode* pnode, CConnman& connman) const; - void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; } - bool IsExpired(int nHeight) const; - bool IsTimedOut() const; - bool IsFailed() const; - - bool Sign(); - bool CheckSignature() const; - - void Relay(CConnman& connman) const; -}; - -/** - * An InstantSend OutpointLock. - */ -class COutPointLock -{ -private: - COutPoint outpoint; ///< UTXO - std::map mapMasternodeVotes; ///< Masternode outpoint - vote - bool fAttacked = false; - -public: - COutPointLock() {} - - COutPointLock(const COutPoint& outpointIn) : - outpoint(outpointIn), - mapMasternodeVotes() - {} - - COutPoint GetOutpoint() const { return outpoint; } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(outpoint); - READWRITE(mapMasternodeVotes); - READWRITE(fAttacked); - } - - bool AddVote(const CTxLockVote& vote); - std::vector GetVotes() const; - bool HasMasternodeVoted(const COutPoint& outpointMasternodeIn) const; - int CountVotes() const { return fAttacked ? 0 : mapMasternodeVotes.size(); } - bool IsReady() const; - void MarkAsAttacked() { fAttacked = true; } - - void Relay(CConnman& connman) const; -}; - -/** - * An InstantSend transaction lock candidate. - */ -class CTxLockCandidate -{ -private: - int nConfirmedHeight; /// mapOutPointLocks; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(txLockRequest); - READWRITE(mapOutPointLocks); - READWRITE(nTimeCreated); - READWRITE(nConfirmedHeight); - } - - uint256 GetHash() const { return txLockRequest.GetHash(); } - - void AddOutPointLock(const COutPoint& outpoint); - void MarkOutpointAsAttacked(const COutPoint& outpoint); - bool AddVote(const CTxLockVote& vote); - bool IsAllOutPointsReady() const; - - bool HasMasternodeVoted(const COutPoint& outpointIn, const COutPoint& outpointMasternodeIn); - int CountVotes() const; - - void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; } - bool IsExpired(int nHeight) const; - bool IsTimedOut() const; - - void Relay(CConnman& connman) const; -}; - -#endif diff --git a/src/llmq/quorums_chainlocks.cpp b/src/llmq/quorums_chainlocks.cpp index 5a8a37b9a1..bbb106d37a 100644 --- a/src/llmq/quorums_chainlocks.cpp +++ b/src/llmq/quorums_chainlocks.cpp @@ -286,7 +286,7 @@ void CChainLocksHandler::TrySignChainTip() // considered safe when it is ixlocked or at least known since 10 minutes (from mempool or block). These checks are // performed for the tip (which we try to sign) and the previous 5 blocks. If a ChainLocked block is found on the // way down, we consider all TXs to be safe. - if (IsNewInstantSendEnabled() && sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) { + if (IsInstantSendEnabled() && sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) { auto pindexWalk = pindex; while (pindexWalk) { if (pindex->nHeight - pindexWalk->nHeight > 5) { @@ -453,7 +453,7 @@ bool CChainLocksHandler::IsTxSafeForMining(const uint256& txid) if (!sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) { return true; } - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return true; } diff --git a/src/llmq/quorums_instantsend.cpp b/src/llmq/quorums_instantsend.cpp index 3b20bcd0fd..6aee659c11 100644 --- a/src/llmq/quorums_instantsend.cpp +++ b/src/llmq/quorums_instantsend.cpp @@ -19,9 +19,6 @@ #include "wallet/wallet.h" #endif -// needed for AUTO_IX_MEMPOOL_THRESHOLD -#include "instantsend.h" - #include #include @@ -383,7 +380,7 @@ void CInstantSendManager::InterruptWorkerThread() bool CInstantSendManager::ProcessTx(const CTransaction& tx, const Consensus::Params& params) { - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return true; } @@ -466,10 +463,6 @@ bool CInstantSendManager::ProcessTx(const CTransaction& tx, const Consensus::Par bool CInstantSendManager::CheckCanLock(const CTransaction& tx, bool printDebug, const Consensus::Params& params) { - if (sporkManager.IsSporkActive(SPORK_16_INSTANTSEND_AUTOLOCKS) && (mempool.UsedMemoryShare() > CInstantSend::AUTO_IX_MEMPOOL_THRESHOLD)) { - return false; - } - if (tx.vin.empty()) { // can't lock TXs without inputs (e.g. quorum commitments) return false; @@ -485,18 +478,6 @@ bool CInstantSendManager::CheckCanLock(const CTransaction& tx, bool printDebug, nValueIn += v; } - // TODO decide if we should limit max input values. This was ok to do in the old system, but in the new system - // where we want to have all TXs locked at some point, this is counterproductive (especially when ChainLocks later - // depend on all TXs being locked first) -// CAmount maxValueIn = sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE); -// if (nValueIn > maxValueIn * COIN) { -// if (printDebug) { -// LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s: TX input value too high. nValueIn=%f, maxValueIn=%d", __func__, -// tx.GetHash().ToString(), nValueIn / (double)COIN, maxValueIn); -// } -// return false; -// } - return true; } @@ -556,7 +537,7 @@ bool CInstantSendManager::CheckCanLock(const COutPoint& outpoint, bool printDebu void CInstantSendManager::HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) { - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return; } @@ -674,7 +655,7 @@ void CInstantSendManager::HandleNewInstantSendLockRecoveredSig(const llmq::CReco void CInstantSendManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) { - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return; } @@ -747,7 +728,7 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks() return false; } - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return false; } @@ -936,7 +917,7 @@ void CInstantSendManager::UpdateWalletTransaction(const CTransactionRef& tx, con void CInstantSendManager::ProcessNewTransaction(const CTransactionRef& tx, const CBlockIndex* pindex) { - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return; } @@ -985,7 +966,7 @@ void CInstantSendManager::TransactionAddedToMempool(const CTransactionRef& tx) void CInstantSendManager::BlockConnected(const std::shared_ptr& pblock, const CBlockIndex* pindex, const std::vector& vtxConflicted) { - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return; } @@ -1323,7 +1304,7 @@ bool CInstantSendManager::ProcessPendingRetryLockTxs() return false; } - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return false; } @@ -1380,7 +1361,7 @@ bool CInstantSendManager::ProcessPendingRetryLockTxs() bool CInstantSendManager::AlreadyHave(const CInv& inv) { - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return true; } @@ -1390,7 +1371,7 @@ bool CInstantSendManager::AlreadyHave(const CInv& inv) bool CInstantSendManager::GetInstantSendLockByHash(const uint256& hash, llmq::CInstantSendLock& ret) { - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return false; } @@ -1405,7 +1386,7 @@ bool CInstantSendManager::GetInstantSendLockByHash(const uint256& hash, llmq::CI bool CInstantSendManager::IsLocked(const uint256& txHash) { - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return false; } @@ -1420,7 +1401,7 @@ bool CInstantSendManager::IsConflicted(const CTransaction& tx) CInstantSendLockPtr CInstantSendManager::GetConflictingLock(const CTransaction& tx) { - if (!IsNewInstantSendEnabled()) { + if (!IsInstantSendEnabled()) { return nullptr; } @@ -1459,16 +1440,6 @@ void CInstantSendManager::WorkThreadMain() } } -bool IsOldInstantSendEnabled() -{ - return sporkManager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED) && !sporkManager.IsSporkActive(SPORK_20_INSTANTSEND_LLMQ_BASED); -} - -bool IsNewInstantSendEnabled() -{ - return sporkManager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED) && sporkManager.IsSporkActive(SPORK_20_INSTANTSEND_LLMQ_BASED); -} - bool IsInstantSendEnabled() { return sporkManager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED); diff --git a/src/llmq/quorums_instantsend.h b/src/llmq/quorums_instantsend.h index 4ba1e3a678..0be4e47b6c 100644 --- a/src/llmq/quorums_instantsend.h +++ b/src/llmq/quorums_instantsend.h @@ -170,13 +170,6 @@ public: extern CInstantSendManager* quorumInstantSendManager; -// This involves 2 sporks: SPORK_2_INSTANTSEND_ENABLED and SPORK_20_INSTANTSEND_LLMQ_BASED -// SPORK_2_INSTANTSEND_ENABLED generally enables/disables InstantSend and SPORK_20_INSTANTSEND_LLMQ_BASED switches -// between the old and the new (LLMQ based) system -// TODO When the new system is fully deployed and enabled, we can remove this special handling in a future version -// and revert to only using SPORK_2_INSTANTSEND_ENABLED. -bool IsOldInstantSendEnabled(); -bool IsNewInstantSendEnabled(); bool IsInstantSendEnabled(); } diff --git a/src/net.cpp b/src/net.cpp index 7a09e54672..8a8e94a17f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -25,10 +25,9 @@ #include "utilstrencodings.h" #include "validation.h" -#include "instantsend.h" #include "masternode/masternode-sync.h" #include "privatesend/privatesend.h" -#include "llmq/quorums_instantsend.h" +#include "evo/deterministicmns.h" #ifdef WIN32 #include @@ -2892,21 +2891,11 @@ void CConnman::RelayTransaction(const CTransaction& tx) int nInv = MSG_TX; if (CPrivateSend::GetDSTX(hash)) { nInv = MSG_DSTX; - } else if (llmq::IsOldInstantSendEnabled() && instantsend.HasTxLockRequest(hash)) { - nInv = MSG_TXLOCK_REQUEST; } CInv inv(nInv, hash); LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { - if (nInv == MSG_TXLOCK_REQUEST) { - // Additional filtering for lock requests. - // Make it here because lock request processing - // differs from simple tx processing in PushInventory - // and tx info will not be available there. - LOCK(pnode->cs_filter); - if(pnode->pfilter && !pnode->pfilter->IsRelevantAndUpdate(tx)) continue; - } pnode->PushInventory(inv); } } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 5bd7897033..da1c2232c7 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -32,7 +32,6 @@ #include "spork.h" #include "governance/governance.h" -#include "instantsend.h" #include "masternode/masternode-payments.h" #include "masternode/masternode-sync.h" #include "masternode/masternode-meta.h" @@ -954,6 +953,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) switch (inv.type) { case MSG_TX: + case MSG_LEGACY_TXLOCK_REQUEST: // we treat legacy IX messages as TX messages { assert(recentRejects); if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip) @@ -989,11 +989,6 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) We're going to be asking many nodes upfront for the full inventory list, so we'll get duplicates of these. We want to only update the time on new hits, so that we can time out appropriately if needed. */ - case MSG_TXLOCK_REQUEST: - return instantsend.AlreadyHave(inv.hash); - - case MSG_TXLOCK_VOTE: - return instantsend.AlreadyHave(inv.hash); case MSG_SPORK: { @@ -1215,8 +1210,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // Send stream from relay memory bool push = false; - // Only serve MSG_TX from mapRelay. - // Otherwise we may send out a normal TX instead of a IX if (inv.type == MSG_TX) { auto mi = mapRelay.find(inv.hash); if (mi != mapRelay.end()) { @@ -1233,22 +1226,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } } - if (!push && inv.type == MSG_TXLOCK_REQUEST) { - CTxLockRequest txLockRequest; - if(instantsend.GetTxLockRequest(inv.hash, txLockRequest)) { - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::TXLOCKREQUEST, txLockRequest)); - push = true; - } - } - - if (!push && inv.type == MSG_TXLOCK_VOTE) { - CTxLockVote vote; - if(instantsend.GetTxLockVote(inv.hash, vote)) { - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::TXLOCKVOTE, vote)); - push = true; - } - } - if (!push && inv.type == MSG_SPORK) { CSporkMessage spork; if(sporkManager.GetSporkByHash(inv.hash, spork)) { @@ -2087,7 +2064,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } - else if (strCommand == NetMsgType::TX || strCommand == NetMsgType::DSTX || strCommand == NetMsgType::TXLOCKREQUEST) + else if (strCommand == NetMsgType::TX || strCommand == NetMsgType::DSTX || strCommand == NetMsgType::LEGACYTXLOCKREQUEST) { // Stop processing the transaction early if // We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off @@ -2100,25 +2077,15 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr std::deque vWorkQueue; std::vector vEraseQueue; CTransactionRef ptx; - CTxLockRequest txLockRequest; CPrivateSendBroadcastTx dstx; int nInvType = MSG_TX; - bool fCanAutoLock = false; // Read data and assign inv type if(strCommand == NetMsgType::TX) { vRecv >> ptx; - txLockRequest = CTxLockRequest(ptx); - fCanAutoLock = llmq::IsOldInstantSendEnabled() && CInstantSend::CanAutoLock() && txLockRequest.IsSimple(); - } else if(strCommand == NetMsgType::TXLOCKREQUEST) { - vRecv >> txLockRequest; - ptx = txLockRequest.tx; - nInvType = MSG_TXLOCK_REQUEST; - if (llmq::IsNewInstantSendEnabled()) { - // the new system does not require explicit lock requests - // changing the inv type to MSG_TX also results in re-broadcasting the TX as normal TX - nInvType = MSG_TX; - } + } else if(strCommand == NetMsgType::LEGACYTXLOCKREQUEST) { + // we keep processing the legacy IX message here but revert to handling it as a regular TX + vRecv >> ptx; } else if (strCommand == NetMsgType::DSTX) { vRecv >> dstx; ptx = dstx.tx; @@ -2134,18 +2101,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } // Process custom logic, no matter if tx will be accepted to mempool later or not - if (nInvType == MSG_TXLOCK_REQUEST || fCanAutoLock) { - if(!instantsend.ProcessTxLockRequest(txLockRequest, connman)) { - LogPrint(BCLog::INSTANTSEND, "TXLOCKREQUEST -- failed %s\n", txLockRequest.GetHash().ToString()); - // Should not really happen for "fCanAutoLock == true" but just in case: - if (!fCanAutoLock) { - // Fail only for "true" IS here - return false; - } - // Fallback for normal txes to process as usual - fCanAutoLock = false; - } - } else if (nInvType == MSG_DSTX) { + if (nInvType == MSG_DSTX) { uint256 hashTx = tx.GetHash(); if (!dstx.IsValidStructure()) { LogPrint(BCLog::PRIVATESEND, "DSTX -- Invalid DSTX structure: %s\n", hashTx.ToString()); @@ -2190,11 +2146,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LogPrintf("DSTX -- Masternode transaction accepted, txid=%s, peer=%d\n", tx.GetHash().ToString(), pfrom->GetId()); CPrivateSend::AddDSTX(dstx); - } else if (nInvType == MSG_TXLOCK_REQUEST || fCanAutoLock) { - LogPrintf("TXLOCKREQUEST -- Transaction Lock Request accepted, txid=%s, peer=%d\n", - tx.GetHash().ToString(), pfrom->GetId()); - instantsend.AcceptLockRequest(txLockRequest); - instantsend.Vote(tx.GetHash(), connman); } mempool.check(pcoinsTip); @@ -2306,19 +2257,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } } - if (nInvType == MSG_TXLOCK_REQUEST && !AlreadyHave(inv)) { - // i.e. AcceptToMemoryPool failed, probably because it's conflicting - // with existing normal tx or tx lock for another tx. For the same tx lock - // AlreadyHave would have return "true" already. - - // It's the first time we failed for this tx lock request, - // this should switch AlreadyHave to "true". - instantsend.RejectLockRequest(txLockRequest); - // this lets other nodes to create lock request candidate i.e. - // this allows multiple conflicting lock requests to compete for votes - connman.RelayTransaction(tx); - } - if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { // Always relay transactions received from whitelisted peers, even // if they were already in the mempool or rejected from it due @@ -3020,7 +2958,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr privateSendClient.ProcessMessage(pfrom, strCommand, vRecv, connman); #endif // ENABLE_WALLET privateSendServer.ProcessMessage(pfrom, strCommand, vRecv, connman); - instantsend.ProcessMessage(pfrom, strCommand, vRecv, connman); sporkManager.ProcessSpork(pfrom, strCommand, vRecv, connman); masternodeSync.ProcessMessage(pfrom, strCommand, vRecv); governance.ProcessMessage(pfrom, strCommand, vRecv, connman); diff --git a/src/protocol.cpp b/src/protocol.cpp index 3449b54f80..0e519a4b6a 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -39,8 +39,7 @@ const char *CMPCTBLOCK="cmpctblock"; const char *GETBLOCKTXN="getblocktxn"; const char *BLOCKTXN="blocktxn"; // Dash message types -const char *TXLOCKREQUEST="ix"; -const char *TXLOCKVOTE="txlvote"; +const char *LEGACYTXLOCKREQUEST="ix"; const char *SPORK="spork"; const char *GETSPORKS="getsporks"; const char *DSACCEPT="dsa"; @@ -75,43 +74,6 @@ const char *ISLOCK="islock"; const char *MNAUTH="mnauth"; }; -static const char* ppszTypeName[] = -{ - "ERROR", // Should never occur - NetMsgType::TX, - NetMsgType::BLOCK, - "filtered block", // Should never occur - // Dash message types - // NOTE: include non-implmented here, we must keep this list in sync with enum in protocol.h - NetMsgType::TXLOCKREQUEST, - NetMsgType::TXLOCKVOTE, - NetMsgType::SPORK, - "unused inv type 7", - "unused inv type 8", - "unused inv type 9", - "unused inv type 10", - "unused inv type 11", - "unused inv type 12", - "unused inv type 13", - "unused inv type 14", - "unused inv type 15", - NetMsgType::DSTX, - NetMsgType::MNGOVERNANCEOBJECT, - NetMsgType::MNGOVERNANCEOBJECTVOTE, - "unused inv type 19", - "compact block", // Should never occur - NetMsgType::QFCOMMITMENT, - "qdcommit", // was only shortly used on testnet - NetMsgType::QCONTRIB, - NetMsgType::QCOMPLAINT, - NetMsgType::QJUSTIFICATION, - NetMsgType::QPCOMMITMENT, - "qdebugstatus", // was only shortly used on testnet - NetMsgType::QSIGREC, - NetMsgType::CLSIG, - NetMsgType::ISLOCK, -}; - /** All known message types. Keep this in the same order as the list of * messages above and in protocol.h. */ @@ -143,8 +105,7 @@ const static std::string allNetMessageTypes[] = { NetMsgType::BLOCKTXN, // Dash message types // NOTE: do NOT include non-implmented here, we want them to be "Unknown command" in ProcessMessage() - NetMsgType::TXLOCKREQUEST, - NetMsgType::TXLOCKVOTE, + NetMsgType::LEGACYTXLOCKREQUEST, NetMsgType::SPORK, NetMsgType::GETSPORKS, NetMsgType::SENDDSQUEUE, @@ -259,22 +220,6 @@ CInv::CInv() CInv::CInv(int typeIn, const uint256& hashIn) : type(typeIn), hash(hashIn) {} -CInv::CInv(const std::string& strType, const uint256& hashIn) -{ - unsigned int i; - for (i = 1; i < ARRAYLEN(ppszTypeName); i++) - { - if (strType == ppszTypeName[i]) - { - type = i; - break; - } - } - if (i == ARRAYLEN(ppszTypeName)) - throw std::out_of_range(strprintf("CInv::CInv(string, uint256): unknown type '%s'", strType)); - hash = hashIn; -} - bool operator<(const CInv& a, const CInv& b) { return (a.type < b.type || (a.type == b.type && a.hash < b.hash)); @@ -282,22 +227,51 @@ bool operator<(const CInv& a, const CInv& b) bool CInv::IsKnownType() const { - return (type >= 1 && type < (int)ARRAYLEN(ppszTypeName)); + return GetCommandInternal() != nullptr; } -const char* CInv::GetCommand() const +const char* CInv::GetCommandInternal() const { - if (!IsKnownType()) + switch (type) + { + case MSG_TX: return NetMsgType::TX; + case MSG_BLOCK: return NetMsgType::BLOCK; + case MSG_FILTERED_BLOCK: return NetMsgType::MERKLEBLOCK; + case MSG_LEGACY_TXLOCK_REQUEST: return NetMsgType::LEGACYTXLOCKREQUEST; + case MSG_CMPCT_BLOCK: return NetMsgType::CMPCTBLOCK; + case MSG_SPORK: return NetMsgType::SPORK; + case MSG_DSTX: return NetMsgType::DSTX; + case MSG_GOVERNANCE_OBJECT: return NetMsgType::MNGOVERNANCEOBJECT; + case MSG_GOVERNANCE_OBJECT_VOTE: return NetMsgType::MNGOVERNANCEOBJECTVOTE; + case MSG_QUORUM_FINAL_COMMITMENT: return NetMsgType::QFCOMMITMENT; + case MSG_QUORUM_CONTRIB: return NetMsgType::QCONTRIB; + case MSG_QUORUM_COMPLAINT: return NetMsgType::QCOMPLAINT; + case MSG_QUORUM_JUSTIFICATION: return NetMsgType::QJUSTIFICATION; + case MSG_QUORUM_PREMATURE_COMMITMENT: return NetMsgType::QPCOMMITMENT; + case MSG_QUORUM_RECOVERED_SIG: return NetMsgType::QSIGREC; + case MSG_CLSIG: return NetMsgType::CLSIG; + case MSG_ISLOCK: return NetMsgType::ISLOCK; + default: + return nullptr; + } +} + +std::string CInv::GetCommand() const +{ + auto cmd = GetCommandInternal(); + if (cmd == nullptr) { throw std::out_of_range(strprintf("CInv::GetCommand(): type=%d unknown type", type)); - return ppszTypeName[type]; + } + return cmd; } std::string CInv::ToString() const { - try { - return strprintf("%s %s", GetCommand(), hash.ToString()); - } catch(const std::out_of_range &) { + auto cmd = GetCommandInternal(); + if (!cmd) { return strprintf("0x%08x %s", type, hash.ToString()); + } else { + return strprintf("%s %s", cmd, hash.ToString()); } } diff --git a/src/protocol.h b/src/protocol.h index bce6790c66..9f363fe058 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -239,8 +239,7 @@ extern const char *BLOCKTXN; // Dash message types // NOTE: do NOT declare non-implmented here, we don't want them to be exposed to the outside // TODO: add description -extern const char *TXLOCKREQUEST; -extern const char *TXLOCKVOTE; +extern const char *LEGACYTXLOCKREQUEST; // only present for backwards compatibility extern const char *SPORK; extern const char *GETSPORKS; extern const char *DSACCEPT; @@ -355,8 +354,8 @@ enum GetDataMsg { MSG_FILTERED_BLOCK = 3, //!< Defined in BIP37 // Dash message types // NOTE: declare non-implmented here, we must keep this enum consistent and backwards compatible - MSG_TXLOCK_REQUEST = 4, - MSG_TXLOCK_VOTE = 5, + MSG_LEGACY_TXLOCK_REQUEST = 4, + /* MSG_TXLOCK_VOTE = 5, Legacy InstantSend and not used anymore */ MSG_SPORK = 6, /* 7 - 15 were used in old Dash versions and were mainly budget and MN broadcast/ping related*/ MSG_DSTX = 16, @@ -384,7 +383,6 @@ class CInv public: CInv(); CInv(int typeIn, const uint256& hashIn); - CInv(const std::string& strType, const uint256& hashIn); ADD_SERIALIZE_METHODS; @@ -398,9 +396,12 @@ public: friend bool operator<(const CInv& a, const CInv& b); bool IsKnownType() const; - const char* GetCommand() const; + std::string GetCommand() const; std::string ToString() const; +private: + const char* GetCommandInternal() const; + // TODO: make private (improves encapsulation) public: int type; diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index ab8ee15376..f6c47e025f 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -21,7 +21,6 @@ #include "validation.h" // For mempool #include "wallet/wallet.h" -#include "instantsend.h" #include "privatesend/privatesend-client.h" #include @@ -536,10 +535,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) nBytesInputs += 148; // in all error cases, simply assume 148 here } else nBytesInputs += 148; - - // Add inputs to calculate InstantSend Fee later - if(coinControl->fUseInstantSend) - txDummy.vin.push_back(CTxIn()); } // calculation @@ -556,9 +551,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // Fee nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, ::mempool, ::feeEstimator); - // InstantSend Fee - if (coinControl->fUseInstantSend) nPayFee = std::max(nPayFee, CTxLockRequest(txDummy).GetMinFee(true)); - if (nPayAmount > 0) { nChange = nAmount - nPayAmount; diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui index 83909a0596..cc19bb2125 100644 --- a/src/qt/forms/receivecoinsdialog.ui +++ b/src/qt/forms/receivecoinsdialog.ui @@ -127,7 +127,7 @@ - + @@ -176,23 +176,13 @@ - + - - - - Request InstantSend - - - true - - - diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 45953e7a22..2510135444 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -1278,22 +1278,6 @@ - - - - true - - - - 85 - 0 - - - - InstantSend - - - diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 9fca533cf1..5a75c7ea0c 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -165,7 +165,6 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out) QList > items = uriQuery.queryItems(); #endif - rv.fUseInstantSend = false; for (QList >::iterator i = items.begin(); i != items.end(); i++) { bool fShouldReturnFalse = false; @@ -182,9 +181,7 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out) } if (i->first == "IS") { - if(i->second.compare(QString("1")) == 0) - rv.fUseInstantSend = true; - + // we simply ignore IS fShouldReturnFalse = false; } if (i->first == "message") @@ -253,12 +250,6 @@ QString formatBitcoinURI(const SendCoinsRecipient &info) paramCount++; } - if(info.fUseInstantSend) - { - ret += QString("%1IS=1").arg(paramCount == 0 ? "?" : "&"); - paramCount++; - } - return ret; } diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 9cbe884601..95c70218fb 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -18,7 +18,6 @@ #include "utilitydialog.h" #include "walletmodel.h" -#include "instantsend.h" #include "masternode/masternode-sync.h" #include "privatesend/privatesend-client.h" diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 1d087aec74..11a105cb56 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -157,7 +157,6 @@ void ReceiveCoinsDialog::on_receiveButton_clicked() } SendCoinsRecipient info(address, label, ui->reqAmount->value(), ui->reqMessage->text()); - info.fUseInstantSend = ui->checkUseInstantSend->isChecked(); ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setModel(model->getOptionsModel()); diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 25461f1bab..b9fcc0198f 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -149,7 +149,6 @@ void ReceiveRequestDialog::update() html += ""+tr("Label")+": " + GUIUtil::HtmlEscape(info.label) + "
"; if(!info.message.isEmpty()) html += ""+tr("Message")+": " + GUIUtil::HtmlEscape(info.message) + "
"; - html += ""+tr("InstantSend")+": " + (info.fUseInstantSend ? tr("Yes") : tr("No")) + "
"; ui->outUri->setText(html); #ifdef USE_QRCODE diff --git a/src/qt/res/css/crownium.css b/src/qt/res/css/crownium.css index e05fd4d24e..126ea85f79 100644 --- a/src/qt/res/css/crownium.css +++ b/src/qt/res/css/crownium.css @@ -1288,16 +1288,6 @@ background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 border-radius:5px; padding-top:20px; padding-bottom:18px; -} - -QDialog#SendCoinsDialog .QCheckBox#checkUseInstantSend { /* InstantSend Checkbox */ -color:#555555; -font-weight:bold; -background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 rgba(248, 246, 246, 128), stop: 1 rgba(0, 0, 0, 0)); -border-radius:5px; -padding-top:20px; -padding-bottom:18px; -margin-left:10px; margin-right:20px; } diff --git a/src/qt/res/css/drkblue.css b/src/qt/res/css/drkblue.css index 7df96e7160..1c412fafb1 100644 --- a/src/qt/res/css/drkblue.css +++ b/src/qt/res/css/drkblue.css @@ -1272,16 +1272,6 @@ background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 border-radius:5px; padding-top:20px; padding-bottom:18px; -} - -QDialog#SendCoinsDialog .QCheckBox#checkUseInstantSend { /* InstantSend Checkbox */ -color:#616161; -font-weight:bold; -background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 rgba(248, 246, 246, 128), stop: 1 rgba(0, 0, 0, 0)); -border-radius:5px; -padding-top:20px; -padding-bottom:18px; -margin-left:10px; margin-right:20px; } diff --git a/src/qt/res/css/light-hires-retro.css b/src/qt/res/css/light-hires-retro.css index 7e3925bd87..fa0b157f00 100644 --- a/src/qt/res/css/light-hires-retro.css +++ b/src/qt/res/css/light-hires-retro.css @@ -1278,16 +1278,6 @@ background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 border-radius:5px; padding-top:20px; padding-bottom:18px; -} - -QDialog#SendCoinsDialog .QCheckBox#checkUseInstantSend { /* InstantSend Checkbox */ -color:#616161; -font-weight:bold; -background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 rgba(248, 246, 246, 128), stop: 1 rgba(0, 0, 0, 0)); -border-radius:5px; -padding-top:20px; -padding-bottom:18px; -margin-left:10px; margin-right:20px; } diff --git a/src/qt/res/css/light-hires.css b/src/qt/res/css/light-hires.css index c049e3957e..253394c880 100644 --- a/src/qt/res/css/light-hires.css +++ b/src/qt/res/css/light-hires.css @@ -1278,16 +1278,6 @@ background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 border-radius:5px; padding-top:20px; padding-bottom:18px; -} - -QDialog#SendCoinsDialog .QCheckBox#checkUseInstantSend { /* InstantSend Checkbox */ -color:#616161; -font-weight:bold; -background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 rgba(248, 246, 246, 128), stop: 1 rgba(0, 0, 0, 0)); -border-radius:5px; -padding-top:20px; -padding-bottom:18px; -margin-left:10px; margin-right:20px; } diff --git a/src/qt/res/css/light-retro.css b/src/qt/res/css/light-retro.css index b3b9769aa9..e7bac102f2 100644 --- a/src/qt/res/css/light-retro.css +++ b/src/qt/res/css/light-retro.css @@ -1279,16 +1279,6 @@ background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 border-radius:5px; padding-top:20px; padding-bottom:18px; -} - -QDialog#SendCoinsDialog .QCheckBox#checkUseInstantSend { /* InstantSend Checkbox */ -color:#616161; -font-weight:bold; -background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 rgba(248, 246, 246, 128), stop: 1 rgba(0, 0, 0, 0)); -border-radius:5px; -padding-top:20px; -padding-bottom:18px; -margin-left:10px; margin-right:20px; } diff --git a/src/qt/res/css/light.css b/src/qt/res/css/light.css index 2b92b8fd0c..2d88feb277 100644 --- a/src/qt/res/css/light.css +++ b/src/qt/res/css/light.css @@ -1279,16 +1279,6 @@ background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 border-radius:5px; padding-top:20px; padding-bottom:18px; -} - -QDialog#SendCoinsDialog .QCheckBox#checkUseInstantSend { /* InstantSend Checkbox */ -color:#616161; -font-weight:bold; -background: qradialgradient(cx:0.5, cy:0.5, radius: 0.5, fx:0.5, fy:0.5, stop:0 rgba(248, 246, 246, 128), stop: 1 rgba(0, 0, 0, 0)); -border-radius:5px; -padding-top:20px; -padding-bottom:18px; -margin-left:10px; margin-right:20px; } diff --git a/src/qt/res/css/trad.css b/src/qt/res/css/trad.css index 0937a3f007..52706cb402 100644 --- a/src/qt/res/css/trad.css +++ b/src/qt/res/css/trad.css @@ -11,11 +11,6 @@ QWidget#contentWidget { /* The actual content with the text/buttons/etc... */ /* SEND DIALOG */ -QDialog#SendCoinsDialog .QCheckBox#checkUseInstantSend { /* InstantSend Checkbox */ -margin-left:10px; -margin-right:20px; -} - QDialog#SendCoinsDialog QLabel#labelBalance { margin-left:0px; padding-left:0px; diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index f4841446a8..bc9e571370 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -82,11 +82,11 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p //TODO remove InstantX sometime after 0.14.1 if (settings.contains("bUseInstantX")) { - settings.setValue("bUseInstantSend", settings.value("bUseInstantX").toBool()); settings.remove("bUseInstantX"); } - if (!settings.contains("bUseInstantSend")) - settings.setValue("bUseInstantSend", false); + if (settings.contains("bUseInstantSend")) { + settings.remove("bUseInstantSend"); + } if (!privateSendClient.fEnablePrivateSend) { ui->checkUsePrivateSend->setChecked(false); @@ -99,17 +99,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p connect(ui->checkUsePrivateSend, SIGNAL(stateChanged ( int )), this, SLOT(updateDisplayUnit())); } - if (fLiteMode) { - ui->checkUseInstantSend->setChecked(false); - ui->checkUseInstantSend->setVisible(false); - CoinControlDialog::coinControl->fUseInstantSend = false; - } else{ - bool fUseInstantSend = settings.value("bUseInstantSend").toBool(); - ui->checkUseInstantSend->setChecked(fUseInstantSend); - CoinControlDialog::coinControl->fUseInstantSend = fUseInstantSend; - connect(ui->checkUseInstantSend, SIGNAL(stateChanged ( int )), this, SLOT(updateInstantSend())); - } - // Coin Control: clipboard actions QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this); QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this); @@ -284,14 +273,8 @@ void SendCoinsDialog::on_sendButton_clicked() strFunds = tr("using") + " " + tr("any available funds (not anonymous)") + ""; } - if(model->IsOldInstantSendEnabled() && ui->checkUseInstantSend->isChecked()) { - strFunds += " "; - strFunds += tr("and InstantSend"); - } - for (SendCoinsRecipient& rcp : recipients) { rcp.inputType = ui->checkUsePrivateSend->isChecked() ? ONLY_DENOMINATED : ALL_COINS; - rcp.fUseInstantSend = model->IsOldInstantSendEnabled() && ui->checkUseInstantSend->isChecked(); } fNewRecipientAllowed = false; @@ -622,14 +605,6 @@ void SendCoinsDialog::updateDisplayUnit() updateSmartFeeLabel(); } -void SendCoinsDialog::updateInstantSend() -{ - QSettings settings; - settings.setValue("bUseInstantSend", ui->checkUseInstantSend->isChecked()); - CoinControlDialog::coinControl->fUseInstantSend = model->IsOldInstantSendEnabled() && ui->checkUseInstantSend->isChecked(); - coinControlUpdateLabels(); -} - void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg) { QPair msgParams; diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 4be4a93853..ae34d1e6a9 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -79,7 +79,6 @@ private Q_SLOTS: void on_buttonMinimizeFee_clicked(); void removeEntry(SendCoinsEntry* entry); void updateDisplayUnit(); - void updateInstantSend(); void coinControlFeatureChanged(bool); void coinControlButtonClicked(); void coinControlChangeChecked(int); diff --git a/src/qt/test/uritests.cpp b/src/qt/test/uritests.cpp index fd55151249..1c70a0b81c 100644 --- a/src/qt/test/uritests.cpp +++ b/src/qt/test/uritests.cpp @@ -64,31 +64,20 @@ void URITests::uriTests() uri.setUrl(QString("dash:XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg?amount=1,000.0&label=Some Example")); QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); - uri.setUrl(QString("dash:XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg?amount=100&label=Some Example&message=Some Example Message&IS=1")); + uri.setUrl(QString("dash:XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg?amount=100&label=Some Example&message=Some Example Message")); QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); QVERIFY(rv.address == QString("XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg")); QVERIFY(rv.amount == 10000000000LL); QVERIFY(rv.label == QString("Some Example")); QVERIFY(rv.message == QString("Some Example Message")); - QVERIFY(rv.fUseInstantSend == 1); - - uri.setUrl(QString("dash:XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg?amount=100&label=Some Example&message=Some Example Message&IS=Something Invalid")); - QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); - QVERIFY(rv.address == QString("XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg")); - QVERIFY(rv.amount == 10000000000LL); - QVERIFY(rv.label == QString("Some Example")); - QVERIFY(rv.message == QString("Some Example Message")); - QVERIFY(rv.fUseInstantSend != 1); + // Verify that IS=xxx does not lead to an error (we ignore the field) uri.setUrl(QString("dash:XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg?IS=1")); QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); - QVERIFY(rv.fUseInstantSend == 1); - uri.setUrl(QString("dash:XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg?IS=0")); + uri.setUrl(QString("dash:XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg?req-IS=1")); QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); - QVERIFY(rv.fUseInstantSend != 1); uri.setUrl(QString("dash:XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg")); QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); - QVERIFY(rv.fUseInstantSend != 1); } diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 00ed287ce9..8a495eddc1 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -19,8 +19,6 @@ #include "wallet/db.h" #include "wallet/wallet.h" -#include "instantsend.h" - #include #include @@ -57,26 +55,10 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) } } - if (wtx.IsLockedByLLMQInstantSend()) { + if (wtx.IsLockedByInstantSend()) { strTxStatus += " (" + tr("verified via LLMQ based InstantSend") + ")"; - return strTxStatus; } - if(!instantsend.HasTxLockRequest(wtx.GetHash())) return strTxStatus; // regular tx - - int nSignatures = instantsend.GetTransactionLockSignatures(wtx.GetHash()); - int nSignaturesMax = CTxLockRequest(wtx).GetMaxSignatures(); - // InstantSend - strTxStatus += " ("; - if(instantsend.IsLockedInstantSendTransaction(wtx.GetHash())) { - strTxStatus += tr("verified via InstantSend"); - } else if(!instantsend.IsTxLockCandidateTimedOut(wtx.GetHash())) { - strTxStatus += tr("InstantSend verification in progress - %1 of %2 signatures").arg(nSignatures).arg(nSignaturesMax); - } else { - strTxStatus += tr("InstantSend verification failed"); - } - strTxStatus += ")"; - return strTxStatus; } } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 2a8e8fbf16..71b3b37b2a 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -24,7 +24,6 @@ #include "wallet/wallet.h" #include "wallet/walletdb.h" // for BackupWallet -#include "instantsend.h" #include "spork.h" #include "privatesend/privatesend-client.h" #include "llmq/quorums_instantsend.h" @@ -217,11 +216,6 @@ int WalletModel::getNumISLocks() const return cachedNumISLocks; } -bool WalletModel::IsOldInstantSendEnabled() const -{ - return llmq::IsOldInstantSendEnabled(); -} - void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, const QString &purpose, int status) { @@ -320,12 +314,6 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact return AmountExceedsBalance; } - if(recipients[0].fUseInstantSend && IsOldInstantSendEnabled() && total > sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)*COIN) { - Q_EMIT message(tr("Send Coins"), tr("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH.").arg(sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)), - CClientUIInterface::MSG_ERROR); - return TransactionCreationFailed; - } - CAmount nFeeRequired = 0; CAmount nValueOut = 0; size_t nVinSize = 0; @@ -341,7 +329,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact CWalletTx* newTx = transaction.getTransaction(); CReserveKey *keyChange = transaction.getPossibleKeyChange(); - fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, nChangePosRet, strFailReason, coinControl, true, recipients[0].inputType, recipients[0].fUseInstantSend); + fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, nChangePosRet, strFailReason, coinControl, true, recipients[0].inputType); transaction.setTransactionFee(nFeeRequired); if (fSubtractFeeFromAmount && fCreated) transaction.reassignAmounts(); @@ -350,18 +338,6 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact nVinSize = newTx->tx->vin.size(); } - if(recipients[0].fUseInstantSend && IsOldInstantSendEnabled()) { - if(nValueOut > sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)*COIN) { - Q_EMIT message(tr("Send Coins"), tr("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH.").arg(sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)), - CClientUIInterface::MSG_ERROR); - return TransactionCreationFailed; - } - if(nVinSize > CTxLockRequest::WARN_MANY_INPUTS) { - Q_EMIT message(tr("Send Coins"), tr("Used way too many inputs (>%1) for this InstantSend transaction, fees could be huge.").arg(CTxLockRequest::WARN_MANY_INPUTS), - CClientUIInterface::MSG_WARNING); - } - } - if(!fCreated) { if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance) @@ -414,12 +390,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran CReserveKey *keyChange = transaction.getPossibleKeyChange(); CValidationState state; - // the new IX system does not require explicit IX messages - std::string strCommand = NetMsgType::TX; - if (recipients[0].fUseInstantSend && IsOldInstantSendEnabled()) { - strCommand = NetMsgType::TXLOCKREQUEST; - } - if(!wallet->CommitTransaction(*newTx, *keyChange, g_connman.get(), state, strCommand)) + if(!wallet->CommitTransaction(*newTx, *keyChange, g_connman.get(), state)) return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(state.GetRejectReason())); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 095c94a1d6..c8fdf43007 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -54,7 +54,6 @@ public: #ifdef ENABLE_WALLET AvailableCoinsType inputType; #endif // ENABLE_WALLET - bool fUseInstantSend; CAmount amount; // If from a payment request, this is used for storing the memo QString message; @@ -228,8 +227,6 @@ public: int getDefaultConfirmTarget() const; int getNumISLocks() const; - bool IsOldInstantSendEnabled() const; - private: CWallet *wallet; bool fHaveWatchOnly; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index d4aa600211..7806f425ae 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -13,7 +13,6 @@ #include "coins.h" #include "core_io.h" #include "consensus/validation.h" -#include "instantsend.h" #include "validation.h" #include "core_io.h" #include "policy/feerate.h" @@ -368,7 +367,6 @@ std::string EntryDescriptionString() " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n" " \"transactionid\", (string) parent transaction id\n" " ... ],\n" - " \"instantsend\" : true|false, (boolean) True if this transaction was sent as an InstantSend one\n" " \"instantlock\" : true|false (boolean) True if this transaction was locked via InstantSend\n"; } @@ -402,8 +400,7 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) } info.push_back(Pair("depends", depends)); - info.push_back(Pair("instantsend", instantsend.HasTxLockRequest(tx.GetHash()))); - info.push_back(Pair("instantlock", instantsend.IsLockedInstantSendTransaction(tx.GetHash()) || llmq::quorumInstantSendManager->IsLocked(tx.GetHash()))); + info.push_back(Pair("instantlock", llmq::quorumInstantSendManager->IsLocked(tx.GetHash()))); } UniValue mempoolToJSON(bool fVerbose) diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index 9e3f695bed..b4e47fb5e5 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -127,7 +127,7 @@ void gobject_prepare_help(CWallet* const pwallet) "2. revision (numeric, required) object revision in the system\n" "3. time (numeric, required) time this object was created\n" "4. data-hex (string, required) data in hex string form\n" - "5. use-IS (boolean, optional, default=false) InstantSend lock the collateral, only requiring one chain confirmation\n" + "5. use-IS (boolean, optional, default=false) Deprecated and ignored\n" "6. outputHash (string, optional) the single output to submit the proposal fee from\n" "7. outputIndex (numeric, optional) The output index.\n" ); @@ -160,8 +160,6 @@ UniValue gobject_prepare(const JSONRPCRequest& request) int nRevision = atoi(strRevision); int64_t nTime = atoi64(strTime); std::string strDataHex = request.params[4].get_str(); - bool useIS = false; - if (request.params.size() > 5) useIS = request.params[5].getBool(); // CREATE A NEW COLLATERAL TRANSACTION FOR THIS SPECIFIC OBJECT @@ -206,7 +204,7 @@ UniValue gobject_prepare(const JSONRPCRequest& request) } CWalletTx wtx; - if (!pwallet->GetBudgetSystemCollateralTX(wtx, govobj.GetHash(), govobj.GetMinCollateralFee(), useIS, outpoint)) { + if (!pwallet->GetBudgetSystemCollateralTX(wtx, govobj.GetHash(), govobj.GetMinCollateralFee(), outpoint)) { std::string err = "Error making collateral transaction for governance object. Please check your wallet balance and make sure your wallet is unlocked."; if (request.params.size() == 8) err += "Please verify your specified output is valid and is enough for the combined proposal fee and transaction fee."; throw JSONRPCError(RPC_INTERNAL_ERROR, err); @@ -216,7 +214,7 @@ UniValue gobject_prepare(const JSONRPCRequest& request) CReserveKey reservekey(pwallet); // -- send the tx to the network CValidationState state; - if (!pwallet->CommitTransaction(wtx, reservekey, g_connman.get(), state, NetMsgType::TX)) { + if (!pwallet->CommitTransaction(wtx, reservekey, g_connman.get(), state)) { throw JSONRPCError(RPC_INTERNAL_ERROR, "CommitTransaction failed! Reason given: " + state.GetRejectReason()); } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 72c6a8eb0a..e5b7d64a06 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -24,7 +24,6 @@ #include "txmempool.h" #include "uint256.h" #include "utilstrencodings.h" -#include "instantsend.h" #ifdef ENABLE_WALLET #include "wallet/rpcwallet.h" #include "wallet/wallet.h" @@ -94,10 +93,9 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) } } - bool fLocked = instantsend.IsLockedInstantSendTransaction(txid); - bool fLLMQLocked = llmq::quorumInstantSendManager->IsLocked(txid); - entry.push_back(Pair("instantlock", fLocked || fLLMQLocked || chainLock)); - entry.push_back(Pair("instantlock_internal", fLocked || fLLMQLocked)); + bool fLocked = llmq::quorumInstantSendManager->IsLocked(txid); + entry.push_back(Pair("instantlock", fLocked || chainLock)); + entry.push_back(Pair("instantlock_internal", fLocked)); entry.push_back(Pair("chainlock", chainLock)); } @@ -855,7 +853,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) "\nArguments:\n" "1. \"hexstring\" (string, required) The hex string of the raw transaction)\n" "2. allowhighfees (boolean, optional, default=false) Allow high fees\n" - "3. instantsend (boolean, optional, default=false) Use InstantSend to send this transaction\n" + "3. instantsend (boolean, optional, default=false) Deprecated and ignored\n" "4. bypasslimits (boolean, optional, default=false) Bypass transaction policy limits\n" "\nResult:\n" "\"hex\" (string) The transaction hash in hex\n" @@ -884,10 +882,6 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) if (request.params.size() > 1 && request.params[1].get_bool()) nMaxRawTxFee = 0; - bool fInstantSend = false; - if (request.params.size() > 2) - fInstantSend = request.params[2].get_bool(); - bool fBypassLimits = false; if (request.params.size() > 3) fBypassLimits = request.params[3].get_bool(); @@ -901,9 +895,6 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) bool fHaveMempool = mempool.exists(hashTx); if (!fHaveMempool && !fHaveChain) { // push to local node and sync with wallets - if (fInstantSend && !instantsend.ProcessTxLockRequest(*tx, *g_connman)) { - throw JSONRPCError(RPC_TRANSACTION_ERROR, "Not a valid InstantSend transaction, see debug.log for more info"); - } CValidationState state; bool fMissingInputs; if (!AcceptToMemoryPool(mempool, state, std::move(tx), !fBypassLimits, &fMissingInputs, false, nMaxRawTxFee)) { diff --git a/src/rpc/rpcevo.cpp b/src/rpc/rpcevo.cpp index 35913e245e..2588be0161 100644 --- a/src/rpc/rpcevo.cpp +++ b/src/rpc/rpcevo.cpp @@ -212,7 +212,7 @@ static void FundSpecialTx(CWallet* pwallet, CMutableTransaction& tx, const Speci int nChangePos = -1; std::string strFailReason; - if (!pwallet->CreateTransaction(vecSend, wtx, reservekey, nFee, nChangePos, strFailReason, &coinControl, false, ALL_COINS, false, tx.vExtraPayload.size())) { + if (!pwallet->CreateTransaction(vecSend, wtx, reservekey, nFee, nChangePos, strFailReason, &coinControl, false, ALL_COINS, tx.vExtraPayload.size())) { throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason); } diff --git a/src/spork.cpp b/src/spork.cpp index 953db496c6..9b4a4d77b8 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -17,9 +17,8 @@ const std::string CSporkManager::SERIALIZATION_VERSION_STRING = "CSporkManager-V #define MAKE_SPORK_DEF(name, defaultValue) CSporkDef{name, defaultValue, #name} std::vector sporkDefs = { - MAKE_SPORK_DEF(SPORK_2_INSTANTSEND_ENABLED, 0), // ON - MAKE_SPORK_DEF(SPORK_3_INSTANTSEND_BLOCK_FILTERING, 0), // ON - MAKE_SPORK_DEF(SPORK_5_INSTANTSEND_MAX_VALUE, 1000), // 1000 Dash + MAKE_SPORK_DEF(SPORK_2_INSTANTSEND_ENABLED, 4070908800ULL), // OFF + MAKE_SPORK_DEF(SPORK_3_INSTANTSEND_BLOCK_FILTERING, 4070908800ULL), // OFF MAKE_SPORK_DEF(SPORK_6_NEW_SIGS, 4070908800ULL), // OFF MAKE_SPORK_DEF(SPORK_9_SUPERBLOCKS_ENABLED, 4070908800ULL), // OFF MAKE_SPORK_DEF(SPORK_15_DETERMINISTIC_MNS_ENABLED, 4070908800ULL), // OFF diff --git a/src/spork.h b/src/spork.h index 1c4efb3506..d2aadcbf65 100644 --- a/src/spork.h +++ b/src/spork.h @@ -23,7 +23,6 @@ class CSporkManager; enum SporkId : int32_t { SPORK_2_INSTANTSEND_ENABLED = 10001, SPORK_3_INSTANTSEND_BLOCK_FILTERING = 10002, - SPORK_5_INSTANTSEND_MAX_VALUE = 10004, SPORK_6_NEW_SIGS = 10005, SPORK_9_SUPERBLOCKS_ENABLED = 10008, SPORK_15_DETERMINISTIC_MNS_ENABLED = 10014, diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 1836b13529..2542091c51 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -7,7 +7,6 @@ #include "consensus/consensus.h" #include "consensus/validation.h" -#include "instantsend.h" #include "validation.h" #include "policy/policy.h" #include "policy/fees.h" @@ -1394,16 +1393,6 @@ size_t CTxMemPool::DynamicMemoryUsage() const { return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + memusage::DynamicUsage(vTxHashes) + cachedInnerUsage; } -double CTxMemPool::UsedMemoryShare() const -{ - // use 1000000 instead of real bytes number in megabyte because of - // this param is calculated in such way in other places (see AppInit - // function in src/init.cpp or mempoolInfoToJSON function in - // src/rpc/blockchain.cpp) - size_t maxmempool = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; - return double(DynamicMemoryUsage()) / maxmempool; -} - void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) { AssertLockHeld(cs); UpdateForRemoveFromMempool(stage, updateDescendants); @@ -1418,7 +1407,7 @@ int CTxMemPool::Expire(int64_t time) { setEntries toremove; while (it != mapTx.get().end() && it->GetTime() < time) { // locked txes do not expire until mined and have sufficient confirmations - if (instantsend.IsLockedInstantSendTransaction(it->GetTx().GetHash()) || llmq::quorumInstantSendManager->IsLocked(it->GetTx().GetHash())) { + if (llmq::quorumInstantSendManager->IsLocked(it->GetTx().GetHash())) { it++; continue; } diff --git a/src/txmempool.h b/src/txmempool.h index bb37c606cd..04b6587bd0 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -672,8 +672,6 @@ public: bool existsProviderTxConflict(const CTransaction &tx) const; size_t DynamicMemoryUsage() const; - // returns share of the used memory to maximum allowed memory - double UsedMemoryShare() const; boost::signals2::signal NotifyEntryAdded; boost::signals2::signal NotifyEntryRemoved; diff --git a/src/validation.cpp b/src/validation.cpp index 5541eb6452..969d242119 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -40,7 +40,6 @@ #include "versionbits.h" #include "warnings.h" -#include "instantsend.h" #include "masternode/masternode-payments.h" #include "evo/specialtx.h" @@ -695,21 +694,6 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool if (pool.exists(hash)) return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool"); - // If this is a Transaction Lock Request check to see if it's valid - if(instantsend.HasTxLockRequest(hash) && !CTxLockRequest(tx).IsValid()) - return state.DoS(10, error("AcceptToMemoryPool : CTxLockRequest %s is invalid", hash.ToString()), - REJECT_INVALID, "bad-txlockrequest"); - - // Check for conflicts with a completed Transaction Lock - BOOST_FOREACH(const CTxIn &txin, tx.vin) - { - uint256 hashLocked; - if(instantsend.GetLockedOutPointTxHash(txin.prevout, hashLocked) && hash != hashLocked) - return state.DoS(10, error("AcceptToMemoryPool : Transaction %s conflicts with completed Transaction Lock %s", - hash.ToString(), hashLocked.ToString()), - REJECT_INVALID, "tx-txlock-conflict"); - } - llmq::CInstantSendLockPtr conflictLock = llmq::quorumInstantSendManager->GetConflictingLock(tx); if (conflictLock) { CTransactionRef txConflict; @@ -732,18 +716,6 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool { const CTransaction *ptxConflicting = itConflicting->second; - // InstantSend txes are not replacable - if(instantsend.HasTxLockRequest(ptxConflicting->GetHash())) { - // this tx conflicts with a Transaction Lock Request candidate - return state.DoS(0, error("AcceptToMemoryPool : Transaction %s conflicts with Transaction Lock Request %s", - hash.ToString(), ptxConflicting->GetHash().ToString()), - REJECT_INVALID, "tx-txlockreq-mempool-conflict"); - } else if (instantsend.HasTxLockRequest(hash)) { - // this tx is a tx lock request and it conflicts with a normal tx - return state.DoS(0, error("AcceptToMemoryPool : Transaction Lock Request %s conflicts with transaction %s", - hash.ToString(), ptxConflicting->GetHash().ToString()), - REJECT_INVALID, "txlockreq-tx-mempool-conflict"); - } // Transaction conflicts with mempool and RBF doesn't exist in Dash return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict"); } @@ -1807,10 +1779,6 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s } } - // make sure the flag is reset in case of a chain reorg - // (we reused the DIP3 deployment) - instantsend.isAutoLockBip9Active = pindex->nHeight >= Params().GetConsensus().DIP0003Height; - evoDb->WriteBestBlock(pindex->pprev->GetBlockHash()); return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; @@ -2251,17 +2219,6 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd for (const auto& tx : block.vtx) { // skip txes that have no inputs if (tx->vin.empty()) continue; - // LOOK FOR TRANSACTION LOCK IN OUR MAP OF OUTPOINTS - for (const auto& txin : tx->vin) { - uint256 hashLocked; - if (instantsend.GetLockedOutPointTxHash(txin.prevout, hashLocked) && hashLocked != tx->GetHash()) { - // The node which relayed this should switch to correct chain. - // TODO: relay instantsend data/proof. - LOCK(cs_main); - return state.DoS(10, error("ConnectBlock(DASH): transaction %s conflicts with transaction lock %s", tx->GetHash().ToString(), hashLocked.ToString()), - REJECT_INVALID, "conflict-tx-lock"); - } - } llmq::CInstantSendLockPtr conflictLock = llmq::quorumInstantSendManager->GetConflictingLock(*tx); if (!conflictLock) { continue; diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h index 2c4c6e7107..1226f0bb80 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -14,7 +14,6 @@ class CCoinControl public: CTxDestination destChange; bool fUsePrivateSend; - bool fUseInstantSend; //! If false, allows unselected inputs, but requires all selected inputs be used if fAllowOtherInputs is true (default) bool fAllowOtherInputs; //! If false, only include as many inputs as necessary to fulfill a coin selection request. Only usable together with fAllowOtherInputs @@ -40,7 +39,6 @@ public: fRequireAllInputs = true; fAllowWatchOnly = false; setSelected.clear(); - fUseInstantSend = false; fUsePrivateSend = true; nFeeRate = CFeeRate(0); fOverrideFeeRate = false; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0adbedcf25..39a8267c81 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -10,7 +10,6 @@ #include "consensus/validation.h" #include "core_io.h" #include "init.h" -#include "instantsend.h" #include "net.h" #include "policy/feerate.h" #include "policy/fees.h" @@ -65,15 +64,14 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) { AssertLockHeld(cs_main); // for mapBlockIndex int confirms = wtx.GetDepthInMainChain(); - bool fLocked = instantsend.IsLockedInstantSendTransaction(wtx.GetHash()); - bool fLLMQLocked = llmq::quorumInstantSendManager->IsLocked(wtx.GetHash()); + bool fLocked = llmq::quorumInstantSendManager->IsLocked(wtx.GetHash()); bool chainlock = false; if (confirms > 0) { chainlock = llmq::chainLocksHandler->HasChainLock(mapBlockIndex[wtx.hashBlock]->nHeight, wtx.hashBlock); } entry.push_back(Pair("confirmations", confirms)); - entry.push_back(Pair("instantlock", fLocked || fLLMQLocked || chainlock)); - entry.push_back(Pair("instantlock_internal", fLocked || fLLMQLocked)); + entry.push_back(Pair("instantlock", fLocked || chainlock)); + entry.push_back(Pair("instantlock_internal", fLocked)); entry.push_back(Pair("chainlock", chainlock)); if (wtx.IsCoinBase()) entry.push_back(Pair("generated", true)); @@ -354,7 +352,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request) return ret; } -static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, bool fUseInstantSend = false, bool fUsePrivateSend = false) +static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, bool fUsePrivateSend = false) { CAmount curBalance = pwallet->GetBalance(); @@ -381,18 +379,13 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount}; vecSend.push_back(recipient); if (!pwallet->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, - strError, NULL, true, fUsePrivateSend ? ONLY_DENOMINATED : ALL_COINS, fUseInstantSend)) { + strError, NULL, true, fUsePrivateSend ? ONLY_DENOMINATED : ALL_COINS)) { if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance) strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired)); throw JSONRPCError(RPC_WALLET_ERROR, strError); } CValidationState state; - // the new IX system does not require explicit IX messages - std::string strCommand = NetMsgType::TX; - if (fUseInstantSend && llmq::IsOldInstantSendEnabled()) { - strCommand = NetMsgType::TXLOCKREQUEST; - } - if (!pwallet->CommitTransaction(wtxNew, reservekey, g_connman.get(), state, strCommand)) { + if (!pwallet->CommitTransaction(wtxNew, reservekey, g_connman.get(), state)) { strError = strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()); throw JSONRPCError(RPC_WALLET_ERROR, strError); } @@ -420,7 +413,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request) " transaction, just kept in your wallet.\n" "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n" " The recipient will receive less amount of Dash than you enter in the amount field.\n" - "6. \"use_is\" (bool, optional, default=false) Send this transaction as InstantSend\n" + "6. \"use_is\" (bool, optional, default=false) Deprecated and ignored\n" "7. \"use_ps\" (bool, optional, default=false) Use anonymized funds only\n" "\nResult:\n" "\"txid\" (string) The transaction id.\n" @@ -453,77 +446,25 @@ UniValue sendtoaddress(const JSONRPCRequest& request) if (request.params.size() > 4) fSubtractFeeFromAmount = request.params[4].get_bool(); - bool fUseInstantSend = false; bool fUsePrivateSend = false; - if (request.params.size() > 5) - fUseInstantSend = request.params[5].get_bool(); if (request.params.size() > 6) fUsePrivateSend = request.params[6].get_bool(); EnsureWalletIsUnlocked(pwallet); - SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, fUseInstantSend, fUsePrivateSend); + SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, fUsePrivateSend); return wtx.GetHash().GetHex(); } +// DEPRECATED UniValue instantsendtoaddress(const JSONRPCRequest& request) { - CWallet* const pwallet = GetWalletForJSONRPCRequest(request); - if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) - return NullUniValue; - - if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) - throw std::runtime_error( - "instantsendtoaddress \"address\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n" - "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n" - + HelpRequiringPassphrase(pwallet) + - "\nArguments:\n" - "1. \"address\" (string, required) The dash address to send to.\n" - "2. \"amount\" (numeric, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n" - "3. \"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" - "4. \"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" - "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n" - " The recipient will receive less amount of Dash than you enter in the amount field.\n" - "\nResult:\n" - "\"transactionid\" (string) The transaction id.\n" - "\nExamples:\n" - + HelpExampleCli("instantsendtoaddress", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwG\" 0.1") - + HelpExampleCli("instantsendtoaddress", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwG\" 0.1 \"donation\" \"seans outpost\"") - + HelpExampleCli("instantsendtoaddress", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwG\" 0.1 \"\" \"\" true") - + HelpExampleRpc("instantsendtoaddress", "\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwG\", 0.1, \"donation\", \"seans outpost\"") - ); - - LOCK2(cs_main, pwallet->cs_wallet); - - CBitcoinAddress address(request.params[0].get_str()); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address"); - - // Amount - CAmount nAmount = AmountFromValue(request.params[1]); - if (nAmount <= 0) - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); - - // Wallet comments - CWalletTx wtx; - if (request.params.size() > 2 && !request.params[2].isNull() && !request.params[2].get_str().empty()) - wtx.mapValue["comment"] = request.params[2].get_str(); - if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty()) - wtx.mapValue["to"] = request.params[3].get_str(); - - bool fSubtractFeeFromAmount = false; - if (request.params.size() > 4) - fSubtractFeeFromAmount = request.params[4].get_bool(); - - EnsureWalletIsUnlocked(pwallet); - - SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, true); - - return wtx.GetHash().GetHex(); + if (request.fHelp) { + throw std::runtime_error("instantsendtoaddress is deprecated and sendtoaddress should be used instead"); + } + LogPrintf("WARNING: Used deprecated RPC method 'instantsendtoaddress'! Please use 'sendtoaddress' instead\n"); + return sendtoaddress(request); } UniValue listaddressgroupings(const JSONRPCRequest& request) @@ -1022,7 +963,7 @@ UniValue sendmany(const JSONRPCRequest& request) " \"address\" (string) Subtract fee from this address\n" " ,...\n" " ]\n" - "7. \"use_is\" (bool, optional, default=false) Send this transaction as InstantSend\n" + "7. \"use_is\" (bool, optional, default=false) Deprecated and ignored\n" "8. \"use_ps\" (bool, optional, default=false) Use anonymized funds only\n" "\nResult:\n" "\"txid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n" @@ -1102,24 +1043,16 @@ UniValue sendmany(const JSONRPCRequest& request) CAmount nFeeRequired = 0; int nChangePosRet = -1; std::string strFailReason; - bool fUseInstantSend = false; bool fUsePrivateSend = false; - if (request.params.size() > 6) - fUseInstantSend = request.params[6].get_bool(); if (request.params.size() > 7) fUsePrivateSend = request.params[7].get_bool(); bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, - NULL, true, fUsePrivateSend ? ONLY_DENOMINATED : ALL_COINS, fUseInstantSend); + NULL, true, fUsePrivateSend ? ONLY_DENOMINATED : ALL_COINS); if (!fCreated) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); CValidationState state; - // the new IX system does not require explicit IX messages - std::string strCommand = NetMsgType::TX; - if (fUseInstantSend && llmq::IsOldInstantSendEnabled()) { - strCommand = NetMsgType::TXLOCKREQUEST; - } - if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state, strCommand)) { + if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state)) { strFailReason = strprintf("Transaction commit failed:: %s", state.GetRejectReason()); throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); } @@ -3065,7 +2998,7 @@ static const CRPCCommand commands[] = { "wallet", "removeprunedfunds", &removeprunedfunds, true, {"txid"} }, { "wallet", "keepass", &keepass, true, {} }, - { "wallet", "instantsendtoaddress", &instantsendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount"} }, + { "hidden", "instantsendtoaddress", &instantsendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount"} }, { "wallet", "dumphdinfo", &dumphdinfo, true, {} }, { "wallet", "importelectrumwallet", &importelectrumwallet, true, {"filename", "index"} }, diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b5712e7ce7..976d55f7b5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -31,7 +31,6 @@ #include "utilmoneystr.h" #include "governance/governance.h" -#include "instantsend.h" #include "keepass.h" #include "privatesend/privatesend-client.h" #include "spork.h" @@ -1910,7 +1909,7 @@ void CWallet::ReacceptWalletTransactions() } } -bool CWalletTx::RelayWalletTransaction(CConnman* connman, const std::string& strCommand) +bool CWalletTx::RelayWalletTransaction(CConnman* connman) { assert(pwallet->GetBroadcastTransactions()); if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain() == 0) @@ -1921,15 +1920,6 @@ bool CWalletTx::RelayWalletTransaction(CConnman* connman, const std::string& str uint256 hash = GetHash(); LogPrintf("Relaying wtx %s\n", hash.ToString()); - if ((strCommand == NetMsgType::TXLOCKREQUEST) || - ((CTxLockRequest(*this).IsSimple()) && CInstantSend::CanAutoLock())) { - if (instantsend.ProcessTxLockRequest((CTxLockRequest)*this, *connman)) { - instantsend.AcceptLockRequest((CTxLockRequest)*this); - } else { - instantsend.RejectLockRequest((CTxLockRequest)*this); - } - } - if (connman) { connman->RelayTransaction((CTransaction)*this); return true; @@ -2540,13 +2530,12 @@ CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, cons return balance; } -void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t &nMaximumCount, const int &nMinDepth, const int &nMaxDepth, AvailableCoinsType nCoinType, bool fUseInstantSend) const +void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t &nMaximumCount, const int &nMinDepth, const int &nMaxDepth, AvailableCoinsType nCoinType) const { vCoins.clear(); { LOCK2(cs_main, cs_wallet); - int nInstantSendConfirmationsRequired = Params().GetConsensus().nInstantSendConfirmationsRequired; CAmount nTotal = 0; @@ -2562,9 +2551,6 @@ void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const continue; int nDepth = pcoin->GetDepthInMainChain(); - // do not use IX for inputs that have less then nInstantSendConfirmationsRequired blockchain confirmations - if (fUseInstantSend && nDepth < nInstantSendConfirmationsRequired) - continue; // We should not consider coins which aren't at least in our mempool // It's possible for these to be conflicted via ancestors which we may never be able to detect @@ -2638,19 +2624,13 @@ void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const } static void ApproximateBestSubset(const std::vector& vValue, const CAmount& nTotalLower, const CAmount& nTargetValue, - std::vector& vfBest, CAmount& nBest, bool fUseInstantSend = false, int iterations = 1000) + std::vector& vfBest, CAmount& nBest, int iterations = 1000) { std::vector vfIncluded; vfBest.assign(vValue.size(), true); nBest = nTotalLower; - if (!llmq::IsOldInstantSendEnabled()) { - // The new system does not require special handling for InstantSend as this is all done in CInstantSendManager. - // There is also no need for an extra fee anymore. - fUseInstantSend = false; - } - FastRandomContext insecure_rand; for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++) @@ -2662,9 +2642,6 @@ static void ApproximateBestSubset(const std::vector& vValue, const C { for (unsigned int i = 0; i < vValue.size(); i++) { - if (fUseInstantSend && nTotal + vValue[i].txout.nValue > sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)*COIN) { - continue; - } //The solver here uses a randomized algorithm, //the randomness serves no real security purpose but is just //needed to prevent degenerate behavior and it is important @@ -2718,27 +2695,16 @@ bool less_then_denom (const COutput& out1, const COutput& out2) } bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, std::vector vCoins, - std::set& setCoinsRet, CAmount& nValueRet, AvailableCoinsType nCoinType, bool fUseInstantSend) const + std::set& setCoinsRet, CAmount& nValueRet, AvailableCoinsType nCoinType) const { setCoinsRet.clear(); nValueRet = 0; - if (!llmq::IsOldInstantSendEnabled()) { - // The new system does not require special handling for InstantSend as this is all done in CInstantSendManager. - // There is also no need for an extra fee anymore. - fUseInstantSend = false; - } - // List of values less than target boost::optional coinLowestLarger; std::vector vValue; CAmount nTotalLower = 0; - // TODO: drop SPORK_5_INSTANTSEND_MAX_VALUE spork - if (fUseInstantSend && nTargetValue > sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE) * COIN && llmq::IsOldInstantSendEnabled()) { - return false; - } - random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); int tryDenomStart = 0; @@ -2845,9 +2811,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin std::vector vfBest; CAmount nBest; - ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, fUseInstantSend); + ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest); if (nBest != nTargetValue && nTotalLower >= nTargetValue + nMinChange) - ApproximateBestSubset(vValue, nTotalLower, nTargetValue + nMinChange, vfBest, nBest, fUseInstantSend); + ApproximateBestSubset(vValue, nTotalLower, nTargetValue + nMinChange, vfBest, nBest); // If we have a bigger coin and (either the stochastic approximation didn't find a good solution, // or the next bigger coin is closer), return the bigger coin @@ -2876,7 +2842,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin return nCoinType == ONLY_DENOMINATED ? (nValueRet - nTargetValue <= maxTxFee) : true; } -bool CWallet::SelectCoins(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl, AvailableCoinsType nCoinType, bool fUseInstantSend) const +bool CWallet::SelectCoins(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl, AvailableCoinsType nCoinType) const { // Note: this function should never be used for "always free" tx types like dstx @@ -2949,13 +2915,13 @@ bool CWallet::SelectCoins(const std::vector& vAvailableCoins, const CAm bool fRejectLongChains = gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS); bool res = nTargetValue <= nValueFromPresetInputs || - SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend) || - SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, 0, vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend) || - (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, 2, vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend)) || - (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::min((size_t)4, nMaxChainLength/3), vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend)) || - (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength/2, vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend)) || - (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength, vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend)) || - (bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::numeric_limits::max(), vCoins, setCoinsRet, nValueRet, nCoinType, fUseInstantSend)); + SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet, nCoinType) || + SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, 0, vCoins, setCoinsRet, nValueRet, nCoinType) || + (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, 2, vCoins, setCoinsRet, nValueRet, nCoinType)) || + (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::min((size_t)4, nMaxChainLength/3), vCoins, setCoinsRet, nValueRet, nCoinType)) || + (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength/2, vCoins, setCoinsRet, nValueRet, nCoinType)) || + (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength, vCoins, setCoinsRet, nValueRet, nCoinType)) || + (bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::numeric_limits::max(), vCoins, setCoinsRet, nValueRet, nCoinType)); // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end()); @@ -2994,7 +2960,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov CReserveKey reservekey(this); CWalletTx wtx; - if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, &coinControl, false, ALL_COINS, false, nExtraPayloadSize)) + if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, &coinControl, false, ALL_COINS, nExtraPayloadSize)) return false; if (nChangePosInOut != -1) @@ -3041,7 +3007,7 @@ bool CWallet::SelectPSInOutPairsByDenominations(int nDenom, CAmount nValueMin, C return false; } - AvailableCoins(vCoins, true, NULL, 1, MAX_MONEY, MAX_MONEY, 0, 0, 9999999, ONLY_DENOMINATED, false); + AvailableCoins(vCoins, true, NULL, 1, MAX_MONEY, MAX_MONEY, 0, 0, 9999999, ONLY_DENOMINATED); LogPrintf("CWallet::%s -- vCoins.size(): %d\n", __func__, vCoins.size()); std::random_shuffle(vCoins.rbegin(), vCoins.rend(), GetRandInt); @@ -3356,7 +3322,7 @@ bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std return true; } -bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, bool fUseInstantSend, const COutPoint& outpoint) +bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, const COutPoint& outpoint) { // make our change address CReserveKey reservekey(this); @@ -3374,7 +3340,7 @@ bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount a if (!outpoint.IsNull()) { coinControl.Select(outpoint); } - bool success = CreateTransaction(vecSend, tx, reservekey, nFeeRet, nChangePosRet, strFail, &coinControl, true, ALL_COINS, fUseInstantSend); + bool success = CreateTransaction(vecSend, tx, reservekey, nFeeRet, nChangePosRet, strFail, &coinControl, true, ALL_COINS); if(!success){ LogPrintf("CWallet::GetBudgetSystemCollateralTX -- Error: %s\n", strFail); return false; @@ -3402,16 +3368,8 @@ bool CWallet::ConvertList(std::vector vecTxIn, std::vector& vecA } bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, - int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign, AvailableCoinsType nCoinType, bool fUseInstantSend, int nExtraPayloadSize) + int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign, AvailableCoinsType nCoinType, int nExtraPayloadSize) { - if (!llmq::IsOldInstantSendEnabled()) { - // The new system does not require special handling for InstantSend as this is all done in CInstantSendManager. - // There is also no need for an extra fee anymore. - fUseInstantSend = false; - } - - CAmount nFeePay = fUseInstantSend ? CTxLockRequest().GetMinFee(true) : 0; - CAmount nValue = 0; int nChangePosRequest = nChangePosInOut; unsigned int nSubtractFeeFromAmount = 0; @@ -3476,11 +3434,9 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT LOCK2(cs_main, cs_wallet); { std::vector vAvailableCoins; - AvailableCoins(vAvailableCoins, true, coinControl, 1, MAX_MONEY, MAX_MONEY, 0, 0, 9999999, nCoinType, fUseInstantSend); - int nInstantSendConfirmationsRequired = Params().GetConsensus().nInstantSendConfirmationsRequired; + AvailableCoins(vAvailableCoins, true, coinControl, 1, MAX_MONEY, MAX_MONEY, 0, 0, 9999999, nCoinType); nFeeRet = 0; - if(nFeePay > 0) nFeeRet = nFeePay; // Start with no fee and loop until there is enough fee while (true) { @@ -3528,7 +3484,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT // Choose coins to use CAmount nValueIn = 0; setCoins.clear(); - if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl, nCoinType, fUseInstantSend)) + if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl, nCoinType)) { if (nCoinType == ONLY_NONDENOMINATED) { strFailReason = _("Unable to locate enough PrivateSend non-denominated funds for this transaction."); @@ -3537,18 +3493,10 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT strFailReason += " " + _("PrivateSend uses exact denominated amounts to send funds, you might simply need to anonymize some more coins."); } else if (nValueIn < nValueToSelect) { strFailReason = _("Insufficient funds."); - if (fUseInstantSend) { - // could be not true but most likely that's the reason - strFailReason += " " + strprintf(_("InstantSend requires inputs with at least %d confirmations, you might need to wait a few minutes and try again."), nInstantSendConfirmationsRequired); - } } return false; } - if (fUseInstantSend && nValueIn > sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)*COIN) { - strFailReason += " " + strprintf(_("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH."), sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)); - return false; - } const CAmount nChange = nValueIn - nValueToSelect; CTxOut newTxOut; @@ -3716,10 +3664,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT if (coinControl && coinControl->nConfirmTarget > 0) currentConfirmationTarget = coinControl->nConfirmTarget; - CAmount nFeeNeeded = std::max(nFeePay, GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator)); - if(fUseInstantSend) { - nFeeNeeded = std::max(nFeeNeeded, CTxLockRequest(txNew).GetMinFee(true)); - } + CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, ::mempool, ::feeEstimator); if (coinControl && coinControl->fOverrideFeeRate) nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes); @@ -3813,7 +3758,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT /** * Call after CreateTransaction unless you want to abort */ -bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state, const std::string& strCommand) +bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state) { { LOCK2(cs_main, cs_wallet); @@ -3851,7 +3796,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon LogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", state.GetRejectReason()); // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure. } else { - wtxNew.RelayWalletTransaction(connman, strCommand); + wtxNew.RelayWalletTransaction(connman); } } } @@ -5389,11 +5334,6 @@ int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const } bool CMerkleTx::IsLockedByInstantSend() const -{ - return instantsend.IsLockedInstantSendTransaction(GetHash()) || llmq::quorumInstantSendManager->IsLocked(GetHash()); -} - -bool CMerkleTx::IsLockedByLLMQInstantSend() const { return llmq::quorumInstantSendManager->IsLocked(GetHash()); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 7eb94c2cdc..283ead0923 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -268,7 +268,6 @@ public: int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); } bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; } bool IsLockedByInstantSend() const; - bool IsLockedByLLMQInstantSend() const; bool IsChainLocked() const; int GetBlocksToMaturity() const; /** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */ @@ -507,7 +506,7 @@ public: int64_t GetTxTime() const; int GetRequestCount() const; - bool RelayWalletTransaction(CConnman* connman, const std::string& strCommand="tx"); + bool RelayWalletTransaction(CConnman* connman); std::set GetConflicts() const; }; @@ -702,7 +701,7 @@ private: * all coins from coinControl are selected; Never select unconfirmed coins * if they are not ours */ - bool SelectCoins(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend = true) const; + bool SelectCoins(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL, AvailableCoinsType nCoinType=ALL_COINS) const; CWalletDB *pwalletdbEncryption; @@ -883,7 +882,7 @@ public: /** * populate vCoins with vector of available COutputs. */ - void AvailableCoins(std::vector& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = NULL, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t& nMaximumCount = 0, const int& nMinDepth = 0, const int& nMaxDepth = 9999999, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend = false) const; + void AvailableCoins(std::vector& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = NULL, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t& nMaximumCount = 0, const int& nMinDepth = 0, const int& nMaxDepth = 9999999, AvailableCoinsType nCoinType=ALL_COINS) const; /** * Shuffle and select coins until nTargetValue is reached while avoiding @@ -891,7 +890,7 @@ public: * completion the coin set and corresponding actual target value is * assembled */ - bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector vCoins, std::set& setCoinsRet, CAmount& nValueRet, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend = false) const; + bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector vCoins, std::set& setCoinsRet, CAmount& nValueRet, AvailableCoinsType nCoinType=ALL_COINS) const; // Coin selection bool SelectPSInOutPairsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector< std::pair >& vecPSInOutPairsRet); @@ -1023,7 +1022,7 @@ public: CAmount GetNormalizedAnonymizedBalance() const; CAmount GetDenominatedBalance(bool unconfirmed=false) const; - bool GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, bool fUseInstantSend, const COutPoint& outpoint=COutPoint()/*defaults null*/); + bool GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, CAmount amount, const COutPoint& outpoint=COutPoint()/*defaults null*/); /** * Insert additional inputs into the transaction by @@ -1037,8 +1036,8 @@ public: * @note passing nChangePosInOut as -1 will result in setting a random position */ bool CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, - std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend=false, int nExtraPayloadSize = 0); - bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state, const std::string& strCommand="tx"); + std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true, AvailableCoinsType nCoinType=ALL_COINS, int nExtraPayloadSize = 0); + bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state); bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason); bool ConvertList(std::vector vecTxIn, std::vector& vecAmounts); diff --git a/src/zmq/zmqconfig.h b/src/zmq/zmqconfig.h index 0ce679fdfb..c3122df6ec 100644 --- a/src/zmq/zmqconfig.h +++ b/src/zmq/zmqconfig.h @@ -22,8 +22,6 @@ #include "governance/governance-object.h" #include "governance/governance-vote.h" -#include "instantsend.h" - #include "llmq/quorums_chainlocks.h" #include "llmq/quorums_instantsend.h" diff --git a/test/functional/autois-mempool.py b/test/functional/autois-mempool.py deleted file mode 100755 index 71b23727de..0000000000 --- a/test/functional/autois-mempool.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2018 The Dash Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -from test_framework.mininode import * -from test_framework.test_framework import DashTestFramework -from test_framework.util import * -from time import * - -''' -autois-mempool.py - -Checks if automatic InstantSend locks stop working when transaction mempool -is full (more than 0.1 part from max value). - -''' - -MAX_MEMPOOL_SIZE = 1 # max node mempool in MBs -MB_SIZE = 1000000 # C++ code use this coefficient to calc MB in mempool -AUTO_IX_MEM_THRESHOLD = 0.1 - - -class AutoISMempoolTest(DashTestFramework): - def __init__(self): - super().__init__(8, 5, ["-maxmempool=%d" % MAX_MEMPOOL_SIZE, '-limitdescendantsize=10'], fast_dip3_enforcement=True) - # set sender, receiver - self.receiver_idx = 1 - self.sender_idx = 2 - - def get_mempool_usage(self, node): - info = node.getmempoolinfo() - return info['usage'] - - def fill_mempool(self): - # send lots of txes to yourself just to fill the mempool - counter = 0 - sync_period = 10 - dummy_address = self.nodes[0].getnewaddress() - while self.get_mempool_usage(self.nodes[self.sender_idx]) < MAX_MEMPOOL_SIZE * MB_SIZE * AUTO_IX_MEM_THRESHOLD: - self.nodes[0].sendtoaddress(dummy_address, 1.0) - counter += 1 - if counter % sync_period == 0: - # sync nodes - self.sync_all() - self.sync_all() - - def run_test(self): - # make sure masternodes are synced - sync_masternodes(self.nodes) - - self.nodes[0].spork("SPORK_17_QUORUM_DKG_ENABLED", 0) - self.wait_for_sporks_same() - self.mine_quorum() - - self.log.info("Test old InstantSend") - self.test_auto(); - - # Generate 6 block to avoid retroactive signing overloading Travis - self.nodes[0].generate(6) - sync_blocks(self.nodes) - - self.nodes[0].spork("SPORK_20_INSTANTSEND_LLMQ_BASED", 0) - self.wait_for_sporks_same() - - self.log.info("Test new InstantSend") - self.test_auto(True); - - def test_auto(self, new_is = False): - self.activate_autois_bip9(self.nodes[0]) - self.set_autois_spork_state(self.nodes[0], True) - - # check pre-conditions for autoIS - assert(self.get_autois_bip9_status(self.nodes[0]) == 'active') - assert(self.get_autois_spork_state(self.nodes[0])) - - # create 3 inputs for txes on sender node and give them enough confirmations - sender = self.nodes[self.sender_idx] - receiver = self.nodes[self.receiver_idx] - sender_address = sender.getnewaddress() - for i in range(0, 4): - self.nodes[0].sendtoaddress(sender_address, 2.0) - for i in range(0, 2): - set_mocktime(get_mocktime() + 1) - set_node_times(self.nodes, get_mocktime()) - self.nodes[0].generate(1) - self.sync_all() - - # autoIS is working - assert(self.send_simple_tx(sender, receiver)) - - # fill mempool with transactions - self.set_autois_spork_state(self.nodes[0], False) - self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 4070908800) - self.wait_for_sporks_same() - self.fill_mempool() - self.set_autois_spork_state(self.nodes[0], True) - self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 0) - self.wait_for_sporks_same() - - # autoIS is not working now - assert(not self.send_simple_tx(sender, receiver)) - # regular IS is still working for old IS but not for new one - assert(not self.send_regular_instantsend(sender, receiver, False) if new_is else self.send_regular_instantsend(sender, receiver)) - - # generate one block to clean up mempool and retry auto and regular IS - # generate 5 more blocks to avoid retroactive signing (which would overload Travis) - set_mocktime(get_mocktime() + 1) - set_node_times(self.nodes, get_mocktime()) - self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 4070908800) - self.wait_for_sporks_same() - self.nodes[0].generate(6) - self.sync_all() - set_mocktime(get_mocktime() + 1) - set_node_times(self.nodes, get_mocktime()) - self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 0) - self.wait_for_sporks_same() - assert(self.send_simple_tx(sender, receiver)) - assert(self.send_regular_instantsend(sender, receiver, not new_is)) - - -if __name__ == '__main__': - AutoISMempoolTest().main() diff --git a/test/functional/dip3-deterministicmns.py b/test/functional/dip3-deterministicmns.py index 99403686d7..3ebc397a6e 100755 --- a/test/functional/dip3-deterministicmns.py +++ b/test/functional/dip3-deterministicmns.py @@ -114,9 +114,6 @@ class DIP3Test(BitcoinTestFramework): self.sync_all() self.assert_mnlists(mns) - self.log.info("testing instant send") - self.test_instantsend(10, 3) - self.log.info("test that MNs disappear from the list when the ProTx collateral is spent") spend_mns_count = 3 mns_tmp = [] + mns @@ -191,9 +188,6 @@ class DIP3Test(BitcoinTestFramework): self.start_mn(new_mn) self.sync_all() - self.log.info("testing instant send with replaced MNs") - self.test_instantsend(10, 3, timeout=20) - def prepare_mn(self, node, idx, alias): mn = Masternode() mn.idx = idx @@ -306,57 +300,6 @@ class DIP3Test(BitcoinTestFramework): return time.sleep(0.1) - def test_instantsend(self, tx_count, repeat, timeout=20): - self.nodes[0].spork('SPORK_2_INSTANTSEND_ENABLED', 0) - self.wait_for_sporks() - - # give all nodes some coins first - for i in range(tx_count): - outputs = {} - for node in self.nodes[1:]: - outputs[node.getnewaddress()] = 1 - rawtx = self.nodes[0].createrawtransaction([], outputs) - rawtx = self.nodes[0].fundrawtransaction(rawtx)['hex'] - rawtx = self.nodes[0].signrawtransaction(rawtx)['hex'] - self.nodes[0].sendrawtransaction(rawtx) - self.nodes[0].generate(1) - self.sync_all() - - for j in range(repeat): - for i in range(tx_count): - while True: - from_node_idx = random.randint(1, len(self.nodes) - 1) - from_node = self.nodes[from_node_idx] - if from_node is not None: - break - while True: - to_node_idx = random.randint(0, len(self.nodes) - 1) - to_node = self.nodes[to_node_idx] - if to_node is not None and from_node is not to_node: - break - to_address = to_node.getnewaddress() - txid = from_node.instantsendtoaddress(to_address, 0.1) - for node in self.nodes: - if node is not None: - self.wait_for_instant_lock(node, to_node_idx, txid, timeout=timeout) - self.nodes[0].generate(6) - self.sync_all() - - def wait_for_instant_lock(self, node, node_idx, txid, timeout=10): - st = time.time() - while time.time() < st + timeout: - try: - tx = node.getrawtransaction(txid, 1) - except: - tx = None - if tx is None: - time.sleep(0.5) - continue - if tx['instantlock']: - return - time.sleep(0.5) - raise AssertionError("wait_for_instant_lock timed out for: {} on node {}".format(txid, node_idx)) - def assert_mnlists(self, mns): for node in self.nodes: self.assert_mnlist(node, mns) diff --git a/test/functional/llmq-chainlocks.py b/test/functional/llmq-chainlocks.py index cca1f90741..11eee59922 100755 --- a/test/functional/llmq-chainlocks.py +++ b/test/functional/llmq-chainlocks.py @@ -91,7 +91,8 @@ class LLMQChainLocksTest(DashTestFramework): assert(self.nodes[0].getbestblockhash() == self.nodes[1].getbestblockhash()) # Enable LLMQ bases InstantSend, which also enables checks for "safe" transactions - self.nodes[0].spork("SPORK_20_INSTANTSEND_LLMQ_BASED", 0) + self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 0) + self.nodes[0].spork("SPORK_3_INSTANTSEND_BLOCK_FILTERING", 0) self.wait_for_sporks_same() # Isolate a node and let it create some transactions which won't get IS locked @@ -108,10 +109,10 @@ class LLMQChainLocksTest(DashTestFramework): sleep(1) assert(not self.nodes[0].getblock(self.nodes[0].getbestblockhash())["chainlock"]) # Disable LLMQ based InstantSend for a very short time (this never gets propagated to other nodes) - self.nodes[0].spork("SPORK_20_INSTANTSEND_LLMQ_BASED", 4070908800) + self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 4070908800) # Now the TXs should be included self.nodes[0].generate(1) - self.nodes[0].spork("SPORK_20_INSTANTSEND_LLMQ_BASED", 0) + self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 0) # Assert that TXs got included now for txid in txs: tx = self.nodes[0].getrawtransaction(txid, 1) diff --git a/test/functional/llmq-is-cl-conflicts.py b/test/functional/llmq-is-cl-conflicts.py index f376f3b7d6..17d2d035d3 100755 --- a/test/functional/llmq-is-cl-conflicts.py +++ b/test/functional/llmq-is-cl-conflicts.py @@ -61,7 +61,8 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework): self.nodes[0].spork("SPORK_17_QUORUM_DKG_ENABLED", 0) self.nodes[0].spork("SPORK_19_CHAINLOCKS_ENABLED", 0) - self.nodes[0].spork("SPORK_20_INSTANTSEND_LLMQ_BASED", 0) + self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 0) + self.nodes[0].spork("SPORK_3_INSTANTSEND_BLOCK_FILTERING", 0) self.wait_for_sporks_same() self.mine_quorum() diff --git a/test/functional/multikeysporks.py b/test/functional/multikeysporks.py index df1764b060..1ea37d1b59 100755 --- a/test/functional/multikeysporks.py +++ b/test/functional/multikeysporks.py @@ -119,7 +119,7 @@ class MultiKeySporkTest(BitcoinTestFramework): def run_test(self): # check test spork default state for node in self.nodes: - assert(self.get_test_spork_state(node) == 0) + assert(self.get_test_spork_state(node) == 4070908800) set_mocktime(get_mocktime() + 1) set_node_times(self.nodes, get_mocktime()) diff --git a/test/functional/p2p-autoinstantsend.py b/test/functional/p2p-autoinstantsend.py deleted file mode 100755 index 707265a1c2..0000000000 --- a/test/functional/p2p-autoinstantsend.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2018 The Dash Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -from test_framework.mininode import * -from test_framework.test_framework import DashTestFramework -from test_framework.util import * -from time import * - -''' -p2p-autoinstantsend.py - -Test automatic InstantSend locks functionality. - -Checks that simple transactions automatically become InstantSend locked, -complex transactions don't become IS-locked and this functionality is -activated only if SPORK_16_INSTANTSEND_AUTOLOCKS is active. - -Also checks that this functionality doesn't influence regular InstantSend -transactions with high fee. -''' - -class AutoInstantSendTest(DashTestFramework): - def __init__(self): - super().__init__(8, 5, [], fast_dip3_enforcement=True) - # set sender, receiver, isolated nodes - self.receiver_idx = 1 - self.sender_idx = 2 - - def run_test(self): - # make sure masternodes are synced - sync_masternodes(self.nodes) - - self.nodes[0].spork("SPORK_17_QUORUM_DKG_ENABLED", 0) - self.wait_for_sporks_same() - self.mine_quorum() - - self.log.info("Test old InstantSend") - self.test_auto(); - - # Generate 6 block to avoid retroactive signing overloading Travis - self.nodes[0].generate(6) - sync_blocks(self.nodes) - - self.nodes[0].spork("SPORK_20_INSTANTSEND_LLMQ_BASED", 0) - self.wait_for_sporks_same() - - self.log.info("Test new InstantSend") - self.test_auto(True); - - def test_auto(self, new_is = False): - sender = self.nodes[self.sender_idx] - receiver = self.nodes[self.receiver_idx] - # feed the sender with some balance, make sure there are enough inputs - recipients = {} - for i in range(0, 30): - recipients[sender.getnewaddress()] = 1 - # use a single transaction to not overload Travis with InstantSend - self.nodes[0].sendmany("", recipients) - - # make sender funds mature for InstantSend - for i in range(0, 2): - set_mocktime(get_mocktime() + 1) - set_node_times(self.nodes, get_mocktime()) - self.nodes[0].generate(1) - self.sync_all() - - assert(not self.get_autois_spork_state(self.nodes[0])) - - assert(self.send_regular_instantsend(sender, receiver, not new_is)) - assert(self.send_simple_tx(sender, receiver) if new_is else not self.send_simple_tx(sender, receiver)) - assert(self.send_complex_tx(sender, receiver) if new_is else not self.send_complex_tx(sender, receiver)) - - self.activate_autois_bip9(self.nodes[0]) - self.set_autois_spork_state(self.nodes[0], True) - - assert(self.get_autois_bip9_status(self.nodes[0]) == 'active') - assert(self.get_autois_spork_state(self.nodes[0])) - - assert(self.send_regular_instantsend(sender, receiver, not new_is)) - assert(self.send_simple_tx(sender, receiver)) - assert(self.send_complex_tx(sender, receiver) if new_is else not self.send_complex_tx(sender, receiver)) - - self.set_autois_spork_state(self.nodes[0], False) - assert(not self.get_autois_spork_state(self.nodes[0])) - - assert(self.send_regular_instantsend(sender, receiver, not new_is)) - assert(self.send_simple_tx(sender, receiver) if new_is else not self.send_simple_tx(sender, receiver)) - assert(self.send_complex_tx(sender, receiver) if new_is else not self.send_complex_tx(sender, receiver)) - - # mine all mempool txes - set_mocktime(get_mocktime() + 1) - set_node_times(self.nodes, get_mocktime()) - self.nodes[0].generate(1) - self.sync_all() - -if __name__ == '__main__': - AutoInstantSendTest().main() diff --git a/test/functional/p2p-instantsend.py b/test/functional/p2p-instantsend.py index 03a078d094..d0d4171ef9 100755 --- a/test/functional/p2p-instantsend.py +++ b/test/functional/p2p-instantsend.py @@ -25,17 +25,10 @@ class InstantSendTest(DashTestFramework): self.wait_for_sporks_same() self.mine_quorum() - self.log.info("Test old InstantSend") - self.test_block_doublespend() - - # Generate 6 block to avoid retroactive signing overloading Travis - self.nodes[0].generate(6) - sync_blocks(self.nodes) - - self.nodes[0].spork("SPORK_20_INSTANTSEND_LLMQ_BASED", 0) + self.nodes[0].spork("SPORK_2_INSTANTSEND_ENABLED", 0) + self.nodes[0].spork("SPORK_3_INSTANTSEND_BLOCK_FILTERING", 0) self.wait_for_sporks_same() - self.log.info("Test new InstantSend") self.test_mempool_doublespend() self.test_block_doublespend() @@ -56,7 +49,7 @@ class InstantSendTest(DashTestFramework): isolate_node(isolated) # instantsend to receiver receiver_addr = receiver.getnewaddress() - is_id = sender.instantsendtoaddress(receiver_addr, 0.9) + is_id = sender.sendtoaddress(receiver_addr, 0.9) for node in self.nodes: if node is not isolated: self.wait_for_instantlock(is_id, node) @@ -112,7 +105,7 @@ class InstantSendTest(DashTestFramework): # instantsend to receiver. The previously isolated node should prune the doublespend TX and request the correct # TX from other nodes. receiver_addr = receiver.getnewaddress() - is_id = sender.instantsendtoaddress(receiver_addr, 0.9) + is_id = sender.sendtoaddress(receiver_addr, 0.9) for node in self.nodes: self.wait_for_instantlock(is_id, node) assert_raises_jsonrpc(-5, "No such mempool or blockchain transaction", isolated.getrawtransaction, dblspnd_txid) diff --git a/test/functional/sporks.py b/test/functional/sporks.py index b72045bfc1..e7b21ef099 100755 --- a/test/functional/sporks.py +++ b/test/functional/sporks.py @@ -39,16 +39,16 @@ class SporkTest(BitcoinTestFramework): def run_test(self): # check test spork default state - assert(self.get_test_spork_state(self.nodes[0])) - assert(self.get_test_spork_state(self.nodes[1])) - assert(self.get_test_spork_state(self.nodes[2])) + assert(not self.get_test_spork_state(self.nodes[0])) + assert(not self.get_test_spork_state(self.nodes[1])) + assert(not self.get_test_spork_state(self.nodes[2])) # check spork propagation for connected nodes - self.set_test_spork_state(self.nodes[0], False) + self.set_test_spork_state(self.nodes[0], True) start = time() sent = False while True: - if not self.get_test_spork_state(self.nodes[1]): + if self.get_test_spork_state(self.nodes[1]): sent = True break if time() > start + 10: @@ -61,8 +61,8 @@ class SporkTest(BitcoinTestFramework): self.stop_node(1) self.nodes[0] = self.start_node(0, self.options.tmpdir) self.nodes[1] = self.start_node(1, self.options.tmpdir) - assert(not self.get_test_spork_state(self.nodes[0])) - assert(not self.get_test_spork_state(self.nodes[1])) + assert(self.get_test_spork_state(self.nodes[0])) + assert(self.get_test_spork_state(self.nodes[1])) # Force finish mnsync node as otherwise it will never send out headers to other peers wait_to_sync(self.nodes[1], fast_mnsync=True) @@ -75,7 +75,7 @@ class SporkTest(BitcoinTestFramework): start = time() sent = False while True: - if not self.get_test_spork_state(self.nodes[2]): + if self.get_test_spork_state(self.nodes[2]): sent = True break if time() > start + 10: diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 7d6f94cad4..a663482eb3 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -549,66 +549,6 @@ class DashTestFramework(BitcoinTestFramework): for status in mn_info.values(): assert (status == 'ENABLED') - def get_autois_bip9_status(self, node): - info = node.getblockchaininfo() - # we reuse the dip3 deployment - return info['bip9_softforks']['dip0003']['status'] - - def activate_autois_bip9(self, node): - # sync nodes periodically - # if we sync them too often, activation takes too many time - # if we sync them too rarely, nodes failed to update its state and - # bip9 status is not updated - # so, in this code nodes are synced once per 20 blocks - counter = 0 - sync_period = 10 - - while self.get_autois_bip9_status(node) == 'defined': - set_mocktime(get_mocktime() + 1) - set_node_times(self.nodes, get_mocktime()) - node.generate(1) - counter += 1 - if counter % sync_period == 0: - # sync nodes - self.sync_all() - - while self.get_autois_bip9_status(node) == 'started': - set_mocktime(get_mocktime() + 1) - set_node_times(self.nodes, get_mocktime()) - node.generate(1) - counter += 1 - if counter % sync_period == 0: - # sync nodes - self.sync_all() - - while self.get_autois_bip9_status(node) == 'locked_in': - set_mocktime(get_mocktime() + 1) - set_node_times(self.nodes, get_mocktime()) - node.generate(1) - counter += 1 - if counter % sync_period == 0: - # sync nodes - self.sync_all() - - # sync nodes - self.sync_all() - - assert(self.get_autois_bip9_status(node) == 'active') - - def get_autois_spork_state(self, node): - info = node.spork('active') - return info['SPORK_16_INSTANTSEND_AUTOLOCKS'] - - def set_autois_spork_state(self, node, state): - # Increment mocktime as otherwise nodes will not update sporks - set_mocktime(get_mocktime() + 1) - set_node_times(self.nodes, get_mocktime()) - if state: - value = 0 - else: - value = 4070908800 - node.spork('SPORK_16_INSTANTSEND_AUTOLOCKS', value) - def create_raw_tx(self, node_from, node_to, amount, min_inputs, max_inputs): assert (min_inputs <= max_inputs) # fill inputs @@ -656,31 +596,6 @@ class DashTestFramework(BitcoinTestFramework): ret = {**decoded, **ret} return ret - # sends regular instantsend with high fee - def send_regular_instantsend(self, sender, receiver, check_fee = True): - receiver_addr = receiver.getnewaddress() - txid = sender.instantsendtoaddress(receiver_addr, 1.0) - if (check_fee): - MIN_FEE = satoshi_round(-0.0001) - fee = sender.gettransaction(txid)['fee'] - expected_fee = MIN_FEE * len(sender.getrawtransaction(txid, True)['vin']) - assert_equal(fee, expected_fee) - return self.wait_for_instantlock(txid, sender) - - # sends simple tx, it should become locked if autolocks are allowed - def send_simple_tx(self, sender, receiver): - raw_tx = self.create_raw_tx(sender, receiver, 1.0, 1, 4) - txid = self.nodes[0].sendrawtransaction(raw_tx['hex']) - self.sync_all() - return self.wait_for_instantlock(txid, sender) - - # sends complex tx, it should never become locked for old instentsend - def send_complex_tx(self, sender, receiver): - raw_tx = self.create_raw_tx(sender, receiver, 1.0, 5, 100) - txid = sender.sendrawtransaction(raw_tx['hex']) - self.sync_all() - return self.wait_for_instantlock(txid, sender) - def wait_for_instantlock(self, txid, node): # wait for instantsend locks start = time.time() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 041890cd03..5fabd71e76 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -60,8 +60,6 @@ BASE_SCRIPTS= [ 'p2p-fullblocktest.py', # NOTE: needs dash_hash to pass 'fundrawtransaction.py', 'fundrawtransaction-hd.py', - 'p2p-autoinstantsend.py', - 'autois-mempool.py', # vv Tests less than 2m vv 'p2p-instantsend.py', 'wallet.py',