feat(zcash_local_net)!: prefetch block templates via getblocktemplate long polling - #284
Merged
Merged
Conversation
… long polling Profiling zingolib's send_shield_cycle round trip showed that every generated regtest block pays about 2.2 seconds inside zebrad's getblocktemplate handler, which constructs a fresh shielded coinbase transaction, proof included, for each template. Zebra already owns the remedy: a getblocktemplate call that presents the previous template's longpollid makes zebrad precompute the next coinbase while it waits for the tip to change, and answer the tip change with a provisional empty template built from that precomputation. Zebrad::generate_blocks now parks exactly that long-poll request after each mined block, so zebrad performs the coinbase proof work while the calling test syncs wallets and runs assertions. The next generate_blocks call consumes the prefetched template only when three guards hold: the mempool is empty, the template's height is the target height, and the template carries no transactions. Any other state aborts the prefetch and falls back to the previous fetch-fresh path, which preserves the documented contract that generated blocks confirm the transactions the server has received. Measured on send_shield_cycle, empty separation blocks drop from about 2.5 seconds to between 0.4 and 1.6 seconds, and the fixture's total mining cost falls from about 28 to 23 seconds. BlockTemplate gains the long_poll_id field, and submit_template_block splits into fetch_block_template, fetch_block_template_long_poll, and submit_block_from_template, with mempool_txids exposing the gate's mempool probe. The field addition is the breaking surface, recorded in the crate CHANGELOG. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Every generated regtest block pays about 2.2 seconds inside zebrad's
getblocktemplatehandler. The handler builds a fresh shielded coinbase transaction for each template, and the build includes a proof. Zebra already owns the remedy. Agetblocktemplatecall that presents the previous template'slongpollidmakes zebrad precompute the next coinbase while it waits for the tip to change. Zebrad then answers the tip change with a provisional empty template built from that precomputation.Zebrad::generate_blocksnow parks that long-poll request after each mined block. Zebrad performs the coinbase proof work while the calling test syncs wallets and runs assertions. The nextgenerate_blockscall consumes the prefetched template instead of paying the template construction inline.Correctness guards
The prefetched template is an empty provisional block. The harness consumes it only when three conditions hold:
Any other state aborts the prefetch and falls back to the previous fetch-fresh path. The documented contract holds: generated blocks confirm the transactions the server has received.
Measured effect
Measured on zingolib's
send_shield_cyclefixture, with per-phase instrumentation, two runs per configuration:Transaction-bearing confirmation blocks keep the full path and their cost is unchanged.
API surface
BlockTemplategains along_poll_idfield (deserialized fromlongpollid), which is the breaking surface and carries a CHANGELOG entry.submit_template_blocksplits intofetch_block_template,fetch_block_template_long_poll, andsubmit_block_from_template.mempool_txidsexposes the consumption gate's mempool probe. Existing callers ofsubmit_template_blockare unaffected.🤖 Generated with Claude Code