Skip to content
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

feat(sozo): add events command back and event better #2619

Merged
merged 2 commits into from
Nov 4, 2024

Conversation

glihm
Copy link
Collaborator

@glihm glihm commented Nov 3, 2024

Now the sozo events command is able to resolve all tags and addresses for a very complete logbook without the need of spinning up a Torii.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new Events command to inspect events emitted by the world.
    • Added support for specifying a block number in Layout, Schema, and Get commands for model data retrieval.
    • Enhanced event handling with improved error management and asynchronous processing.
  • Bug Fixes

    • Improved error messages in model layout functionality for better clarity.
  • Chores

    • Removed outdated event filtering and parsing functionalities to streamline the codebase.

These updates enhance the overall user experience by providing more robust event handling and flexible data retrieval options.

Copy link

coderabbitai bot commented Nov 3, 2024

Walkthrough

Ohayo, sensei! This pull request introduces several significant changes across multiple files, primarily focusing on enhancing event handling and command processing in the system. Key modifications include the restructuring of the EventsArgs struct and its run method to support asynchronous operations, the addition of a new Events command variant, and the introduction of block-specific parameters in various model commands. Additionally, new methods for handling ABI entries are added to the ResourceDiff and ResourceLocal enums, while some outdated event parsing functionality is removed.

Changes

File Path Change Summary
bin/sozo/src/commands/events.rs - Updated EventsArgs struct with default chunk_size value.
- Overhauled run method for async flow and event processing.
- Added async fn match_event for individual event handling.
bin/sozo/src/commands/mod.rs - Added Events command variant to Commands enum.
- Updated run function to handle Events command.
- Declared events module.
bin/sozo/src/commands/model.rs - Added optional block argument to Layout, Schema, and Get commands.
- Updated command implementations to utilize block parameter.
crates/dojo/world/src/diff/resource.rs - Introduced abi method to ResourceDiff enum for ABI entry retrieval.
crates/dojo/world/src/local/resource.rs - Added abi method to ResourceLocal implementation for ABI entry retrieval.
- Updated import statement for AbiEntry.
crates/sozo/ops/src/events.rs - Removed events.rs file containing event filtering and parsing functionalities.
crates/sozo/ops/src/model.rs - Enhanced model_layout, model_schema, and model_get functions with block_id parameter.
- Updated return types and error handling for clarity.

Possibly related PRs

Suggested reviewers

  • neotheprogramist
  • kariy

🪧 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 resolve resolve all the CodeRabbit review comments.
  • @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.

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.

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: 6

🧹 Outside diff range and nitpick comments (10)
crates/dojo/world/src/diff/resource.rs (1)

112-118: Implementation follows consistent patterns, sensei!

The new abi() method:

  • Maintains consistency with existing methods in the enum
  • Properly delegates to the local resource for all variants
  • Follows the same pattern as other accessor methods

This implementation aligns well with the single responsibility principle, delegating the actual ABI retrieval to the local resource while maintaining a consistent interface at the diff level.

crates/dojo/world/src/local/resource.rs (1)

103-111: Consider adding documentation for the new method.

Ohayo sensei! The implementation looks solid and follows the established patterns in the codebase. However, it would be beneficial to add documentation comments explaining:

  • The purpose of the method
  • What the ABI entries represent
  • Why certain resource types return an empty vector

Consider adding documentation like this:

+    /// Returns the ABI entries for the resource.
+    ///
+    /// # Returns
+    /// - For Contract, Model, and Event resources: The ABI entries from their class
+    /// - For other resource types: An empty vector
     pub fn abi(&self) -> Vec<AbiEntry> {
bin/sozo/src/commands/mod.rs (1)

Line range hint 1-138: Consider adding integration tests for the Events command.

Sensei, while the code structure looks good, it would be beneficial to have integration tests to verify the Events command behavior, especially since it's being added back with enhanced functionality.

Would you like me to help create integration tests for the Events command functionality?

bin/sozo/src/commands/model.rs (2)

75-80: Block parameter additions are well-structured, sensei!

The optional block parameters are consistently implemented across commands with clear help messages. Consider adding examples to the help text to show the expected format of block numbers.

 #[arg(
-    help = "Block number at which to retrieve the model layout (pending block by default)"
+    help = "Block number at which to retrieve the model layout (e.g., 123456, defaults to pending block)"
 )]

Also applies to: 97-102, 120-123


165-179: Implementation looks solid, sensei! A few suggestions for enhancement.

The block handling implementation is consistent and robust across all commands. However, for the Get command's output, consider structuring the response in a more readable format.

Consider enhancing the output formatting in the Get command:

-                    println!("{}", record);
+                    println!("Block: {}", block_id);
+                    println!("Record: {:#?}", record);

This would provide more context and better formatting for the output.

