| 12 | #include <unordered_set> |
| 13 | |
| 14 | bool CheckPackage(const Package& txns, PackageValidationState& state) |
| 15 | { |
| 16 | const unsigned int package_count = txns.size(); |
| 17 | |
| 18 | if (package_count > MAX_PACKAGE_COUNT) { |
| 19 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-many-transactions"); |
| 20 | } |
| 21 | |
| 22 | const int64_t total_size = std::accumulate(txns.cbegin(), txns.cend(), 0, |
| 23 | [](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 | if (package_count > 1 && total_size > MAX_PACKAGE_SIZE * 1000) { |
| 26 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-large"); |
| 27 | } |
| 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 | std::unordered_set<uint256, SaltedTxidHasher> later_txids; |
| 34 | std::transform(txns.cbegin(), txns.cend(), std::inserter(later_txids, later_txids.end()), |
| 35 | [](const auto& tx) { return tx->GetHash(); }); |
| 36 | for (const auto& tx : txns) { |
| 37 | for (const auto& input : tx->vin) { |
| 38 | if (later_txids.find(input.prevout.hash) != later_txids.end()) { |
| 39 | // The parent is a subsequent transaction in the package. |
| 40 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-sorted"); |
| 41 | } |
| 42 | } |
| 43 | later_txids.erase(tx->GetHash()); |
| 44 | } |
| 45 | |
| 46 | // Don't allow any conflicting transactions, i.e. spending the same inputs, in a package. |
| 47 | std::unordered_set<COutPoint, SaltedOutpointHasher> inputs_seen; |
| 48 | for (const auto& tx : txns) { |
| 49 | for (const auto& input : tx->vin) { |
| 50 | if (inputs_seen.find(input.prevout) != inputs_seen.end()) { |
| 51 | // This input is also present in another tx in the package. |
| 52 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "conflict-in-package"); |
| 53 | } |
| 54 | } |
| 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 | std::transform(tx->vin.cbegin(), tx->vin.cend(), std::inserter(inputs_seen, inputs_seen.end()), |
| 59 | [](const auto& input) { return input.prevout; }); |
| 60 | } |
| 61 | return true; |
| 62 | } |
| 63 | |
| 64 | bool IsChildWithParents(const Package& package) |
| 65 | { |