Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/dashpay/dash into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
PastaPastaPasta committed Aug 22, 2024
2 parents 236c9e0 + 045e178 commit 1c150d8
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 65 deletions.
7 changes: 4 additions & 3 deletions src/evo/deterministicmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,16 @@ std::vector<CDeterministicMNCPtr> CDeterministicMNList::GetProjectedMNPayees(gsl
if (nCount < 0 ) {
return {};
}
const auto weighted_count = GetValidWeightedMNsCount();
const bool isMNRewardReallocation = DeploymentActiveAfter(pindexPrev, Params().GetConsensus(),
Consensus::DEPLOYMENT_MN_RR);
const auto weighted_count = isMNRewardReallocation ? GetValidMNsCount() : GetValidWeightedMNsCount();
nCount = std::min(nCount, int(weighted_count));

std::vector<CDeterministicMNCPtr> result;
result.reserve(weighted_count);

int remaining_evo_payments{0};
CDeterministicMNCPtr evo_to_be_skipped{nullptr};
const bool isMNRewardReallocation{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR)};
if (!isMNRewardReallocation) {
ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) {
if (dmn->pdmnState->nLastPaidHeight == nHeight) {
Expand All @@ -242,7 +243,7 @@ std::vector<CDeterministicMNCPtr> CDeterministicMNList::GetProjectedMNPayees(gsl

ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) {
if (dmn == evo_to_be_skipped) return;
for ([[maybe_unused]] auto _ : irange::range(GetMnType(dmn->nType).voting_weight)) {
for ([[maybe_unused]] auto _ : irange::range(isMNRewardReallocation ? 1 : GetMnType(dmn->nType).voting_weight)) {
result.emplace_back(dmn);
}
});
Expand Down
101 changes: 42 additions & 59 deletions src/test/transaction_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,132 +378,118 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
key.MakeNewKey(true);
t.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));

std::string reason;
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
constexpr auto CheckIsStandard = [](const auto& t) {
std::string reason;
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
BOOST_CHECK(reason.empty());
};
constexpr auto CheckIsNotStandard = [](const auto& t, const std::string& reason_in) {
std::string reason;
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason_in, reason);
};

CheckIsStandard(t);

// Check dust with default relay fee:
CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK()/1000;
CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK() / 1000;
BOOST_CHECK_EQUAL(nDustThreshold, 546);
// dust:
t.vout[0].nValue = nDustThreshold - 1;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "dust");
CheckIsNotStandard(t, "dust");
// not dust:
t.vout[0].nValue = nDustThreshold;
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);

// Disallowed nVersion
t.nVersion = -1;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "version");
CheckIsNotStandard(t, "version");

t.nVersion = 0;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "version");
CheckIsNotStandard(t, "version");

t.nVersion = 4;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "version");
CheckIsNotStandard(t, "version");

// Allowed nVersion
t.nVersion = 1;
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);

t.nVersion = 2;
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);

t.nVersion = 3;
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);
// Check dust with odd relay fee to verify rounding:
// nDustThreshold = 182 * 3702 / 1000
minRelayTxFee = CFeeRate(3702);
// dust:
t.vout[0].nValue = 546 - 1;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "dust");
CheckIsNotStandard(t, "dust");
// not dust:
t.vout[0].nValue = 546;
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);
minRelayTxFee = CFeeRate(DUST_RELAY_TX_FEE);

t.vout[0].scriptPubKey = CScript() << OP_1;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "scriptpubkey");
CheckIsNotStandard(t, "scriptpubkey");

// MAX_OP_RETURN_RELAY-byte TxoutType::NULL_DATA (standard)
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size());
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);

// MAX_OP_RETURN_RELAY+1-byte TxoutType::NULL_DATA (non-standard)
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size());
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "scriptpubkey");
CheckIsNotStandard(t, "scriptpubkey");

// Data payload can be encoded in any way...
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("");
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("00") << ParseHex("01");
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);
// OP_RESERVED *is* considered to be a PUSHDATA type opcode by IsPushOnly()!
t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RESERVED << -1 << 0 << ParseHex("01") << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16;
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);
t.vout[0].scriptPubKey = CScript() << OP_RETURN << 0 << ParseHex("01") << 2 << ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);

// ...so long as it only contains PUSHDATA's
t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RETURN;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "scriptpubkey");
CheckIsNotStandard(t, "scriptpubkey");

// TxoutType::NULL_DATA w/o PUSHDATA
t.vout.resize(1);
t.vout[0].scriptPubKey = CScript() << OP_RETURN;
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);

// Only one TxoutType::NULL_DATA permitted in all cases
t.vout.resize(2);
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
t.vout[0].nValue = 0;
t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
t.vout[1].nValue = 0;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "multi-op-return");
CheckIsNotStandard(t, "multi-op-return");

t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
t.vout[1].scriptPubKey = CScript() << OP_RETURN;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "multi-op-return");
CheckIsNotStandard(t, "multi-op-return");

t.vout[0].scriptPubKey = CScript() << OP_RETURN;
t.vout[1].scriptPubKey = CScript() << OP_RETURN;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "multi-op-return");
CheckIsNotStandard(t, "multi-op-return");

// Check large scriptSig (non-standard if size is >1650 bytes)
t.vout.resize(1);
t.vout[0].nValue = MAX_MONEY;
t.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
// OP_PUSHDATA2 with len (3 bytes) + data (1647 bytes) = 1650 bytes
t.vin[0].scriptSig = CScript() << std::vector<unsigned char>(1647, 0); // 1650
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);

