mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
Merge pull request #3202 from codablock/pr_v14_backports
[v0.14.0.x] Backport pending PRs from develop into v14
This commit is contained in:
commit
c7630f0f4e
@ -10,8 +10,8 @@ build_darwin_SHA256SUM = shasum -a 256
|
||||
build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) -o
|
||||
|
||||
#darwin host on darwin builder. overrides darwin host preferences.
|
||||
darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION)
|
||||
darwin_CXX:=$(shell xcrun -f clang++) -mmacosx-version-min=$(OSX_MIN_VERSION) -stdlib=libc++ -fvisibility=hidden
|
||||
darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(shell xcrun --show-sdk-path)
|
||||
darwin_CXX:=$(shell xcrun -f clang++) -mmacosx-version-min=$(OSX_MIN_VERSION) -stdlib=libc++ -fvisibility=hidden --sysroot $(shell xcrun --show-sdk-path)
|
||||
darwin_AR:=$(shell xcrun -f ar)
|
||||
darwin_RANLIB:=$(shell xcrun -f ranlib)
|
||||
darwin_STRIP:=$(shell xcrun -f strip)
|
||||
|
@ -194,6 +194,23 @@ class DIP3Test(BitcoinTestFramework):
|
||||
self.log.info("testing instant send with replaced MNs")
|
||||
self.test_instantsend(10, 3, timeout=20)
|
||||
|
||||
self.log.info("testing masternode status updates")
|
||||
# change voting address and see if changes are reflected in `masternode status` rpc output
|
||||
mn = mns[0]
|
||||
node = self.nodes[0]
|
||||
old_dmnState = mn.node.masternode("status")["dmnState"]
|
||||
old_voting_address = old_dmnState["votingAddress"]
|
||||
new_voting_address = node.getnewaddress()
|
||||
assert(old_voting_address != new_voting_address)
|
||||
# also check if funds from payout address are used when no fee source address is specified
|
||||
node.sendtoaddress(mn.rewards_address, 0.001)
|
||||
node.protx('update_registrar', mn.protx_hash, "", new_voting_address, mn.rewards_address)
|
||||
node.generate(1)
|
||||
self.sync_all()
|
||||
new_dmnState = mn.node.masternode("status")["dmnState"]
|
||||
new_voting_address_from_rpc = new_dmnState["votingAddress"]
|
||||
assert(new_voting_address_from_rpc == new_voting_address)
|
||||
|
||||
def prepare_mn(self, node, idx, alias):
|
||||
mn = Masternode()
|
||||
mn.idx = idx
|
||||
|
@ -670,9 +670,6 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||
# Make sure there is exactly one input so coin selection can't skew the result
|
||||
assert_equal(len(self.nodes[3].listunspent(1)), 1)
|
||||
|
||||
# Disable BIP69 sorting of inputs and outputs
|
||||
self.nodes[3].setbip69enabled(False)
|
||||
|
||||
inputs = []
|
||||
outputs = {self.nodes[2].getnewaddress(): 1}
|
||||
rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
|
||||
@ -701,9 +698,10 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||
keys = list(outputs.keys())
|
||||
rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
|
||||
|
||||
result = [self.nodes[3].fundrawtransaction(rawtx),
|
||||
# Add changePosition=4 to circumvent BIP69 input/output sorting
|
||||
result = [self.nodes[3].fundrawtransaction(rawtx, {"changePosition": 4}),
|
||||
# split the fee between outputs 0, 2, and 3, but not output 1
|
||||
self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0, 2, 3]})]
|
||||
self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0, 2, 3], "changePosition": 4})]
|
||||
|
||||
dec_tx = [self.nodes[3].decoderawtransaction(result[0]['hex']),
|
||||
self.nodes[3].decoderawtransaction(result[1]['hex'])]
|
||||
@ -736,8 +734,5 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||
# the total subtracted from the outputs is equal to the fee
|
||||
assert_equal(share[0] + share[2] + share[3], result[0]['fee'])
|
||||
|
||||
# Reenable BIP69 sorting of inputs and outputs
|
||||
self.nodes[3].setbip69enabled(True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
RawTransactionsTest().main()
|
||||
|
@ -19,8 +19,8 @@ class MempoolPackagesTest(BitcoinTestFramework):
|
||||
|
||||
def setup_network(self):
|
||||
self.nodes = []
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000"]))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-maxorphantx=1000", "-limitancestorcount=5"]))
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantxsize=1000"]))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-maxorphantxsize=1000", "-limitancestorcount=5"]))
|
||||
connect_nodes(self.nodes[0], 1)
|
||||
self.is_network_split = False
|
||||
self.sync_all()
|
||||
|
@ -78,6 +78,9 @@ class InstantSendTest(DashTestFramework):
|
||||
assert (res['hash'] != wrong_block)
|
||||
# wait for long time only for first node
|
||||
timeout = 1
|
||||
# send coins back to the controller node without waiting for confirmations
|
||||
receiver.sendtoaddress(self.nodes[0].getnewaddress(), 0.9, "", "", True)
|
||||
assert_equal(receiver.getwalletinfo()["balance"], 0)
|
||||
# mine more blocks
|
||||
# TODO: mine these blocks on an isolated node
|
||||
set_mocktime(get_mocktime() + 1)
|
||||
@ -116,6 +119,9 @@ class InstantSendTest(DashTestFramework):
|
||||
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)
|
||||
# send coins back to the controller node without waiting for confirmations
|
||||
receiver.sendtoaddress(self.nodes[0].getnewaddress(), 0.9, "", "", True)
|
||||
assert_equal(receiver.getwalletinfo()["balance"], 0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
InstantSendTest().main()
|
||||
|
@ -156,7 +156,7 @@ class EstimateFeeTest(BitcoinTestFramework):
|
||||
"""
|
||||
self.nodes = []
|
||||
# Use node0 to mine blocks for input splitting
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000",
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantxsize=1000",
|
||||
"-whitelist=127.0.0.1"]))
|
||||
|
||||
self.log.info("This test is time consuming, please be patient")
|
||||
@ -194,12 +194,12 @@ class EstimateFeeTest(BitcoinTestFramework):
|
||||
# (17k is room enough for 110 or so transactions)
|
||||
self.nodes.append(start_node(1, self.options.tmpdir,
|
||||
["-blockmaxsize=17000",
|
||||
"-maxorphantx=1000"]))
|
||||
"-maxorphantxsize=1000"]))
|
||||
connect_nodes(self.nodes[1], 0)
|
||||
|
||||
# Node2 is a stingy miner, that
|
||||
# produces too small blocks (room for only 55 or so transactions)
|
||||
node2args = ["-blockmaxsize=8000", "-maxorphantx=1000"]
|
||||
node2args = ["-blockmaxsize=8000", "-maxorphantxsize=1000"]
|
||||
|
||||
self.nodes.append(start_node(2, self.options.tmpdir, node2args))
|
||||
connect_nodes(self.nodes[0], 2)
|
||||
|
@ -16,14 +16,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>@CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@.@CLIENT_VERSION_BUILD@, Copyright © 2009-@COPYRIGHT_YEAR@ The Bitcoin Core developers, 2014-@COPYRIGHT_YEAR@ @COPYRIGHT_HOLDERS_FINAL@</string>
|
||||
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@</string>
|
||||
<string>@CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@.@CLIENT_VERSION_BUILD@</string>
|
||||
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@</string>
|
||||
<string>@CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@.@CLIENT_VERSION_BUILD@</string>
|
||||
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
@ -100,6 +97,9 @@
|
||||
<key>NSRequiresAquaSystemAppearance</key>
|
||||
<string>True</string>
|
||||
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2009-@COPYRIGHT_YEAR@ The Bitcoin Core developers, 2014-@COPYRIGHT_YEAR@ @COPYRIGHT_HOLDERS_FINAL@</string>
|
||||
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.finance</string>
|
||||
</dict>
|
||||
|
@ -26,6 +26,8 @@ std::string CActiveMasternodeManager::GetStateString() const
|
||||
return "REMOVED";
|
||||
case MASTERNODE_OPERATOR_KEY_CHANGED:
|
||||
return "OPERATOR_KEY_CHANGED";
|
||||
case MASTERNODE_PROTX_IP_CHANGED:
|
||||
return "PROTX_IP_CHANGED";
|
||||
case MASTERNODE_READY:
|
||||
return "READY";
|
||||
case MASTERNODE_ERROR:
|
||||
@ -46,6 +48,8 @@ std::string CActiveMasternodeManager::GetStatus() const
|
||||
return "Masternode removed from list";
|
||||
case MASTERNODE_OPERATOR_KEY_CHANGED:
|
||||
return "Operator key changed or revoked";
|
||||
case MASTERNODE_PROTX_IP_CHANGED:
|
||||
return "IP address specified in ProTx changed";
|
||||
case MASTERNODE_READY:
|
||||
return "Ready";
|
||||
case MASTERNODE_ERROR:
|
||||
@ -94,11 +98,9 @@ void CActiveMasternodeManager::Init()
|
||||
return;
|
||||
}
|
||||
|
||||
mnListEntry = dmn;
|
||||
LogPrintf("CActiveMasternodeManager::Init -- proTxHash=%s, proTx=%s\n", dmn->proTxHash.ToString(), dmn->ToString());
|
||||
|
||||
LogPrintf("CActiveMasternodeManager::Init -- proTxHash=%s, proTx=%s\n", mnListEntry->proTxHash.ToString(), mnListEntry->ToString());
|
||||
|
||||
if (activeMasternodeInfo.service != mnListEntry->pdmnState->addr) {
|
||||
if (activeMasternodeInfo.service != dmn->pdmnState->addr) {
|
||||
state = MASTERNODE_ERROR;
|
||||
strError = "Local address does not match the address from ProTx";
|
||||
LogPrintf("CActiveMasternodeManager::Init -- ERROR: %s", strError);
|
||||
@ -120,8 +122,8 @@ void CActiveMasternodeManager::Init()
|
||||
}
|
||||
}
|
||||
|
||||
activeMasternodeInfo.proTxHash = mnListEntry->proTxHash;
|
||||
activeMasternodeInfo.outpoint = mnListEntry->collateralOutpoint;
|
||||
activeMasternodeInfo.proTxHash = dmn->proTxHash;
|
||||
activeMasternodeInfo.outpoint = dmn->collateralOutpoint;
|
||||
state = MASTERNODE_READY;
|
||||
}
|
||||
|
||||
@ -134,24 +136,41 @@ void CActiveMasternodeManager::UpdatedBlockTip(const CBlockIndex* pindexNew, con
|
||||
if (!deterministicMNManager->IsDIP3Enforced(pindexNew->nHeight)) return;
|
||||
|
||||
if (state == MASTERNODE_READY) {
|
||||
auto mnList = deterministicMNManager->GetListForBlock(pindexNew);
|
||||
if (!mnList.IsMNValid(mnListEntry->proTxHash)) {
|
||||
auto oldMNList = deterministicMNManager->GetListForBlock(pindexNew->pprev);
|
||||
auto newMNList = deterministicMNManager->GetListForBlock(pindexNew);
|
||||
if (!newMNList.IsMNValid(activeMasternodeInfo.proTxHash)) {
|
||||
// MN disappeared from MN list
|
||||
state = MASTERNODE_REMOVED;
|
||||
activeMasternodeInfo.proTxHash = uint256();
|
||||
activeMasternodeInfo.outpoint.SetNull();
|
||||
// MN might have reappeared in same block with a new ProTx
|
||||
Init();
|
||||
} else if (mnList.GetMN(mnListEntry->proTxHash)->pdmnState->pubKeyOperator != mnListEntry->pdmnState->pubKeyOperator) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto oldDmn = oldMNList.GetMN(activeMasternodeInfo.proTxHash);
|
||||
auto newDmn = newMNList.GetMN(activeMasternodeInfo.proTxHash);
|
||||
if (newDmn->pdmnState->pubKeyOperator != oldDmn->pdmnState->pubKeyOperator) {
|
||||
// MN operator key changed or revoked
|
||||
state = MASTERNODE_OPERATOR_KEY_CHANGED;
|
||||
activeMasternodeInfo.proTxHash = uint256();
|
||||
activeMasternodeInfo.outpoint.SetNull();
|
||||
// MN might have reappeared in same block with a new ProTx
|
||||
Init();
|
||||
return;
|
||||
}
|
||||
|
||||
if (newDmn->pdmnState->addr != oldDmn->pdmnState->addr) {
|
||||
// MN IP changed
|
||||
state = MASTERNODE_PROTX_IP_CHANGED;
|
||||
activeMasternodeInfo.proTxHash = uint256();
|
||||
activeMasternodeInfo.outpoint.SetNull();
|
||||
Init();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// MN might have (re)appeared with a new ProTx or we've found some peers and figured out our local address
|
||||
// MN might have (re)appeared with a new ProTx or we've found some peers
|
||||
// and figured out our local address
|
||||
Init();
|
||||
}
|
||||
}
|
||||
|
@ -46,12 +46,12 @@ public:
|
||||
MASTERNODE_POSE_BANNED,
|
||||
MASTERNODE_REMOVED,
|
||||
MASTERNODE_OPERATOR_KEY_CHANGED,
|
||||
MASTERNODE_PROTX_IP_CHANGED,
|
||||
MASTERNODE_READY,
|
||||
MASTERNODE_ERROR,
|
||||
};
|
||||
|
||||
private:
|
||||
CDeterministicMNCPtr mnListEntry;
|
||||
masternode_state_t state{MASTERNODE_WAITING_FOR_PROTX};
|
||||
std::string strError;
|
||||
|
||||
@ -60,8 +60,6 @@ public:
|
||||
|
||||
void Init();
|
||||
|
||||
CDeterministicMNCPtr GetDMN() const { return mnListEntry; }
|
||||
|
||||
std::string GetStateString() const;
|
||||
std::string GetStatus() const;
|
||||
|
||||
|
@ -444,7 +444,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
|
||||
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
|
||||
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file on startup"));
|
||||
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
|
||||
strUsage += HelpMessageOpt("-maxorphantxsize=<n>", strprintf(_("Maximum total size of all orphan transactions in megabytes (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS_SIZE));
|
||||
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
|
||||
strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(_("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY));
|
||||
strUsage += HelpMessageOpt("-blockreconstructionextratxn=<n>", strprintf(_("Extra transactions to keep in memory for compact block reconstructions (default: %u)"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN));
|
||||
@ -1402,6 +1402,10 @@ bool AppInitParameterInteraction()
|
||||
return InitError("LLMQ type for ChainLocks can only be overridden on devnet.");
|
||||
}
|
||||
|
||||
if (IsArgSet("-maxorphantx")) {
|
||||
InitWarning("-maxorphantx is not supported anymore. Use -maxorphantxsize instead.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -676,18 +676,10 @@ void CSigSharesManager::ProcessSigShare(NodeId nodeId, const CSigShare& sigShare
|
||||
if (!sigShares.Add(sigShare.GetKey(), sigShare)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sigSharesToAnnounce.Add(sigShare.GetKey(), true);
|
||||
|
||||
auto it = timeSeenForSessions.find(sigShare.GetSignHash());
|
||||
if (it == timeSeenForSessions.end()) {
|
||||
auto t = GetTimeMillis();
|
||||
// insert first-seen and last-seen time
|
||||
timeSeenForSessions.emplace(sigShare.GetSignHash(), std::make_pair(t, t));
|
||||
} else {
|
||||
// update last-seen time
|
||||
it->second.second = GetTimeMillis();
|
||||
}
|
||||
// Update the time we've seen the last sigShare
|
||||
timeSeenForSessions[sigShare.GetSignHash()] = GetTimeMillis();
|
||||
|
||||
if (!quorumNodes.empty()) {
|
||||
// don't announce and wait for other nodes to request this share and directly send it to them
|
||||
@ -1215,10 +1207,9 @@ void CSigSharesManager::Cleanup()
|
||||
std::unordered_set<uint256, StaticSaltedHasher> timeoutSessions;
|
||||
for (auto& p : timeSeenForSessions) {
|
||||
auto& signHash = p.first;
|
||||
int64_t firstSeenTime = p.second.first;
|
||||
int64_t lastSeenTime = p.second.second;
|
||||
int64_t lastSeenTime = p.second;
|
||||
|
||||
if (now - firstSeenTime >= SESSION_TOTAL_TIMEOUT || now - lastSeenTime >= SESSION_NEW_SHARES_TIMEOUT) {
|
||||
if (now - lastSeenTime >= SESSION_NEW_SHARES_TIMEOUT) {
|
||||
timeoutSessions.emplace(signHash);
|
||||
}
|
||||
}
|
||||
|
@ -330,7 +330,6 @@ public:
|
||||
class CSigSharesManager : public CRecoveredSigsListener
|
||||
{
|
||||
static const int64_t SESSION_NEW_SHARES_TIMEOUT = 60 * 1000;
|
||||
static const int64_t SESSION_TOTAL_TIMEOUT = 5 * 60 * 1000;
|
||||
static const int64_t SIG_SHARE_REQUEST_TIMEOUT = 5 * 1000;
|
||||
|
||||
// we try to keep total message size below 10k
|
||||
@ -348,8 +347,8 @@ private:
|
||||
|
||||
SigShareMap<CSigShare> sigShares;
|
||||
|
||||
// stores time of first and last receivedSigShare. Used to detect timeouts
|
||||
std::unordered_map<uint256, std::pair<int64_t, int64_t>, StaticSaltedHasher> timeSeenForSessions;
|
||||
// stores time of last receivedSigShare. Used to detect timeouts
|
||||
std::unordered_map<uint256, int64_t, StaticSaltedHasher> timeSeenForSessions;
|
||||
|
||||
std::unordered_map<NodeId, CSigSharesNodeState> nodeStates;
|
||||
SigShareMap<std::pair<NodeId, int64_t>> sigSharesRequested;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "primitives/transaction.h"
|
||||
#include "random.h"
|
||||
#include "tinyformat.h"
|
||||
#include "txdb.h"
|
||||
#include "txmempool.h"
|
||||
#include "ui_interface.h"
|
||||
#include "util.h"
|
||||
@ -76,10 +77,12 @@ struct COrphanTx {
|
||||
CTransactionRef tx;
|
||||
NodeId fromPeer;
|
||||
int64_t nTimeExpire;
|
||||
size_t nTxSize;
|
||||
};
|
||||
static CCriticalSection g_cs_orphans;
|
||||
std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans);
|
||||
std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(g_cs_orphans);
|
||||
size_t nMapOrphanTransactionsSize = 0;
|
||||
void EraseOrphansFor(NodeId peer);
|
||||
|
||||
static size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0;
|
||||
@ -659,7 +662,7 @@ bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRE
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME});
|
||||
auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME, sz});
|
||||
assert(ret.second);
|
||||
BOOST_FOREACH(const CTxIn& txin, tx->vin) {
|
||||
mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first);
|
||||
@ -667,6 +670,8 @@ bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRE
|
||||
|
||||
AddToCompactExtraTransactions(tx);
|
||||
|
||||
nMapOrphanTransactionsSize += sz;
|
||||
|
||||
LogPrint("mempool", "stored orphan tx %s (mapsz %u outsz %u)\n", hash.ToString(),
|
||||
mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size());
|
||||
return true;
|
||||
@ -686,6 +691,8 @@ int static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
|
||||
if (itPrev->second.empty())
|
||||
mapOrphanTransactionsByPrev.erase(itPrev);
|
||||
}
|
||||
assert(nMapOrphanTransactionsSize >= it->second.nTxSize);
|
||||
nMapOrphanTransactionsSize -= it->second.nTxSize;
|
||||
mapOrphanTransactions.erase(it);
|
||||
return 1;
|
||||
}
|
||||
@ -707,7 +714,7 @@ void EraseOrphansFor(NodeId peer)
|
||||
}
|
||||
|
||||
|
||||
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
|
||||
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphansSize)
|
||||
{
|
||||
LOCK(g_cs_orphans);
|
||||
|
||||
@ -732,7 +739,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
|
||||
nNextSweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL;
|
||||
if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx due to expiration\n", nErased);
|
||||
}
|
||||
while (mapOrphanTransactions.size() > nMaxOrphans)
|
||||
while (!mapOrphanTransactions.empty() && nMapOrphanTransactionsSize > nMaxOrphansSize)
|
||||
{
|
||||
// Evict a random orphan:
|
||||
uint256 randomhash = GetRandHash();
|
||||
@ -970,10 +977,16 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
if (mapOrphanTransactions.count(inv.hash)) return true;
|
||||
}
|
||||
|
||||
return recentRejects->contains(inv.hash) ||
|
||||
// When we receive an islock for a previously rejected transaction, we have to
|
||||
// drop the first-seen tx (which such a locked transaction was conflicting with)
|
||||
// and re-request the locked transaction (which did not make it into the mempool
|
||||
// previously due to txn-mempool-conflict rule). This means that we must ignore
|
||||
// recentRejects filter for such locked txes here.
|
||||
return (recentRejects->contains(inv.hash) && !llmq::quorumInstantSendManager->IsLocked(inv.hash)) ||
|
||||
mempool.exists(inv.hash) ||
|
||||
pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1
|
||||
pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1));
|
||||
pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1)) ||
|
||||
(fTxIndex && pblocktree->HasTxIndex(inv.hash));
|
||||
}
|
||||
|
||||
case MSG_BLOCK:
|
||||
@ -2291,8 +2304,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||
AddOrphanTx(ptx, pfrom->GetId());
|
||||
|
||||
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
|
||||
unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS));
|
||||
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx);
|
||||
unsigned int nMaxOrphanTxSize = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantxsize", DEFAULT_MAX_ORPHAN_TRANSACTIONS_SIZE)) * 1000000;
|
||||
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTxSize);
|
||||
if (nEvicted > 0)
|
||||
LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted);
|
||||
} else {
|
||||
@ -3761,5 +3774,6 @@ public:
|
||||
// orphan transactions
|
||||
mapOrphanTransactions.clear();
|
||||
mapOrphanTransactionsByPrev.clear();
|
||||
nMapOrphanTransactionsSize = 0;
|
||||
}
|
||||
} instance_of_cnetprocessingcleanup;
|
||||
|
@ -9,8 +9,8 @@
|
||||
#include "net.h"
|
||||
#include "validationinterface.h"
|
||||
|
||||
/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
|
||||
static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
|
||||
/** Default for -maxorphantxsize, maximum size in megabytes the orphan map can grow before entries are removed */
|
||||
static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS_SIZE = 10; // this allows around 100 TXs of max size (and many more of normal size)
|
||||
/** Expiration time for orphan transactions in seconds */
|
||||
static const int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60;
|
||||
/** Minimum time between orphan transactions expire time checks in seconds */
|
||||
|
125
src/netbase.cpp
125
src/netbase.cpp
@ -198,6 +198,48 @@ struct timeval MillisToTimeval(int64_t nTimeout)
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/** SOCKS version */
|
||||
enum SOCKSVersion: uint8_t {
|
||||
SOCKS4 = 0x04,
|
||||
SOCKS5 = 0x05
|
||||
};
|
||||
|
||||
/** Values defined for METHOD in RFC1928 */
|
||||
enum SOCKS5Method: uint8_t {
|
||||
NOAUTH = 0x00, //! No authentication required
|
||||
GSSAPI = 0x01, //! GSSAPI
|
||||
USER_PASS = 0x02, //! Username/password
|
||||
NO_ACCEPTABLE = 0xff, //! No acceptable methods
|
||||
};
|
||||
|
||||
/** Values defined for CMD in RFC1928 */
|
||||
enum SOCKS5Command: uint8_t {
|
||||
CONNECT = 0x01,
|
||||
BIND = 0x02,
|
||||
UDP_ASSOCIATE = 0x03
|
||||
};
|
||||
|
||||
/** Values defined for REP in RFC1928 */
|
||||
enum SOCKS5Reply: uint8_t {
|
||||
SUCCEEDED = 0x00, //! Succeeded
|
||||
GENFAILURE = 0x01, //! General failure
|
||||
NOTALLOWED = 0x02, //! Connection not allowed by ruleset
|
||||
NETUNREACHABLE = 0x03, //! Network unreachable
|
||||
HOSTUNREACHABLE = 0x04, //! Network unreachable
|
||||
CONNREFUSED = 0x05, //! Connection refused
|
||||
TTLEXPIRED = 0x06, //! TTL expired
|
||||
CMDUNSUPPORTED = 0x07, //! Command not supported
|
||||
ATYPEUNSUPPORTED = 0x08, //! Address type not supported
|
||||
};
|
||||
|
||||
/** Values defined for ATYPE in RFC1928 */
|
||||
enum SOCKS5Atyp: uint8_t {
|
||||
IPV4 = 0x01,
|
||||
DOMAINNAME = 0x03,
|
||||
IPV6 = 0x04,
|
||||
};
|
||||
|
||||
/** Status codes that can be returned by InterruptibleRecv */
|
||||
enum class IntrRecvError {
|
||||
OK,
|
||||
Timeout,
|
||||
@ -217,7 +259,7 @@ enum class IntrRecvError {
|
||||
*
|
||||
* @note This function requires that hSocket is in non-blocking mode.
|
||||
*/
|
||||
static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSocket)
|
||||
static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, SOCKET& hSocket)
|
||||
{
|
||||
int64_t curTime = GetTimeMillis();
|
||||
int64_t endTime = curTime + timeout;
|
||||
@ -225,7 +267,7 @@ static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, SOCK
|
||||
// to break off in case of an interruption.
|
||||
const int64_t maxWait = 1000;
|
||||
while (len > 0 && curTime < endTime) {
|
||||
ssize_t ret = recv(hSocket, data, len, 0); // Optimistically try the recv first
|
||||
ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
|
||||
if (ret > 0) {
|
||||
len -= ret;
|
||||
data += ret;
|
||||
@ -256,24 +298,35 @@ static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, SOCK
|
||||
return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
|
||||
}
|
||||
|
||||
/** Credentials for proxy authentication */
|
||||
struct ProxyCredentials
|
||||
{
|
||||
std::string username;
|
||||
std::string password;
|
||||
};
|
||||
|
||||
std::string Socks5ErrorString(int err)
|
||||
/** Convert SOCKS5 reply to a an error message */
|
||||
std::string Socks5ErrorString(uint8_t err)
|
||||
{
|
||||
switch(err) {
|
||||
case 0x01: return "general failure";
|
||||
case 0x02: return "connection not allowed";
|
||||
case 0x03: return "network unreachable";
|
||||
case 0x04: return "host unreachable";
|
||||
case 0x05: return "connection refused";
|
||||
case 0x06: return "TTL expired";
|
||||
case 0x07: return "protocol error";
|
||||
case 0x08: return "address type not supported";
|
||||
default: return "unknown";
|
||||
case SOCKS5Reply::GENFAILURE:
|
||||
return "general failure";
|
||||
case SOCKS5Reply::NOTALLOWED:
|
||||
return "connection not allowed";
|
||||
case SOCKS5Reply::NETUNREACHABLE:
|
||||
return "network unreachable";
|
||||
case SOCKS5Reply::HOSTUNREACHABLE:
|
||||
return "host unreachable";
|
||||
case SOCKS5Reply::CONNREFUSED:
|
||||
return "connection refused";
|
||||
case SOCKS5Reply::TTLEXPIRED:
|
||||
return "TTL expired";
|
||||
case SOCKS5Reply::CMDUNSUPPORTED:
|
||||
return "protocol error";
|
||||
case SOCKS5Reply::ATYPEUNSUPPORTED:
|
||||
return "address type not supported";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,34 +341,34 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
|
||||
}
|
||||
// Accepted authentication methods
|
||||
std::vector<uint8_t> vSocks5Init;
|
||||
vSocks5Init.push_back(0x05);
|
||||
vSocks5Init.push_back(SOCKSVersion::SOCKS5);
|
||||
if (auth) {
|
||||
vSocks5Init.push_back(0x02); // # METHODS
|
||||
vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
|
||||
vSocks5Init.push_back(0x02); // X'02' USERNAME/PASSWORD (RFC1929)
|
||||
vSocks5Init.push_back(0x02); // Number of methods
|
||||
vSocks5Init.push_back(SOCKS5Method::NOAUTH);
|
||||
vSocks5Init.push_back(SOCKS5Method::USER_PASS);
|
||||
} else {
|
||||
vSocks5Init.push_back(0x01); // # METHODS
|
||||
vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
|
||||
vSocks5Init.push_back(0x01); // Number of methods
|
||||
vSocks5Init.push_back(SOCKS5Method::NOAUTH);
|
||||
}
|
||||
ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
|
||||
if (ret != (ssize_t)vSocks5Init.size()) {
|
||||
CloseSocket(hSocket);
|
||||
return error("Error sending to proxy");
|
||||
}
|
||||
char pchRet1[2];
|
||||
uint8_t pchRet1[2];
|
||||
if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
|
||||
CloseSocket(hSocket);
|
||||
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
|
||||
return false;
|
||||
}
|
||||
if (pchRet1[0] != 0x05) {
|
||||
if (pchRet1[0] != SOCKSVersion::SOCKS5) {
|
||||
CloseSocket(hSocket);
|
||||
return error("Proxy failed to initialize");
|
||||
}
|
||||
if (pchRet1[1] == 0x02 && auth) {
|
||||
if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) {
|
||||
// Perform username/password authentication (as described in RFC1929)
|
||||
std::vector<uint8_t> vAuth;
|
||||
vAuth.push_back(0x01);
|
||||
vAuth.push_back(0x01); // Current (and only) version of user/pass subnegotiation
|
||||
if (auth->username.size() > 255 || auth->password.size() > 255)
|
||||
return error("Proxy username or password too long");
|
||||
vAuth.push_back(auth->username.size());
|
||||
@ -328,7 +381,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
|
||||
return error("Error sending authentication to proxy");
|
||||
}
|
||||
LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
|
||||
char pchRetA[2];
|
||||
uint8_t pchRetA[2];
|
||||
if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
|
||||
CloseSocket(hSocket);
|
||||
return error("Error reading proxy authentication response");
|
||||
@ -337,17 +390,17 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
|
||||
CloseSocket(hSocket);
|
||||
return error("Proxy authentication unsuccessful");
|
||||
}
|
||||
} else if (pchRet1[1] == 0x00) {
|
||||
} else if (pchRet1[1] == SOCKS5Method::NOAUTH) {
|
||||
// Perform no authentication
|
||||
} else {
|
||||
CloseSocket(hSocket);
|
||||
return error("Proxy requested wrong authentication method %02x", pchRet1[1]);
|
||||
}
|
||||
std::vector<uint8_t> vSocks5;
|
||||
vSocks5.push_back(0x05); // VER protocol version
|
||||
vSocks5.push_back(0x01); // CMD CONNECT
|
||||
vSocks5.push_back(0x00); // RSV Reserved
|
||||
vSocks5.push_back(0x03); // ATYP DOMAINNAME
|
||||
vSocks5.push_back(SOCKSVersion::SOCKS5); // VER protocol version
|
||||
vSocks5.push_back(SOCKS5Command::CONNECT); // CMD CONNECT
|
||||
vSocks5.push_back(0x00); // RSV Reserved must be 0
|
||||
vSocks5.push_back(SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME
|
||||
vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function
|
||||
vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
|
||||
vSocks5.push_back((port >> 8) & 0xFF);
|
||||
@ -357,7 +410,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
|
||||
CloseSocket(hSocket);
|
||||
return error("Error sending to proxy");
|
||||
}
|
||||
char pchRet2[4];
|
||||
uint8_t pchRet2[4];
|
||||
if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
|
||||
CloseSocket(hSocket);
|
||||
if (recvr == IntrRecvError::Timeout) {
|
||||
@ -369,26 +422,26 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
|
||||
return error("Error while reading proxy response");
|
||||
}
|
||||
}
|
||||
if (pchRet2[0] != 0x05) {
|
||||
if (pchRet2[0] != SOCKSVersion::SOCKS5) {
|
||||
CloseSocket(hSocket);
|
||||
return error("Proxy failed to accept request");
|
||||
}
|
||||
if (pchRet2[1] != 0x00) {
|
||||
if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) {
|
||||
// Failures to connect to a peer that are not proxy errors
|
||||
CloseSocket(hSocket);
|
||||
LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
|
||||
return false;
|
||||
}
|
||||
if (pchRet2[2] != 0x00) {
|
||||
if (pchRet2[2] != 0x00) { // Reserved field must be 0
|
||||
CloseSocket(hSocket);
|
||||
return error("Error: malformed proxy response");
|
||||
}
|
||||
char pchRet3[256];
|
||||
uint8_t pchRet3[256];
|
||||
switch (pchRet2[3])
|
||||
{
|
||||
case 0x01: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
|
||||
case 0x04: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
|
||||
case 0x03:
|
||||
case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
|
||||
case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
|
||||
case SOCKS5Atyp::DOMAINNAME:
|
||||
{
|
||||
recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
|
||||
if (recvr != IntrRecvError::OK) {
|
||||
|
@ -55,12 +55,17 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string&
|
||||
// LogPrint("privatesend", "DSQUEUE -- %s seen\n", dsq.ToString());
|
||||
return;
|
||||
}
|
||||
if (q.fReady == dsq.fReady && q.masternodeOutpoint == dsq.masternodeOutpoint) {
|
||||
// no way the same mn can send another dsq with the same readiness this soon
|
||||
LogPrint("privatesend", "DSQUEUE -- Peer %d is sending WAY too many dsq messages for a masternode with collateral %s\n", pfrom->id, dsq.masternodeOutpoint.ToStringShort());
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // cs_vecqueue
|
||||
|
||||
LogPrint("privatesend", "DSQUEUE -- %s new\n", dsq.ToString());
|
||||
|
||||
if (dsq.IsExpired()) return;
|
||||
if (dsq.IsTimeOutOfBounds()) return;
|
||||
|
||||
auto mnList = deterministicMNManager->GetListAtChainTip();
|
||||
auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint);
|
||||
@ -84,18 +89,6 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string&
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOCK(cs_deqsessions); // have to lock this first to avoid deadlocks with cs_vecqueue
|
||||
TRY_LOCK(cs_vecqueue, lockRecv);
|
||||
if (!lockRecv) return;
|
||||
|
||||
for (const auto& q : vecPrivateSendQueue) {
|
||||
if (q.masternodeOutpoint == dsq.masternodeOutpoint) {
|
||||
// no way same mn can send another "not yet ready" dsq this soon
|
||||
LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending WAY too many dsq messages\n", dmn->pdmnState->ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq();
|
||||
int nThreshold = nLastDsq + mnList.GetValidMNsCount() / 5;
|
||||
LogPrint("privatesend", "DSQUEUE -- nLastDsq: %d threshold: %d nDsqCount: %d\n", nLastDsq, nThreshold, mmetaman.GetDsqCount());
|
||||
@ -108,12 +101,17 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string&
|
||||
mmetaman.AllowMixing(dmn->proTxHash);
|
||||
|
||||
LogPrint("privatesend", "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString());
|
||||
|
||||
LOCK(cs_deqsessions);
|
||||
for (auto& session : deqSessions) {
|
||||
CDeterministicMNCPtr mnMixing;
|
||||
if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->collateralOutpoint == dsq.masternodeOutpoint) {
|
||||
dsq.fTried = true;
|
||||
}
|
||||
}
|
||||
|
||||
TRY_LOCK(cs_vecqueue, lockRecv);
|
||||
if (!lockRecv) return;
|
||||
vecPrivateSendQueue.push_back(dsq);
|
||||
dsq.Relay(connman);
|
||||
}
|
||||
@ -1425,8 +1423,12 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(CConnman& connman)
|
||||
{
|
||||
if (!pwalletMain) return false;
|
||||
|
||||
// NOTE: We do not allow txes larger than 100kB, so we have to limit number of inputs here.
|
||||
// We still want to consume a lot of inputs to avoid creating only smaller denoms though.
|
||||
// Knowing that each CTxIn is at least 148b big, 400 inputs should take 400 x ~148b = ~60kB.
|
||||
// This still leaves more than enough room for another data of typical MakeCollateralAmounts tx.
|
||||
std::vector<CompactTallyItem> vecTally;
|
||||
if (!pwalletMain->SelectCoinsGroupedByAddresses(vecTally, false, false)) {
|
||||
if (!pwalletMain->SelectCoinsGroupedByAddresses(vecTally, false, false, true, 400)) {
|
||||
LogPrint("privatesend", "CPrivateSendClientSession::MakeCollateralAmounts -- SelectCoinsGroupedByAddresses can't find any inputs!\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -93,9 +93,6 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm
|
||||
}
|
||||
|
||||
} else if (strCommand == NetMsgType::DSQUEUE) {
|
||||
TRY_LOCK(cs_vecqueue, lockRecv);
|
||||
if (!lockRecv) return;
|
||||
|
||||
if (pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) {
|
||||
LogPrint("privatesend", "DSQUEUE -- peer=%d using obsolete version %i\n", pfrom->id, pfrom->nVersion);
|
||||
connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, strprintf("Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION)));
|
||||
@ -105,17 +102,27 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm
|
||||
CPrivateSendQueue dsq;
|
||||
vRecv >> dsq;
|
||||
|
||||
// process every dsq only once
|
||||
for (const auto& q : vecPrivateSendQueue) {
|
||||
if (q == dsq) {
|
||||
// LogPrint("privatesend", "DSQUEUE -- %s seen\n", dsq.ToString());
|
||||
return;
|
||||
{
|
||||
TRY_LOCK(cs_vecqueue, lockRecv);
|
||||
if (!lockRecv) return;
|
||||
|
||||
// process every dsq only once
|
||||
for (const auto& q : vecPrivateSendQueue) {
|
||||
if (q == dsq) {
|
||||
// LogPrint("privatesend", "DSQUEUE -- %s seen\n", dsq.ToString());
|
||||
return;
|
||||
}
|
||||
if (q.fReady == dsq.fReady && q.masternodeOutpoint == dsq.masternodeOutpoint) {
|
||||
// no way the same mn can send another dsq with the same readiness this soon
|
||||
LogPrint("privatesend", "DSQUEUE -- Peer %d is sending WAY too many dsq messages for a masternode with collateral %s\n", pfrom->id, dsq.masternodeOutpoint.ToStringShort());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // cs_vecqueue
|
||||
|
||||
LogPrint("privatesend", "DSQUEUE -- %s new\n", dsq.ToString());
|
||||
|
||||
if (dsq.IsExpired()) return;
|
||||
if (dsq.IsTimeOutOfBounds()) return;
|
||||
|
||||
auto mnList = deterministicMNManager->GetListAtChainTip();
|
||||
auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint);
|
||||
@ -128,14 +135,6 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm
|
||||
}
|
||||
|
||||
if (!dsq.fReady) {
|
||||
for (const auto& q : vecPrivateSendQueue) {
|
||||
if (q.masternodeOutpoint == dsq.masternodeOutpoint) {
|
||||
// no way same mn can send another "not yet ready" dsq this soon
|
||||
LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending WAY too many dsq messages\n", dmn->pdmnState->addr.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq();
|
||||
int nThreshold = nLastDsq + mnList.GetValidMNsCount() / 5;
|
||||
LogPrint("privatesend", "DSQUEUE -- nLastDsq: %d threshold: %d nDsqCount: %d\n", nLastDsq, nThreshold, mmetaman.GetDsqCount());
|
||||
@ -147,6 +146,9 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm
|
||||
mmetaman.AllowMixing(dmn->proTxHash);
|
||||
|
||||
LogPrint("privatesend", "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString());
|
||||
|
||||
TRY_LOCK(cs_vecqueue, lockRecv);
|
||||
if (!lockRecv) return;
|
||||
vecPrivateSendQueue.push_back(dsq);
|
||||
dsq.Relay(connman);
|
||||
}
|
||||
@ -507,10 +509,11 @@ void CPrivateSendServer::ChargeRandomFees(CConnman& connman)
|
||||
void CPrivateSendServer::CheckTimeout(CConnman& connman)
|
||||
{
|
||||
if (!fMasternodeMode) return;
|
||||
if (nState == POOL_STATE_IDLE) return;
|
||||
|
||||
CheckQueue();
|
||||
|
||||
if (nState == POOL_STATE_IDLE) return;
|
||||
|
||||
int nTimeout = (nState == POOL_STATE_SIGNING) ? PRIVATESEND_SIGNING_TIMEOUT : PRIVATESEND_QUEUE_TIMEOUT;
|
||||
bool fTimeout = GetTime() - nTimeLastSuccessfulStep >= nTimeout;
|
||||
|
||||
|
@ -80,6 +80,11 @@ bool CPrivateSendQueue::Relay(CConnman& connman)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPrivateSendQueue::IsTimeOutOfBounds() const
|
||||
{
|
||||
return GetAdjustedTime() - nTime > PRIVATESEND_QUEUE_TIMEOUT || nTime - GetAdjustedTime() > PRIVATESEND_QUEUE_TIMEOUT;
|
||||
}
|
||||
|
||||
uint256 CPrivateSendBroadcastTx::GetSignatureHash() const
|
||||
{
|
||||
return SerializeHash(*this);
|
||||
@ -149,8 +154,8 @@ void CPrivateSendBaseManager::CheckQueue()
|
||||
// check mixing queue objects for timeouts
|
||||
std::vector<CPrivateSendQueue>::iterator it = vecPrivateSendQueue.begin();
|
||||
while (it != vecPrivateSendQueue.end()) {
|
||||
if ((*it).IsExpired()) {
|
||||
LogPrint("privatesend", "CPrivateSendBaseManager::%s -- Removing expired queue (%s)\n", __func__, (*it).ToString());
|
||||
if ((*it).IsTimeOutOfBounds()) {
|
||||
LogPrint("privatesend", "CPrivateSendBaseManager::%s -- Removing a queue (%s)\n", __func__, (*it).ToString());
|
||||
it = vecPrivateSendQueue.erase(it);
|
||||
} else
|
||||
++it;
|
||||
@ -164,7 +169,7 @@ bool CPrivateSendBaseManager::GetQueueItemAndTry(CPrivateSendQueue& dsqRet)
|
||||
|
||||
for (auto& dsq : vecPrivateSendQueue) {
|
||||
// only try each queue once
|
||||
if (dsq.fTried || dsq.IsExpired()) continue;
|
||||
if (dsq.fTried || dsq.IsTimeOutOfBounds()) continue;
|
||||
dsq.fTried = true;
|
||||
dsqRet = dsq;
|
||||
return true;
|
||||
|
@ -229,8 +229,8 @@ public:
|
||||
|
||||
bool Relay(CConnman& connman);
|
||||
|
||||
/// Is this queue expired?
|
||||
bool IsExpired() { return GetAdjustedTime() - nTime > PRIVATESEND_QUEUE_TIMEOUT; }
|
||||
/// Check if a queue is too old or too far into the future
|
||||
bool IsTimeOutOfBounds() const;
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
|
@ -136,7 +136,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
{ "prioritisetransaction", 1, "fee_delta" },
|
||||
{ "setban", 2, "bantime" },
|
||||
{ "setban", 3, "absolute" },
|
||||
{ "setbip69enabled", 0, "enabled" },
|
||||
{ "setnetworkactive", 0, "state" },
|
||||
{ "setprivatesendrounds", 0, "rounds" },
|
||||
{ "setprivatesendamount", 0, "amount" },
|
||||
|
@ -354,7 +354,7 @@ UniValue masternode_status(const JSONRPCRequest& request)
|
||||
mnObj.push_back(Pair("outpoint", activeMasternodeInfo.outpoint.ToStringShort()));
|
||||
mnObj.push_back(Pair("service", activeMasternodeInfo.service.ToString()));
|
||||
|
||||
auto dmn = activeMasternodeManager->GetDMN();
|
||||
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(activeMasternodeInfo.proTxHash);
|
||||
if (dmn) {
|
||||
mnObj.push_back(Pair("proTxHash", dmn->proTxHash.ToString()));
|
||||
mnObj.push_back(Pair("collateralHash", dmn->collateralOutpoint.hash.ToString()));
|
||||
|
@ -193,6 +193,10 @@ bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockF
|
||||
return WriteBatch(batch, true);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::HasTxIndex(const uint256& txid) {
|
||||
return Exists(std::make_pair(DB_TXINDEX, txid));
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
|
||||
return Read(std::make_pair(DB_TXINDEX, txid), pos);
|
||||
}
|
||||
|
@ -122,6 +122,7 @@ public:
|
||||
bool ReadLastBlockFile(int &nFile);
|
||||
bool WriteReindexing(bool fReindex);
|
||||
bool ReadReindexing(bool &fReindex);
|
||||
bool HasTxIndex(const uint256 &txid);
|
||||
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
|
||||
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
|
||||
bool ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
|
||||
|
@ -1755,6 +1755,13 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s
|
||||
// move best block pointer to prevout block
|
||||
view.SetBestBlock(pindex->pprev->GetBlockHash());
|
||||
|
||||
if (fSpentIndex) {
|
||||
if (!pblocktree->UpdateSpentIndex(spentIndex)) {
|
||||
AbortNode("Failed to delete spent index");
|
||||
return DISCONNECT_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fAddressIndex) {
|
||||
if (!pblocktree->EraseAddressIndex(addressIndex)) {
|
||||
AbortNode(state, "Failed to delete address index");
|
||||
|
@ -2977,27 +2977,6 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue setbip69enabled(const JSONRPCRequest& request)
|
||||
{
|
||||
CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
if (request.fHelp || request.params.size() != 1)
|
||||
throw std::runtime_error(
|
||||
"setbip69enabled enable\n"
|
||||
"\nEnable/Disable BIP69 input/output sorting (-regtest only)\n"
|
||||
"\nArguments:\n"
|
||||
"1. enable (bool, required) true or false"
|
||||
);
|
||||
if (Params().NetworkIDString() != CBaseChainParams::REGTEST)
|
||||
throw std::runtime_error("setbip69enabled for regression testing (-regtest mode) only");
|
||||
|
||||
bBIP69Enabled = request.params[0].get_bool();
|
||||
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||
extern UniValue importprivkey(const JSONRPCRequest& request);
|
||||
extern UniValue importaddress(const JSONRPCRequest& request);
|
||||
@ -3068,8 +3047,6 @@ static const CRPCCommand commands[] =
|
||||
{ "wallet", "instantsendtoaddress", &instantsendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount"} },
|
||||
{ "wallet", "dumphdinfo", &dumphdinfo, true, {} },
|
||||
{ "wallet", "importelectrumwallet", &importelectrumwallet, true, {"filename", "index"} },
|
||||
|
||||
{ "hidden", "setbip69enabled", &setbip69enabled, true, {} },
|
||||
};
|
||||
|
||||
void RegisterWalletRPCCommands(CRPCTable &t)
|
||||
|
@ -50,7 +50,6 @@ CWallet* pwalletMain = NULL;
|
||||
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
|
||||
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
|
||||
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
|
||||
bool bBIP69Enabled = true;
|
||||
|
||||
const char * DEFAULT_WALLET_DAT = "wallet.dat";
|
||||
|
||||
@ -1314,6 +1313,12 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex,
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
|
||||
// v0.14.0.x: Simulates the behavior found in the develop branch when ::BlockConnected/BlockDisconnected are called
|
||||
if (pindex != nullptr && (posInBlock == 0 || posInBlock == CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK)) {
|
||||
fAnonymizableTallyCached = false;
|
||||
fAnonymizableTallyCachedNonDenom = false;
|
||||
}
|
||||
|
||||
if (!AddToWalletIfInvolvingMe(tx, pindex, posInBlock, true))
|
||||
return; // Not one of ours
|
||||
|
||||
@ -2565,6 +2570,7 @@ static void ApproximateBestSubset(std::vector<std::pair<CAmount, std::pair<const
|
||||
|
||||
vfBest.assign(vValue.size(), true);
|
||||
nBest = nTotalLower;
|
||||
int nBestInputCount = 0;
|
||||
|
||||
if (!llmq::IsOldInstantSendEnabled()) {
|
||||
// The new system does not require special handling for InstantSend as this is all done in CInstantSendManager.
|
||||
@ -2578,6 +2584,7 @@ static void ApproximateBestSubset(std::vector<std::pair<CAmount, std::pair<const
|
||||
{
|
||||
vfIncluded.assign(vValue.size(), false);
|
||||
CAmount nTotal = 0;
|
||||
int nTotalInputCount = 0;
|
||||
bool fReachedTarget = false;
|
||||
for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
|
||||
{
|
||||
@ -2595,16 +2602,19 @@ static void ApproximateBestSubset(std::vector<std::pair<CAmount, std::pair<const
|
||||
if (nPass == 0 ? insecure_rand.rand32()&1 : !vfIncluded[i])
|
||||
{
|
||||
nTotal += vValue[i].first;
|
||||
++nTotalInputCount;
|
||||
vfIncluded[i] = true;
|
||||
if (nTotal >= nTargetValue)
|
||||
{
|
||||
fReachedTarget = true;
|
||||
if (nTotal < nBest)
|
||||
if (nTotal < nBest || (nTotal == nBest && nTotalInputCount < nBestInputCount))
|
||||
{
|
||||
nBest = nTotal;
|
||||
nBestInputCount = nTotalInputCount;
|
||||
vfBest = vfIncluded;
|
||||
}
|
||||
nTotal -= vValue[i].first;
|
||||
--nTotalInputCount;
|
||||
vfIncluded[i] = false;
|
||||
}
|
||||
}
|
||||
@ -2690,8 +2700,10 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
|
||||
|
||||
const CWalletTx *pcoin = output.tx;
|
||||
|
||||
bool fLockedByIS = pcoin->IsLockedByInstantSend();
|
||||
|
||||
// if (fDebug) LogPrint("selectcoins", "value %s confirms %d\n", FormatMoney(pcoin->vout[output.i].nValue), output.nDepth);
|
||||
if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))
|
||||
if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs) && !fLockedByIS)
|
||||
continue;
|
||||
|
||||
if (!mempool.TransactionWithinChainLimit(pcoin->GetHash(), nMaxAncestors))
|
||||
@ -2767,7 +2779,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
|
||||
CAmount nBest;
|
||||
|
||||
ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, fUseInstantSend);
|
||||
if (nBest != nTargetValue && nTotalLower >= nTargetValue + nMinChange)
|
||||
if (nBest != nTargetValue && nMinChange != 0 && nTotalLower >= nTargetValue + nMinChange)
|
||||
ApproximateBestSubset(vValue, nTotalLower, nTargetValue + nMinChange, vfBest, nBest, fUseInstantSend);
|
||||
|
||||
// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
|
||||
@ -3001,8 +3013,9 @@ bool CWallet::SelectCoinsGroupedByAddresses(std::vector<CompactTallyItem>& vecTa
|
||||
|
||||
isminefilter filter = ISMINE_SPENDABLE;
|
||||
|
||||
// try to use cache for already confirmed anonymizable inputs, no cache should be used when the limit is specified
|
||||
if(nMaxOupointsPerAddress != -1 && fAnonymizable && fSkipUnconfirmed) {
|
||||
// Try using the cache for already confirmed anonymizable inputs.
|
||||
// This should only be used if nMaxOupointsPerAddress was NOT specified.
|
||||
if(nMaxOupointsPerAddress == -1 && fAnonymizable && fSkipUnconfirmed) {
|
||||
if(fSkipDenominated && fAnonymizableTallyCachedNonDenom) {
|
||||
vecTallyRet = vecAnonymizableTallyCachedNonDenom;
|
||||
LogPrint("selectcoins", "SelectCoinsGroupedByAddresses - using cache for non-denom inputs %d\n", vecTallyRet.size());
|
||||
@ -3074,8 +3087,9 @@ bool CWallet::SelectCoinsGroupedByAddresses(std::vector<CompactTallyItem>& vecTa
|
||||
vecTallyRet.push_back(item.second);
|
||||
}
|
||||
|
||||
// cache already confirmed anonymizable entries for later use, no cache should be saved when the limit is specified
|
||||
if(nMaxOupointsPerAddress != -1 && fAnonymizable && fSkipUnconfirmed) {
|
||||
// Cache already confirmed anonymizable entries for later use.
|
||||
// This should only be used if nMaxOupointsPerAddress was NOT specified.
|
||||
if(nMaxOupointsPerAddress == -1 && fAnonymizable && fSkipUnconfirmed) {
|
||||
if(fSkipDenominated) {
|
||||
vecAnonymizableTallyCachedNonDenom = vecTallyRet;
|
||||
fAnonymizableTallyCachedNonDenom = true;
|
||||
@ -3578,7 +3592,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
|
||||
txNew.vin.push_back(txin);
|
||||
}
|
||||
|
||||
if (bBIP69Enabled) {
|
||||
// If no specific change position was requested, apply BIP69
|
||||
if (nChangePosRequest == -1) {
|
||||
std::sort(txNew.vin.begin(), txNew.vin.end(), CompareInputBIP69());
|
||||
std::sort(vecTxDSInTmp.begin(), vecTxDSInTmp.end(), CompareInputBIP69());
|
||||
std::sort(txNew.vout.begin(), txNew.vout.end(), CompareOutputBIP69());
|
||||
|
@ -43,7 +43,6 @@ extern CWallet* pwalletMain;
|
||||
extern CFeeRate payTxFee;
|
||||
extern unsigned int nTxConfirmTarget;
|
||||
extern bool bSpendZeroConfChange;
|
||||
extern bool bBIP69Enabled;
|
||||
|
||||
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
|
||||
//! -paytxfee default
|
||||
|
Loading…
Reference in New Issue
Block a user