Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coinjoin/coinjoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ bool CCoinJoinQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const

bool CCoinJoinQueue::IsTimeOutOfBounds(int64_t current_time) const
{
if (current_time < 0 || nTime < 0) return true;
return current_time - nTime > COINJOIN_QUEUE_TIMEOUT ||
nTime - current_time > COINJOIN_QUEUE_TIMEOUT;
}
Expand Down
1 change: 1 addition & 0 deletions src/coinjoin/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ constexpr bool IsCollateralAmount(CAmount nInputAmount)

constexpr int CalculateAmountPriority(CAmount nInputAmount)
{
if (nInputAmount < 0 || nInputAmount > MAX_MONEY) return 0;
if (auto optDenom = util::find_if_opt(GetStandardDenominations(),
[&nInputAmount](const auto& denom) { return nInputAmount == denom; })) {
return (float)COIN / *optDenom * 10000;
Expand Down
49 changes: 49 additions & 0 deletions src/test/coinjoin_queue_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@
#include <active/masternode.h>
#include <bls/bls.h>
#include <coinjoin/coinjoin.h>
#include <coinjoin/common.h>
#include <consensus/amount.h>

#include <uint256.h>

#include <climits>
#include <cstdint>

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(coinjoin_queue_tests, TestingSetup)
Expand Down Expand Up @@ -96,4 +101,48 @@ BOOST_AUTO_TEST_CASE(queue_timestamp_validation)
BOOST_CHECK(q.IsTimeOutOfBounds(current_time));
}

BOOST_AUTO_TEST_CASE(queue_timestamp_extreme_values)
{
CCoinJoinQueue q;
q.nDenom = CoinJoin::AmountToDenomination(CoinJoin::GetSmallestDenomination());
q.m_protxHash = uint256::ONE;

// Negative timestamps are rejected by the guard
q.nTime = INT64_MIN;
BOOST_CHECK(q.IsTimeOutOfBounds(INT64_MAX));

q.nTime = INT64_MAX;
BOOST_CHECK(q.IsTimeOutOfBounds(INT64_MIN));

q.nTime = INT64_MIN;
BOOST_CHECK(q.IsTimeOutOfBounds(INT64_MIN));

// Large positive timestamp with same value: zero diff, in bounds
q.nTime = INT64_MAX;
BOOST_CHECK(!q.IsTimeOutOfBounds(INT64_MAX));

// Zero vs extreme positive: huge gap, out of bounds
q.nTime = 0;
BOOST_CHECK(q.IsTimeOutOfBounds(INT64_MAX));

// Zero vs negative: rejected by guard
q.nTime = 0;
BOOST_CHECK(q.IsTimeOutOfBounds(INT64_MIN));
}

static_assert(CoinJoin::CalculateAmountPriority(MAX_MONEY) == -(MAX_MONEY / COIN));
static_assert(CoinJoin::CalculateAmountPriority(static_cast<CAmount>(INT64_MAX)) == 0);
static_assert(CoinJoin::CalculateAmountPriority(static_cast<CAmount>(-1)) == 0);

BOOST_AUTO_TEST_CASE(calculate_amount_priority_guard)
{
// Realistic amount: MAX_MONEY (21 million DASH)
BOOST_CHECK_EQUAL(CoinJoin::CalculateAmountPriority(MAX_MONEY), -(MAX_MONEY / COIN));

// Out-of-range amounts return 0
BOOST_CHECK_EQUAL(CoinJoin::CalculateAmountPriority(static_cast<CAmount>(INT64_MAX)), 0);
BOOST_CHECK_EQUAL(CoinJoin::CalculateAmountPriority(static_cast<CAmount>(-1)), 0);
BOOST_CHECK_EQUAL(CoinJoin::CalculateAmountPriority(MAX_MONEY + 1), 0);
}

BOOST_AUTO_TEST_SUITE_END()
Loading