Follow-up to #35675. This addresses the getblocktemplate part of the "Remove remaining global states" TODO in #33758, as suggested in #35675#pullrequestreview-5299625960.
getblocktemplate reuses the last template it built until the tip changes, or until the mempool changed and the template is more than 5 seconds old. That cache currently lives in four function-local statics (pindexPrev, block_template, nTransactionsUpdatedLast, time_start). Because they are statics, they:
- live as long as the process, so the cached
CBlockIndex*can outlive theChainstateManagerthat owns it when a process creates more than one node context (as the unit tests do); - rely on callers holding
cs_main, which nothing checks at compile time; - cannot be unit tested.
This PR moves the cache into BlockTemplateManager, which already builds templates for the RPC and the mining interface:
- node: adds
RefreshCachedTemplate()andGetCachedTransactionsUpdated(). The cache isGUARDED_BY(::cs_main), as suggested in the review linked above, so clang's thread-safety analysis checks every access. The manager reads the active tip itself and compares it with the template'shashPrevBlock, so the cache stores noCBlockIndex*and can never pair a template with the wrong tip. A new unit test covers each rebuild rule and the retry after a failed build. - rpc: replaces the statics with the manager's cache.
pindexPrevand thelongpollidnow come from the template'shashPrevBlock.
This is a move, not a redesign: no RPC behavior change is intended. The rebuild rules, the longpoll counter and the retry after a failed build work as on master. Only getblocktemplate uses the cache; it is not shared with mining interface clients.
For now, the cache uses cs_main rather than its own mutex: the RPC already holds cs_main across the refresh, and CreateNewBlock() takes it anyway. Until the cache has readers that don't hold cs_main, a separate lock would only add a lock order without taking cs_main off the build path.
In short: the getblocktemplate cache stops being hidden process-wide state and becomes node-owned state with checked locking and unit tests, which also gives other improvements a single place to make their changes.