Refactor few things here and there (#3066)

* Refactor `HandleFullyConfirmedBlock()`

* Pass `pindexMined` into `AddNonLockedTx()`

* Unify time import in Dash specific tests

* Refactor UpdateSpork and SetPrivKey
This commit is contained in:
UdjinM6 2019-08-28 14:51:59 +03:00 committed by GitHub
parent f2dcac3a4f
commit 9abc393839
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 106 additions and 102 deletions

View File

@ -983,8 +983,7 @@ void CInstantSendManager::ProcessNewTransaction(const CTransactionRef& tx, const
LOCK(cs);
if (!chainlocked && islockHash.IsNull()) {
// TX is not locked, so make sure it is tracked
AddNonLockedTx(tx);
nonLockedTxs.at(tx->GetHash()).pindexMined = pindex;
AddNonLockedTx(tx, pindex);
} else {
// TX is locked, so make sure we don't track it anymore
RemoveNonLockedTx(tx->GetHash(), true);
@ -1025,11 +1024,12 @@ void CInstantSendManager::BlockDisconnected(const std::shared_ptr<const CBlock>&
}
}
void CInstantSendManager::AddNonLockedTx(const CTransactionRef& tx)
void CInstantSendManager::AddNonLockedTx(const CTransactionRef& tx, const CBlockIndex* pindexMined)
{
AssertLockHeld(cs);
auto res = nonLockedTxs.emplace(tx->GetHash(), NonLockedTxInfo());
auto& info = res.first->second;
info.pindexMined = pindexMined;
if (!info.tx) {
info.tx = tx;
@ -1123,50 +1123,48 @@ void CInstantSendManager::UpdatedBlockTip(const CBlockIndex* pindexNew)
void CInstantSendManager::HandleFullyConfirmedBlock(const CBlockIndex* pindex)
{
LOCK(cs);
auto& consensusParams = Params().GetConsensus();
std::unordered_map<uint256, CInstantSendLockPtr> removeISLocks;
{
LOCK(cs);
auto removeISLocks = db.RemoveConfirmedInstantSendLocks(pindex->nHeight);
removeISLocks = db.RemoveConfirmedInstantSendLocks(pindex->nHeight);
if (pindex->nHeight > 100) {
db.RemoveArchivedInstantSendLocks(pindex->nHeight - 100);
}
for (auto& p : removeISLocks) {
auto& islockHash = p.first;
auto& islock = p.second;
LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: removed islock as it got fully confirmed\n", __func__,
islock->txid.ToString(), islockHash.ToString());
if (pindex->nHeight > 100) {
db.RemoveArchivedInstantSendLocks(pindex->nHeight - 100);
}
for (auto& p : removeISLocks) {
auto& islockHash = p.first;
auto& islock = p.second;
LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: removed islock as it got fully confirmed\n", __func__,
islock->txid.ToString(), islockHash.ToString());
for (auto& in : islock->inputs) {
auto inputRequestId = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in));
inputRequestIds.erase(inputRequestId);
for (auto& in : islock->inputs) {
auto inputRequestId = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in));
inputRequestIds.erase(inputRequestId);
// no need to keep recovered sigs for fully confirmed IS locks, as there is no chance for conflicts
// from now on. All inputs are spent now and can't be spend in any other TX.
quorumSigningManager->RemoveRecoveredSig(consensusParams.llmqForInstantSend, inputRequestId);
}
// same as in the loop
quorumSigningManager->RemoveRecoveredSig(consensusParams.llmqForInstantSend, islock->GetRequestId());
// no need to keep recovered sigs for fully confirmed IS locks, as there is no chance for conflicts
// from now on. All inputs are spent now and can't be spend in any other TX.
quorumSigningManager->RemoveRecoveredSig(consensusParams.llmqForInstantSend, inputRequestId);
}
// Find all previously unlocked TXs that got locked by this fully confirmed (ChainLock) block and remove them
// from the nonLockedTxs map. Also collect all children of these TXs and mark them for retrying of IS locking.
std::vector<uint256> toRemove;
for (auto& p : nonLockedTxs) {
auto pindexMined = p.second.pindexMined;
// same as in the loop
quorumSigningManager->RemoveRecoveredSig(consensusParams.llmqForInstantSend, islock->GetRequestId());
}
if (pindexMined && pindex->GetAncestor(pindexMined->nHeight) == pindexMined) {
toRemove.emplace_back(p.first);
}
}
for (auto& txid : toRemove) {
// This will also add children to pendingRetryTxs
RemoveNonLockedTx(txid, true);
// Find all previously unlocked TXs that got locked by this fully confirmed (ChainLock) block and remove them
// from the nonLockedTxs map. Also collect all children of these TXs and mark them for retrying of IS locking.
std::vector<uint256> toRemove;
for (auto& p : nonLockedTxs) {
auto pindexMined = p.second.pindexMined;
if (pindexMined && pindex->GetAncestor(pindexMined->nHeight) == pindexMined) {
toRemove.emplace_back(p.first);
}
}
for (auto& txid : toRemove) {
// This will also add children to pendingRetryTxs
RemoveNonLockedTx(txid, true);
}
}
void CInstantSendManager::RemoveMempoolConflictsForLock(const uint256& hash, const CInstantSendLock& islock)

View File

@ -145,7 +145,8 @@ public:
void TransactionAddedToMempool(const CTransactionRef& tx);
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted);
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected);
void AddNonLockedTx(const CTransactionRef& tx);
void AddNonLockedTx(const CTransactionRef& tx, const CBlockIndex* pindexMined);
void RemoveNonLockedTx(const uint256& txid, bool retryChildren);
void RemoveConflictedTx(const CTransaction& tx);