Also applies to: 182-194, 200-218

bin/sozo/src/commands/events.rs (5)

6-6: Ohayo, sensei! Confirm the need for colored::Colorize.

The addition of use colored::Colorize; suggests that colorized output is intended. Ensure this aligns with the application's requirements and that it doesn't cause issues in environments where color support is limited.


35-35: Set a meaningful default for chunk_size.

The default value for chunk_size is set to 100. Consider whether this default optimally balances performance and resource utilization for typical use cases.


80-82: Improve error handling for event parsing.

In the match statement handling WorldEvent::try_from(event), consider providing more detailed error messages or retry logic to handle transient parsing issues.


103-106: Ohayo, sensei! Provide guidance on using continuation tokens.

When printing the continuation token, consider adding instructions for the user on how to use it to fetch subsequent pages of events.


301-318: Implement pretty printing for updated members.

The TODO comment on line 302 suggests the intention to improve the output format. Implementing this enhancement will provide clearer information to the users.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 32af19e and 4a06068.

📒 Files selected for processing (7)
  • bin/sozo/src/commands/events.rs (3 hunks)
  • bin/sozo/src/commands/mod.rs (4 hunks)
  • bin/sozo/src/commands/model.rs (6 hunks)
  • crates/dojo/world/src/diff/resource.rs (2 hunks)
  • crates/dojo/world/src/local/resource.rs (2 hunks)
  • crates/sozo/ops/src/events.rs (0 hunks)
  • crates/sozo/ops/src/model.rs (5 hunks)
💤 Files with no reviewable changes (1)
  • crates/sozo/ops/src/events.rs
🔇 Additional comments (14)
crates/dojo/world/src/diff/resource.rs (1)

3-3: Ohayo! Clean import addition, sensei!

The AbiEntry import is well-placed and properly grouped with other starknet-related imports.

crates/dojo/world/src/local/resource.rs (1)

2-2: LGTM! Clean import addition.

Ohayo! The addition of AbiEntry to the existing import is clean and focused.

bin/sozo/src/commands/mod.rs (3)

5-5: LGTM! Clean module organization.

Ohayo! The new events module is properly imported and declared, maintaining good code organization principles.

Also applies to: 13-13


57-58: LGTM! Well-documented command addition.

The Events command is added with a clear, descriptive about text that aligns with the PR objectives. The use of Box is appropriate for heap allocation of potentially large event data.


74-74: LGTM! Consistent formatting implementation.

The fmt implementation follows the established pattern for command string representation.

bin/sozo/src/commands/model.rs (2)

7-7: Ohayo! Import changes look good, sensei!

The addition of BlockId and BlockTag types is well-aligned with the new block-specific functionality being introduced.


173-179: Verify model operations integration.

Let's ensure that the model operations properly handle the block_id parameter.

Also applies to: 208-213

✅ Verification successful

Let me gather more information about how these model operations are implemented.


Block ID is properly handled in model operations, sensei! ✨

The verification shows that all model operations (model_layout, model_schema, and model_get) correctly handle the block_id parameter by:

  • Accepting block_id: BlockId as a parameter
  • Setting it on the WorldContractReader via world_reader.set_block(block_id)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if model operations properly handle block_id parameter
# Expected: Find implementations of model operations showing block_id handling

# Search for model operation implementations
rg -A 5 "fn model_(layout|schema|get)" "crates/sozo/ops/src/model.rs"

Length of output: 468


Script:

#!/bin/bash
# Check the implementation details of model operations
rg -A 15 "pub async fn model_(layout|schema|get)" "crates/sozo/ops/src/model.rs"

# Also check for any block_id usage in the implementations
rg "block_id" "crates/sozo/ops/src/model.rs"

Length of output: 1622

crates/sozo/ops/src/model.rs (4)

47-57: Ohayo! The block_id parameter addition looks good, sensei!

The enhancement to model_layout function with the block_id parameter provides more flexibility in block management, aligning well with the PR objectives.


78-85: The model_schema changes are consistent, sensei!

The addition of block_id parameter maintains consistency with other model operations while enhancing block management capabilities.


104-105: Nice improvements to model_get, sensei!

The changes enhance the function in two ways:

  1. Added block_id parameter for consistent block management
  2. Enhanced return type to include formatted string representation, improving usability

Also applies to: 114-114, 120-120


516-521: Clean implementation of format_deep_record, sensei!

The function effectively combines keys and values while maintaining the existing formatting logic, providing a good foundation for the enhanced model_get return type.

bin/sozo/src/commands/events.rs (3)

58-59: Ohayo, sensei! Verify error propagation from get_world_diff_and_provider.

When calling utils::get_world_diff_and_provider, ensure that any errors are properly propagated and that the user receives clear feedback if the operation fails.


