Skip to content

Commit d80de2a

Browse files
committed
fix: bound CoinJoin entry intake
1 parent 7704aa8 commit d80de2a

3 files changed

Lines changed: 68 additions & 7 deletions

File tree

src/coinjoin/coinjoin.h

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,39 @@ class CCoinJoinEntry
167167
{
168168
}
169169

170-
SERIALIZE_METHODS(CCoinJoinEntry, obj)
170+
template <typename Stream>
171+
void Serialize(Stream& s) const
171172
{
172-
READWRITE(obj.vecTxDSIn, obj.txCollateral, obj.vecTxOut);
173+
s << vecTxDSIn << txCollateral << vecTxOut;
174+
}
175+
176+
template <typename Stream>
177+
void Unserialize(Stream& s)
178+
{
179+
vecTxDSIn.clear();
180+
vecTxOut.clear();
181+
182+
const size_t txdsin_size = ReadCompactSize(s);
183+
if (txdsin_size > COINJOIN_ENTRY_MAX_SIZE) {
184+
throw std::ios_base::failure("CCoinJoinEntry::vecTxDSIn size too large");
185+
}
186+
vecTxDSIn.reserve(txdsin_size);
187+
while (vecTxDSIn.size() < txdsin_size) {
188+
vecTxDSIn.emplace_back();
189+
s >> vecTxDSIn.back();
190+
}
191+
192+
s >> txCollateral;
193+
194+
const size_t txout_size = ReadCompactSize(s);
195+
if (txout_size > COINJOIN_ENTRY_MAX_SIZE) {
196+
throw std::ios_base::failure("CCoinJoinEntry::vecTxOut size too large");
197+
}
198+
vecTxOut.reserve(txout_size);
199+
while (vecTxOut.size() < txout_size) {
200+
vecTxOut.emplace_back();
201+
s >> vecTxOut.back();
202+
}
173203
}
174204

175205
bool AddScriptSig(const CTxIn& txin);

src/coinjoin/server.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -592,19 +592,26 @@ bool CCoinJoinServer::AddEntry(const CCoinJoinEntry& entry, PoolMessage& nMessag
592592
return false;
593593
}
594594

595-
if (!CoinJoin::IsCollateralValid(m_chainman, m_isman, mempool, *entry.txCollateral)) {
596-
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- ERROR: collateral not valid!\n", __func__);
597-
nMessageIDRet = ERR_INVALID_COLLATERAL;
595+
if (entry.vecTxDSIn.size() > COINJOIN_ENTRY_MAX_SIZE) {
596+
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- ERROR: too many inputs! %d/%d\n", __func__, entry.vecTxDSIn.size(), COINJOIN_ENTRY_MAX_SIZE);
597+
nMessageIDRet = ERR_MAXIMUM;
598+
ConsumeCollateral(entry.txCollateral);
598599
return false;
599600
}
600601

601-
if (entry.vecTxDSIn.size() > COINJOIN_ENTRY_MAX_SIZE) {
602-
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- ERROR: too many inputs! %d/%d\n", __func__, entry.vecTxDSIn.size(), COINJOIN_ENTRY_MAX_SIZE);
602+
if (entry.vecTxOut.size() > COINJOIN_ENTRY_MAX_SIZE) {
603+
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- ERROR: too many outputs! %d/%d\n", __func__, entry.vecTxOut.size(), COINJOIN_ENTRY_MAX_SIZE);
603604
nMessageIDRet = ERR_MAXIMUM;
604605
ConsumeCollateral(entry.txCollateral);
605606
return false;
606607
}
607608

609+
if (!CoinJoin::IsCollateralValid(m_chainman, m_isman, mempool, *entry.txCollateral)) {
610+
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- ERROR: collateral not valid!\n", __func__);
611+
nMessageIDRet = ERR_INVALID_COLLATERAL;
612+
return false;
613+
}
614+
608615
std::vector<CTxIn> vin;
609616
for (const auto& txin : entry.vecTxDSIn) {
610617
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- txin=%s\n", __func__, txin.ToString());

src/test/coinjoin_inouts_tests.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <coinjoin/common.h>
1515
#include <evo/chainhelper.h>
1616
#include <script/script.h>
17+
#include <streams.h>
1718
#include <uint256.h>
1819
#include <util/check.h>
1920
#include <util/time.h>
@@ -155,6 +156,29 @@ BOOST_AUTO_TEST_CASE(entry_addscriptsig_matches_and_rejects)
155156
}
156157
}
157158

159+
BOOST_AUTO_TEST_CASE(entry_rejects_oversized_vectors_before_materializing)
160+
{
161+
{
162+
CDataStream stream{SER_NETWORK, PROTOCOL_VERSION};
163+
WriteCompactSize(stream, COINJOIN_ENTRY_MAX_SIZE + 1);
164+
165+
CCoinJoinEntry entry;
166+
BOOST_CHECK_THROW(stream >> entry, std::ios_base::failure);
167+
BOOST_CHECK(entry.vecTxDSIn.empty());
168+
}
169+
170+
{
171+
CDataStream stream{SER_NETWORK, PROTOCOL_VERSION};
172+
WriteCompactSize(stream, 0);
173+
stream << MakeTransactionRef(CMutableTransaction{});
174+
WriteCompactSize(stream, COINJOIN_ENTRY_MAX_SIZE + 1);
175+
176+
CCoinJoinEntry entry;
177+
BOOST_CHECK_THROW(stream >> entry, std::ios_base::failure);
178+
BOOST_CHECK(entry.vecTxOut.empty());
179+
}
180+
}
181+
158182
BOOST_AUTO_TEST_CASE(queue_timeout_bounds)
159183
{
160184
CCoinJoinQueue dsq;

0 commit comments

Comments
 (0)