View File

@ -197,23 +197,27 @@ bool CSporkManager::UpdateSpork(SporkId nSporkID, int64_t nValue, CConnman& conn
{
CSporkMessage spork = CSporkMessage(nSporkID, nValue, GetAdjustedTime());
LOCK(cs);
bool fSpork6IsActive = IsSporkActive(SPORK_6_NEW_SIGS);
if(spork.Sign(sporkPrivKey, fSpork6IsActive)) {
CKeyID keyIDSigner;
if (!spork.GetSignerKeyID(keyIDSigner, fSpork6IsActive) || !setSporkPubKeyIDs.count(keyIDSigner)) {
LogPrintf("CSporkManager::UpdateSpork: failed to find keyid for private key\n");
return false;
}
{
LOCK(cs);
mapSporksByHash[spork.GetHash()] = spork;
mapSporksActive[nSporkID][keyIDSigner] = spork;
}
spork.Relay(connman);
return true;
if (!spork.Sign(sporkPrivKey, fSpork6IsActive)) {
LogPrintf("CSporkManager::%s -- ERROR: signing failed for spork %d\n", __func__, nSporkID);
return false;
}
return false;
CKeyID keyIDSigner;
if (!spork.GetSignerKeyID(keyIDSigner, fSpork6IsActive) || !setSporkPubKeyIDs.count(keyIDSigner)) {
LogPrintf("CSporkManager::UpdateSpork: failed to find keyid for private key\n");
return false;
}
LogPrintf("CSporkManager::%s -- signed %d %s\n", __func__, nSporkID, spork.GetHash().ToString());
mapSporksByHash[spork.GetHash()] = spork;
mapSporksActive[nSporkID][keyIDSigner] = spork;
spork.Relay(connman);
return true;
}
bool CSporkManager::IsSporkActive(SporkId nSporkID)
@ -312,17 +316,16 @@ bool CSporkManager::SetPrivKey(const std::string& strPrivKey)
}
CSporkMessage spork;
if (spork.Sign(key, IsSporkActive(SPORK_6_NEW_SIGS))) {
LOCK(cs);
// Test signing successful, proceed
LogPrintf("CSporkManager::SetPrivKey -- Successfully initialized as spork signer\n");
sporkPrivKey = key;
return true;
} else {
if (!spork.Sign(key, IsSporkActive(SPORK_6_NEW_SIGS))) {
LogPrintf("CSporkManager::SetPrivKey -- Test signing failed\n");
return false;
}
// Test signing successful, proceed
LOCK(cs);
LogPrintf("CSporkManager::SetPrivKey -- Successfully initialized as spork signer\n");
sporkPrivKey = key;
return true;
}
std::string CSporkManager::ToString() const

View File

@ -7,7 +7,6 @@ from collections import namedtuple
from test_framework.mininode import *
from test_framework.test_framework import DashTestFramework
from test_framework.util import *
from time import *
'''
dip4-coinbasemerkleroots.py

View File

@ -3,10 +3,11 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import time
from test_framework.mininode import *
from test_framework.test_framework import DashTestFramework
from test_framework.util import *
from time import *
'''
llmq-chainlocks.py
@ -77,10 +78,10 @@ class LLMQChainLocksTest(DashTestFramework):
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# Now try to reorg the chain
self.nodes[0].generate(2)
sleep(6)
time.sleep(6)
assert(self.nodes[1].getbestblockhash() == good_tip)
self.nodes[0].generate(2)
sleep(6)
time.sleep(6)
assert(self.nodes[1].getbestblockhash() == good_tip)
# Now let the node which is on the wrong chain reorg back to the locked chain
@ -106,7 +107,7 @@ class LLMQChainLocksTest(DashTestFramework):
for txid in txs:
tx = self.nodes[0].getrawtransaction(txid, 1)
assert("confirmations" not in tx)
sleep(1)
time.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_2_INSTANTSEND_ENABLED", 4070908800)
@ -132,8 +133,8 @@ class LLMQChainLocksTest(DashTestFramework):
self.wait_for_chainlock(node, tip)
def wait_for_chainlock(self, node, block_hash):
t = time()
while time() - t < 15:
t = time.time()
while time.time() - t < 15:
try:
block = node.getblock(block_hash)
if block["confirmations"] > 0 and block["chainlock"]:
@ -141,7 +142,7 @@ class LLMQChainLocksTest(DashTestFramework):
except:
# block might not be on the node yet
pass
sleep(0.1)
time.sleep(0.1)
raise AssertionError("wait_for_chainlock timed out")
def create_chained_txs(self, node, amount):

View File

@ -2,11 +2,12 @@
# Copyright (c) 2015-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.
import time
from test_framework.blocktools import get_masternode_payment, create_coinbase, create_block
from test_framework.mininode import *
from test_framework.test_framework import DashTestFramework
from test_framework.util import *
from time import *
'''
llmq-is-cl-conflicts.py
@ -113,7 +114,7 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
# Give the CLSIG some time to propagate. We unfortunately can't check propagation here as "getblock/getblockheader"
# is required to check for CLSIGs, but this requires the block header to be propagated already
sleep(1)
time.sleep(1)
# The block should get accepted now, and at the same time prune the conflicting ISLOCKs
submit_result = self.nodes[1].submitblock(ToHex(block))
@ -183,7 +184,7 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
# Send the ISLOCK, which should result in the last 2 blocks to be invalidated, even though the nodes don't know
# the locked transaction yet
self.test_node.send_islock(islock)
sleep(5)
time.sleep(5)
assert(self.nodes[0].getbestblockhash() == good_tip)
assert(self.nodes[1].getbestblockhash() == good_tip)
@ -210,8 +211,8 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
self.wait_for_chainlock(node, tip)
def wait_for_chainlock(self, node, block_hash):
t = time()
while time() - t < 15:
t = time.time()
while time.time() - t < 15:
try:
block = node.getblockheader(block_hash)
if block["confirmations"] > 0 and block["chainlock"]:
@ -219,7 +220,7 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
except:
# block might not be on the node yet
pass
sleep(0.1)
time.sleep(0.1)
raise AssertionError("wait_for_chainlock timed out")
def create_block(self, node, vtx=[]):
@ -293,13 +294,13 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
recSig = None
t = time()
while time() - t < 10:
t = time.time()
while time.time() - t < 10:
try:
recSig = self.nodes[0].quorum('getrecsig', 100, request_id, message_hash)
break
except:
sleep(0.1)
time.sleep(0.1)
assert(recSig is not None)
clsig = msg_clsig(height, blockHash, hex_str_to_bytes(recSig['sig']))
@ -322,13 +323,13 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
recSig = None
t = time()
while time() - t < 10:
t = time.time()
while time.time() - t < 10:
try:
recSig = self.nodes[0].quorum('getrecsig', 100, request_id, message_hash)
break
except:
sleep(0.1)
time.sleep(0.1)
assert(recSig is not None)
islock = msg_islock(inputs, tx.sha256, hex_str_to_bytes(recSig['sig']))

View File

@ -3,10 +3,11 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import time
from test_framework.mininode import *
from test_framework.test_framework import DashTestFramework
from test_framework.util import *
from time import *
'''
llmq-signing.py
@ -41,18 +42,18 @@ class LLMQSigningTest(DashTestFramework):
return True
def wait_for_sigs(hasrecsigs, isconflicting1, isconflicting2, timeout):
t = time()
while time() - t < timeout:
t = time.time()
while time.time() - t < timeout:
if check_sigs(hasrecsigs, isconflicting1, isconflicting2):
return
sleep(0.1)
time.sleep(0.1)
raise AssertionError("wait_for_sigs timed out")
def assert_sigs_nochange(hasrecsigs, isconflicting1, isconflicting2, timeout):
t = time()
while time() - t < timeout:
t = time.time()
while time.time() - t < timeout:
assert(check_sigs(hasrecsigs, isconflicting1, isconflicting2))
sleep(0.1)
time.sleep(0.1)
# Initial state
wait_for_sigs(False, False, False, 1)

View File

@ -3,9 +3,10 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import time
from test_framework.test_framework import DashTestFramework
from test_framework.util import *
from time import *
'''
llmq-simplepose.py
@ -36,8 +37,8 @@ class LLMQSimplePoSeTest(DashTestFramework):
self.stop_node(mn.nodeIdx)
self.nodes.remove(mn.node)
t = time()
while (not self.check_punished(mn) or not self.check_banned(mn)) and (time() - t) < 120:
t = time.time()
while (not self.check_punished(mn) or not self.check_banned(mn)) and (time.time() - t) < 120:
self.mine_quorum(expected_contributions=i-1, expected_complaints=i-1, expected_commitments=i-1)
assert(self.check_punished(mn) and self.check_banned(mn))

View File

@ -2,11 +2,11 @@
# 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.
import time
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from time import *
'''
multikeysporks.py
@ -105,15 +105,15 @@ class MultiKeySporkTest(BitcoinTestFramework):
node.spork('SPORK_2_INSTANTSEND_ENABLED', value)
def wait_for_test_spork_state(self, node, value):
start = time()
start = time.time()
got_state = False
while True:
if self.get_test_spork_state(node) == value:
got_state = True
break
if time() > start + 10:
if time.time() > start + 10:
break
sleep(0.1)
time.sleep(0.1)
return got_state
def run_test(self):

View File

@ -6,7 +6,6 @@
from test_framework.mininode import *
from test_framework.test_framework import DashTestFramework
from test_framework.util import *
from time import *
'''
InstantSendTest -- test InstantSend functionality (prevent doublespend for unconfirmed transactions)

View File

@ -2,11 +2,11 @@
# 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.
import time
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from time import *
'''
'''
@ -45,15 +45,15 @@ class SporkTest(BitcoinTestFramework):
# check spork propagation for connected nodes
self.set_test_spork_state(self.nodes[0], True)
start = time()
start = time.time()
sent = False
while True:
if self.get_test_spork_state(self.nodes[1]):
sent = True
break
if time() > start + 10:
if time.time() > start + 10:
break
sleep(0.1)
time.sleep(0.1)
assert(sent)
# restart nodes to check spork persistence
@ -72,15 +72,15 @@ class SporkTest(BitcoinTestFramework):
# connect new node and check spork propagation after restoring from cache
connect_nodes(self.nodes[1], 2)
start = time()
start = time.time()
sent = False
while True:
if self.get_test_spork_state(self.nodes[2]):
sent = True
break
if time() > start + 10:
if time.time() > start + 10:
break
sleep(0.1)
time.sleep(0.1)
assert(sent)