91-92: Avoid logging sensitive event information.

When logging errors in tracing::error!(?e, "Failed to process event: {:?}", ev);, ensure that no sensitive or private data from the event is included in the logs.

[security_issue]


370-373: Ohayo, sensei! Verify that block and transaction formatting is user-friendly.

The block and transaction identifiers are formatted for display. Ensure that they are displayed in a way that users can easily reference them.

@@ -90,6 +95,7 @@ pub fn run(command: Commands, config: &Config) -> Result<()> {
Commands::Hash(args) => args.run().map(|_| ()),
Commands::Init(args) => args.run(config),
Commands::Model(args) => args.run(config),
Commands::Events(args) => args.run(config),
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Error handling needs improvement in EventsArgs::run implementation

Ohayo sensei! After reviewing the implementation, there are some concerning patterns in the error handling:

  • The main run function properly propagates errors with ? operator for critical operations
  • However, there are multiple unsafe .unwrap() calls when accessing tags, which could panic:
    • Multiple instances of tags.get(&e.selector).unwrap()
    • tags.get(&e.resource).unwrap()
    • These should be handled gracefully with proper error propagation or provide meaningful error messages

The code should be updated to handle missing tags safely, either by:

  • Using tags.get().ok_or_else(|| anyhow!("Missing tag for selector: {}", selector))?
  • Or providing default values with tags.get().unwrap_or_default()
🔗 Analysis chain

Verify error propagation in the Events command.

The run implementation follows the pattern of other commands, but let's verify the error handling in the EventsArgs::run implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check error handling patterns in EventsArgs::run
# Look for proper error handling patterns in the events implementation

# Search for Result/Error types and error handling
ast-grep --pattern 'Result<$_>' events.rs

# Look for error propagation patterns
rg '(\?|\.unwrap\(\)|\.expect\(|panic!)' events.rs

Length of output: 203


Script:

#!/bin/bash
# First, let's find the correct path to the events implementation
fd -t f "events" --exec echo '{}'

# Then let's examine the implementation
ast-grep --pattern 'impl EventsArgs {
  $$$
  fn run($$$) -> Result<$_> {
    $$$
  }
  $$$
}'

# Also search for any file containing EventsArgs struct and its run method
rg -A 5 "struct EventsArgs" 
rg -A 10 "impl EventsArgs"

# Look for error handling patterns in files containing EventsArgs
fd -t f "events" --exec rg -l "EventsArgs" {} \; | xargs rg '(\?|\.unwrap\(\)|\.expect\(|panic!)'

Length of output: 3711

Comment on lines +56 to +57
let ws = scarb::ops::read_workspace(config.manifest_path(), config)?;

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure proper error handling when loading the workspace.

In let ws = scarb::ops::read_workspace(config.manifest_path(), config)?;, if the workspace fails to load, the error might not provide sufficient context. Enhance error messages to aid in troubleshooting.

Would you like assistance in improving the error handling for workspace loading?

let to_block = self.to_block.map(BlockId::Number);
let keys = self
.events
.map(|e| vec![e.iter().map(|event| starknet_keccak(event.as_bytes())).collect()]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle empty event lists gracefully.

When mapping over self.events, if the list is empty, the event filter may not behave as expected. Consider adding a check to handle empty event lists to prevent potential issues.

Comment on lines +113 to +376
.collect::<Vec<String>>()
.join(", "),
record
),
)
}
WorldEvent::StoreUpdateRecord(e) => {
let tag = tags.get(&e.selector).unwrap();
// TODO: model value impl + print.
(
format!("Store update record ({})", tag),
format!(
"Selector: {:#066x}\nEntity ID: {:#066x}\nValues: {}",
e.selector,
e.entity_id,
e.values
.iter()
.map(|v| format!("{:#066x}", v))
.collect::<Vec<String>>()
.join(", "),
),
)
}
WorldEvent::StoreUpdateMember(e) => {
let tag = tags.get(&e.selector).unwrap();
// TODO: pretty print of the value.
(
format!("Store update member ({})", tag),
format!(
"Selector: {:#066x}\nEntity ID: {:#066x}\nMember selector: {:#066x}\nValues: \
{}",
e.selector,
e.entity_id,
e.member_selector,
e.values
.iter()
.map(|v| format!("{:#066x}", v))
.collect::<Vec<String>>()
.join(", "),
),
)
}
WorldEvent::StoreDelRecord(e) => {
let tag = tags.get(&e.selector).unwrap();
(
format!("Store del record ({})", tag),
format!("Selector: {:#066x}\nEntity ID: {:#066x}", e.selector, e.entity_id,),
)
}
WorldEvent::EventEmitted(e) => {
let tag = tags.get(&e.selector).unwrap();
let contract_tag = if let Some(selector) =
contract_selectors_from_address.get(&e.system_address.into())
{
tags.get(selector).unwrap().to_string()
} else {
format!("{:#066x}", e.system_address.0)
};

let (record, _, _) = model::model_get(
tag.clone(),
e.keys.clone(),
world_diff.world_info.address,
provider,
block_id,
)
.await?;

(
format!("Event emitted ({})", tag),
format!(
"Selector: {:#066x}\nContract: {}\nHistorical: {}\nKeys: {}\nValues: \
{}\nData:\n{}",
e.selector,
contract_tag,
e.historical,
e.keys
.iter()
.map(|k| format!("{:#066x}", k))
.collect::<Vec<String>>()
.join(", "),
e.values
.iter()
.map(|v| format!("{:#066x}", v))
.collect::<Vec<String>>()
.join(", "),
record
),
)
}
_ => ("Unprocessed event".to_string(), format!("Event: {:?}", event)),
};

