Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13711443
D12135.id35440.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
9 KB
Subscribers
None
D12135.id35440.diff
View Options
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -599,6 +599,7 @@
node/ui_interface.cpp
noui.cpp
policy/fees.cpp
+ policy/packages.cpp
policy/settings.cpp
pow/aserti32d.cpp
pow/daa.cpp
diff --git a/src/policy/packages.h b/src/policy/packages.h
--- a/src/policy/packages.h
+++ b/src/policy/packages.h
@@ -40,4 +40,14 @@
class PackageValidationState : public ValidationState<PackageValidationResult> {
};
+/**
+ * Context-free package policy checks:
+ * 1. The number of transactions cannot exceed MAX_PACKAGE_COUNT.
+ * 2. The total virtual size cannot exceed MAX_PACKAGE_SIZE.
+ * 3. If any dependencies exist between transactions, parents must appear before
+ * children.
+ * 4. Transactions cannot conflict, i.e., spend the same inputs.
+ */
+bool CheckPackage(const Package &txns, PackageValidationState &state);
+
#endif // BITCOIN_POLICY_PACKAGES_H
diff --git a/src/policy/packages.cpp b/src/policy/packages.cpp
new file mode 100644
--- /dev/null
+++ b/src/policy/packages.cpp
@@ -0,0 +1,75 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <consensus/validation.h>
+#include <policy/packages.h>
+#include <primitives/transaction.h>
+#include <util/hasher.h>
+
+#include <numeric>
+#include <unordered_set>
+
+bool CheckPackage(const Package &txns, PackageValidationState &state) {
+ const size_t package_count = txns.size();
+
+ // These context-free package limits can be checked before taking the
+ // mempool lock.
+ if (package_count > MAX_PACKAGE_COUNT) {
+ return state.Invalid(PackageValidationResult::PCKG_POLICY,
+ "package-too-many-transactions");
+ }
+
+ const int64_t total_size = std::accumulate(
+ txns.cbegin(), txns.cend(), 0, [](int64_t sum, const auto &tx) {
+ return sum + GetVirtualTransactionSize(*tx);
+ });
+ // If the package only contains 1 tx, it's better to report the policy
+ // violation on individual tx size.
+ if (package_count > 1 && total_size > MAX_PACKAGE_SIZE * 1000) {
+ return state.Invalid(PackageValidationResult::PCKG_POLICY,
+ "package-too-large");
+ }
+
+ // Require the package to be sorted in order of dependency, i.e. parents
+ // appear before children.
+ // An unsorted package will fail anyway on missing-inputs, but it's better
+ // to quit earlier and fail on something less ambiguous (missing-inputs
+ // could also be an orphan or trying to spend nonexistent coins).
+ std::unordered_set<TxId, SaltedTxIdHasher> later_txids;
+ std::transform(txns.cbegin(), txns.cend(),
+ std::inserter(later_txids, later_txids.end()),
+ [](const auto &tx) { return tx->GetId(); });
+ for (const auto &tx : txns) {
+ for (const auto &input : tx->vin) {
+ if (later_txids.find(input.prevout.GetTxId()) !=
+ later_txids.end()) {
+ // The parent is a subsequent transaction in the package.
+ return state.Invalid(PackageValidationResult::PCKG_POLICY,
+ "package-not-sorted");
+ }
+ }
+ later_txids.erase(tx->GetId());
+ }
+
+ // Don't allow any conflicting transactions, i.e. spending the same
+ // inputs, in a package.
+ std::unordered_set<COutPoint, SaltedOutpointHasher> inputs_seen;
+ for (const auto &tx : txns) {
+ for (const auto &input : tx->vin) {
+ if (inputs_seen.find(input.prevout) != inputs_seen.end()) {
+ // This input is also present in another tx in the package.
+ return state.Invalid(PackageValidationResult::PCKG_POLICY,
+ "conflict-in-package");
+ }
+ }
+ // Batch-add all the inputs for a tx at a time. If we added them 1
+ // at a time, we could catch duplicate inputs within a single tx.
+ // This is a more severe, consensus error, and we want to report
+ // that from CheckTransaction instead.
+ std::transform(tx->vin.cbegin(), tx->vin.cend(),
+ std::inserter(inputs_seen, inputs_seen.end()),
+ [](const auto &input) { return input.prevout; });
+ }
+ return true;
+}
diff --git a/src/validation.cpp b/src/validation.cpp
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -734,83 +734,24 @@
const std::vector<CTransactionRef> &txns, ATMPArgs &args) {
AssertLockHeld(cs_main);
+ // These context-free package limits can be done before taking the mempool
+ // lock.
PackageValidationState package_state;
- const size_t package_count = txns.size();
-
- // These context-free package limits can be checked before taking the
- // mempool lock.
- if (package_count > MAX_PACKAGE_COUNT) {
- package_state.Invalid(PackageValidationResult::PCKG_POLICY,
- "package-too-many-transactions");
- return PackageMempoolAcceptResult(package_state, {});
- }
-
- const int64_t total_size = std::accumulate(
- txns.cbegin(), txns.cend(), 0, [](int64_t sum, const auto &tx) {
- return sum + GetVirtualTransactionSize(*tx);
- });
- // If the package only contains 1 tx, it's better to report the policy
- // violation on individual tx size.
- if (package_count > 1 && total_size > MAX_PACKAGE_SIZE * 1000) {
- package_state.Invalid(PackageValidationResult::PCKG_POLICY,
- "package-too-large");
+ if (!CheckPackage(txns, package_state)) {
return PackageMempoolAcceptResult(package_state, {});
}
- // Construct workspaces and check package policies.
std::vector<Workspace> workspaces{};
- workspaces.reserve(package_count);
- {
- std::unordered_set<TxId, SaltedTxIdHasher> later_txids;
- std::transform(txns.cbegin(), txns.cend(),
- std::inserter(later_txids, later_txids.end()),
- [](const auto &tx) { return tx->GetId(); });
- // Require the package to be sorted in order of dependency, i.e.
- // parents appear before children.
- // An unsorted package will fail anyway on missing-inputs, but it's
- // better to quit earlier and fail on something less ambiguous
- // (missing-inputs could also be an orphan or trying to spend
- // nonexistent coins).
- for (const auto &tx : txns) {
- for (const auto &input : tx->vin) {
- if (later_txids.find(input.prevout.GetTxId()) !=
- later_txids.end()) {
- // The parent is a subsequent transaction in the package.
- package_state.Invalid(PackageValidationResult::PCKG_POLICY,
- "package-not-sorted");
- return PackageMempoolAcceptResult(package_state, {});
- }
- }
- later_txids.erase(tx->GetId());
- workspaces.emplace_back(
- tx, GetNextBlockScriptFlags(
- args.m_config.GetChainParams().GetConsensus(),
- m_active_chainstate.m_chain.Tip()));
- }
- }
+ workspaces.reserve(txns.size());
+ std::transform(txns.cbegin(), txns.cend(), std::back_inserter(workspaces),
+ [&args, this](const auto &tx) {
+ return Workspace(
+ tx,
+ GetNextBlockScriptFlags(
+ args.m_config.GetChainParams().GetConsensus(),
+ m_active_chainstate.m_chain.Tip()));
+ });
std::map<const TxId, const MempoolAcceptResult> results;
- {
- // Don't allow any conflicting transactions, i.e. spending the same
- // inputs, in a package.
- std::unordered_set<COutPoint, SaltedOutpointHasher> inputs_seen;
- for (const auto &tx : txns) {
- for (const auto &input : tx->vin) {
- if (inputs_seen.find(input.prevout) != inputs_seen.end()) {
- // This input is also present in another tx in the package.
- package_state.Invalid(PackageValidationResult::PCKG_POLICY,
- "conflict-in-package");
- return PackageMempoolAcceptResult(package_state, {});
- }
- }
- // Batch-add all the inputs for a tx at a time. If we added them 1
- // at a time, we could catch duplicate inputs within a single tx.
- // This is a more severe, consensus error, and we want to report
- // that from CheckTransaction instead.
- std::transform(tx->vin.cbegin(), tx->vin.cend(),
- std::inserter(inputs_seen, inputs_seen.end()),
- [](const auto &input) { return input.prevout; });
- }
- }
LOCK(m_pool.cs);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 26, 12:05 (2 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5570945
Default Alt Text
D12135.id35440.diff (9 KB)
Attached To
D12135: MOVEONLY: context-free package policies
Event Timeline
Log In to Comment