Skip to content

Commit e32ba15

Browse files
committed
[txpackages] IsChildWithParentsTree()
Many edge cases exist when parents in a child-with-parents package can spend each other. However, this pattern should also be uncommon in normal use cases.
1 parent b4f28cc commit e32ba15

File tree

3 files changed

+22
-0
lines changed

3 files changed

+22
-0
lines changed

src/policy/packages.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,18 @@ bool IsChildWithParents(const Package& package)
8888
return std::all_of(package.cbegin(), package.cend() - 1,
8989
[&input_txids](const auto& ptx) { return input_txids.count(ptx->GetHash()) > 0; });
9090
}
91+
92+
bool IsChildWithParentsTree(const Package& package)
93+
{
94+
if (!IsChildWithParents(package)) return false;
95+
std::unordered_set<uint256, SaltedTxidHasher> parent_txids;
96+
std::transform(package.cbegin(), package.cend() - 1, std::inserter(parent_txids, parent_txids.end()),
97+
[](const auto& ptx) { return ptx->GetHash(); });
98+
// Each parent must not have an input who is one of the other parents.
99+
return std::all_of(package.cbegin(), package.cend() - 1, [&](const auto& ptx) {
100+
for (const auto& input : ptx->vin) {
101+
if (parent_txids.count(input.prevout.hash) > 0) return false;
102+
}
103+
return true;
104+
});
105+
}

src/policy/packages.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,8 @@ bool CheckPackage(const Package& txns, PackageValidationState& state);
6363
*/
6464
bool IsChildWithParents(const Package& package);
6565

66+
/** Context-free check that a package IsChildWithParents() and none of the parents depend on each
67+
* other (the package is a "tree").
68+
*/
69+
bool IsChildWithParentsTree(const Package& package);
6670
#endif // BITCOIN_POLICY_PACKAGES_H

src/test/txpackage_tests.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup)
162162
BOOST_CHECK_EQUAL(state.GetResult(), PackageValidationResult::PCKG_POLICY);
163163
BOOST_CHECK_EQUAL(state.GetRejectReason(), "package-not-sorted");
164164
BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));
165+
BOOST_CHECK(IsChildWithParentsTree({tx_parent, tx_child}));
165166
}
166167

167168
// 24 Parents and 1 Child
@@ -187,6 +188,7 @@ BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup)
187188
PackageValidationState state;
188189
BOOST_CHECK(CheckPackage(package, state));
189190
BOOST_CHECK(IsChildWithParents(package));
191+
BOOST_CHECK(IsChildWithParentsTree(package));
190192

191193
package.erase(package.begin());
192194
BOOST_CHECK(IsChildWithParents(package));
@@ -219,6 +221,7 @@ BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup)
219221
BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child}));
220222
BOOST_CHECK(IsChildWithParents({tx_parent, tx_child}));
221223
BOOST_CHECK(IsChildWithParents({tx_parent, tx_parent_also_child, tx_child}));
224+
BOOST_CHECK(!IsChildWithParentsTree({tx_parent, tx_parent_also_child, tx_child}));
222225
// IsChildWithParents does not detect unsorted parents.
223226
BOOST_CHECK(IsChildWithParents({tx_parent_also_child, tx_parent, tx_child}));
224227
BOOST_CHECK(CheckPackage({tx_parent, tx_parent_also_child, tx_child}, state));

0 commit comments

Comments
 (0)