Skip to content

Commit f4d7947

Browse files
committed
wallet: coin selection, add duplicated inputs checks
As no process should be able to trigger this error using the regular transaction creation process, throw a runtime_error if happens to tell users/devs to report the bug if happens.
1 parent 0aa065b commit f4d7947

File tree

2 files changed

+19
-6
lines changed

2 files changed

+19
-6
lines changed

src/wallet/coinselection.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -446,15 +446,17 @@ void SelectionResult::Clear()
446446

447447
void SelectionResult::AddInput(const OutputGroup& group)
448448
{
449-
util::insert(m_selected_inputs, group.m_outputs);
449+
// As it can fail, combine inputs first
450+
InsertInputs(group.m_outputs);
450451
m_use_effective = !group.m_subtract_fee_outputs;
451452

452453
m_weight += group.m_weight;
453454
}
454455

455456
void SelectionResult::AddInputs(const std::set<COutput>& inputs, bool subtract_fee_outputs)
456457
{
457-
util::insert(m_selected_inputs, inputs);
458+
// As it can fail, combine inputs first
459+
InsertInputs(inputs);
458460
m_use_effective = !subtract_fee_outputs;
459461

460462
m_weight += std::accumulate(inputs.cbegin(), inputs.cend(), 0, [](int sum, const auto& coin) {
@@ -464,16 +466,14 @@ void SelectionResult::AddInputs(const std::set<COutput>& inputs, bool subtract_f
464466

465467
void SelectionResult::Merge(const SelectionResult& other)
466468
{
467-
// Obtain the expected selected inputs count after the merge (for now, duplicates are not allowed)
468-
const size_t expected_count = m_selected_inputs.size() + other.m_selected_inputs.size();
469+
// As it can fail, combine inputs first
470+
InsertInputs(other.m_selected_inputs);
469471

470472
m_target += other.m_target;
471473
m_use_effective |= other.m_use_effective;
472474
if (m_algo == SelectionAlgorithm::MANUAL) {
473475
m_algo = other.m_algo;
474476
}
475-
util::insert(m_selected_inputs, other.m_selected_inputs);
476-
assert(m_selected_inputs.size() == expected_count);
477477

478478
m_weight += other.m_weight;
479479
}

src/wallet/coinselection.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <policy/feerate.h>
1111
#include <primitives/transaction.h>
1212
#include <random.h>
13+
#include <util/system.h>
14+
#include <util/check.h>
1315

1416
#include <optional>
1517

@@ -302,6 +304,17 @@ struct SelectionResult
302304
/** Total weight of the selected inputs */
303305
int m_weight{0};
304306

307+
template<typename T>
308+
void InsertInputs(const T& inputs)
309+
{
310+
// Store sum of combined input sets to check that the results have no shared UTXOs
311+
const size_t expected_count = m_selected_inputs.size() + inputs.size();
312+
util::insert(m_selected_inputs, inputs);
313+
if (m_selected_inputs.size() != expected_count) {
314+
throw std::runtime_error(STR_INTERNAL_BUG("Shared UTXOs among selection results"));
315+
}
316+
}
317+
305318
public:
306319
explicit SelectionResult(const CAmount target, SelectionAlgorithm algo)
307320
: m_target(target), m_algo(algo) {}

0 commit comments

Comments
 (0)