|
16 | 16 | #include <consensus/validation.h>
|
17 | 17 | #include <deploymentstatus.h>
|
18 | 18 | #include <logging.h>
|
| 19 | +#include <node/context.h> |
| 20 | +#include <node/kernel_notifications.h> |
19 | 21 | #include <policy/feerate.h>
|
20 | 22 | #include <policy/policy.h>
|
21 | 23 | #include <pow.h>
|
22 | 24 | #include <primitives/transaction.h>
|
23 | 25 | #include <util/moneystr.h>
|
| 26 | +#include <util/signalinterrupt.h> |
24 | 27 | #include <util/time.h>
|
25 | 28 | #include <validation.h>
|
26 | 29 |
|
@@ -447,4 +450,93 @@ void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t
|
447 | 450 | block.nNonce = nonce;
|
448 | 451 | block.hashMerkleRoot = BlockMerkleRoot(block);
|
449 | 452 | }
|
| 453 | + |
| 454 | +std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman, |
| 455 | + KernelNotifications& kernel_notifications, |
| 456 | + CTxMemPool* mempool, |
| 457 | + const std::unique_ptr<CBlockTemplate>& block_template, |
| 458 | + const BlockWaitOptions& options, |
| 459 | + const BlockAssembler::Options& assemble_options) |
| 460 | +{ |
| 461 | + // Delay calculating the current template fees, just in case a new block |
| 462 | + // comes in before the next tick. |
| 463 | + CAmount current_fees = -1; |
| 464 | + |
| 465 | + // Alternate waiting for a new tip and checking if fees have risen. |
| 466 | + // The latter check is expensive so we only run it once per second. |
| 467 | + auto now{NodeClock::now()}; |
| 468 | + const auto deadline = now + options.timeout; |
| 469 | + const MillisecondsDouble tick{1000}; |
| 470 | + const bool allow_min_difficulty{chainman.GetParams().GetConsensus().fPowAllowMinDifficultyBlocks}; |
| 471 | + |
| 472 | + do { |
| 473 | + bool tip_changed{false}; |
| 474 | + { |
| 475 | + WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock); |
| 476 | + // Note that wait_until() checks the predicate before waiting |
| 477 | + kernel_notifications.m_tip_block_cv.wait_until(lock, std::min(now + tick, deadline), [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) { |
| 478 | + AssertLockHeld(kernel_notifications.m_tip_block_mutex); |
| 479 | + const auto tip_block{kernel_notifications.TipBlock()}; |
| 480 | + // We assume tip_block is set, because this is an instance |
| 481 | + // method on BlockTemplate and no template could have been |
| 482 | + // generated before a tip exists. |
| 483 | + tip_changed = Assume(tip_block) && tip_block != block_template->block.hashPrevBlock; |
| 484 | + return tip_changed || chainman.m_interrupt; |
| 485 | + }); |
| 486 | + } |
| 487 | + |
| 488 | + if (chainman.m_interrupt) return nullptr; |
| 489 | + // At this point the tip changed, a full tick went by or we reached |
| 490 | + // the deadline. |
| 491 | + |
| 492 | + // Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks. |
| 493 | + LOCK(::cs_main); |
| 494 | + |
| 495 | + // On test networks return a minimum difficulty block after 20 minutes |
| 496 | + if (!tip_changed && allow_min_difficulty) { |
| 497 | + const NodeClock::time_point tip_time{std::chrono::seconds{chainman.ActiveChain().Tip()->GetBlockTime()}}; |
| 498 | + if (now > tip_time + 20min) { |
| 499 | + tip_changed = true; |
| 500 | + } |
| 501 | + } |
| 502 | + |
| 503 | + /** |
| 504 | + * We determine if fees increased compared to the previous template by generating |
| 505 | + * a fresh template. There may be more efficient ways to determine how much |
| 506 | + * (approximate) fees for the next block increased, perhaps more so after |
| 507 | + * Cluster Mempool. |
| 508 | + * |
| 509 | + * We'll also create a new template if the tip changed during this iteration. |
| 510 | + */ |
| 511 | + if (options.fee_threshold < MAX_MONEY || tip_changed) { |
| 512 | + auto new_tmpl{BlockAssembler{ |
| 513 | + chainman.ActiveChainstate(), |
| 514 | + mempool, |
| 515 | + assemble_options} |
| 516 | + .CreateNewBlock()}; |
| 517 | + |
| 518 | + // If the tip changed, return the new template regardless of its fees. |
| 519 | + if (tip_changed) return new_tmpl; |
| 520 | + |
| 521 | + // Calculate the original template total fees if we haven't already |
| 522 | + if (current_fees == -1) { |
| 523 | + current_fees = 0; |
| 524 | + for (CAmount fee : block_template->vTxFees) { |
| 525 | + current_fees += fee; |
| 526 | + } |
| 527 | + } |
| 528 | + |
| 529 | + CAmount new_fees = 0; |
| 530 | + for (CAmount fee : new_tmpl->vTxFees) { |
| 531 | + new_fees += fee; |
| 532 | + Assume(options.fee_threshold != MAX_MONEY); |
| 533 | + if (new_fees >= current_fees + options.fee_threshold) return new_tmpl; |
| 534 | + } |
| 535 | + } |
| 536 | + |
| 537 | + now = NodeClock::now(); |
| 538 | + } while (now < deadline); |
| 539 | + |
| 540 | + return nullptr; |
| 541 | +} |
450 | 542 | } // namespace node
|
0 commit comments