Background
Each time we send an IPC client a new BlockTemplate, via createNewBlock or waitNext on the Mining interface, libmultiprocess ensures that we hold on to its encapsulated CBlockTemplate. It’s just as if our own code has a shared pointer to it.
We let go of it when either the client calls the destroy method or they disconnect (cc @ryanofsky ??).
The CBlockTemplate in turn contains a CBlock which contains pointers to individual transactions. Those transactions were in the mempool at the time the template was created, so initially there’s barely any memory overhead. But as time goes by the mempool changes and the template keeps holding on to them.
This is an important behavior, because at any time the client may call submitSolution(). That method only takes the nVersion, nTime, nonce and a coinbase transaction as arguments, so it’s up to us to reconstruct the block and broadcast it to our peers.
Additionally, in scenarios where a miner proposes blocks to the pool, such as pool may request some or all of the transactions for inspection.
At some point however we need to let go of CBlockTemplate references, because otherwise the node runs out of memory.
I think we should leave it up to the client to decide which templates they want us to hold on to. That’s because there isn’t an obvious best way to do this. For example, we might be sending the client many new templates that build on the same prevhash but have more fees. They may decide to rate limit how many to forward downstream to the miner. Or a miner proxy might do such rate limiting. Mining equipment also needs some time to switch work, so it might send us a solution to a slightly older template.
In sv2-tp so far I implemented a fairly simple heuristic: 10 seconds after the tip changes, wipe all templates that refer to the previous tip. Additionally it limits the frequency of new templates to once every -sv2interval seconds (default 30), though I’m considering dropping that rate limiting in https://github.com/stratum-mining/sv2-tp/issues/60.
The work-in-progress SRI implementation in https://github.com/stratum-mining/sv2-apps/pull/59 currently wipes templates as soon as the tip updates and has no rate limiting other than by fee delta.
Memory management implementation
There are probably different ways we can go about memory management here.
The most straightforward approach is probably to track the additional memory footprint and bound it to -maxtemplatepoolsize. If we default that to 50MB it should be plenty for the block template manager proposed in #33758, when it’s not used for mining.
The node could refuse to make new templates when it gets to 80% full and automatically drop the oldest template if it crosses 100%.
Memory management interface
createNewBlock and waitNext could throw an exception or return null if the template memory is full. Both are a bit tricky to handle, so maybe they need an additional response status argument to communicate the situation.
We could also add an additional method to obtain how much memory is used and available. That would allow the Template Provider to pre-empt situations where we refuse to provide it new templates, and worse, where we start dropping them unilaterally.