mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
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
This commit is contained in:
parent
7a440d626b
commit
2f21e55514
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted)
|
||||
@ -94,13 +89,6 @@ void CDSNotificationInterface::BlockConnected(const std::shared_ptr<const CBlock
|
||||
llmq::quorumInstantSendManager->BlockConnected(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<const CBlock>& pblock, const CBlockIndex* pindexDisconnected)
|
||||
@ -108,10 +96,6 @@ void CDSNotificationInterface::BlockDisconnected(const std::shared_ptr<const CBl
|
||||
llmq::quorumInstantSendManager->BlockDisconnected(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)
|
||||
|
27
src/init.cpp
27
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<CNetFulfilledRequestManager> flatdb4("netfulfilled.dat", "magicFulfilledCache");
|
||||
flatdb4.Dump(netfulfilledman);
|
||||
if(fEnableInstantSend)
|
||||
{
|
||||
CFlatDB<CInstantSend> flatdb5("instantsend.dat", "magicInstantSendCache");
|
||||
flatdb5.Dump(instantsend);
|
||||
}
|
||||
CFlatDB<CSporkManager> 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=<cmd>", _("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<CInstantSend> 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);
|
||||
|
1264
src/instantsend.cpp
1264
src/instantsend.cpp
File diff suppressed because it is too large
Load Diff
@ -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<uint256, CTxLockRequest> mapLockRequestAccepted; ///< Tx hash - Tx
|
||||
std::map<uint256, CTxLockRequest> mapLockRequestRejected; ///< Tx hash - Tx
|
||||
std::map<uint256, CTxLockVote> mapTxLockVotes; ///< Vote hash - Vote
|
||||
std::map<uint256, CTxLockVote> mapTxLockVotesOrphan; ///< Vote hash - Vote
|
||||
|
||||
std::map<uint256, CTxLockCandidate> mapTxLockCandidates; ///< Tx hash - Lock candidate
|
||||
|
||||
std::map<COutPoint, std::set<uint256> > mapVotedOutpoints; ///< UTXO - Tx hash set
|
||||
std::map<COutPoint, uint256> mapLockedOutpoints; ///< UTXO - Tx hash
|
||||
|
||||
/// Track masternodes who voted with no txlockrequest (for DOS protection)
|
||||
std::map<COutPoint, int64_t> 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 <typename Stream, typename Operation>
|
||||
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<bool> 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 <typename Stream, typename Operation>
|
||||
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<unsigned char> 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 <typename Stream, typename Operation>
|
||||
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<COutPoint, CTxLockVote> 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 <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(outpoint);
|
||||
READWRITE(mapMasternodeVotes);
|
||||
READWRITE(fAttacked);
|
||||
}
|
||||
|
||||
bool AddVote(const CTxLockVote& vote);
|
||||
std::vector<CTxLockVote> 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; ///<When corresponding tx is 0-confirmed or conflicted, nConfirmedHeight is -1
|
||||
int64_t nTimeCreated;
|
||||
|
||||
public:
|
||||
CTxLockCandidate() :
|
||||
nConfirmedHeight(-1),
|
||||
nTimeCreated(GetTime())
|
||||
{}
|
||||
|
||||
CTxLockCandidate(const CTxLockRequest& txLockRequestIn) :
|
||||
nConfirmedHeight(-1),
|
||||
nTimeCreated(GetTime()),
|
||||
txLockRequest(txLockRequestIn),
|
||||
mapOutPointLocks()
|
||||
{}
|
||||
|
||||
CTxLockRequest txLockRequest;
|
||||
std::map<COutPoint, COutPointLock> mapOutPointLocks;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
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
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,6 @@
|
||||
#include "wallet/wallet.h"
|
||||
#endif
|
||||
|
||||
// needed for AUTO_IX_MEMPOOL_THRESHOLD
|
||||
#include "instantsend.h"
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
@ -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<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& 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);
|
||||
|
@ -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();
|
||||
|
||||
}
|
||||
|
13
src/net.cpp
13
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 <string.h>
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<COutPoint> vWorkQueue;
|
||||
std::vector<uint256> 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);
|
||||
|
102
src/protocol.cpp
102
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "validation.h" // For mempool
|
||||
#include "wallet/wallet.h"
|
||||
|
||||
#include "instantsend.h"
|
||||
#include "privatesend/privatesend-client.h"
|
||||
|
||||
#include <QApplication>
|
||||
@ -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;
|
||||
|
@ -127,7 +127,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="2">
|
||||
<item row="8" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="receiveButton">
|
||||
@ -176,23 +176,13 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="2">
|
||||
<widget class="QCheckBox" name="checkUseInstantSend">
|
||||
<property name="text">
|
||||
<string>Request InstantSend</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -1278,22 +1278,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkUseInstantSend">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>85</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>InstantSend</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
|
@ -165,7 +165,6 @@ bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
|
||||
QList<QPair<QString, QString> > items = uriQuery.queryItems();
|
||||
#endif
|
||||
|
||||
rv.fUseInstantSend = false;
|
||||
for (QList<QPair<QString, QString> >::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;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "utilitydialog.h"
|
||||
#include "walletmodel.h"
|
||||
|
||||
#include "instantsend.h"
|
||||
#include "masternode/masternode-sync.h"
|
||||
#include "privatesend/privatesend-client.h"
|
||||
|
||||
|
@ -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());
|
||||
|
@ -149,7 +149,6 @@ void ReceiveRequestDialog::update()
|
||||
html += "<b>"+tr("Label")+"</b>: " + GUIUtil::HtmlEscape(info.label) + "<br>";
|
||||
if(!info.message.isEmpty())
|
||||
html += "<b>"+tr("Message")+"</b>: " + GUIUtil::HtmlEscape(info.message) + "<br>";
|
||||
html += "<b>"+tr("InstantSend")+"</b>: " + (info.fUseInstantSend ? tr("Yes") : tr("No")) + "<br>";
|
||||
ui->outUri->setText(html);
|
||||
|
||||
#ifdef USE_QRCODE
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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") + " <b>" + tr("any available funds (not anonymous)") + "</b>";
|
||||
}
|
||||
|
||||
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<QString, CClientUIInterface::MessageBoxFlags> msgParams;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -19,8 +19,6 @@
|
||||
#include "wallet/db.h"
|
||||
#include "wallet/wallet.h"
|
||||
|
||||
#include "instantsend.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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<CSporkDef> 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
|
||||
|
@ -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,
|
||||
|
@ -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<entry_time>().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;
|
||||
}
|
||||
|
@ -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<void (CTransactionRef)> NotifyEntryAdded;
|
||||
boost::signals2::signal<void (CTransactionRef, MemPoolRemovalReason)> NotifyEntryRemoved;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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"} },
|
||||
|
||||
|
@ -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<COutput> &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<COutput> &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<COutput> &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<COutput> &vCoins, bool fOnlySafe, const
|
||||
}
|
||||
|
||||
static void ApproximateBestSubset(const std::vector<CInputCoin>& vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
|
||||
std::vector<char>& vfBest, CAmount& nBest, bool fUseInstantSend = false, int iterations = 1000)
|
||||
std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
|
||||
{
|
||||
std::vector<char> 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<CInputCoin>& 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<COutput> vCoins,
|
||||
std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, AvailableCoinsType nCoinType, bool fUseInstantSend) const
|
||||
std::set<CInputCoin>& 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<CInputCoin> coinLowestLarger;
|
||||
std::vector<CInputCoin> 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<char> 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<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl, AvailableCoinsType nCoinType, bool fUseInstantSend) const
|
||||
bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& 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<COutput>& 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<uint64_t>::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<uint64_t>::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<CTxIn> vecTxIn, std::vector<CAmount>& vecA
|
||||
}
|
||||
|
||||
bool CWallet::CreateTransaction(const std::vector<CRecipient>& 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<CRecipient>& vecSend, CWalletT
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
{
|
||||
std::vector<COutput> 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<CRecipient>& 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<CRecipient>& 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<CRecipient>& 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<CRecipient>& 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());
|
||||
}
|
||||
|
@ -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<uint256> 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<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL, AvailableCoinsType nCoinType=ALL_COINS, bool fUseInstantSend = true) const;
|
||||
bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& 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<COutput>& 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<COutput>& 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<COutput> vCoins, std::set<CInputCoin>& 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<COutput> vCoins, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, AvailableCoinsType nCoinType=ALL_COINS) const;
|
||||
|
||||
// Coin selection
|
||||
bool SelectPSInOutPairsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector< std::pair<CTxDSIn, CTxOut> >& 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<CRecipient>& 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<CTxIn> vecTxIn, std::vector<CAmount>& vecAmounts);
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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()
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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())
|
||||
|
@ -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()
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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()
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user