t.vin[0].scriptSig = CScript() << std::vector<unsigned char>(1648, 0); // 1651
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "scriptsig-size");
CheckIsNotStandard(t, "scriptsig-size");

// Check scriptSig format (non-standard if there are any other ops than just PUSHs)
t.vin[0].scriptSig = CScript()
Expand All @@ -512,7 +498,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
<< std::vector<unsigned char>(235, 0) // OP_PUSHDATA1 x [...x bytes...]
<< std::vector<unsigned char>(1234, 0) // OP_PUSHDATA2 x [...x bytes...]
<< OP_9;
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);

const std::vector<unsigned char> non_push_ops = { // arbitrary set of non-push operations
OP_NOP, OP_VERIFY, OP_IF, OP_ROT, OP_3DUP, OP_SIZE, OP_EQUAL, OP_ADD, OP_SUB,
Expand All @@ -532,23 +518,20 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
// replace current push-op with each non-push-op
for (auto op : non_push_ops) {
t.vin[0].scriptSig[index] = op;
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "scriptsig-not-pushonly");
CheckIsNotStandard(t, "scriptsig-not-pushonly");
}
t.vin[0].scriptSig[index] = orig_op; // restore op
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);
}

// Check bare multisig (standard if policy flag fIsBareMultisigStd is set)
fIsBareMultisigStd = true;
t.vout[0].scriptPubKey = GetScriptForMultisig(1, {key.GetPubKey()}); // simple 1-of-1
t.vin[0].scriptSig = CScript() << std::vector<unsigned char>(65, 0);
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
CheckIsStandard(t);

fIsBareMultisigStd = false;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "bare-multisig");
CheckIsNotStandard(t, "bare-multisig");
fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
}

Expand Down
42 changes: 39 additions & 3 deletions test/functional/feature_llmq_evo.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
QuorumId, ser_uint256
from test_framework.test_framework import DashTestFramework
from test_framework.util import (
assert_equal, p2p_port
assert_equal, assert_greater_than_or_equal, p2p_port
)


Expand Down Expand Up @@ -46,7 +46,7 @@ def getmnlistdiff(self, baseBlockHash, blockHash):

class LLMQEvoNodesTest(DashTestFramework):
def set_test_params(self):
self.set_dash_test_params(5, 4, fast_dip3_enforcement=True, evo_count=7)
self.set_dash_test_params(5, 4, fast_dip3_enforcement=True, evo_count=5)
self.set_dash_llmq_test_params(4, 4)

def run_test(self):
Expand Down Expand Up @@ -90,7 +90,7 @@ def run_test(self):
self.mine_cycle_quorum(llmq_type_name='llmq_test_dip0024', llmq_type=103)

evo_protxhash_list = list()
for i in range(5):
for i in range(self.evo_count):
evo_info = self.dynamically_add_masternode(evo=True)
evo_protxhash_list.append(evo_info.proTxHash)
self.nodes[0].generate(8)
Expand All @@ -113,6 +113,7 @@ def run_test(self):

self.log.info("Test that EvoNodes are paid 4x blocks in a row")
self.test_evo_payments(window_analysis=48)
self.test_masternode_winners()

self.activate_v20()
self.activate_mn_rr()
Expand All @@ -125,6 +126,7 @@ def run_test(self):

self.log.info("Test that EvoNodes are paid 1 block in a row after MN RewardReallocation activation")
self.test_evo_payments(window_analysis=48, v20active=True)
self.test_masternode_winners(mn_rr_active=True)

self.log.info(self.nodes[0].masternodelist())

Expand Down Expand Up @@ -246,6 +248,40 @@ def test_masternode_count(self, expected_mns_count, expected_evo_count):
assert_equal(detailed_count['regular']['total'], expected_mns_count)
assert_equal(detailed_count['evo']['total'], expected_evo_count)

def test_masternode_winners(self, mn_rr_active=False):
# ignore recent winners, test future ones only
# we get up to 21 entries here: tip + up to 20 future payees
winners = self.nodes[0].masternode('winners', '0')
weighted_count = self.mn_count + self.evo_count * (1 if mn_rr_active else 4)
assert_equal(len(winners.keys()) - 1, 20 if weighted_count > 20 else weighted_count)
consecutive_payments = 0
full_consecutive_payments_found = 0
payment_cycles = 0
first_payee = None
prev_winner = None
for height in winners.keys():
winner = winners[height]
if mn_rr_active:
assert_equal(prev_winner == winner, False)
else:
if prev_winner == winner:
consecutive_payments += 1
else:
if consecutive_payments == 3:
full_consecutive_payments_found += 1
consecutive_payments = 0
assert_greater_than_or_equal(3, consecutive_payments)
if consecutive_payments == 0 and winner == first_payee:
payment_cycles += 1
if first_payee is None:
first_payee = winner
prev_winner = winner
if mn_rr_active:
assert_equal(full_consecutive_payments_found, 0)
else:
assert_greater_than_or_equal(full_consecutive_payments_found, (len(winners.keys()) - 1 - self.mn_count) // 4 - 1)
assert_equal(payment_cycles, (len(winners.keys()) - 1) // weighted_count)

def test_getmnlistdiff(self, baseBlockHash, blockHash, baseMNList, expectedDeleted, expectedUpdated):
d = self.test_getmnlistdiff_base(baseBlockHash, blockHash)

Expand Down

0 comments on commit 1c150d8

Please sign in to comment.