| 242 | } |
| 243 | |
| 244 | void MiniMiner::BuildMockTemplate(std::optional<CFeeRate> target_feerate) |
| 245 | { |
| 246 | const auto num_txns{m_entries_by_txid.size()}; |
| 247 | uint32_t sequence_num{0}; |
| 248 | while (!m_entries_by_txid.empty()) { |
| 249 | // Sort again, since transaction removal may change some m_entries' ancestor feerates. |
| 250 | std::sort(m_entries.begin(), m_entries.end(), AncestorFeerateComparator()); |
| 251 | |
| 252 | // Pick highest ancestor feerate entry. |
| 253 | auto best_iter = m_entries.begin(); |
| 254 | Assume(best_iter != m_entries.end()); |
| 255 | const auto ancestor_package_size = (*best_iter)->second.GetSizeWithAncestors(); |
| 256 | const auto ancestor_package_fee = (*best_iter)->second.GetModFeesWithAncestors(); |
| 257 | // Stop here. Everything that didn't "make it into the block" has bumpfee. |
| 258 | if (target_feerate.has_value() && |
| 259 | ancestor_package_fee < target_feerate->GetFee(ancestor_package_size)) { |
| 260 | break; |
| 261 | } |
| 262 | |
| 263 | // Calculate ancestors on the fly. This lookup should be fairly cheap, and ancestor sets |
| 264 | // change at every iteration, so this is more efficient than maintaining a cache. |
| 265 | std::set<MockEntryMap::iterator, IteratorComparator> ancestors; |
| 266 | { |
| 267 | std::set<MockEntryMap::iterator, IteratorComparator> to_process; |
| 268 | to_process.insert(*best_iter); |
| 269 | while (!to_process.empty()) { |
| 270 | auto iter = to_process.begin(); |
| 271 | Assume(iter != to_process.end()); |
| 272 | ancestors.insert(*iter); |
| 273 | for (const auto& input : (*iter)->second.GetTx().vin) { |
| 274 | if (auto parent_it{m_entries_by_txid.find(input.prevout.hash)}; parent_it != m_entries_by_txid.end()) { |
| 275 | if (!ancestors.contains(parent_it)) { |
| 276 | to_process.insert(parent_it); |
| 277 | } |
| 278 | } |
| 279 | } |
| 280 | to_process.erase(iter); |
| 281 | } |
| 282 | } |
| 283 | // Track the order in which transactions were selected. |
| 284 | for (const auto& ancestor : ancestors) { |
| 285 | m_inclusion_order.emplace(ancestor->first, sequence_num); |
| 286 | } |
| 287 | DeleteAncestorPackage(ancestors); |
| 288 | SanityCheck(); |
| 289 | ++sequence_num; |
| 290 | } |
| 291 | if (!target_feerate.has_value()) { |
| 292 | Assume(m_in_block.size() == num_txns); |
| 293 | } else { |
| 294 | Assume(m_in_block.empty() || m_total_fees >= target_feerate->GetFee(m_total_vsize)); |
| 295 | } |
| 296 | Assume(m_in_block.empty() || sequence_num > 0); |
| 297 | Assume(m_in_block.size() == m_inclusion_order.size()); |
| 298 | // Do not try to continue building the block template with a different feerate. |
| 299 | m_ready_to_calculate = false; |
| 300 | } |
| 301 | |