Skip to content

Mint instantly if the uncle rate is below the configured value #4438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: dag-master
Choose a base branch
from

Conversation

jackzhhuang
Copy link
Collaborator

@jackzhhuang jackzhhuang commented Mar 25, 2025

Pull request type

Please check the type of change your PR introduces:

  • Bugfix
  • Feature
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • Documentation content changes
  • Other (please describe):

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Other information

Summary by CodeRabbit

  • New Features

    • Enhanced synchronization events now include detailed block execution context.
    • Block-related events now carry additional data, improving overall responsiveness.
  • Refactor

    • Transitioned from time-based to state-based evaluation for block events, resulting in more accurate performance metrics.
    • Streamlined error handling in block connectivity for a cleaner, more robust processing flow.
  • Chores

    • Updated project dependencies to support expanded functionalities.

Copy link

coderabbitai bot commented Mar 25, 2025

Walkthrough

The changes introduce a new workspace dependency in the miner project and refactor event handling logic across modules. In the miner component, a time-based field is removed and replaced by a storage reference to support state-based processing of block events. The sync component streamlines block connectivity and error handling while adding an executed block field to synchronization events. Additionally, system event structures have been updated to carry block header information.

Changes

File(s) Change Summary
miner/Cargo.toml Added workspace dependency: starcoin-statedb = { workspace = true }.
miner/src/generate_block_event_pacemaker.rs Removed last_time_received and added storage field; updated event handling to use state and epoch info for uncle rate calculation.
sync/src/block_connector/.../block_connector_service.rs Modified is_near_block calculation and streamlined error handling in PeerNewBlock events.
sync/src/sync.rs, types/src/system_events.rs Introduced executed_block field in SpecificSyncDone and NewDagBlockFromPeer to provide block execution context.
sync/src/tasks/.../continue_execute_absent_block.rs Simplified return type in new method from anyhow::Result<ContinueExecuteAbsentBlock<'a>> to anyhow::Result<Self>.

Suggested reviewers

  • nkysg
  • sanlee42
  • welbon
  • simonjiao

Poem

I'm a bouncy rabbit in the code burrow,
Hopping through dependencies, feeling quite thorough.
Removed the old time ticks for a new storage embrace,
With cleaner logic and error handling in place.
I nibble on changes with a happy heart,
Leaping ahead—coding's a joyful art! 🐇
Burrow deep into commits, let the progress start!

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@jackzhhuang jackzhhuang removed the request for review from jolestar March 25, 2025 07:26
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2505910 and 7408ea2.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • miner/Cargo.toml (1 hunks)
  • miner/src/generate_block_event_pacemaker.rs (3 hunks)
  • sync/src/block_connector/block_connector_service.rs (2 hunks)
  • sync/src/sync.rs (3 hunks)
  • types/src/system_events.rs (2 hunks)
🧰 Additional context used
🧬 Code Definitions (3)
types/src/system_events.rs (1)
types/src/block/mod.rs (1)
  • block (1405-1407)
miner/src/generate_block_event_pacemaker.rs (4)
sync/src/sync.rs (4)
  • create (660-666)
  • ctx (223-223)
  • new (79-122)
  • new (821-827)
chain/src/chain.rs (5)
  • chain_state (1695-1697)
  • new (76-87)
  • e (178-178)
  • e (684-684)
  • e (1557-1557)
chain/api/src/chain.rs (1)
  • chain_state (134-134)
network-rpc/src/rpc.rs (1)
  • new (42-54)
sync/src/sync.rs (5)
sync/src/tasks/mod.rs (2)
  • new (575-577)
  • new (598-600)
sync/src/tasks/block_sync_task.rs (3)
  • new (49-55)
  • new (77-103)
  • chain (354-355)
sync/src/block_connector/block_connector_service.rs (1)
  • new (62-71)
sync/src/tasks/inner_sync_task.rs (1)
  • new (50-76)
sync/src/tasks/mock.rs (5)
  • new (53-59)
  • new (104-106)
  • new (142-144)
  • new (189-216)
  • chain (338-340)
