Skip to content

Add chunked submission strategy for multi-block solutions (#987)#1016

Merged
sigurpol merged 5 commits intomainfrom
chunked_submission_strategy
Apr 15, 2025
Merged

Add chunked submission strategy for multi-block solutions (#987)#1016
sigurpol merged 5 commits intomainfrom
chunked_submission_strategy

Conversation

@sigurpol
Copy link
Copy Markdown
Contributor

@sigurpol sigurpol commented Apr 14, 2025

The current implementation submits all pages concurrently, which can be the fastest option if all submissions succeed quickly and the network or node can handle the load efficiently. However, if an early transaction fails (e.g., nonce N+1), all subsequent transactions will also fail due to the nonce gap. This leads to wasted submission attempts and potentially high load on the network or node from retransmissions.

This commit introduces support for a chunked submission strategy, allowing the chunk size to be specified in the experimental monitor command e.g.

RUST_LOG="polkadot-staking-miner=trace,info" ./target/release/polkadot-staking-miner --uri ws://127.0.0.1:9966 experimental-monitor-multi-block --seed-or-path //Bob --chunk-size 4

If the chunk size is not specified or set to zero, we will use the fully concurrent approach. Otherwise, we will submit a chunk of N pages, wait for all of them to be successfully included in a block, and then proceed to the next chunk.

This approach aims to balance speed and robustness, but it requires careful validation in real use cases to prove that it is actually worthwhile. Note that if the chunk size is set to 1, we will have a fully sequential solution: submit one page, wait, then submit the next page, and so on, which may significantly slow down the process.

Testing against a simple zombienet setup with 8-page or 64-page solution:

Election pages Submission Strategy Time (seconds)
8 Fully concurrent ~77s
8 Chunked (size=4) ~105s
64 Fully concurrent ~121s
64 Chunked (size=16) ~300s

Example of logs for a 8-page solution with chunk size = 4:

2025-04-15T07:00:30.956678Z TRACE polkadot-staking-miner: Mining solution took 2664ms
2025-04-15T07:00:30.959007Z TRACE polkadot-staking-miner: submit `register score` nonce=0
2025-04-15T07:00:32.253065Z TRACE polkadot-staking-miner: Processing block=135 round=1, phase=Signed(28)
2025-04-15T07:00:40.273491Z TRACE polkadot-staking-miner: Processing block=136 round=1, phase=Signed(27)
2025-04-15T07:00:44.283541Z TRACE polkadot-staking-miner: Processing block=137 round=1, phase=Signed(26)
2025-04-15T07:00:52.297174Z TRACE polkadot-staking-miner: Processing block=138 round=1, phase=Signed(25)
2025-04-15T07:00:56.306654Z TRACE polkadot-staking-miner: Processing block=139 round=1, phase=Signed(24)
2025-04-15T07:01:04.317378Z TRACE polkadot-staking-miner: Processing block=140 round=1, phase=Signed(23)
2025-04-15T07:01:08.326988Z TRACE polkadot-staking-miner: Processing block=141 round=1, phase=Signed(22)
2025-04-15T07:01:08.328175Z  INFO polkadot-staking-miner: Score registered at block 0x949d0dc3a038e66ea3abcc33ff987e1689412a3b8a8be8f4a9e72eee5a539137
2025-04-15T07:01:08.328665Z  INFO polkadot-staking-miner: Submitting pages [0, 1, 2, 3] (out of 8)
2025-04-15T07:01:08.341045Z TRACE polkadot-staking-miner: submit `submit page 0` nonce=1
2025-04-15T07:01:08.362011Z TRACE polkadot-staking-miner: submit `submit page 1` nonce=2
2025-04-15T07:01:08.379370Z TRACE polkadot-staking-miner: submit `submit page 2` nonce=3
2025-04-15T07:01:08.395042Z TRACE polkadot-staking-miner: submit `submit page 3` nonce=4
2025-04-15T07:01:16.342847Z TRACE polkadot-staking-miner: Processing block=142 round=1, phase=Signed(21)
2025-04-15T07:01:28.367009Z TRACE polkadot-staking-miner: Processing block=143 round=1, phase=Signed(20)
2025-04-15T07:01:32.375057Z TRACE polkadot-staking-miner: Processing block=144 round=1, phase=Signed(19)
2025-04-15T07:01:40.390902Z TRACE polkadot-staking-miner: Processing block=145 round=1, phase=Signed(18)
2025-04-15T07:01:44.402842Z TRACE polkadot-staking-miner: Processing block=146 round=1, phase=Signed(17)
2025-04-15T07:01:44.410967Z  INFO polkadot-staking-miner: Page 3 included in block 0x1120811374d54bde5b19930da480d4f02b65b9a7d758940ccf7f70c1753e0778
2025-04-15T07:01:44.418309Z  INFO polkadot-staking-miner: Page 1 included in block 0x1120811374d54bde5b19930da480d4f02b65b9a7d758940ccf7f70c1753e0778
2025-04-15T07:01:44.423645Z  INFO polkadot-staking-miner: Page 2 included in block 0x1120811374d54bde5b19930da480d4f02b65b9a7d758940ccf7f70c1753e0778
2025-04-15T07:01:44.428995Z  INFO polkadot-staking-miner: Page 0 included in block 0x1120811374d54bde5b19930da480d4f02b65b9a7d758940ccf7f70c1753e0778
2025-04-15T07:01:44.429016Z  INFO polkadot-staking-miner: All pages [0, 1, 2, 3] were successfully included in blocks
2025-04-15T07:01:44.429050Z  INFO polkadot-staking-miner: Submitting pages [4, 5, 6, 7] (out of 8)
2025-04-15T07:01:44.436763Z TRACE polkadot-staking-miner: submit `submit page 4` nonce=5
2025-04-15T07:01:44.450949Z TRACE polkadot-staking-miner: submit `submit page 5` nonce=6
2025-04-15T07:01:44.465991Z TRACE polkadot-staking-miner: submit `submit page 6` nonce=7
2025-04-15T07:01:44.480767Z TRACE polkadot-staking-miner: submit `submit page 7` nonce=8
2025-04-15T07:01:52.422102Z TRACE polkadot-staking-miner: Processing block=147 round=1, phase=Signed(16)
2025-04-15T07:01:56.428809Z TRACE polkadot-staking-miner: Processing block=148 round=1, phase=Signed(15)
2025-04-15T07:02:04.447329Z TRACE polkadot-staking-miner: Processing block=149 round=1, phase=Signed(14)
2025-04-15T07:02:08.454671Z TRACE polkadot-staking-miner: Processing block=150 round=1, phase=Signed(13)
2025-04-15T07:02:16.475457Z TRACE polkadot-staking-miner: Processing block=151 round=1, phase=Signed(12)
2025-04-15T07:02:28.499718Z TRACE polkadot-staking-miner: Processing block=152 round=1, phase=Signed(11)
2025-04-15T07:02:32.504498Z TRACE polkadot-staking-miner: Processing block=153 round=1, phase=Signed(10)
2025-04-15T07:02:40.525290Z TRACE polkadot-staking-miner: Processing block=154 round=1, phase=Signed(9)
2025-04-15T07:02:44.539709Z TRACE polkadot-staking-miner: Processing block=155 round=1, phase=Signed(8)
2025-04-15T07:02:44.548389Z  INFO polkadot-staking-miner: Page 7 included in block 0xe5f6b928ab7b2c1988bb535fe559dc99283bdc980efbee814b39d9df78ba288b
2025-04-15T07:02:44.556615Z  INFO polkadot-staking-miner: Page 4 included in block 0xe5f6b928ab7b2c1988bb535fe559dc99283bdc980efbee814b39d9df78ba288b
2025-04-15T07:02:44.565155Z  INFO polkadot-staking-miner: Page 5 included in block 0xe5f6b928ab7b2c1988bb535fe559dc99283bdc980efbee814b39d9df78ba288b
2025-04-15T07:02:44.572941Z  INFO polkadot-staking-miner: Page 6 included in block 0xe5f6b928ab7b2c1988bb535fe559dc99283bdc980efbee814b39d9df78ba288b
2025-04-15T07:02:44.572967Z  INFO polkadot-staking-miner: All pages [4, 5, 6, 7] were successfully included in blocks
2025-04-15T07:02:44.573154Z TRACE polkadot-staking-miner: Register score and solution pages took 133616ms

The recommended approach is to merge this PR and test the miner with both fully concurrent and chunked strategy in the field against AH leaving the fully concurrent submission strategy as default.

NOTE: in a followup experimental PR built on top of this one, I've also tried to change the confirmation strategy from waiting for events to on-chain polling, with no benefit in comparison with the current implementation so the suggestion is to park the on-chain polling variant.

Associated issue here

The current implementation submits all pages concurrently, which can be
fastest if all submissions succeed quickly and the network/node can
handle the load efficiently. However, if an early transaction fails
(e.g., nonce N+1), all subsequent transactions will fail due to the
nonce gap, resulting in wasted submission attempts and potentially
high load on the network/node due to retransmissions.

This commit adds support for a `chunked submission strategy` where the
size of the chunk can be specified in the `experimental monitor
command`. If the chunk size is not specified or zero, we use the
fully concurrent approach. Otherwise, we submit a chunk of N pages,
wait for all of them to be successfully included in a block, and then
move to the next chunk.

This offers a good balance between speed and robustness/load. Note
that if the chunk size equals 1, we end up with a fully sequential
solution (submit 1 page - wait - submit next page, etc.).

Testing against a simple zombienet setup with an 8-page solution:

| Submission Strategy | Time (seconds) |
|---------------------|----------------|
| Fully concurrent    | ~77s           |
| Chunked (size=4)    | ~105s          |
@sigurpol sigurpol marked this pull request as draft April 14, 2025 10:09
@sigurpol sigurpol force-pushed the chunked_submission_strategy branch 2 times, most recently from 9238140 to 93daa2c Compare April 14, 2025 12:04
@sigurpol sigurpol changed the title Add chunked submission strategy for multi-block solutions (#987) [Experimental] Add chunked submission strategy for multi-block solutions (#987) Apr 14, 2025
@sigurpol sigurpol force-pushed the chunked_submission_strategy branch 4 times, most recently from 79031de to 0f603af Compare April 14, 2025 20:48
Extract common functionality from inner_submit_pages_concurrent and
inner_submit_pages_chunked into a shared submit_pages_batch helper
function. This reduces code duplication while preserving the distinct
behavior of each submission strategy:

- Concurrent: Submit all pages in one batch
- Chunked: Submit pages in multiple batches, waiting for each batch
  to complete before starting the next

The refactoring improves maintainability and makes the code easier to
understand without changing the underlying functionality or performance
characteristics.
@sigurpol sigurpol force-pushed the chunked_submission_strategy branch from 0f603af to 0c51ea6 Compare April 15, 2025 07:06
@sigurpol sigurpol changed the title [Experimental] Add chunked submission strategy for multi-block solutions (#987) Add chunked submission strategy for multi-block solutions (#987) Apr 15, 2025
@sigurpol sigurpol marked this pull request as ready for review April 15, 2025 07:09
@sigurpol
Copy link
Copy Markdown
Contributor Author

@niklasad1 , @kianenigma PTAL when/if you have time 🙏 🙇

@sigurpol sigurpol requested a review from niklasad1 April 15, 2025 07:16
let total_pages = paged_raw_solution.len();

// Process pages in chunks
for chunk_start in (0..total_pages).step_by(chunk_size) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could perhaps use https://doc.rust-lang.org/std/primitive.slice.html#method.chunks here instead of doing it yourself.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL. Done here

pages_to_submit: Vec<(u32, T::Solution)>,
listen: Listen,
) -> Result<Vec<u32>, Error> {
) -> Result<(Vec<u32>, HashSet<u32>), Error>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both submitted pages and failed pages are returned mostly for logging purposes?

It would be use with a separate type for this like SubmissionResult/Status or something like that wraps that

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Done here

T: MinerConfig<AccountId = AccountId> + Send + Sync + 'static,
T::Solution: Send,
T::Pages: Send,
T::Solution: Send + Sync + 'static,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you know why these extra trait bounds are needed?

Copy link
Copy Markdown
Contributor Author

@sigurpol sigurpol Apr 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was a leftover from some intermediate version. Should be better now with this commit

Copy link
Copy Markdown
Contributor

@niklasad1 niklasad1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good 👍

@sigurpol sigurpol force-pushed the chunked_submission_strategy branch from 6ca18ea to c8a41fc Compare April 15, 2025 08:44
@sigurpol sigurpol force-pushed the chunked_submission_strategy branch from c8a41fc to 9a11d16 Compare April 15, 2025 09:43
@sigurpol sigurpol merged commit 4828ea3 into main Apr 15, 2025
10 checks passed
@sigurpol sigurpol deleted the chunked_submission_strategy branch April 15, 2025 09:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants