forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathcoinjoin_inouts_tests.cpp
More file actions
108 lines (93 loc) · 3.6 KB
/
coinjoin_inouts_tests.cpp
File metadata and controls
108 lines (93 loc) · 3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Copyright (c) 2025 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <test/util/setup_common.h>
#include <algorithm>
#include <array>
#include <cstdint>
#include <vector>
#include <chain.h>
#include <coinjoin/coinjoin.h>
#include <coinjoin/common.h>
#include <evo/chainhelper.h>
#include <script/script.h>
#include <uint256.h>
#include <util/check.h>
#include <util/time.h>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(coinjoin_inouts_tests, TestingSetup)
static CScript P2PKHScript(uint8_t tag = 0x01)
{
// OP_DUP OP_HASH160 <20-byte-tag> OP_EQUALVERIFY OP_CHECKSIG
std::vector<unsigned char> hash(20, tag);
return CScript{} << OP_DUP << OP_HASH160 << hash << OP_EQUALVERIFY << OP_CHECKSIG;
}
BOOST_AUTO_TEST_CASE(broadcasttx_isvalidstructure_good_and_bad)
{
// Good: equal vin/vout sizes, vin count >= min participants, <= max*entry_size, P2PKH outputs with standard denominations
CCoinJoinBroadcastTx good;
{
CMutableTransaction mtx;
// Use min pool participants (e.g. 3). Build 3 inputs and 3 denominated outputs
const int participants = std::max(3, CoinJoin::GetMinPoolParticipants());
for (int i = 0; i < participants; ++i) {
CTxIn in;
in.prevout = COutPoint(uint256::ONE, static_cast<uint32_t>(i));
mtx.vin.push_back(in);
// Pick the smallest denomination
CTxOut out{CoinJoin::GetSmallestDenomination(), P2PKHScript(static_cast<uint8_t>(i))};
mtx.vout.push_back(out);
}
good.tx = MakeTransactionRef(mtx);
good.m_protxHash = uint256::ONE; // at least one of (outpoint, protxhash) must be set
}
BOOST_CHECK(good.IsValidStructure());
// Bad: both identifiers null
CCoinJoinBroadcastTx bad_ids = good;
bad_ids.m_protxHash = uint256{};
bad_ids.masternodeOutpoint.SetNull();
BOOST_CHECK(!bad_ids.IsValidStructure());
// Bad: vin/vout size mismatch
CCoinJoinBroadcastTx bad_sizes = good;
{
CMutableTransaction mtx(*good.tx);
mtx.vout.pop_back();
bad_sizes.tx = MakeTransactionRef(mtx);
}
BOOST_CHECK(!bad_sizes.IsValidStructure());
// Bad: non-P2PKH output
CCoinJoinBroadcastTx bad_script = good;
{
CMutableTransaction mtx(*good.tx);
mtx.vout[0].scriptPubKey = CScript() << OP_RETURN << std::vector<unsigned char>{'x'};
bad_script.tx = MakeTransactionRef(mtx);
}
BOOST_CHECK(!bad_script.IsValidStructure());
// Bad: non-denominated amount
CCoinJoinBroadcastTx bad_amount = good;
{
CMutableTransaction mtx(*good.tx);
mtx.vout[0].nValue = 42; // not a valid denom
bad_amount.tx = MakeTransactionRef(mtx);
}
BOOST_CHECK(!bad_amount.IsValidStructure());
}
BOOST_AUTO_TEST_CASE(queue_timeout_bounds)
{
CCoinJoinQueue dsq;
dsq.nDenom = CoinJoin::AmountToDenomination(CoinJoin::GetSmallestDenomination());
dsq.m_protxHash = uint256::ONE;
dsq.nTime = GetAdjustedTime();
// current time -> not out of bounds
BOOST_CHECK(!dsq.IsTimeOutOfBounds());
// Too old (beyond COINJOIN_QUEUE_TIMEOUT)
SetMockTime(GetTime() + (COINJOIN_QUEUE_TIMEOUT + 1));
BOOST_CHECK(dsq.IsTimeOutOfBounds());
// Too far in the future
SetMockTime(GetTime() - 2 * (COINJOIN_QUEUE_TIMEOUT + 1)); // move back to anchor baseline
dsq.nTime = GetAdjustedTime() + (COINJOIN_QUEUE_TIMEOUT + 1);
BOOST_CHECK(dsq.IsTimeOutOfBounds());
// Reset mock time
SetMockTime(0);
}
BOOST_AUTO_TEST_SUITE_END()