🔇 Additional comments (11)
miner/Cargo.toml (1)

25-25: Dependency addition confirmed.

The new workspace dependency starcoin-statedb is properly declared.

types/src/system_events.rs (1)

40-42: New field addition appears appropriate.

Adding executed_block as an Arc<BlockHeader> is a reasonable choice and should facilitate concurrent usage with minimal overhead.

sync/src/sync.rs (4)

35-35: Import usage check.

The newly added imports for Block, BlockHeader, and BlockIdAndNumber are valid and align with the logic introduced in this file.


731-733: Struct naming is consistent.

SpecificSyncDone's single field for the executed block header is concise. If you plan to add more details, consider grouping them in a dedicated struct.


736-739: Event broadcasting is coherent.

Broadcasting NewDagBlockFromPeer with the newly added executed_block is consistent with the changes.


420-422:

✅ Verification successful

Verify the correctness of passing only the block header.

It might be worth confirming that referencing only the header with Arc::new(chain.current_header()) provides sufficient data for downstream operations.

You can inspect all uses of SpecificSyncDone to confirm that no full block data is required:


🏁 Script executed:

#!/bin/bash
# Searching for usage of `SpecificSyncDone` to see if a full block is needed anywhere.
ast-grep --pattern $'SpecificSyncDone { $$$ }'

Length of output: 240


Verification Complete: Passing Only the Block Header is Sufficient

The search result confirms that the only usage of SpecificSyncDone is in sync/src/sync.rs at lines 420–422, where only the block header (wrapped in an Arc) is provided. There’s no indication elsewhere in the codebase that full block data is required for downstream operations.

miner/src/generate_block_event_pacemaker.rs (3)

9-11: Imports are suitable.

The introduction of AccountStateReader, ChainStateDB, and Storage aligns with the new state-based logic.


22-22: New struct field is needed for state access.

Adding storage enables on-demand ChainStateDB creation.


30-30: Field injection confirmed.

Acquiring storage from the shared context seamlessly provides the necessary state access.

sync/src/block_connector/block_connector_service.rs (2)

325-391: Improved error handling with enhanced event broadcasting.

The error handling logic has been restructured to use a single match statement for the result of try_connect, making the code more readable and maintainable. Additionally, the successful case now broadcasts a NewDagBlockFromPeer event with the executed block header, providing more context about the executed block.

The new structure:

  1. First handles the success case by broadcasting the block header
  2. Then handles error cases in a more organized way
  3. Keeps the FutureBlock handling logic intact

This change complements the modification to NewDagBlockFromPeer struct which now includes an executed_block field.


145-145:

❓ Verification inconclusive

Significant increase in near block threshold.

The calculation for config_gap has been changed from k.saturating_mul(2) to k.saturating_mul(k), which squares the value instead of doubling it. This change significantly increases the threshold for what's considered a "near" block, potentially allowing blocks that are much further away to be processed via the specific/lightweight sync operation rather than the burden sync operation.


🏁 Script executed:

#!/bin/bash
# Search for k value usage in the codebase to understand the impact
rg -B 5 -A 5 "ghost_dag_manager.*k\(\)" --type rust

Length of output: 1117


Important: Verify the Increased Near Block Threshold Computation

The calculation for config_gap is now using k.saturating_mul(k), which squares the value of k instead of doubling it (as in k.saturating_mul(2)). Since k is sourced from ghost_dag_manager().k(), when k > 2 this change substantially raises the threshold for what qualifies as a "near" block. This may result in blocks much further away being processed using the lightweight sync operation instead of the burden sync path.

  • Location: sync/src/block_connector/block_connector_service.rs (around line 145)
  • Implication: Verify that the squaring of k is intentional, as it could have broader effects on the sync behavior.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
miner/src/generate_block_event_pacemaker.rs (4)

102-129: The uncle rate-based block generation logic is well implemented but has room for improvement.

The implementation correctly:

  1. Retrieves the state root and sets up the chain state
  2. Gets epoch information and calculates the uncle rate
  3. Checks for division by zero (addressing the previous review comment)
  4. Compares the uncle rate with the configured target

