Persistence trait#1902
Conversation
60783fb to
eff35c2
Compare
|
did you try this suggestion? #1866 (comment) |
Yes, and if any of the hot path calls return and error, it will need to be handled and bubbled up or ignored. In a case where the function returns early for a Persistence failure, I don't believe we'd want to return early from the function. This would also mean expanding: pub enum ShareValidationError {
Invalid,
Stale,
InvalidJobId,
DoesNotMeetTarget,
VersionRollingNotAllowed,
DuplicateShare,
NoChainTip,
}All these errors are specific to the validation of the shares and it seemed inappropriate to add Persistence errors since it broadens the scope of this function's returned type beyond what the this function actually does. Without refactoring this critical piece of code, I saw expanding to use Results for ShareAccounting becoming very messy since we want infallible code in the hot path of validating a Share or Block. pub fn validate_share(
&mut self,
share: SubmitSharesExtended,
) -> Result<ShareValidationResult, ShareValidationError> {
// ........other validation logic......
// check if a block was found
if network_target.is_met_by(hash) {
self.share_accounting.update_share_accounting(
target_to_difficulty(self.target.clone()) as u64,
share.sequence_number,
hash.to_raw_hash(),
);
return Ok(ShareValidationResult::BlockFound);
}
// check if the share hash meets the channel target
if hash_as_target < self.target {\
if self.share_accounting.is_share_seen(hash.to_raw_hash()) {
return Err(ShareValidationError::DuplicateShare);
}
self.share_accounting.update_share_accounting(
target_to_difficulty(self.target.clone()) as u64,
share.sequence_number,
hash.to_raw_hash(),
);
// update the best diff
self.share_accounting.update_best_diff(hash_as_diff);
return Ok(ShareValidationResult::Valid);
}Additionally, anything other than in-memory ShareAccounting has the chance to introduce latency, which I don't think is desirable for processing shares/blocks. |
|
FWIW, I want to create an example |
7660a13 to
b20fc3a
Compare
|
The latest push implements a simple file writer Persistence which outputs a file. Of note, I think the Persistence implementation here could use the |
|
I think there was meaningful progress here, but it still has a lot of unnecessary complexity that should be cleaned up also not sure why we have #1916 making changes that were are correlated to this PR, while both are draft? I mean, there are scenarios where breaking things down into different PRs do make sense, but I don't really understand the rationale here and overall it makes the review process unnecessarily confusing and convoluted |
ACK, thank you. Will address.
Will consolidate into one draft, I just wanted to keep things separate until I knew features are desired by SRI. |
06ee15c to
bc58320
Compare
- Add optional share_persistence_file_path configuration in pool config examples - Include comments explaining the purpose and usage of share persistence logging
- Replace `NoPersistence` with generic `Persistence<TestPersistence>` in test cases - Add `TestPersistence` struct implementing `PersistenceHandler` trait
- Remove `status_tx` parameter from `ShareFileHandler::new()` method - Remove status sender from `ShareFileHandler` struct - Simplify share persistence error handling This refactoring removes the direct status communication from the share persistence module, improving separation of concerns and reducing complexity.
- Relocate share persistence implementation from pool role to stratum-apps - Remove local share_persistence module from pool role - Update import paths in channel_manager modules - Add new share_persistence module to stratum-apps with existing implementation - Improve modularity and reusability of share persistence code - Prepare for potential cross-role share persistence usage
- Change share work sum type from u64 to f64 for more precise difficulty tracking - Remove unnecessary type casting of difficulty to u64 in share accounting methods - Update share accounting methods to use floating-point difficulty values - Remove unused NoPersistence import in multiple files - Simplify share accounting event persistence tracking - Improve comments describing share work and difficulty calculations This refactoring improves the precision of share difficulty tracking and simplifies the share accounting implementation across multiple Stratum V2 protocol components.
793b162 to
510c7d7
Compare
| let receiver = share_file_handler.get_receiver(); | ||
|
|
||
| // Spawn the share file handler task | ||
| task_manager.spawn(async move { |
There was a problem hiding this comment.
During review, I identified a potential data loss issue with share persistence during pool shutdown.
Current Behavior
The share persistence task runs in the background with a 1024-event buffer. During Pool shutdown:
(roles/pool/src/lib/mod.rs:165-167):
task_manager.abort_all().await; // Immediately aborts all tasks
task_manager.join_all().await; // Waits for aborted tasksAny pending share events in the channel buffer are lost when the task is aborted.
Impact
- When: Only during pool shutdown (Ctrl+C, crashes)
- What's lost: Up to 1024 pending share events
- Severity: Depends on use case - critical if used for payment calculation, minor if just for auditing
Possible Solution
I think this can be accomplished in a follow up PR as follows:
Store the persistence task handle separately and add graceful shutdown:
- Stop accepting new mining work
- Drop persistence field to signal channel closure
- Wait for persistence task to drain its queue naturally
- Then abort remaining tasks
This ensures all shares are persisted before shutdown completes.
Alternatively, we can just document for implementers as this is an application side consideration/trade off and not protocol specific.
|
The fmt check is failing but I don't see that issue in the current commit Tested with BitAxe locally. |
On our CI we use Try by running |
|
@average-gary, wouldn’t it make more sense to handle this event logic at the application layer instead of coupling channel_sv2 with the persistence trait? Channel_sv2 already exposes the necessary APIs that the application layer can use to record relevant events into a storage engine. |
@Shourya742 What APIs are you referring to? I can get the ShareAccounting using Standard or Extended Channel but the ShareAccouting only surfaces summary data. I didn't see a way to access the complete context of a share outside of directly in the channel validation logic but I could have missed a different API. Perhaps if |
…m persistence events" This reverts commit fb7e4aa.
|
This PR becomes an application concern when #1966 lands. Closing. |

After digging into the ShareAccounting more, I noticed there were calls within the hot path for mining messages. Notably,
validate_share.Since this validation and mining messages in general are on the critical path, I don't think #1866 with Results for ShareAccounting functions is the correct approach.
In this approach, the Channel constructor would pass in a Sender for the Channel to use to pass data through the a Persistence implementation that is then responsible for handling it's own threads, state, errors, etc.