/bitcoin/src/policy/packages.cpp
Line | Count | Source |
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 | 4.43k | { |
21 | | // Avoid misusing this function: later_txids should contain the txids of txns. |
22 | 4.43k | 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 | 8.87k | for (const auto& tx : txns) { Branch (27:25): [True: 8.87k, False: 4.43k]
|
28 | 19.9k | for (const auto& input : tx->vin) { Branch (28:32): [True: 19.9k, False: 8.87k]
|
29 | 19.9k | if (later_txids.find(input.prevout.hash) != later_txids.end()) { Branch (29:17): [True: 0, False: 19.9k]
|
30 | | // The parent is a subsequent transaction in the package. |
31 | 0 | return false; |
32 | 0 | } |
33 | 19.9k | } |
34 | | // Avoid misusing this function: later_txids must contain every tx. |
35 | 8.87k | Assume(later_txids.erase(tx->GetHash()) == 1); |
36 | 8.87k | } |
37 | | |
38 | | // Avoid misusing this function: later_txids should have contained the txids of txns. |
39 | 4.43k | Assume(later_txids.empty()); |
40 | 4.43k | return true; |
41 | 4.43k | } |
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 | 4.43k | { |
54 | | // Don't allow any conflicting transactions, i.e. spending the same inputs, in a package. |
55 | 4.43k | std::unordered_set<COutPoint, SaltedOutpointHasher> inputs_seen; |
56 | 8.87k | for (const auto& tx : txns) { Branch (56:25): [True: 8.87k, False: 4.42k]
|
57 | 8.87k | if (tx->vin.empty()) { Branch (57:13): [True: 0, False: 8.87k]
|
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 | 19.8k | for (const auto& input : tx->vin) { Branch (64:32): [True: 19.8k, False: 8.86k]
|
65 | 19.8k | if (inputs_seen.find(input.prevout) != inputs_seen.end()) { Branch (65:17): [True: 12, False: 19.8k]
|
66 | | // This input is also present in another tx in the package. |
67 | 12 | return false; |
68 | 12 | } |
69 | 19.8k | } |
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 | 8.86k | std::transform(tx->vin.cbegin(), tx->vin.cend(), std::inserter(inputs_seen, inputs_seen.end()), |
74 | 19.8k | [](const auto& input) { return input.prevout; }); |
75 | 8.86k | } |
76 | 4.42k | return true; |
77 | 4.43k | } |
78 | | |
79 | | bool IsWellFormedPackage(const Package& txns, PackageValidationState& state, bool require_sorted) |
80 | 4.46k | { |
81 | 4.46k | const unsigned int package_count = txns.size(); |
82 | | |
83 | 4.46k | if (package_count > MAX_PACKAGE_COUNT) { Branch (83:9): [True: 0, False: 4.46k]
|
84 | 0 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-many-transactions"); |
85 | 0 | } |
86 | | |
87 | 4.46k | const int64_t total_weight = std::accumulate(txns.cbegin(), txns.cend(), 0, |
88 | 8.93k | [](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 | 4.46k | if (package_count > 1 && total_weight > MAX_PACKAGE_WEIGHT) { Branch (90:9): [True: 4.46k, False: 0]
Branch (90:30): [True: 29, False: 4.43k]
|
91 | 29 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-large"); |
92 | 29 | } |
93 | | |
94 | 4.43k | std::unordered_set<uint256, SaltedTxidHasher> later_txids; |
95 | 4.43k | std::transform(txns.cbegin(), txns.cend(), std::inserter(later_txids, later_txids.end()), |
96 | 8.87k | [](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 | 4.43k | if (later_txids.size() != txns.size()) { Branch (100:9): [True: 0, False: 4.43k]
|
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 | 4.43k | if (require_sorted && !IsTopoSortedPackage(txns, later_txids)) { Branch (108:9): [True: 4.43k, False: 0]
Branch (108:27): [True: 0, False: 4.43k]
|
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 | 4.43k | if (!IsConsistentPackage(txns)) { Branch (113:9): [True: 12, False: 4.42k]
|
114 | 12 | return state.Invalid(PackageValidationResult::PCKG_POLICY, "conflict-in-package"); |
115 | 12 | } |
116 | 4.42k | return true; |
117 | 4.43k | } |
118 | | |
119 | | bool IsChildWithParents(const Package& package) |
120 | 3.54k | { |
121 | 3.54k | assert(std::all_of(package.cbegin(), package.cend(), [](const auto& tx){return tx != nullptr;})); Branch (121:5): [True: 3.54k, False: 0]
|
122 | 3.54k | if (package.size() < 2) return false; Branch (122:9): [True: 0, False: 3.54k]
|
123 | | |
124 | | // The package is expected to be sorted, so the last transaction is the child. |
125 | 3.54k | const auto& child = package.back(); |
126 | 3.54k | std::unordered_set<uint256, SaltedTxidHasher> input_txids; |
127 | 3.54k | std::transform(child->vin.cbegin(), child->vin.cend(), |
128 | 3.54k | std::inserter(input_txids, input_txids.end()), |
129 | 10.1k | [](const auto& input) { return input.prevout.hash; }); |
130 | | |
131 | | // Every transaction must be a parent of the last transaction in the package. |
132 | 3.54k | return std::all_of(package.cbegin(), package.cend() - 1, |
133 | 3.54k | [&input_txids](const auto& ptx) { return input_txids.count(ptx->GetHash()) > 0; }); |
134 | 3.54k | } |
135 | | |
136 | | bool IsChildWithParentsTree(const Package& package) |
137 | 0 | { |
138 | 0 | if (!IsChildWithParents(package)) return false; Branch (138:9): [True: 0, False: 0]
|
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) { Branch (144:32): [True: 0, False: 0]
|
145 | 0 | if (parent_txids.count(input.prevout.hash) > 0) return false; Branch (145:17): [True: 0, False: 0]
|
146 | 0 | } |
147 | 0 | return true; |
148 | 0 | }); |
149 | 0 | } |
150 | | |
151 | | uint256 GetPackageHash(const std::vector<CTransactionRef>& transactions) |
152 | 5.34k | { |
153 | | // Create a vector of the wtxids. |
154 | 5.34k | std::vector<Wtxid> wtxids_copy; |
155 | 5.34k | std::transform(transactions.cbegin(), transactions.cend(), std::back_inserter(wtxids_copy), |
156 | 10.6k | [](const auto& tx){ return tx->GetWitnessHash(); }); |
157 | | |
158 | | // Sort in ascending order |
159 | 8.23k | std::sort(wtxids_copy.begin(), wtxids_copy.end(), [](const auto& lhs, const auto& rhs) { |
160 | 8.23k | return std::lexicographical_compare(std::make_reverse_iterator(lhs.end()), std::make_reverse_iterator(lhs.begin()), |
161 | 8.23k | std::make_reverse_iterator(rhs.end()), std::make_reverse_iterator(rhs.begin())); |
162 | 8.23k | }); |
163 | | |
164 | | // Get sha256 hash of the wtxids concatenated in this order |
165 | 5.34k | HashWriter hashwriter; |
166 | 10.6k | for (const auto& wtxid : wtxids_copy) { Branch (166:28): [True: 10.6k, False: 5.34k]
|
167 | 10.6k | hashwriter << wtxid; |
168 | 10.6k | } |
169 | 5.34k | return hashwriter.GetSHA256(); |
170 | 5.34k | } |