However, there are a few issues to address:

  1. Using unwrap_or_else with a panic is not ideal for production code
  2. There's a typo in uncle_rate_in_confing
  3. The log at line 126 is very verbose for INFO level

Consider these improvements:

  fn handle_event(&mut self, msg: NewDagBlockFromPeer, ctx: &mut ServiceContext<Self>) {
      let state_root = msg.executed_block.state_root();
      let chain_state =
          ChainStateDB::new(self.storage.clone().into_super_arc(), Some(state_root));
      let account_reader = AccountStateReader::new(&chain_state);
-     let epoch_info = account_reader
-         .get_epoch_info()
-         .unwrap_or_else(|e| panic!("Epoch is none. error: {:?}", e));
+     let epoch_info = match account_reader.get_epoch_info() {
+         Ok(info) => info,
+         Err(e) => {
+             error!("[pacemaker] Failed to get epoch info: {:?}", e);
+             return;
+         }
+     };
      let total_uncles = epoch_info.epoch_data().uncles();
      let blocks = msg
          .executed_block
          .number()
          .saturating_sub(epoch_info.epoch().start_block_number());
      if blocks == 0 {
          debug!("[pacemaker] Zero blocks in the epoch, skipping uncle rate computation.");
          return;
      }
      let uncle_rate = total_uncles * 1000 / blocks;
-     let uncle_rate_in_confing = self
+     let uncle_rate_target = self
          .config
          .net()
          .genesis_config()
          .consensus_config
          .uncle_rate_target;
-     info!("NewDagBlockFromPeer, epoch data: {:?}, blocks in this epoch: {:?}, uncle rate for now: {:?}, uncle rate in config: {:?}", epoch_info.epoch_data(), blocks, uncle_rate, uncle_rate_in_confing);
-     if uncle_rate < uncle_rate_in_confing {
+     debug!("[pacemaker] NewDagBlockFromPeer - blocks: {}, uncles: {}, uncle_rate: {}, target: {}", 
+            blocks, total_uncles, uncle_rate, uncle_rate_target);
+     if uncle_rate < uncle_rate_target {
+         info!("[pacemaker] Uncle rate {} below target {}, triggering block generation", 
+               uncle_rate, uncle_rate_target);
          self.send_event(false, ctx);
      }
  }

120-120: Fix the typo in variable name.

There's a typo in the variable name uncle_rate_in_confing, which should be uncle_rate_in_config or simply uncle_rate_target.

- let uncle_rate_in_confing = self
+ let uncle_rate_target = self

126-126: Adjust log level and improve log message formatting.

The current log message is very verbose for the INFO level and doesn't follow the [pacemaker] prefix convention used elsewhere. Consider moving it to DEBUG level for regular operation and adding a more concise INFO log when actually triggering block generation.

- info!("NewDagBlockFromPeer, epoch data: {:?}, blocks in this epoch: {:?}, uncle rate for now: {:?}, uncle rate in config: {:?}", epoch_info.epoch_data(), blocks, uncle_rate, uncle_rate_in_confing);
+ debug!("[pacemaker] NewDagBlockFromPeer - blocks: {}, uncles: {}, uncle_rate: {}, target: {}", 
+        blocks, total_uncles, uncle_rate, uncle_rate_target);
  if uncle_rate < uncle_rate_target {
+     info!("[pacemaker] Uncle rate {} below target {}, triggering block generation", 
+           uncle_rate, uncle_rate_target);
      self.send_event(false, ctx);
  }

120-125: Consider extracting the config access pattern to improve readability.

The deeply nested config access to retrieve the uncle rate target makes the code harder to read. Consider extracting this to a helper method or caching the value at service initialization.

Option 1 - Extract to a method:

+ impl GenerateBlockEventPacemaker {
+     // ... existing methods ...
+     
+     fn get_uncle_rate_target(&self) -> u64 {
+         self.config
+             .net()
+             .genesis_config()
+             .consensus_config
+             .uncle_rate_target
+     }
+ }

  // In handle_event:
- let uncle_rate_in_confing = self
-     .config
-     .net()
-     .genesis_config()
-     .consensus_config
-     .uncle_rate_target;
+ let uncle_rate_target = self.get_uncle_rate_target();

Option 2 - Cache at initialization:

  pub struct GenerateBlockEventPacemaker {
      config: Arc<NodeConfig>,
      sync_status: Option<SyncStatus>,
      storage: Arc<Storage>,
+     uncle_rate_target: u64,
  }

  impl ServiceFactory<Self> for GenerateBlockEventPacemaker {
      fn create(ctx: &mut ServiceContext<Self>) -> Result<Self> {
+         let config = ctx.get_shared::<Arc<NodeConfig>>()?;
+         let uncle_rate_target = config
+             .net()
+             .genesis_config()
+             .consensus_config
+             .uncle_rate_target;
          Ok(Self {
-             config: ctx.get_shared::<Arc<NodeConfig>>()?,
+             config,
              sync_status: None,
              storage: ctx.get_shared::<Arc<Storage>>()?,
+             uncle_rate_target,
          })
      }
  }

  // In handle_event:
- let uncle_rate_in_confing = self
-     .config
-     .net()
-     .genesis_config()
-     .consensus_config
-     .uncle_rate_target;
+ let uncle_rate_target = self.uncle_rate_target;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7408ea2 and 477ef0f.

📒 Files selected for processing (2)
  • miner/src/generate_block_event_pacemaker.rs (3 hunks)
  • sync/src/tasks/continue_execute_absent_block.rs (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
miner/src/generate_block_event_pacemaker.rs (5)
sync/src/sync.rs (13)
  • create (660-666)
  • ctx (223-223)
  • handle_event (687-696)
  • handle_event (700-727)
  • handle_event (736-740)
  • handle_event (752-807)
  • handle_event (831-836)
  • handle_event (840-848)
  • handle_event (859-895)
  • handle_event (899-906)
  • handle_event (910-915)
  • new (79-122)
  • new (821-827)
miner/src/lib.rs (3)
  • create (109-123)
  • handle_event (273-296)
  • new (79-85)
chain/src/chain.rs (5)
  • chain_state (1695-1697)
  • new (76-87)
  • e (178-178)
  • e (684-684)
  • e (1557-1557)
chain/api/src/chain.rs (1)
  • chain_state (134-134)
network-rpc/src/rpc.rs (1)
  • new (42-54)
🔇 Additional comments (6)
sync/src/tasks/continue_execute_absent_block.rs (1)

30-30: Good use of Self for the return type.

Changing the return type from anyhow::Result<ContinueExecuteAbsentBlock<'a>> to anyhow::Result<Self> is a good practice in Rust. This makes the code more maintainable as it:

  • Reduces redundancy
  • Improves readability
  • Ensures the return type automatically updates if the struct name changes in the future

This is a clean, idiomatic Rust change that maintains the same functionality while making the code more robust to future refactoring.

miner/src/generate_block_event_pacemaker.rs (5)

9-11: New imports support state-based decision making.

The addition of these imports aligns with the shift from a time-based approach to a state-based approach for block generation decisions. This is a good architectural change that allows the pacemaker to make decisions based on blockchain state rather than just elapsed time.


22-22: Appropriate field change from time-based to state-based.

Replacing the last_time_received timestamp with a storage reference is consistent with the new approach of using uncle rate as the trigger for block generation instead of elapsed time.


30-30: Storage initialization is properly implemented.

The service now correctly retrieves the shared Storage instance from the context, which is needed for the state-based block generation decisions.


115-118: Good handling of division by zero case.

You've properly addressed the previous review comment regarding division by zero risk by adding this check. This is important for preventing panics in edge cases.


102-129:

❓ Verification inconclusive

Verify blockchain state performance impact.

The current implementation accesses blockchain state for every NewDagBlockFromPeer event. Consider evaluating the performance impact of this approach, especially the storage clone operation.


🏁 Script executed:

#!/bin/bash
# Check if there are other uses of storage.clone() in event handlers to understand common patterns
echo "Searching for storage.clone() patterns in event handlers..."
rg -A 2 -B 2 "fn handle_event.*\{" | rg "storage\.clone\(\)" -A 5 -B 5

Length of output: 201


Assess the Performance Impact of Frequent Blockchain State Access

The current implementation creates a new chain state via storage.clone() on every NewDagBlockFromPeer event. Since the initial search for similar patterns in event handlers returned no results, it's unclear whether this pattern is common or if it incurs a significant performance overhead. Please manually verify that this approach does not degrade performance under high load. Specifically, consider:

  • Benchmarking the cost of cloning storage for each event.
  • Reviewing whether similar event handlers use alternative, more efficient patterns.
  • Evaluating if caching or lazy initialization of the chain state is feasible to reduce overhead.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
miner/src/generate_block_event_pacemaker.rs (2)

124-129: Verify configuration parameter naming.

There appears to be a typo in the variable name uncle_rate_in_confing, which might make the code slightly less readable.

-        let uncle_rate_in_confing = self
+        let uncle_rate_in_config = self

Make sure to update the reference on line 130 as well.


130-130: Consider log level for production environment.

While informative, this log statement produces output on every new block from peers. Consider whether info is the appropriate log level for this frequent operation, or if debug might be more suitable for production environments.

-        info!("NewDagBlockFromPeer, epoch data: {:?}, blocks in this epoch: {:?}, uncle rate for now: {:?}, uncle rate in config: {:?}", epoch_info.epoch_data(), blocks, uncle_rate, uncle_rate_in_confing);
+        debug!("NewDagBlockFromPeer, epoch data: {:?}, blocks in this epoch: {:?}, uncle rate for now: {:?}, uncle rate in config: {:?}", epoch_info.epoch_data(), blocks, uncle_rate, uncle_rate_in_confing);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 477ef0f and 4b5de37.

📒 Files selected for processing (1)
  • miner/src/generate_block_event_pacemaker.rs (3 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
miner/src/generate_block_event_pacemaker.rs (7)
sync/src/sync.rs (13)
  • create (660-666)
  • ctx (223-223)
  • handle_event (687-696)
  • handle_event (700-727)
  • handle_event (736-740)
  • handle_event (752-807)
  • handle_event (831-836)
  • handle_event (840-848)
  • handle_event (859-895)
  • handle_event (899-906)
  • handle_event (910-915)
  • new (79-122)
  • new (821-827)
miner/src/lib.rs (3)
  • create (109-123)
  • handle_event (273-296)
  • new (79-85)
chain/src/chain.rs (5)
  • chain_state (1695-1697)
  • new (76-87)
  • e (178-178)
  • e (684-684)
  • e (1557-1557)
chain/api/src/chain.rs (1)
  • chain_state (134-134)
sync/src/tasks/continue_execute_absent_block.rs (1)
  • new (26-36)
network-rpc/src/rpc.rs (1)
  • new (42-54)
sync/src/tasks/mock.rs (2)
  • new (53-59)
  • new (104-106)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: run benchmark
🔇 Additional comments (4)
miner/src/generate_block_event_pacemaker.rs (4)

9-11: Appropriate imports added for the state-based approach.

The new imports for AccountStateReader, ChainStateDB, and Storage properly support the refactoring from time-based to state-based block event handling.


22-22: Good structural change to support the new uncle-rate based approach.

The replacement of last_time_received with storage field properly shifts from time-based tracking to state-based evaluation.


30-30: Proper initialization of the storage field.

The storage is correctly retrieved from the shared context, maintaining consistency with other service components.


102-133: Well-implemented state-based evaluation logic for instant minting.

The refactoring from time-based to state-based block event handling is well-structured. The implementation:

  1. Uses blockchain state to assess uncle rates
  2. Properly handles potential division-by-zero issues
  3. Uses appropriate error handling instead of unwrap_or_else with panic
  4. Includes informative logging

The approach of minting instantly when the uncle rate is below the configured target is sound, as it indicates the network can safely process more blocks without risking excessive uncle generation.

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.

1 participant