Branch data Line data Source code
# 1 : : // Copyright (c) 2021 The Bitcoin Core developers
# 2 : : // Distributed under the MIT software license, see the accompanying
# 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 4 : :
# 5 : : #include <consensus/validation.h>
# 6 : : #include <policy/packages.h>
# 7 : : #include <primitives/transaction.h>
# 8 : : #include <uint256.h>
# 9 : : #include <util/hasher.h>
# 10 : :
# 11 : : #include <numeric>
# 12 : : #include <unordered_set>
# 13 : :
# 14 : : bool CheckPackage(const Package& txns, PackageValidationState& state)
# 15 : 122 : {
# 16 : 122 : const unsigned int package_count = txns.size();
# 17 : :
# 18 [ + + ]: 122 : if (package_count > MAX_PACKAGE_COUNT) {
# 19 : 2 : return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-many-transactions");
# 20 : 2 : }
# 21 : :
# 22 : 120 : const int64_t total_size = std::accumulate(txns.cbegin(), txns.cend(), 0,
# 23 : 775 : [](int64_t sum, const auto& tx) { return sum + GetVirtualTransactionSize(*tx); });
# 24 : : // If the package only contains 1 tx, it's better to report the policy violation on individual tx size.
# 25 [ + + ][ + + ]: 120 : if (package_count > 1 && total_size > MAX_PACKAGE_SIZE * 1000) {
# 26 : 2 : return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-large");
# 27 : 2 : }
# 28 : :
# 29 : : // Require the package to be sorted in order of dependency, i.e. parents appear before children.
# 30 : : // An unsorted package will fail anyway on missing-inputs, but it's better to quit earlier and
# 31 : : // fail on something less ambiguous (missing-inputs could also be an orphan or trying to
# 32 : : // spend nonexistent coins).
# 33 : 118 : std::unordered_set<uint256, SaltedTxidHasher> later_txids;
# 34 : 118 : std::transform(txns.cbegin(), txns.cend(), std::inserter(later_txids, later_txids.end()),
# 35 : 767 : [](const auto& tx) { return tx->GetHash(); });
# 36 [ + + ]: 737 : for (const auto& tx : txns) {
# 37 [ + + ]: 3165 : for (const auto& input : tx->vin) {
# 38 [ + + ]: 3165 : if (later_txids.find(input.prevout.hash) != later_txids.end()) {
# 39 : : // The parent is a subsequent transaction in the package.
# 40 : 5 : return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-sorted");
# 41 : 5 : }
# 42 : 3165 : }
# 43 : 732 : later_txids.erase(tx->GetHash());
# 44 : 732 : }
# 45 : :
# 46 : : // Don't allow any conflicting transactions, i.e. spending the same inputs, in a package.
# 47 : 113 : std::unordered_set<COutPoint, SaltedOutpointHasher> inputs_seen;
# 48 [ + + ]: 732 : for (const auto& tx : txns) {
# 49 [ + + ]: 3160 : for (const auto& input : tx->vin) {
# 50 [ + + ]: 3160 : if (inputs_seen.find(input.prevout) != inputs_seen.end()) {
# 51 : : // This input is also present in another tx in the package.
# 52 : 3 : return state.Invalid(PackageValidationResult::PCKG_POLICY, "conflict-in-package");
# 53 : 3 : }
# 54 : 3160 : }
# 55 : : // Batch-add all the inputs for a tx at a time. If we added them 1 at a time, we could
# 56 : : // catch duplicate inputs within a single tx. This is a more severe, consensus error,
# 57 : : // and we want to report that from CheckTransaction instead.
# 58 : 729 : std::transform(tx->vin.cbegin(), tx->vin.cend(), std::inserter(inputs_seen, inputs_seen.end()),
# 59 : 3157 : [](const auto& input) { return input.prevout; });
# 60 : 729 : }
# 61 : 110 : return true;
# 62 : 113 : }
# 63 : :
# 64 : : bool IsChildWithParents(const Package& package)
# 65 : 48 : {
# 66 : 48 : assert(std::all_of(package.cbegin(), package.cend(), [](const auto& tx){return tx != nullptr;}));
# 67 [ - + ]: 48 : if (package.size() < 2) return false;
# 68 : :
# 69 : : // The package is expected to be sorted, so the last transaction is the child.
# 70 : 48 : const auto& child = package.back();
# 71 : 48 : std::unordered_set<uint256, SaltedTxidHasher> input_txids;
# 72 : 48 : std::transform(child->vin.cbegin(), child->vin.cend(),
# 73 : 48 : std::inserter(input_txids, input_txids.end()),
# 74 : 198 : [](const auto& input) { return input.prevout.hash; });
# 75 : :
# 76 : : // Every transaction must be a parent of the last transaction in the package.
# 77 : 48 : return std::all_of(package.cbegin(), package.cend() - 1,
# 78 : 146 : [&input_txids](const auto& ptx) { return input_txids.count(ptx->GetHash()) > 0; });
# 79 : 48 : }
|