mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Merge pull request #4805 from PastaPastaPasta/v18.x-bc-pr2
[18.x] V18.x backport pr2
This commit is contained in:
commit
ce0aa5336d
@ -209,7 +209,7 @@ public:
|
||||
|
||||
/**
|
||||
* Execute a callback on all masternodes in the mnList. This will pass a reference
|
||||
* of each masternode to the callback function. This should be prefered over ForEachMNShared.
|
||||
* of each masternode to the callback function. This should be preferred over ForEachMNShared.
|
||||
* @param onlyValid Run on all masternodes, or only "valid" (not banned) masternodes
|
||||
* @param cb callback to execute
|
||||
*/
|
||||
|
@ -262,7 +262,7 @@ static constexpr std::array<LLMQParams, 10> available_llmqs = {
|
||||
.dkgPhaseBlocks = 2,
|
||||
.dkgMiningWindowStart = 10, // dkgPhaseBlocks * 5 = after finalization
|
||||
.dkgMiningWindowEnd = 18,
|
||||
.dkgBadVotesThreshold = 40,
|
||||
.dkgBadVotesThreshold = 48,
|
||||
|
||||
.signingActiveQuorumCount = 32,
|
||||
.keepOldConnections = 33,
|
||||
|
@ -65,9 +65,9 @@ std::vector<CDeterministicMNCPtr> CLLMQUtils::GetAllQuorumMembers(Consensus::LLM
|
||||
}
|
||||
/*
|
||||
* Quorums created with rotation are now created in a different way. All signingActiveQuorumCount are created during the period of dkgInterval.
|
||||
* But they are not created exactly in the same block, they are spreaded overtime: one quorum in each block until all signingActiveQuorumCount are created.
|
||||
* But they are not created exactly in the same block, they are spread overtime: one quorum in each block until all signingActiveQuorumCount are created.
|
||||
* The new concept of quorumIndex is introduced in order to identify them.
|
||||
* In every dkgInterval blocks (also called CycleQuorumBaseBlock), the spreaded quorum creation starts like this:
|
||||
* In every dkgInterval blocks (also called CycleQuorumBaseBlock), the spread quorum creation starts like this:
|
||||
* For quorumIndex = 0 : signingActiveQuorumCount
|
||||
* Quorum Q with quorumIndex is created at height CycleQuorumBaseBlock + quorumIndex
|
||||
*/
|
||||
@ -351,69 +351,77 @@ void CLLMQUtils::BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, co
|
||||
|
||||
std::vector<std::vector<CDeterministicMNCPtr>> CLLMQUtils::GetQuorumQuarterMembersBySnapshot(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight)
|
||||
{
|
||||
auto numQuorums = static_cast<size_t>(llmqParams.signingActiveQuorumCount);
|
||||
auto quorumSize = static_cast<size_t>(llmqParams.size);
|
||||
std::vector<CDeterministicMNCPtr> sortedCombinedMns;
|
||||
{
|
||||
const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8);
|
||||
const auto modifier = ::SerializeHash(std::make_pair(llmqParams.type, pWorkBlockIndex->GetBlockHash()));
|
||||
const auto [MnsUsedAtH, MnsNotUsedAtH] = CLLMQUtils::GetMNUsageBySnapshot(llmqParams.type, pQuorumBaseBlockIndex, snapshot, nHeight);
|
||||
// the list begins with all the unused MNs
|
||||
auto sortedMnsNotUsedAtH = MnsNotUsedAtH.CalculateQuorum(MnsNotUsedAtH.GetAllMNsCount(), modifier);
|
||||
sortedCombinedMns = std::move(sortedMnsNotUsedAtH);
|
||||
// Now add the already used MNs to the end of the list
|
||||
auto sortedMnsUsedAtH = MnsUsedAtH.CalculateQuorum(MnsUsedAtH.GetAllMNsCount(), modifier);
|
||||
std::move(sortedMnsUsedAtH.begin(), sortedMnsUsedAtH.end(), std::back_inserter(sortedCombinedMns));
|
||||
}
|
||||
|
||||
auto numQuorums = size_t(llmqParams.signingActiveQuorumCount);
|
||||
auto quorumSize = size_t(llmqParams.size);
|
||||
auto quarterSize = quorumSize / 4;
|
||||
|
||||
std::vector<std::vector<CDeterministicMNCPtr>> quarterQuorumMembers(numQuorums);
|
||||
|
||||
const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8);
|
||||
auto modifier = ::SerializeHash(std::make_pair(llmqParams.type, pWorkBlockIndex->GetBlockHash()));
|
||||
if (sortedCombinedMns.empty()) return quarterQuorumMembers;
|
||||
|
||||
auto [MnsUsedAtH, MnsNotUsedAtH] = CLLMQUtils::GetMNUsageBySnapshot(llmqParams.type, pQuorumBaseBlockIndex, snapshot, nHeight);
|
||||
|
||||
auto sortedMnsUsedAtH = MnsUsedAtH.CalculateQuorum(MnsUsedAtH.GetAllMNsCount(), modifier);
|
||||
auto sortedMnsNotUsedAtH = MnsNotUsedAtH.CalculateQuorum(MnsNotUsedAtH.GetAllMNsCount(), modifier);
|
||||
auto sortedCombinedMns = std::move(sortedMnsNotUsedAtH);
|
||||
for (auto& m : sortedMnsUsedAtH) {
|
||||
sortedCombinedMns.push_back(std::move(m));
|
||||
}
|
||||
|
||||
//Mode 0: No skipping
|
||||
if (snapshot.mnSkipListMode == SnapshotSkipMode::MODE_NO_SKIPPING) {
|
||||
auto itm = sortedCombinedMns.begin();
|
||||
for (auto i = 0; i < llmqParams.signingActiveQuorumCount; ++i) {
|
||||
while (quarterQuorumMembers[i].size() < quarterSize) {
|
||||
quarterQuorumMembers[i].push_back(*itm);
|
||||
itm++;
|
||||
if (itm == sortedCombinedMns.end())
|
||||
itm = sortedCombinedMns.begin();
|
||||
switch (snapshot.mnSkipListMode) {
|
||||
case SnapshotSkipMode::MODE_NO_SKIPPING:
|
||||
{
|
||||
auto itm = sortedCombinedMns.begin();
|
||||
for (auto i = 0; i < llmqParams.signingActiveQuorumCount; ++i) {
|
||||
while (quarterQuorumMembers[i].size() < quarterSize) {
|
||||
quarterQuorumMembers[i].push_back(*itm);
|
||||
itm++;
|
||||
if (itm == sortedCombinedMns.end()) {
|
||||
itm = sortedCombinedMns.begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
return quarterQuorumMembers;
|
||||
}
|
||||
}
|
||||
//Mode 1: List holds entries to be skipped
|
||||
else if (snapshot.mnSkipListMode == SnapshotSkipMode::MODE_SKIPPING_ENTRIES) {
|
||||
size_t first_entry_index = {};
|
||||
std::vector<int> processesdSkipList;
|
||||
for (const auto& s : snapshot.mnSkipList) {
|
||||
if (first_entry_index == 0) {
|
||||
first_entry_index = s;
|
||||
processesdSkipList.push_back(s);
|
||||
} else
|
||||
processesdSkipList.push_back(first_entry_index + s);
|
||||
}
|
||||
|
||||
auto idx = 0;
|
||||
auto itsk = processesdSkipList.begin();
|
||||
for (auto i = 0; i < llmqParams.signingActiveQuorumCount; ++i) {
|
||||
while (quarterQuorumMembers[i].size() < quarterSize) {
|
||||
if (itsk != processesdSkipList.end() && idx == *itsk)
|
||||
itsk++;
|
||||
else
|
||||
quarterQuorumMembers[i].push_back(sortedCombinedMns[idx]);
|
||||
idx++;
|
||||
if (idx == sortedCombinedMns.size())
|
||||
idx = 0;
|
||||
case SnapshotSkipMode::MODE_SKIPPING_ENTRIES: // List holds entries to be skipped
|
||||
{
|
||||
size_t first_entry_index{0};
|
||||
std::vector<int> processesdSkipList;
|
||||
for (const auto& s : snapshot.mnSkipList) {
|
||||
if (first_entry_index == 0) {
|
||||
first_entry_index = s;
|
||||
processesdSkipList.push_back(s);
|
||||
} else {
|
||||
processesdSkipList.push_back(first_entry_index + s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Mode 2: List holds entries to be kept
|
||||
else if (snapshot.mnSkipListMode == SnapshotSkipMode::MODE_NO_SKIPPING_ENTRIES) {
|
||||
//TODO Mode 2 will be written. Not used now
|
||||
}
|
||||
//Mode 3: Every node was skipped. Returning empty quarterQuorumMembers
|
||||
|
||||
return quarterQuorumMembers;
|
||||
auto idx = 0;
|
||||
auto itsk = processesdSkipList.begin();
|
||||
for (auto i = 0; i < llmqParams.signingActiveQuorumCount; ++i) {
|
||||
while (quarterQuorumMembers[i].size() < quarterSize) {
|
||||
if (itsk != processesdSkipList.end() && idx == *itsk) {
|
||||
itsk++;
|
||||
} else {
|
||||
quarterQuorumMembers[i].push_back(sortedCombinedMns[idx]);
|
||||
}
|
||||
idx++;
|
||||
if (idx == sortedCombinedMns.size()) {
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return quarterQuorumMembers;
|
||||
}
|
||||
case SnapshotSkipMode::MODE_NO_SKIPPING_ENTRIES: // List holds entries to be kept
|
||||
case SnapshotSkipMode::MODE_ALL_SKIPPED: // Every node was skipped. Returning empty quarterQuorumMembers
|
||||
default:
|
||||
return quarterQuorumMembers;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<CDeterministicMNList, CDeterministicMNList> CLLMQUtils::GetMNUsageBySnapshot(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight)
|
||||
@ -579,6 +587,12 @@ std::set<uint256> CLLMQUtils::GetQuorumRelayMembers(const Consensus::LLMQParams&
|
||||
std::set<uint256> result;
|
||||
|
||||
auto calcOutbound = [&](size_t i, const uint256& proTxHash) {
|
||||
if (mns.size() == 1) {
|
||||
// No outbound connections are needed when there is one MN only.
|
||||
// Also note that trying to calculate results via the algorithm below
|
||||
// would result in an endless loop.
|
||||
return std::set<uint256>();
|
||||
}
|
||||
// Relay to nodes at indexes (i+2^k)%n, where
|
||||
// k: 0..max(1, floor(log2(n-1))-1)
|
||||
// n: size of the quorum/ring
|
||||
|
@ -9,21 +9,23 @@
|
||||
#define UNUSED
|
||||
#endif
|
||||
static const char UNUSED *dash_strings[] = {
|
||||
QT_TRANSLATE_NOOP("dash-core", "Dash Core"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "The %s developers"),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"%s corrupt. Try using the wallet tool dash-wallet to salvage or restoring a "
|
||||
"backup."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"%s file contains all private keys from this wallet. Do not share it with "
|
||||
"anyone!"),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"%s uses exact denominated amounts to send funds, you might simply need to "
|
||||
"mix some more coins."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"-masternode option is deprecated and ignored, specifying -"
|
||||
"masternodeblsprivkey is enough to start this node as a masternode."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"-maxtxfee is set very high! Fees this large could be paid on a single "
|
||||
"transaction."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Can't generate a change-address key. No keys in the internal keypool and "
|
||||
"can't generate any keys."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Cannot obtain a lock on data directory %s. %s is probably already running."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Cannot provide specific connections and have addrman find outgoing "
|
||||
@ -43,6 +45,9 @@ QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"restarted wallet in less than 60 seconds. You can continue if you are ok "
|
||||
"with this."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -"
|
||||
"fallbackfee."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Found unconfirmed denominated outputs, will wait till they confirm to "
|
||||
"continue."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
@ -78,6 +83,10 @@ QT_TRANSLATE_NOOP("dash-core", ""
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"The transaction amount is too small to send after the fee has been deducted"),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"This error could occur if this wallet was not shutdown cleanly and was last "
|
||||
"loaded using a build with a newer version of Berkeley DB. If so, please use "
|
||||
"the software that last loaded this wallet"),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"This is a pre-release test build - use at your own risk - do not use for "
|
||||
"mining or merchant applications"),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
@ -100,27 +109,16 @@ QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Unable to replay blocks. You will need to rebuild the database using -"
|
||||
"reindex-chainstate."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Unsupported argument -socks found. Setting SOCKS version isn't possible "
|
||||
"anymore, only SOCKS5 proxies are supported."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/"
|
||||
"or -whitelistforcerelay."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"WARNING! Failed to replenish keypool, please unlock your wallet to do so."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Wallet is locked, can't replenish keypool! Automatic backups and mixing are "
|
||||
"disabled, please unlock your wallet to replenish keypool."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Warning: Private keys detected in wallet {%s} with disabled private keys"),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Warning: The network does not appear to fully agree! Some miners appear to "
|
||||
"be experiencing issues."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Warning: Unknown block versions being mined! It's possible unknown rules are "
|
||||
"in effect"),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; "
|
||||
"if your balance or transactions are incorrect you should restore from a "
|
||||
"backup."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"Warning: We do not appear to fully agree with our peers! You may need to "
|
||||
"upgrade, or other nodes may need to upgrade."),
|
||||
QT_TRANSLATE_NOOP("dash-core", ""
|
||||
@ -130,17 +128,17 @@ QT_TRANSLATE_NOOP("dash-core", ""
|
||||
"mode. This will redownload the entire blockchain"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "%d of last 100 blocks have unexpected version"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "%s can't be lower than %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "%s corrupt, salvage failed"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "%s failed"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "%s is idle."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "%s is not a valid backup folder!"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "%s is only allowed with a single wallet file"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "%s is set very high!"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "%s request incomplete: %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "%s request incomplete:"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "-devnet can only be specified once"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "-litemode is deprecated."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "-maxmempool must be at least %d MB"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "-port must be specified when -devnet and -listen are specified"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "-rpcport must be specified when -devnet and -server are specified"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "A fatal internal error occurred, see debug.log for details"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Already have that input."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Automatic backups disabled"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Can't find random Masternode."),
|
||||
@ -148,11 +146,16 @@ QT_TRANSLATE_NOOP("dash-core", "Can't mix while sync in progress."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Can't mix: no compatible inputs found!"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Cannot downgrade wallet"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Cannot resolve -%s address: '%s'"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Cannot set -peerblockfilters without -blockfilterindex."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Cannot write to data directory '%s'; check permissions."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Change index out of range"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Collateral not valid."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Config setting for %s only applied on %s network when in [%s] section."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Copyright (C)"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Corrupted block database detected"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Could not find asmap file %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Could not parse asmap file %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Disk space is too low!"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Do you want to rebuild the block database now?"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Done loading"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "ERROR! Failed to create automatic backup"),
|
||||
@ -161,6 +164,7 @@ QT_TRANSLATE_NOOP("dash-core", "Entry exceeds maximum size."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error initializing block database"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error initializing wallet database environment %s!"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error loading %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error loading %s: Private keys can only be disabled during creation"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error loading %s: Wallet corrupted"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error loading %s: Wallet requires newer version of %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error loading %s: You can't disable HD on an already existing HD wallet"),
|
||||
@ -170,25 +174,24 @@ QT_TRANSLATE_NOOP("dash-core", "Error opening block database"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error reading from database, shutting down."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error upgrading chainstate database"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error upgrading evo database"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error: A fatal internal error occurred, see debug.log for details"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error: Disk space is low!"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error: Disk space is low for %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error: failed to add socket to epollfd (epoll_ctl returned error %s)"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Error: failed to add socket to kqueuefd (kevent returned error %s)"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Exceeded max tries."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to clear fulfilled requests cache at"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to clear governance cache at"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to clear masternode cache at"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to clear fulfilled requests cache at %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to clear governance cache at %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to clear masternode cache at %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to commit EvoDB"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to create backup %s!"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to create backup, error: %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to delete backup, error: %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to find mixing queue to join"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to listen on any port. Use -listen=0 if you want this."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to load fulfilled requests cache from"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to load governance cache from"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to load masternode cache from"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to load sporks cache from"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to load fulfilled requests cache from %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to load governance cache from %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to load masternode cache from %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to load sporks cache from %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to rescan the wallet during initialization"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Failed to start a new mixing queue"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Found enough users, signing ( waiting %s )"),
|
||||
@ -198,13 +201,13 @@ QT_TRANSLATE_NOOP("dash-core", "Incompatible mode."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Incompatible version."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Incorrect -rescan mode, falling back to default value"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Incorrect or no genesis block found. Wrong datadir for network?"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Information"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Initialization sanity check failed. %s is shutting down."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Input is not valid."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Inputs vs outputs size mismatch."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Insufficient funds."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Invalid -onion address or hostname: '%s'"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Invalid -proxy address or hostname: '%s'"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Invalid P2P permission: '%s'"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Invalid amount for -%s=<amount>: '%s'"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Invalid amount for -discardfee=<amount>: '%s'"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Invalid amount for -fallbackfee=<amount>: '%s'"),
|
||||
@ -214,8 +217,6 @@ QT_TRANSLATE_NOOP("dash-core", "Invalid minimum number of spork signers specifie
|
||||
QT_TRANSLATE_NOOP("dash-core", "Invalid netmask specified in -whitelist: '%s'"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Invalid script detected."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Invalid spork address specified with -sporkaddr"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "It has been replaced by -disablegovernance."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Its replacement -disablegovernance has been forced instead."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Keypool ran out, please call keypoolrefill first"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Last queue was created too recently."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Last successful action was too recent."),
|
||||
@ -243,12 +244,14 @@ QT_TRANSLATE_NOOP("dash-core", "Not enough file descriptors available."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Not enough funds to mix."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Not in the Masternode list."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Prune cannot be configured with a negative value."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Prune mode is incompatible with -blockfilterindex."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Prune mode is incompatible with -disablegovernance=false."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Prune mode is incompatible with -txindex."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Pruning blockstore..."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Reducing -maxconnections from %d to %d, because of system limitations."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Replaying blocks..."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Rescanning..."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Section [%s] is not recognized."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Session not complete!"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Session timed out."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Signing transaction failed"),
|
||||
@ -262,6 +265,7 @@ QT_TRANSLATE_NOOP("dash-core", "Synchronization finished"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Synchronizing blockchain..."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Synchronizing governance objects..."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "The source code is available from %s."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "The specified config file %s does not exist\n"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "The transaction amount is too small to pay the fee"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "The wallet will avoid paying less than the minimum relay fee."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "This is expected because you are running a pruned node."),
|
||||
@ -275,33 +279,29 @@ QT_TRANSLATE_NOOP("dash-core", "Transaction fees are too high."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Transaction has too long of a mempool chain"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Transaction must have at least one recipient"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Transaction not valid."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Transaction too large for fee policy"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Transaction too large"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Trying to connect..."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unable to bind to %s on this computer (bind returned error %s)"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unable to bind to %s on this computer. %s is probably already running."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unable to create the PID file '%s': %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unable to generate initial keys"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unable to locate enough mixed funds for this transaction."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unable to locate enough non-denominated funds for this transaction."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unable to sign spork message, wrong key?"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unable to start HTTP server. See debug log for details."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unknown -blockfilterindex value %s."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unknown network specified in -onlynet: '%s'"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unknown response."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unknown state: id = %u"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unsupported argument -benchmark ignored, use -debug=bench."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unsupported argument -debugnet ignored, use -debug=net."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unsupported argument -tor found, use -onion."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Unsupported logging category %s=%s."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Upgrading UTXO database"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Upgrading txindex database"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "User Agent comment (%s) contains unsafe characters."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Verifying blocks..."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Verifying wallet(s)..."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Very low number of keys left: %d"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Wallet %s resides outside wallet directory %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Wallet is locked."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Wallet needed to be rewritten: restart %s to complete"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Warning"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Warning: %s is deprecated, please use %s instead"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Warning: can't use %s and %s together, will prefer %s"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Warning: incorrect parameter %s, path must exist! Using default path."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Warning: unknown new rules activated (versionbit %i)"),
|
||||
@ -312,7 +312,6 @@ QT_TRANSLATE_NOOP("dash-core", "You can not disable governance validation on a m
|
||||
QT_TRANSLATE_NOOP("dash-core", "You can not start a masternode with wallet enabled."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "You need to rebuild the database using -reindex to change -addressindex"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "You need to rebuild the database using -reindex to change -spentindex"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "You need to rebuild the database using -reindex to change -txindex"),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Your entries added successfully."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "Zapping all transactions from wallet..."),
|
||||
QT_TRANSLATE_NOOP("dash-core", "no mixing available."),
|
||||
|
@ -61,7 +61,7 @@
|
||||
<item>
|
||||
<widget class="QLineEdit" name="filterLineEdit">
|
||||
<property name="toolTip">
|
||||
<string>Filter propsal list</string>
|
||||
<string>Filter proposal list</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -153,14 +153,20 @@ void WalletView::setClientModel(ClientModel *_clientModel)
|
||||
{
|
||||
this->clientModel = _clientModel;
|
||||
|
||||
overviewPage->setClientModel(_clientModel);
|
||||
sendCoinsPage->setClientModel(_clientModel);
|
||||
coinJoinCoinsPage->setClientModel(_clientModel);
|
||||
if (overviewPage != nullptr) {
|
||||
overviewPage->setClientModel(_clientModel);
|
||||
}
|
||||
if (sendCoinsPage != nullptr) {
|
||||
sendCoinsPage->setClientModel(_clientModel);
|
||||
}
|
||||
if (coinJoinCoinsPage != nullptr) {
|
||||
coinJoinCoinsPage->setClientModel(_clientModel);
|
||||
}
|
||||
QSettings settings;
|
||||
if (settings.value("fShowMasternodesTab").toBool()) {
|
||||
if (settings.value("fShowMasternodesTab").toBool() && masternodeListPage != nullptr) {
|
||||
masternodeListPage->setClientModel(_clientModel);
|
||||
}
|
||||
if (settings.value("fShowGovernanceTab").toBool()) {
|
||||
if (settings.value("fShowGovernanceTab").toBool() && governanceListPage != nullptr) {
|
||||
governanceListPage->setClientModel(_clientModel);
|
||||
}
|
||||
}
|
||||
|
@ -647,26 +647,27 @@ static UniValue quorum_getdata(const JSONRPCRequest& request)
|
||||
});
|
||||
}
|
||||
|
||||
static void quorum_getrotationinfo_help()
|
||||
static void quorum_rotationinfo_help()
|
||||
{
|
||||
throw std::runtime_error(
|
||||
RPCHelpMan{
|
||||
"quorum rotationinfo",
|
||||
"Get quorum rotation information\n",
|
||||
{{"blockRequestHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The blockHash of the request."},
|
||||
{"baseBlockHashesNb", RPCArg::Type::NUM, RPCArg::Optional::NO,
|
||||
"Number of baseBlockHashes"},
|
||||
{"extraShare", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Extra share"}},
|
||||
{
|
||||
{"blockRequestHash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The blockHash of the request"},
|
||||
{"extraShare", RPCArg::Type::BOOL, /* default */ "false", "Extra share"},
|
||||
{"baseBlockHash...", RPCArg::Type::STR_HEX, /* default*/ "", "baseBlockHashes"},
|
||||
},
|
||||
RPCResults{},
|
||||
RPCExamples{""},
|
||||
}
|
||||
.ToString());
|
||||
.ToString());
|
||||
}
|
||||
|
||||
static UniValue quorum_getrotationdata(const JSONRPCRequest& request)
|
||||
static UniValue quorum_rotationinfo(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || (request.params.size() < 2)) {
|
||||
quorum_getrotationinfo_help();
|
||||
quorum_rotationinfo_help();
|
||||
}
|
||||
|
||||
llmq::CGetQuorumRotationInfo cmd;
|
||||
@ -674,15 +675,12 @@ static UniValue quorum_getrotationdata(const JSONRPCRequest& request)
|
||||
std::string strError;
|
||||
|
||||
cmd.blockRequestHash = ParseHashV(request.params[1], "blockRequestHash");
|
||||
size_t baseBlockHashesNb = static_cast<uint32_t>(ParseInt32V(request.params[2], "baseBlockHashesNb"));
|
||||
cmd.extraShare = ParseBoolV(request.params[3], "extraShare");
|
||||
cmd.extraShare = request.params[2].isNull() ? false : ParseBoolV(request.params[2], "extraShare");
|
||||
|
||||
/*if (request.params.size() - 2 != cmd.baseBlockHashesNb) {
|
||||
quorum_getrotationinfo_help();
|
||||
}*/
|
||||
|
||||
for (auto i = 0; i < baseBlockHashesNb; i++) {
|
||||
cmd.baseBlockHashes.push_back(ParseHashV(request.params[3 + i], "quorumHash"));
|
||||
size_t idx = 3;
|
||||
while (!request.params[idx].isNull()) {
|
||||
cmd.baseBlockHashes.emplace_back(ParseHashV(request.params[idx], "baseBlockHash"));
|
||||
++idx;
|
||||
}
|
||||
LOCK(cs_main);
|
||||
if (!BuildQuorumRotationInfo(cmd, quorumRotationInfoRet, strError)) {
|
||||
@ -753,7 +751,7 @@ static UniValue _quorum(const JSONRPCRequest& request)
|
||||
} else if (command == "getdata") {
|
||||
return quorum_getdata(request);
|
||||
} else if (command == "rotationinfo") {
|
||||
return quorum_getrotationdata(request);
|
||||
return quorum_rotationinfo(request);
|
||||
} else {
|
||||
quorum_help();
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ void DoCheck(const std::string& prv, const std::string& pub, int flags, const st
|
||||
// When the descriptor is hardened, evaluate with access to the private keys inside.
|
||||
const FlatSigningProvider& key_provider = (flags & HARDENED) ? keys_priv : keys_pub;
|
||||
|
||||
// Evaluate the descriptor selected by `t` in poisition `i`.
|
||||
// Evaluate the descriptor selected by `t` in position `i`.
|
||||
FlatSigningProvider script_provider, script_provider_cached;
|
||||
std::vector<CScript> spks, spks_cached;
|
||||
std::vector<unsigned char> cache;
|
||||
|
@ -51,8 +51,8 @@ class TestP2PConn(P2PInterface):
|
||||
|
||||
class LLMQ_IS_CL_Conflicts(DashTestFramework):
|
||||
def set_test_params(self):
|
||||
self.set_dash_test_params(4, 3, fast_dip3_enforcement=True)
|
||||
#disable_mocktime()
|
||||
self.set_dash_test_params(5, 4, fast_dip3_enforcement=True)
|
||||
self.set_dash_llmq_test_params(4, 4)
|
||||
|
||||
def run_test(self):
|
||||
self.activate_dip8()
|
||||
@ -72,6 +72,14 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
|
||||
self.test_chainlock_overrides_islock(True, False)
|
||||
self.test_chainlock_overrides_islock(True, True)
|
||||
self.test_chainlock_overrides_islock_overrides_nonchainlock(False)
|
||||
self.activate_dip0024()
|
||||
self.log.info("Activated DIP0024 at height:" + str(self.nodes[0].getblockcount()))
|
||||
self.test_chainlock_overrides_islock_overrides_nonchainlock(False)
|
||||
# At this point, we need to move forward 3 cycles (3 x 24 blocks) so the first 3 quarters can be created (without DKG sessions)
|
||||
self.move_to_next_cycle()
|
||||
self.move_to_next_cycle()
|
||||
self.move_to_next_cycle()
|
||||
self.mine_cycle_quorum()
|
||||
self.test_chainlock_overrides_islock_overrides_nonchainlock(True)
|
||||
|
||||
def test_chainlock_overrides_islock(self, test_block_conflict, mine_confllicting=False):
|
||||
@ -320,7 +328,7 @@ class LLMQ_IS_CL_Conflicts(DashTestFramework):
|
||||
|
||||
coinbase.calc_sha256()
|
||||
|
||||
block = create_block(int(tip_hash, 16), coinbase, ntime=bt['curtime'])
|
||||
block = create_block(int(tip_hash, 16), coinbase, ntime=bt['curtime'], version=bt['version'])
|
||||
block.vtx += vtx
|
||||
|
||||
# Add quorum commitments from template
|
||||
|
@ -6,7 +6,7 @@ import time
|
||||
|
||||
from test_framework.messages import CTransaction, FromHex, hash256, ser_compact_size, ser_string
|
||||
from test_framework.test_framework import DashTestFramework
|
||||
from test_framework.util import wait_until, connect_nodes, sync_blocks
|
||||
from test_framework.util import wait_until, connect_nodes
|
||||
|
||||
'''
|
||||
feature_llmq_is_migration.py
|
||||
@ -91,7 +91,7 @@ class LLMQISMigrationTest(DashTestFramework):
|
||||
self.move_to_next_cycle()
|
||||
self.log.info("Cycle H+2C height:" + str(self.nodes[0].getblockcount()))
|
||||
|
||||
(quorum_info_0_0, quorum_info_0_1) = self.mine_cycle_quorum("llmq_test_dip0024", 103)
|
||||
(quorum_info_0_0, quorum_info_0_1) = self.mine_cycle_quorum()
|
||||
|
||||
q_list = self.nodes[0].quorum("list")
|
||||
self.log.info(q_list)
|
||||
@ -118,20 +118,5 @@ class LLMQISMigrationTest(DashTestFramework):
|
||||
assert not n.quorum("hasrecsig", 104, request_id2, txid2)
|
||||
|
||||
|
||||
def move_to_next_cycle(self):
|
||||
cycle_length = 24
|
||||
mninfos_online = self.mninfo.copy()
|
||||
nodes = [self.nodes[0]] + [mn.node for mn in mninfos_online]
|
||||
cur_block = self.nodes[0].getblockcount()
|
||||
|
||||
# move forward to next DKG
|
||||
skip_count = cycle_length - (cur_block % cycle_length)
|
||||
if skip_count != 0:
|
||||
self.bump_mocktime(1, nodes=nodes)
|
||||
self.nodes[0].generate(skip_count)
|
||||
sync_blocks(nodes)
|
||||
time.sleep(1)
|
||||
self.log.info('Moved from block %d to %d' % (cur_block, self.nodes[0].getblockcount()))
|
||||
|
||||
if __name__ == '__main__':
|
||||
LLMQISMigrationTest().main()
|
||||
|
@ -9,7 +9,6 @@ feature_llmq_rotation.py
|
||||
Checks LLMQs Quorum Rotation
|
||||
|
||||
'''
|
||||
import time
|
||||
from test_framework.test_framework import DashTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
@ -128,21 +127,6 @@ class LLMQQuorumRotationTest(DashTestFramework):
|
||||
wait_until(lambda: self.nodes[0].getbestblockhash() == new_quorum_blockhash, sleep=1)
|
||||
assert_equal(self.nodes[0].quorum("list", llmq_type), new_quorum_list)
|
||||
|
||||
def move_to_next_cycle(self):
|
||||
cycle_length = 24
|
||||
mninfos_online = self.mninfo.copy()
|
||||
nodes = [self.nodes[0]] + [mn.node for mn in mninfos_online]
|
||||
cur_block = self.nodes[0].getblockcount()
|
||||
|
||||
# move forward to next DKG
|
||||
skip_count = cycle_length - (cur_block % cycle_length)
|
||||
if skip_count != 0:
|
||||
self.bump_mocktime(1, nodes=nodes)
|
||||
self.nodes[0].generate(skip_count)
|
||||
sync_blocks(nodes)
|
||||
time.sleep(1)
|
||||
self.log.info('Moved from block %d to %d' % (cur_block, self.nodes[0].getblockcount()))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
LLMQQuorumRotationTest().main()
|
||||
|
@ -28,6 +28,7 @@ from test_framework.messages import (
|
||||
msg_clsig,
|
||||
msg_inv,
|
||||
msg_isdlock,
|
||||
msg_islock,
|
||||
msg_tx,
|
||||
ser_string,
|
||||
uint256_from_str,
|
||||
@ -52,24 +53,39 @@ class ZMQPublisher(Enum):
|
||||
raw_recovered_sig = "rawrecoveredsig"
|
||||
|
||||
|
||||
class ZMQSubscriber:
|
||||
def __init__(self, socket, topic):
|
||||
self.socket = socket
|
||||
self.topic = topic
|
||||
|
||||
import zmq
|
||||
self.socket.setsockopt(zmq.SUBSCRIBE, self.topic)
|
||||
|
||||
def receive(self, flags=0):
|
||||
topic, body, seq = self.socket.recv_multipart(flags)
|
||||
# Topic should match the subscriber topic.
|
||||
assert_equal(topic, self.topic)
|
||||
return io.BytesIO(body)
|
||||
|
||||
|
||||
class TestP2PConn(P2PInterface):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.islocks = {}
|
||||
self.txes = {}
|
||||
|
||||
def send_islock(self, islock):
|
||||
def send_islock(self, islock, deterministic):
|
||||
hash = uint256_from_str(hash256(islock.serialize()))
|
||||
self.islocks[hash] = islock
|
||||
|
||||
inv = msg_inv([CInv(30, hash)])
|
||||
inv = msg_inv([CInv(31 if deterministic else 30, hash)])
|
||||
self.send_message(inv)
|
||||
|
||||
def send_tx(self, tx):
|
||||
def send_tx(self, tx, deterministic):
|
||||
hash = uint256_from_str(hash256(tx.serialize()))
|
||||
self.txes[hash] = tx
|
||||
|
||||
inv = msg_inv([CInv(30, hash)])
|
||||
inv = msg_inv([CInv(31 if deterministic else 30, hash)])
|
||||
self.send_message(inv)
|
||||
|
||||
def on_getdata(self, message):
|
||||
@ -89,7 +105,10 @@ class DashZMQTest (DashTestFramework):
|
||||
node0_extra_args.append("-whitelist=127.0.0.1")
|
||||
node0_extra_args.append("-watchquorums") # have to watch quorums to receive recsigs and trigger zmq
|
||||
|
||||
self.set_dash_test_params(4, 3, fast_dip3_enforcement=True, extra_args=[node0_extra_args, [], [], []])
|
||||
extra_args = [[]] * 5
|
||||
extra_args[0] = node0_extra_args
|
||||
self.set_dash_test_params(5, 4, fast_dip3_enforcement=True, extra_args=extra_args)
|
||||
self.set_dash_llmq_test_params(4, 4)
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_py3_zmq()
|
||||
@ -97,16 +116,15 @@ class DashZMQTest (DashTestFramework):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def run_test(self):
|
||||
self.subscribers = {}
|
||||
# Check that dashd has been built with ZMQ enabled.
|
||||
config = configparser.ConfigParser()
|
||||
config.read_file(open(self.options.configfile))
|
||||
import zmq
|
||||
|
||||
try:
|
||||
# Setup the ZMQ subscriber socket
|
||||
# Setup the ZMQ subscriber context
|
||||
self.zmq_context = zmq.Context()
|
||||
self.socket = self.zmq_context.socket(zmq.SUB)
|
||||
self.socket.connect(self.address)
|
||||
# Initialize the network
|
||||
self.activate_dip8()
|
||||
self.nodes[0].spork("SPORK_17_QUORUM_DKG_ENABLED", 0)
|
||||
@ -122,30 +140,41 @@ class DashZMQTest (DashTestFramework):
|
||||
# Test all dash related ZMQ publisher
|
||||
self.test_recovered_signature_publishers()
|
||||
self.test_chainlock_publishers()
|
||||
self.test_instantsend_publishers()
|
||||
self.test_governance_publishers()
|
||||
self.test_getzmqnotifications()
|
||||
self.test_instantsend_publishers(False)
|
||||
self.activate_dip0024()
|
||||
self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash())
|
||||
self.log.info("Activated DIP0024 at height:" + str(self.nodes[0].getblockcount()))
|
||||
self.test_instantsend_publishers(False)
|
||||
# At this point, we need to move forward 3 cycles (3 x 24 blocks) so the first 3 quarters can be created (without DKG sessions)
|
||||
self.move_to_next_cycle()
|
||||
self.test_instantsend_publishers(False)
|
||||
self.move_to_next_cycle()
|
||||
self.test_instantsend_publishers(False)
|
||||
self.move_to_next_cycle()
|
||||
self.test_instantsend_publishers(False)
|
||||
self.mine_cycle_quorum()
|
||||
self.test_instantsend_publishers(True)
|
||||
finally:
|
||||
# Destroy the ZMQ context.
|
||||
self.log.debug("Destroying ZMQ context")
|
||||
self.zmq_context.destroy(linger=None)
|
||||
|
||||
def subscribe(self, publishers):
|
||||
import zmq
|
||||
# Setup the ZMQ subscriber socket
|
||||
socket = self.zmq_context.socket(zmq.SUB)
|
||||
socket.set(zmq.RCVTIMEO, 60000)
|
||||
socket.connect(self.address)
|
||||
# Subscribe to a list of ZMQPublishers
|
||||
for pub in publishers:
|
||||
self.socket.subscribe(pub.value)
|
||||
self.subscribers[pub] = ZMQSubscriber(socket, pub.value.encode())
|
||||
|
||||
def unsubscribe(self, publishers):
|
||||
# Unsubscribe from a list of ZMQPublishers
|
||||
for pub in publishers:
|
||||
self.socket.unsubscribe(pub.value)
|
||||
|
||||
def receive(self, publisher, flags=0):
|
||||
# Receive a ZMQ message and validate it's sent from the correct ZMQPublisher
|
||||
topic, body, seq = self.socket.recv_multipart(flags)
|
||||
# Topic should match the publisher value
|
||||
assert_equal(topic.decode(), publisher.value)
|
||||
return io.BytesIO(body)
|
||||
del self.subscribers[pub]
|
||||
|
||||
def test_recovered_signature_publishers(self):
|
||||
|
||||
@ -153,11 +182,11 @@ class DashZMQTest (DashTestFramework):
|
||||
# Make sure the recovered sig exists by RPC
|
||||
rpc_recovered_sig = self.get_recovered_sig(request_id, msg_hash)
|
||||
# Validate hashrecoveredsig
|
||||
zmq_recovered_sig_hash = self.receive(ZMQPublisher.hash_recovered_sig).read(32).hex()
|
||||
zmq_recovered_sig_hash = self.subscribers[ZMQPublisher.hash_recovered_sig].receive().read(32).hex()
|
||||
assert_equal(zmq_recovered_sig_hash, msg_hash)
|
||||
# Validate rawrecoveredsig
|
||||
zmq_recovered_sig_raw = CRecoveredSig()
|
||||
zmq_recovered_sig_raw.deserialize(self.receive(ZMQPublisher.raw_recovered_sig))
|
||||
zmq_recovered_sig_raw.deserialize(self.subscribers[ZMQPublisher.raw_recovered_sig].receive())
|
||||
assert_equal(zmq_recovered_sig_raw.llmqType, rpc_recovered_sig['llmqType'])
|
||||
assert_equal(uint256_to_string(zmq_recovered_sig_raw.quorumHash), rpc_recovered_sig['quorumHash'])
|
||||
assert_equal(uint256_to_string(zmq_recovered_sig_raw.id), rpc_recovered_sig['id'])
|
||||
@ -207,15 +236,15 @@ class DashZMQTest (DashTestFramework):
|
||||
rpc_chain_lock_hash = rpc_chain_locked_block["hash"]
|
||||
assert_equal(generated_hash, rpc_chain_lock_hash)
|
||||
# Validate hashchainlock
|
||||
zmq_chain_lock_hash = self.receive(ZMQPublisher.hash_chain_lock).read(32).hex()
|
||||
zmq_chain_lock_hash = self.subscribers[ZMQPublisher.hash_chain_lock].receive().read(32).hex()
|
||||
assert_equal(zmq_chain_lock_hash, rpc_best_chain_lock_hash)
|
||||
# Validate rawchainlock
|
||||
zmq_chain_locked_block = CBlock()
|
||||
zmq_chain_locked_block.deserialize(self.receive(ZMQPublisher.raw_chain_lock))
|
||||
zmq_chain_locked_block.deserialize(self.subscribers[ZMQPublisher.raw_chain_lock].receive())
|
||||
assert zmq_chain_locked_block.is_valid()
|
||||
assert_equal(zmq_chain_locked_block.hash, rpc_chain_lock_hash)
|
||||
# Validate rawchainlocksig
|
||||
zmq_chain_lock_sig_stream = self.receive(ZMQPublisher.raw_chain_lock_sig)
|
||||
zmq_chain_lock_sig_stream = self.subscribers[ZMQPublisher.raw_chain_lock_sig].receive()
|
||||
zmq_chain_locked_block = CBlock()
|
||||
zmq_chain_locked_block.deserialize(zmq_chain_lock_sig_stream)
|
||||
assert zmq_chain_locked_block.is_valid()
|
||||
@ -228,7 +257,7 @@ class DashZMQTest (DashTestFramework):
|
||||
# Unsubscribe from ChainLock messages
|
||||
self.unsubscribe(chain_lock_publishers)
|
||||
|
||||
def test_instantsend_publishers(self):
|
||||
def test_instantsend_publishers(self, deterministic):
|
||||
import zmq
|
||||
instantsend_publishers = [
|
||||
ZMQPublisher.hash_tx_lock,
|
||||
@ -251,57 +280,57 @@ class DashZMQTest (DashTestFramework):
|
||||
rpc_raw_tx_1_hash = self.nodes[0].sendrawtransaction(rpc_raw_tx_1['hex'])
|
||||
self.wait_for_instantlock(rpc_raw_tx_1_hash, self.nodes[0])
|
||||
# Validate hashtxlock
|
||||
zmq_tx_lock_hash = self.receive(ZMQPublisher.hash_tx_lock).read(32).hex()
|
||||
zmq_tx_lock_hash = self.subscribers[ZMQPublisher.hash_tx_lock].receive().read(32).hex()
|
||||
assert_equal(zmq_tx_lock_hash, rpc_raw_tx_1['txid'])
|
||||
# Validate rawtxlock
|
||||
zmq_tx_lock_raw = CTransaction()
|
||||
zmq_tx_lock_raw.deserialize(self.receive(ZMQPublisher.raw_tx_lock))
|
||||
zmq_tx_lock_raw.deserialize(self.subscribers[ZMQPublisher.raw_tx_lock].receive())
|
||||
assert zmq_tx_lock_raw.is_valid()
|
||||
assert_equal(zmq_tx_lock_raw.hash, rpc_raw_tx_1['txid'])
|
||||
# Validate rawtxlocksig
|
||||
zmq_tx_lock_sig_stream = self.receive(ZMQPublisher.raw_tx_lock_sig)
|
||||
zmq_tx_lock_sig_stream = self.subscribers[ZMQPublisher.raw_tx_lock_sig].receive()
|
||||
zmq_tx_lock_tx = CTransaction()
|
||||
zmq_tx_lock_tx.deserialize(zmq_tx_lock_sig_stream)
|
||||
assert zmq_tx_lock_tx.is_valid()
|
||||
assert_equal(zmq_tx_lock_tx.hash, rpc_raw_tx_1['txid'])
|
||||
zmq_tx_lock = msg_isdlock()
|
||||
zmq_tx_lock = msg_isdlock() if deterministic else msg_islock()
|
||||
zmq_tx_lock.deserialize(zmq_tx_lock_sig_stream)
|
||||
assert_equal(uint256_to_string(zmq_tx_lock.txid), rpc_raw_tx_1['txid'])
|
||||
# Try to send the second transaction. This must throw an RPC error because it conflicts with rpc_raw_tx_1
|
||||
# which already got the InstantSend lock.
|
||||
assert_raises_rpc_error(-26, "tx-txlock-conflict", self.nodes[0].sendrawtransaction, rpc_raw_tx_2['hex'])
|
||||
# Validate hashinstantsenddoublespend
|
||||
zmq_double_spend_hash2 = self.receive(ZMQPublisher.hash_instantsend_doublespend).read(32).hex()
|
||||
zmq_double_spend_hash1 = self.receive(ZMQPublisher.hash_instantsend_doublespend).read(32).hex()
|
||||
zmq_double_spend_hash2 = self.subscribers[ZMQPublisher.hash_instantsend_doublespend].receive().read(32).hex()
|
||||
zmq_double_spend_hash1 = self.subscribers[ZMQPublisher.hash_instantsend_doublespend].receive().read(32).hex()
|
||||
assert_equal(zmq_double_spend_hash2, rpc_raw_tx_2['txid'])
|
||||
assert_equal(zmq_double_spend_hash1, rpc_raw_tx_1['txid'])
|
||||
# Validate rawinstantsenddoublespend
|
||||
zmq_double_spend_tx_2 = CTransaction()
|
||||
zmq_double_spend_tx_2.deserialize(self.receive(ZMQPublisher.raw_instantsend_doublespend))
|
||||
zmq_double_spend_tx_2.deserialize(self.subscribers[ZMQPublisher.raw_instantsend_doublespend].receive())
|
||||
assert zmq_double_spend_tx_2.is_valid()
|
||||
assert_equal(zmq_double_spend_tx_2.hash, rpc_raw_tx_2['txid'])
|
||||
zmq_double_spend_tx_1 = CTransaction()
|
||||
zmq_double_spend_tx_1.deserialize(self.receive(ZMQPublisher.raw_instantsend_doublespend))
|
||||
zmq_double_spend_tx_1.deserialize(self.subscribers[ZMQPublisher.raw_instantsend_doublespend].receive())
|
||||
assert zmq_double_spend_tx_1.is_valid()
|
||||
assert_equal(zmq_double_spend_tx_1.hash, rpc_raw_tx_1['txid'])
|
||||
# No islock notifications when tx is not received yet
|
||||
self.nodes[0].generate(1)
|
||||
rpc_raw_tx_3 = self.create_raw_tx(self.nodes[0], self.nodes[0], 1, 1, 100)
|
||||
islock = self.create_islock(rpc_raw_tx_3['hex'])
|
||||
self.test_node.send_islock(islock)
|
||||
islock = self.create_islock(rpc_raw_tx_3['hex'], deterministic)
|
||||
self.test_node.send_islock(islock, deterministic)
|
||||
# Validate NO hashtxlock
|
||||
time.sleep(1)
|
||||
try:
|
||||
self.receive(ZMQPublisher.hash_tx_lock, zmq.NOBLOCK)
|
||||
self.subscribers[ZMQPublisher.hash_tx_lock].receive(zmq.NOBLOCK)
|
||||
assert False
|
||||
except zmq.ZMQError:
|
||||
# this is expected
|
||||
pass
|
||||
# Now send the tx itself
|
||||
self.test_node.send_tx(FromHex(msg_tx(), rpc_raw_tx_3['hex']))
|
||||
self.test_node.send_tx(FromHex(msg_tx(), rpc_raw_tx_3['hex']), deterministic)
|
||||
self.wait_for_instantlock(rpc_raw_tx_3['txid'], self.nodes[0])
|
||||
# Validate hashtxlock
|
||||
zmq_tx_lock_hash = self.receive(ZMQPublisher.hash_tx_lock).read(32).hex()
|
||||
zmq_tx_lock_hash = self.subscribers[ZMQPublisher.hash_tx_lock].receive().read(32).hex()
|
||||
assert_equal(zmq_tx_lock_hash, rpc_raw_tx_3['txid'])
|
||||
# Drop test node connection
|
||||
self.nodes[0].disconnect_p2ps()
|
||||
@ -337,10 +366,11 @@ class DashZMQTest (DashTestFramework):
|
||||
self.sync_blocks()
|
||||
rpc_proposal_hash = self.nodes[0].gobject("submit", "0", proposal_rev, proposal_time, proposal_hex, collateral)
|
||||
# Validate hashgovernanceobject
|
||||
zmq_governance_object_hash = self.receive(ZMQPublisher.hash_governance_object).read(32).hex()
|
||||
zmq_governance_object_hash = self.subscribers[ZMQPublisher.hash_governance_object].receive().read(32).hex()
|
||||
assert_equal(zmq_governance_object_hash, rpc_proposal_hash)
|
||||
# Validate rawgovernanceobject
|
||||
zmq_governance_object_raw = CGovernanceObject()
|
||||
zmq_governance_object_raw.deserialize(self.receive(ZMQPublisher.raw_governance_object))
|
||||
zmq_governance_object_raw.deserialize(self.subscribers[ZMQPublisher.raw_governance_object].receive())
|
||||
assert_equal(zmq_governance_object_raw.nHashParent, 0)
|
||||
assert_equal(zmq_governance_object_raw.nRevision, proposal_rev)
|
||||
assert_equal(zmq_governance_object_raw.nTime, proposal_time)
|
||||
@ -365,11 +395,11 @@ class DashZMQTest (DashTestFramework):
|
||||
self.nodes[0].gobject("vote-many", rpc_proposal_hash, map_vote_signals[1], map_vote_outcomes[1])
|
||||
rpc_proposal_votes = self.nodes[0].gobject('getcurrentvotes', rpc_proposal_hash)
|
||||
# Validate hashgovernancevote
|
||||
zmq_governance_vote_hash = self.receive(ZMQPublisher.hash_governance_vote).read(32).hex()
|
||||
zmq_governance_vote_hash = self.subscribers[ZMQPublisher.hash_governance_vote].receive().read(32).hex()
|
||||
assert zmq_governance_vote_hash in rpc_proposal_votes
|
||||
# Validate rawgovernancevote
|
||||
zmq_governance_vote_raw = CGovernanceVote()
|
||||
zmq_governance_vote_raw.deserialize(self.receive(ZMQPublisher.raw_governance_vote))
|
||||
zmq_governance_vote_raw.deserialize(self.subscribers[ZMQPublisher.raw_governance_vote].receive())
|
||||
assert_equal(uint256_to_string(zmq_governance_vote_raw.nParentHash), rpc_proposal_hash)
|
||||
rpc_vote_parts = rpc_proposal_votes[zmq_governance_vote_hash].split(':')
|
||||
rpc_outpoint_parts = rpc_vote_parts[0].split('-')
|
||||
|
@ -82,7 +82,7 @@ class RPCVerifyISLockTest(DashTestFramework):
|
||||
break
|
||||
assert selected_hash == oldest_quorum_hash
|
||||
# Create the ISLOCK, then mine a quorum to move the signing quorum out of the active set
|
||||
islock = self.create_islock(rawtx, True)
|
||||
islock = self.create_islock(rawtx, False)
|
||||
# Mine one block to trigger the "signHeight + dkgInterval" verification for the ISLOCK
|
||||
self.mine_quorum()
|
||||
# Verify the ISLOCK for a transaction that is not yet known by the node
|
||||
|
@ -1038,13 +1038,14 @@ class DashTestFramework(BitcoinTestFramework):
|
||||
request_id = hash256(request_id_buf)[::-1].hex()
|
||||
message_hash = tx.hash
|
||||
|
||||
llmq_type = 103 if deterministic else 104
|
||||
quorum_member = None
|
||||
for mn in self.mninfo:
|
||||
res = mn.node.quorum('sign', 104, request_id, message_hash)
|
||||
res = mn.node.quorum('sign', llmq_type, request_id, message_hash)
|
||||
if (res and quorum_member is None):
|
||||
quorum_member = mn
|
||||
|
||||
rec_sig = self.get_recovered_sig(request_id, message_hash, node=quorum_member.node, llmq_type=104)
|
||||
rec_sig = self.get_recovered_sig(request_id, message_hash, node=quorum_member.node, llmq_type=llmq_type)
|
||||
|
||||
if deterministic:
|
||||
block_count = quorum_member.node.getblockcount()
|
||||
@ -1330,7 +1331,7 @@ class DashTestFramework(BitcoinTestFramework):
|
||||
|
||||
return new_quorum
|
||||
|
||||
def mine_cycle_quorum(self, llmq_type_name="llmq_test", llmq_type=100, expected_connections=None, expected_members=None, expected_contributions=None, expected_complaints=0, expected_justifications=0, expected_commitments=None, mninfos_online=None, mninfos_valid=None):
|
||||
def mine_cycle_quorum(self, llmq_type_name="llmq_test_dip0024", llmq_type=103, expected_connections=None, expected_members=None, expected_contributions=None, expected_complaints=0, expected_justifications=0, expected_commitments=None, mninfos_online=None, mninfos_valid=None):
|
||||
spork21_active = self.nodes[0].spork('show')['SPORK_21_QUORUM_ALL_CONNECTED'] <= 1
|
||||
spork23_active = self.nodes[0].spork('show')['SPORK_23_QUORUM_POSE'] <= 1
|
||||
|
||||
@ -1462,11 +1463,26 @@ class DashTestFramework(BitcoinTestFramework):
|
||||
|
||||
best_block_hash = self.nodes[0].getbestblockhash()
|
||||
block_height = self.nodes[0].getblockcount()
|
||||
quorum_rotation_info = self.nodes[0].quorum("rotationinfo", best_block_hash, 0, False)
|
||||
quorum_rotation_info = self.nodes[0].quorum("rotationinfo", best_block_hash)
|
||||
self.log.info("h("+str(block_height)+"):"+str(quorum_rotation_info))
|
||||
|
||||
return (quorum_info_0, quorum_info_1)
|
||||
|
||||
def move_to_next_cycle(self):
|
||||
cycle_length = 24
|
||||
mninfos_online = self.mninfo.copy()
|
||||
nodes = [self.nodes[0]] + [mn.node for mn in mninfos_online]
|
||||
cur_block = self.nodes[0].getblockcount()
|
||||
|
||||
# move forward to next DKG
|
||||
skip_count = cycle_length - (cur_block % cycle_length)
|
||||
if skip_count != 0:
|
||||
self.bump_mocktime(1, nodes=nodes)
|
||||
self.nodes[0].generate(skip_count)
|
||||
sync_blocks(nodes)
|
||||
time.sleep(1)
|
||||
self.log.info('Moved from block %d to %d' % (cur_block, self.nodes[0].getblockcount()))
|
||||
|
||||
def get_recovered_sig(self, rec_sig_id, rec_sig_msg_hash, llmq_type=100, node=None):
|
||||
# Note: recsigs aren't relayed to regular nodes by default,
|
||||
# make sure to pick a mn as a node to query for recsigs.
|
||||
|
@ -640,7 +640,7 @@ class ImportMultiTest(BitcoinTestFramework):
|
||||
assert_equal(addr2, newaddr2)
|
||||
|
||||
# Import a multisig and make sure the keys don't go into the keypool
|
||||
self.log.info('Imported scripts with pubkeys shoud not have their pubkeys go into the keypool')
|
||||
self.log.info('Imported scripts with pubkeys should not have their pubkeys go into the keypool')
|
||||
addr1 = self.nodes[0].getnewaddress()
|
||||
addr2 = self.nodes[0].getnewaddress()
|
||||
pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey']
|
||||
|
@ -15,6 +15,6 @@ if ! command -v codespell > /dev/null; then
|
||||
fi
|
||||
|
||||
IGNORE_WORDS_FILE=test/lint/lint-spelling.ignore-words.txt
|
||||
if ! codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=${IGNORE_WORDS_FILE} $(git ls-files -- ":(exclude)build-aux/m4/" ":(exclude)contrib/seeds/*.txt" ":(exclude)depends/" ":(exclude)doc/release-notes/" ":(exclude)src/crypto/" ":(exclude)src/leveldb/" ":(exclude)src/qt/locale/" ":(exclude)src/qt/*.qrc" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/"); then
|
||||
if ! codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=${IGNORE_WORDS_FILE} $(git ls-files -- ":(exclude)build-aux/m4/" ":(exclude)contrib/seeds/*.txt" ":(exclude)depends/" ":(exclude)doc/release-notes/" ":(exclude)src/bip39_english.h" ":(exclude)src/crc32c/" ":(exclude)src/crypto/" ":(exclude)src/ctpl_stl.h" ":(exclude)src/cxxtimer.hpp" ":(exclude)src/leveldb/" ":(exclude)src/qt/locale/" ":(exclude)src/qt/*.qrc" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/"); then
|
||||
echo "^ Warning: codespell identified likely spelling errors. Any false positives? Add them to the list of ignored words in ${IGNORE_WORDS_FILE}"
|
||||
fi
|
||||
|
Loading…
Reference in New Issue
Block a user