let block_str = block_number.map(|n| n.to_string()).unwrap_or("pending".to_string());
let ptr = format!("[block:{} / tx:{:#066x}]", block_str, transaction_hash).bright_black();

println!("> {name} {ptr}\n{content}\n-----\n");

Ok(())
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor match_event for better readability and maintainability.

The match_event function is quite extensive, handling numerous event types in a single block. Breaking it down into smaller helper functions or modules could improve readability and make maintenance easier.

For example, you could extract each event type handling into its own function:

async fn handle_world_spawned_event(...) { ... }
async fn handle_world_upgraded_event(...) { ... }
// And so on for each event type.

Comment on lines +253 to +282
let tag = tags.get(&e.selector).unwrap();
let (record, _, _) = model::model_get(
tag.clone(),
e.keys.clone(),
world_diff.world_info.address,
provider,
block_id,
)
.await?;

(
format!("Store set record ({})", tag),
format!(
"Selector: {:#066x}\nEntity ID: {:#066x}\nKeys: {}\nValues: {}\nData:\n{}",
e.selector,
e.entity_id,
e.keys
.iter()
.map(|k| format!("{:#066x}", k))
.collect::<Vec<String>>()
.join(", "),
e.values
.iter()
.map(|v| format!("{:#066x}", v))
.collect::<Vec<String>>()
.join(", "),
record
),
)
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Handle potential errors in StoreSetRecord event processing.

In the StoreSetRecord event handling, ensure that the call to model::model_get handles errors appropriately, possibly with informative messages if the model retrieval fails.

Comment on lines +225 to +245
let tag = tags.get(&e.resource).unwrap();
let grantee =
if let Some(selector) = contract_selectors_from_address.get(&e.contract.into()) {
tags.get(selector).unwrap().to_string()
} else {
format!("{:#066x}", e.contract.0)
};

(
"Writer updated".to_string(),
format!("Target resource: {}\nContract: {}\nValue: {}", tag, grantee, e.value),
)
}
WorldEvent::OwnerUpdated(e) => {
let tag = tags.get(&e.resource).unwrap();
let grantee =
if let Some(selector) = contract_selectors_from_address.get(&e.contract.into()) {
tags.get(selector).unwrap().to_string()
} else {
format!("{:#066x}", e.contract.0)
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo, sensei! Ensure safe unwrapping of options in WriterUpdated and OwnerUpdated events.

In lines where tags.get(&e.resource).unwrap() and tags.get(selector).unwrap() are called, consider handling the None case to prevent potential panics.

Apply this diff to handle possible None values:

-let tag = tags.get(&e.resource).unwrap();
+let tag = match tags.get(&e.resource) {
+    Some(t) => t,
+    None => {
+        tracing::warn!("Tag not found for resource: {:#066x}", e.resource);
+        return Ok(());
+    }
+};

Committable suggestion skipped: line range outside the PR's diff.

Copy link

codecov bot commented Nov 3, 2024

Codecov Report

Attention: Patch coverage is 0% with 313 lines in your changes missing coverage. Please review.

Project coverage is 56.90%. Comparing base (32af19e) to head (4a06068).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
bin/sozo/src/commands/events.rs 0.00% 262 Missing ⚠️
bin/sozo/src/commands/model.rs 0.00% 21 Missing ⚠️
crates/sozo/ops/src/model.rs 0.00% 15 Missing ⚠️
crates/dojo/world/src/local/resource.rs 0.00% 7 Missing ⚠️
crates/dojo/world/src/diff/resource.rs 0.00% 6 Missing ⚠️
bin/sozo/src/commands/mod.rs 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2619      +/-   ##
==========================================
- Coverage   57.25%   56.90%   -0.36%     
==========================================
  Files         396      397       +1     
  Lines       49162    49466     +304     
==========================================
  Hits        28148    28148              
- Misses      21014    21318     +304     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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