Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 751 Lines • ▼ Show 20 Lines | PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions( | ||||
// If the package only contains 1 tx, it's better to report the policy | // If the package only contains 1 tx, it's better to report the policy | ||||
// violation on individual tx size. | // violation on individual tx size. | ||||
if (package_count > 1 && total_size > MAX_PACKAGE_SIZE * 1000) { | if (package_count > 1 && total_size > MAX_PACKAGE_SIZE * 1000) { | ||||
package_state.Invalid(PackageValidationResult::PCKG_POLICY, | package_state.Invalid(PackageValidationResult::PCKG_POLICY, | ||||
"package-too-large"); | "package-too-large"); | ||||
return PackageMempoolAcceptResult(package_state, {}); | return PackageMempoolAcceptResult(package_state, {}); | ||||
} | } | ||||
// Construct workspaces and check package policies. | |||||
std::vector<Workspace> workspaces{}; | std::vector<Workspace> workspaces{}; | ||||
workspaces.reserve(package_count); | workspaces.reserve(package_count); | ||||
std::transform(txns.cbegin(), txns.cend(), std::back_inserter(workspaces), | { | ||||
[&args, this](const auto &tx) { | std::unordered_set<TxId, SaltedTxIdHasher> later_txids; | ||||
return Workspace( | std::transform(txns.cbegin(), txns.cend(), | ||||
tx, | std::inserter(later_txids, later_txids.end()), | ||||
GetNextBlockScriptFlags( | [](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(), | args.m_config.GetChainParams().GetConsensus(), | ||||
m_active_chainstate.m_chain.Tip())); | m_active_chainstate.m_chain.Tip())); | ||||
}); | } | ||||
} | |||||
std::map<const TxId, const MempoolAcceptResult> results; | std::map<const TxId, const MempoolAcceptResult> results; | ||||
{ | { | ||||
// Don't allow any conflicting transactions, i.e. spending the same | // Don't allow any conflicting transactions, i.e. spending the same | ||||
// inputs, in a package. | // inputs, in a package. | ||||
std::unordered_set<COutPoint, SaltedOutpointHasher> inputs_seen; | std::unordered_set<COutPoint, SaltedOutpointHasher> inputs_seen; | ||||
for (const auto &tx : txns) { | for (const auto &tx : txns) { | ||||
for (const auto &input : tx->vin) { | for (const auto &input : tx->vin) { | ||||
if (inputs_seen.find(input.prevout) != inputs_seen.end()) { | if (inputs_seen.find(input.prevout) != inputs_seen.end()) { | ||||
▲ Show 20 Lines • Show All 5,438 Lines • Show Last 20 Lines |