/root/bitcoin/src/policy/packages.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2021-2022 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 <policy/packages.h> |
6 | | #include <policy/policy.h> |
7 | | #include <primitives/transaction.h> |
8 | | #include <uint256.h> |
9 | | #include <util/check.h> |
10 | | |
11 | | #include <algorithm> |
12 | | #include <cassert> |
13 | | #include <iterator> |
14 | | #include <memory> |
15 | | #include <numeric> |
16 | | |
17 | | /** IsTopoSortedPackage where a set of txids has been pre-populated. The set is assumed to be correct and |
18 | | * is mutated within this function (even if return value is false). */ |
19 | | bool IsTopoSortedPackage(const Package& txns, std::unordered_set<uint256, SaltedTxidHasher>& later_txids) |
20 | 0 | { |
21 | | // Avoid misusing this function: later_txids should contain the txids of txns. |
22 | 0 | Assume(txns.size() == later_txids.size()); |
23 | | |
24 | | // later_txids always contains the txids of this transaction and the ones that come later in |
25 | | // txns. If any transaction's input spends a tx in that set, we've found a parent placed later |
26 | | // than its child. |
27 | 0 | for (const auto& tx : txns) { |
28 | 0 | for (const auto& input : tx->vin) { |
29 | 0 | if (later_txids.find(input.prevout.hash) != later_txids.end()) { |
30 | | // The parent is a subsequent transaction in the package. |
31 | 0 | return false; |
32 | 0 | } |
33 | 0 | } |
34 | | // Avoid misusing this function: later_txids must contain every tx. |
35 | 0 | Assume(later_txids.erase(tx->GetHash()) == 1); |
36 | 0 | } |
37 | | |
38 | | // Avoid misusing this function: later_txids should have contained the txids of txns. |
39 | 0 | Assume(later_txids.empty()); |
40 | 0 | return true; |
41 | 0 | } |
42 | | |
43 | | bool IsTopoSortedPackage(const Package& txns) |
44 | 0 | { |
45 | 0 | std::unordered_set<uint256, SaltedTxidHasher> later_txids; |
46 | 0 | std::transform(txns.cbegin(), txns.cend(), std::inserter(later_txids, later_txids.end()), |
47 | 0 | [](const auto& tx) { return tx->GetHash(); }); |
48 | |
|
49 | 0 | return IsTopoSortedPackage(txns, later_txids); |
50 | 0 | } |
51 | | |
52 | | bool IsConsistentPackage(const Package& txns) |
53 | 0 | { |
54 | | // Don't allow any conflicting transactions, i.e. spending the same inputs, in a package. |
55 | 0 | std::unordered_set<COutPoint, SaltedOutpointHasher> inputs_seen; |
56 | 0 | for (const auto& tx : txns) { |
57 | 0 | if (tx->vin.empty()) { |
58 | | // This function checks consistency based on inputs, and we can't do that if there are |
59 | | // no inputs. Duplicate empty transactions are also not consistent with one another. |
60 | | // This doesn't create false negatives, as unconfirmed transactions are not allowed to |
61 | | // have no inputs. |
62 | 0 | return false; |
63 | 0 | } |
64 | 0 | for (const auto& input : tx->vin) { |
65 | 0 | if (inputs_seen.find(input.prevout) != inputs_seen.end()) { |
66 | | // This input is also present in another tx in the package. |
67 | 0 | return false; |
68 | 0 | } |
69 | 0 | } |
70 | | // Batch-add all the inputs for a tx at a time. If we added them 1 at a time, we could |
71 | | // catch duplicate inputs within a single tx. This is a more severe, consensus error, |
72 | | // and we want to report that from CheckTransaction instead. |
73 | 0 | std::transform(tx->vin.cbegin(), tx->vin.cend(), std::inserter(inputs_seen, inputs_seen.end()), |
74 | 0 | [](const auto& input) { return input.prevout; }); |
75 | 0 | } |
76 | 0 | return true; |
77 | 0 | } |
78 | | |
79 | | bool IsWellFormedPackage(const Package& txns, PackageValidationState& state, bool require_sorted) |
80 | 0 | { |
81 | 0 | const unsigned int package_count = txns.size(); |
82 | |
|
83 | 0 | if (package_count > MAX_PACKAGE_COUNT) { |
84 | 0 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-many-transactions"); |
85 | 0 | } |
86 | | |
87 | 0 | const int64_t total_weight = std::accumulate(txns.cbegin(), txns.cend(), 0, |
88 | 0 | [](int64_t sum, const auto& tx) { return sum + GetTransactionWeight(*tx); }); |
89 | | // If the package only contains 1 tx, it's better to report the policy violation on individual tx weight. |
90 | 0 | if (package_count > 1 && total_weight > MAX_PACKAGE_WEIGHT) { |
91 | 0 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-large"); |
92 | 0 | } |
93 | | |
94 | 0 | std::unordered_set<uint256, SaltedTxidHasher> later_txids; |
95 | 0 | std::transform(txns.cbegin(), txns.cend(), std::inserter(later_txids, later_txids.end()), |
96 | 0 | [](const auto& tx) { return tx->GetHash(); }); |
97 | | |
98 | | // Package must not contain any duplicate transactions, which is checked by txid. This also |
99 | | // includes transactions with duplicate wtxids and same-txid-different-witness transactions. |
100 | 0 | if (later_txids.size() != txns.size()) { |
101 | 0 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-contains-duplicates"); |
102 | 0 | } |
103 | | |
104 | | // Require the package to be sorted in order of dependency, i.e. parents appear before children. |
105 | | // An unsorted package will fail anyway on missing-inputs, but it's better to quit earlier and |
106 | | // fail on something less ambiguous (missing-inputs could also be an orphan or trying to |
107 | | // spend nonexistent coins). |
108 | 0 | if (require_sorted && !IsTopoSortedPackage(txns, later_txids)) { |
109 | 0 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-not-sorted"); |
110 | 0 | } |
111 | | |
112 | | // Don't allow any conflicting transactions, i.e. spending the same inputs, in a package. |
113 | 0 | if (!IsConsistentPackage(txns)) { |
114 | 0 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "conflict-in-package"); |
115 | 0 | } |
116 | 0 | return true; |
117 | 0 | } |
118 | | |
119 | | bool IsChildWithParents(const Package& package) |
120 | 0 | { |
121 | 0 | assert(std::all_of(package.cbegin(), package.cend(), [](const auto& tx){return tx != nullptr;})); |
122 | 0 | if (package.size() < 2) return false; |
123 | | |
124 | | // The package is expected to be sorted, so the last transaction is the child. |
125 | 0 | const auto& child = package.back(); |
126 | 0 | std::unordered_set<uint256, SaltedTxidHasher> input_txids; |
127 | 0 | std::transform(child->vin.cbegin(), child->vin.cend(), |
128 | 0 | std::inserter(input_txids, input_txids.end()), |
129 | 0 | [](const auto& input) { return input.prevout.hash; }); |
130 | | |
131 | | // Every transaction must be a parent of the last transaction in the package. |
132 | 0 | return std::all_of(package.cbegin(), package.cend() - 1, |
133 | 0 | [&input_txids](const auto& ptx) { return input_txids.count(ptx->GetHash()) > 0; }); |
134 | 0 | } |
135 | | |
136 | | bool IsChildWithParentsTree(const Package& package) |
137 | 0 | { |
138 | 0 | if (!IsChildWithParents(package)) return false; |
139 | 0 | std::unordered_set<uint256, SaltedTxidHasher> parent_txids; |
140 | 0 | std::transform(package.cbegin(), package.cend() - 1, std::inserter(parent_txids, parent_txids.end()), |
141 | 0 | [](const auto& ptx) { return ptx->GetHash(); }); |
142 | | // Each parent must not have an input who is one of the other parents. |
143 | 0 | return std::all_of(package.cbegin(), package.cend() - 1, [&](const auto& ptx) { |
144 | 0 | for (const auto& input : ptx->vin) { |
145 | 0 | if (parent_txids.count(input.prevout.hash) > 0) return false; |
146 | 0 | } |
147 | 0 | return true; |
148 | 0 | }); |
149 | 0 | } |
150 | | |
151 | | uint256 GetPackageHash(const std::vector<CTransactionRef>& transactions) |
152 | 0 | { |
153 | | // Create a vector of the wtxids. |
154 | 0 | std::vector<Wtxid> wtxids_copy; |
155 | 0 | std::transform(transactions.cbegin(), transactions.cend(), std::back_inserter(wtxids_copy), |
156 | 0 | [](const auto& tx){ return tx->GetWitnessHash(); }); |
157 | | |
158 | | // Sort in ascending order |
159 | 0 | std::sort(wtxids_copy.begin(), wtxids_copy.end(), [](const auto& lhs, const auto& rhs) { |
160 | 0 | return std::lexicographical_compare(std::make_reverse_iterator(lhs.end()), std::make_reverse_iterator(lhs.begin()), |
161 | 0 | std::make_reverse_iterator(rhs.end()), std::make_reverse_iterator(rhs.begin())); |
162 | 0 | }); |
163 | | |
164 | | // Get sha256 hash of the wtxids concatenated in this order |
165 | 0 | HashWriter hashwriter; |
166 | 0 | for (const auto& wtxid : wtxids_copy) { |
167 | 0 | hashwriter << wtxid; |
168 | 0 | } |
169 | 0 | return hashwriter.GetSHA256(); |
170 | 0 | } |