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(torii): index whitelisted erc20/erc721 #2442

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

lambda-0x
Copy link
Collaborator

@lambda-0x lambda-0x commented Sep 18, 2024

Copy link

coderabbitai bot commented Sep 18, 2024

Walkthrough

Ohayo, sensei! This pull request enhances the application by adding support for ERC contract addresses through a new command-line argument. It updates the processing logic for ERC20 and ERC721 transfers and introduces a configuration file for ERC contracts. Additionally, the database schema is expanded to manage token balances and transfers, improving the overall functionality related to ERC tokens.

Changes

File Path Change Summary
bin/torii/src/main.rs Added command-line argument erc_contracts for ERC contract handling; modified main function to load ERC configurations; updated Processors struct to include new ERC20 and ERC721 transfer processors.
bin/torii/torii.toml Introduced example configuration for ERC contracts, allowing users to define contract types and addresses in TOML format.
crates/torii/core/Cargo.toml Added toml crate as a dependency for configuration management.
crates/torii/core/src/engine.rs Modified event processing logic to allow multiple processors for the same event; updated constructor to accept ERC tokens; introduced asynchronous event fetching.
crates/torii/core/src/processors/erc20_legacy_transfer.rs Implemented Erc20LegacyTransferProcessor for handling legacy ERC20 transfers with validation and processing logic.
crates/torii/core/src/processors/erc20_transfer.rs Implemented Erc20TransferProcessor for standard ERC20 transfers, including validation and processing logic.
crates/torii/core/src/processors/erc721_transfer.rs Implemented Erc721TransferProcessor for handling ERC721 transfers with appropriate validation and processing.
crates/torii/core/src/processors/mod.rs Updated event processor handling to support multiple processors per event and made new processors publicly accessible.
crates/torii/core/src/sql/erc.rs Added methods for handling ERC20 and ERC721 transfers in the database; included metadata registration for tokens.
crates/torii/core/src/sql/mod.rs Introduced erc module; modified Sql constructor to accept ERC contracts for initialization.
crates/torii/core/src/sql/utils.rs Added utility functions for converting between Felt and U256 types and their SQL string representations.
crates/torii/core/src/types.rs Introduced ToriiConfig, ErcContract, and ErcType structures for managing ERC contract configurations.
crates/torii/migrations/20240913104418_add_erc.sql Created new tables for managing token balances, tokens, and ERC transfers in the database.
scripts/deploy_erc20_katana.sh Added script for deploying ERC20 tokens using Starkli tool with necessary parameters.
scripts/send_erc20_transfer.sh Introduced script for sending ERC20 token transfers with command-line interface support.

Suggested reviewers

  • glihm: Suggested as a reviewer for expertise in the changes introduced in this PR.

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

Outside diff range and nitpick comments (5)
scripts/deploy_erc20_katana.sh (1)

3-3: Enhance script readability with comments

Sensei, adding comments to explain the purpose of each parameter in the starkli deploy command will improve the script's maintainability and help others understand its functionality.

crates/torii/core/src/processors/erc20_transfer.rs (1)

14-58: Consider adding unit tests for Erc20TransferProcessor

Sensei, to ensure the robustness of the Erc20TransferProcessor, consider adding unit tests that cover various scenarios, including valid events, invalid events, and error handling. This will help maintain code quality and catch potential issues early.

crates/torii/core/src/sql/mod.rs (3)

35-35: Updating test module path to test.rs

The test module path has been updated from sql_test.rs to test.rs. Ensure that this change is reflected in any documentation or build scripts that reference the test module.

Confirm that all tests are still properly located and executed with the new module path.


39-39: Review the necessity of publicly re-exporting the utils module

The line pub use utils::*; publicly exposes all items from the utils module. If these utilities are intended for internal use only within the sql module, consider removing the pub keyword to encapsulate the implementation details.

This change can help maintain a clean public API and prevent unintended usage of internal utilities.


742-746: Simplify conditional expression in build_set_entity_queries_recursive

The conditional expression can be simplified for readability.

Consider rewriting the condition as:

if let Ty::Tuple(t) = &o.ty {
    t.is_empty()
} else {
    false
}

This makes the intent clearer and improves code readability.

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 8613c78 and d2b7c23.

Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
Files selected for processing (15)
  • bin/torii/src/main.rs (7 hunks)
  • bin/torii/torii.toml (1 hunks)
  • crates/torii/core/Cargo.toml (1 hunks)
  • crates/torii/core/src/engine.rs (12 hunks)
  • crates/torii/core/src/processors/erc20_legacy_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/erc20_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/erc721_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/mod.rs (2 hunks)
  • crates/torii/core/src/sql/erc.rs (1 hunks)
  • crates/torii/core/src/sql/mod.rs (6 hunks)
  • crates/torii/core/src/sql/utils.rs (1 hunks)
  • crates/torii/core/src/types.rs (2 hunks)
  • crates/torii/migrations/20240913104418_add_erc.sql (1 hunks)
  • scripts/deploy_erc20_katana.sh (1 hunks)
  • scripts/send_erc20_transfer.sh (1 hunks)
Files skipped from review due to trivial changes (1)
  • bin/torii/torii.toml
Additional comments not posted (20)
scripts/deploy_erc20_katana.sh (1)

3-3: Consider securing your keystore with a password

Sensei, the script uses an empty password for the keystore (--keystore-password ""), which may pose a security risk if the keystore contains sensitive information. It's recommended to secure the keystore with a strong password to protect your private keys.

[security]

scripts/send_erc20_transfer.sh (1)

12-12: Consider securing your keystore with a password

Sensei, the script uses an empty password for the keystore (--keystore-password ""), which may pose a security risk. It's advisable to secure the keystore with a strong password to protect your private keys.

[security]

crates/torii/migrations/20240913104418_add_erc.sql (1)

28-29: Consider adding indexes on from_address and to_address

Sensei, to improve query performance when filtering or joining on from_address and to_address, consider adding indexes on these columns in the erc_transfers table.

[performance]

Apply this SQL to add the indexes:

CREATE INDEX erc_transfers_from_address ON erc_transfers (from_address);
CREATE INDEX erc_transfers_to_address ON erc_transfers (to_address);
crates/torii/core/Cargo.toml (1)

41-41: Dependency addition looks good

Sensei, adding the toml crate to the workspace dependencies is appropriate and will allow for consistent use across the project.

crates/torii/core/src/processors/erc20_legacy_transfer.rs (2)

26-34: Ohayo, sensei! Validation Logic is Solid

The validate method appropriately checks that the event has exactly one key and four data elements, aligning with the expected structure of a legacy ERC20 transfer event. This ensures that only correctly formatted events are processed.


36-57: Efficient Handling of Legacy ERC20 Transfer Events

The process method correctly extracts the from, to, and value fields from the event data. Good job on deserializing the value properly and logging the transfer details. This will help in accurate tracking of token transfers.

crates/torii/core/src/processors/erc721_transfer.rs (2)

26-35: Ohayo, sensei! Proper Validation for ERC721 Events

The validate method correctly checks that the event has five keys and no data, which matches the expected structure of an ERC721 transfer event. This validation ensures that only relevant events are processed.


46-52: Ensure Correct Extraction of from, to, and token_id Fields

Please verify that the indices used to extract from, to, and token_id from event.keys match the ERC721 event structure. Specifically, confirm that:

  • event.keys[1] corresponds to the from address.
  • event.keys[2] corresponds to the to address.
  • event.keys[3..5] are correctly used to deserialize the token_id.
crates/torii/core/src/processors/mod.rs (2)

15-17: Ohayo, sensei! Modules Exported Successfully

Uncommenting the module declarations for erc20_legacy_transfer, erc20_transfer, and erc721_transfer correctly includes these processors in the processing logic. This expansion allows the system to handle a wider range of events related to ERC token transfers.


84-90: Correct Modification to Support Multiple Processors per Event Key

Changing the generate_event_processors_map function to use Vec<Box<dyn EventProcessor<P>>> allows multiple processors to be associated with the same event key. This modification enhances flexibility in event handling.

Please verify that all parts of the codebase that interact with this function can accommodate the updated return type and structure.

bin/torii/src/main.rs (1)

Line range hint 122-145: Ohayo, sensei! Conflicting Arguments Managed Properly

The introduction of the erc_contracts parameter with a conflict against the config parameter is handled correctly. This prevents ambiguous configurations and ensures that only one source of ERC contract configuration is used at a time.

crates/torii/core/src/engine.rs (5)

9-9: Ohayo, sensei! Preparing for concurrent event fetching with join_all

The addition of use futures_util::future::join_all; allows for concurrent execution of futures, which can significantly improve the performance of fetching events from multiple sources.


521-530: Ohayo, sensei! Ensure thread safety when merging local databases in parallel tasks

In the process_tasks method, each task processes events using a local_db, which is then merged into self.db. Ensure that the merge function is thread-safe and can handle concurrent modifications without causing data races or deadlocks.

Please confirm that self.db.merge(local_db)?; is safe in a concurrent context. If necessary, consider adding synchronization mechanisms or using thread-safe data structures to protect shared resources during the merge.


604-606: Filtering events to process only relevant ones

The added condition ensures that only events from the world contract or the specified tokens are processed. This helps in skipping unrelated events and improves processing efficiency.


Line range hint 710-747: Verify task identification logic for parallelized event processing

The task_identifier is determined based on the event data for specific event keys. This mechanism is used to group events for parallel processing.

Please confirm that this approach correctly identifies tasks and that events are grouped appropriately. Also, consider documenting the rationale behind using specific event keys for task identification for clarity.


756-780: Addition of get_all_events function for comprehensive event retrieval

The new get_all_events function properly handles pagination by looping until all events are retrieved. This ensures that all events are collected, which is essential for processing large numbers of events without missing any.

crates/torii/core/src/sql/mod.rs (4)

22-23: Ohayo, sensei! Importing necessary types for ERC contract handling

The addition of imports for ErcContract, Event, EventMessage, and Model ensures that the types needed for the new functionality are available.


33-33: Introducing the erc module for ERC contract support

The inclusion of mod erc; indicates the introduction of a new module to handle ERC contracts. This modular approach keeps the codebase organized and maintainable.


61-65: Ohayo, sensei! Extending Sql::new to initialize with ERC contracts

The Sql::new function now accepts erc_contracts to insert ERC contract data into the database during initialization. This change allows the system to recognize and manage ERC contracts effectively from the start.


79-91: Inserting ERC contracts into the contracts table

The code correctly iterates through erc_contracts and inserts each contract into the contracts table if it doesn't already exist. This ensures that all relevant ERC contracts are accounted for in the database.

scripts/send_erc20_transfer.sh Show resolved Hide resolved
crates/torii/core/src/sql/utils.rs Show resolved Hide resolved
crates/torii/core/src/sql/utils.rs Show resolved Hide resolved
crates/torii/core/src/types.rs Outdated Show resolved Hide resolved
crates/torii/core/src/sql/erc.rs Outdated Show resolved Hide resolved
crates/torii/core/src/engine.rs Outdated Show resolved Hide resolved
@rsodre
Copy link

rsodre commented Sep 18, 2024

@lambda-0x please consider indexing ERC-1155 as well
lots of games will have those

@lambda-0x
Copy link
Collaborator Author

@rsodre thanks for the feedback we have designed tables in such a way that it should be straight forward to add, so will try to add it in this PR itself.

Although I am curious how does game use ERC1155, do they mainly need one ERC20 and multiplle ERC721, or just multiple ERC20s?

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

Outside diff range and nitpick comments (1)
crates/torii/core/src/engine.rs (1)

Line range hint 672-749: Ensure Catch-All Event Processor Invocation

Ohayo, sensei! The current implementation might skip processing events if no specific processors are found, even when the catch_all_event processor is meant to handle them.

Adjust the logic to ensure the catch_all_event processor is invoked appropriately:

let Some(processors) = self.processors.event.get(&event_key) else {
    // If we don't have a processor for this event key
+   if self.processors.catch_all_event.validate(event) {
+       if let Err(e) = self
+           .processors
+           .catch_all_event
+           .process(
+               &self.world,
+               &mut self.db,
+               block_number,
+               block_timestamp,
+               event_id,
+               event,
+           )
+           .await
+       {
+           error!(target: LOG_TARGET, error = %e, "Processing catch-all event.");
+       }
+   } else {
+       // Log unprocessed events if necessary
+   }
    return Ok(());
};

This ensures that events without specific processors are still handled by the catch_all_event processor.

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between d2b7c23 and d53a2e4.

Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
Files selected for processing (18)
  • bin/torii/src/main.rs (7 hunks)
  • bin/torii/torii.toml (1 hunks)
  • crates/torii/core/Cargo.toml (1 hunks)
  • crates/torii/core/src/engine.rs (13 hunks)
  • crates/torii/core/src/lib.rs (0 hunks)
  • crates/torii/core/src/processors/erc20_legacy_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/erc20_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/erc721_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/mod.rs (2 hunks)
  • crates/torii/core/src/processors/store_set_record.rs (1 hunks)
  • crates/torii/core/src/sql/erc.rs (1 hunks)
  • crates/torii/core/src/sql/mod.rs (5 hunks)
  • crates/torii/core/src/sql/utils.rs (1 hunks)
  • crates/torii/core/src/types.rs (2 hunks)
  • crates/torii/libp2p/src/server/mod.rs (1 hunks)
  • crates/torii/migrations/20240913104418_add_erc.sql (1 hunks)
  • scripts/deploy_erc20_katana.sh (1 hunks)
  • scripts/send_erc20_transfer.sh (1 hunks)
Files not reviewed due to no reviewable changes (1)
  • crates/torii/core/src/lib.rs
Files skipped from review due to trivial changes (4)
  • bin/torii/torii.toml
  • crates/torii/core/Cargo.toml
  • crates/torii/core/src/processors/store_set_record.rs
  • crates/torii/libp2p/src/server/mod.rs
Files skipped from review as they are similar to previous changes (10)
  • bin/torii/src/main.rs
  • crates/torii/core/src/processors/erc20_legacy_transfer.rs
  • crates/torii/core/src/processors/erc20_transfer.rs
  • crates/torii/core/src/processors/erc721_transfer.rs
  • crates/torii/core/src/processors/mod.rs
  • crates/torii/core/src/sql/utils.rs
  • crates/torii/core/src/types.rs
  • crates/torii/migrations/20240913104418_add_erc.sql
  • scripts/deploy_erc20_katana.sh
  • scripts/send_erc20_transfer.sh
Additional comments not posted (2)
crates/torii/core/src/engine.rs (1)

518-527: Potential Task Execution Issue with Semaphore Acquisition

Ohayo, sensei! In the process_tasks method, acquiring a semaphore permit inside the spawned task may not effectively limit the number of concurrent tasks, leading to potential resource exhaustion.

Consider acquiring the semaphore permit before spawning the task to ensure proper concurrency control:

for (task_id, events) in self.tasks.drain() {
    let db = self.db.clone();
    let world = self.world.clone();
    let processors = self.processors.clone();
    let semaphore = semaphore.clone();
+   let permit = semaphore.acquire().await.unwrap();

    set.spawn(async move {
-       let _permit = semaphore.acquire().await.unwrap();
+       let _permit = permit; // Keep the permit alive for the task duration
        // Task code...
    });
}

This modification ensures that the semaphore controls the number of tasks being spawned, preventing too many concurrent tasks from executing.

Likely invalid or redundant comment.

crates/torii/core/src/sql/mod.rs (1)

742-746: Correct Enum Handling in Recursive Query Building

Ohayo, sensei! In the build_set_entity_queries_recursive method, the condition for skipping empty enum options may incorrectly return early, causing code that should execute to be skipped.

Modify the condition to prevent unintentional early returns:

if e.options.iter().all(
    |o| match &o.ty {
-       Ty::Tuple(t) => t.is_empty(),
+       Ty::Tuple(t) => t.is_empty(),
+       _ => false,
    },
) {
    return;
}

This adjustment ensures that only enums with all empty tuple options are skipped, allowing proper processing of enums with meaningful variants.

Likely invalid or redundant comment.

crates/torii/core/src/sql/erc.rs Outdated Show resolved Hide resolved
crates/torii/core/src/sql/erc.rs Show resolved Hide resolved
@lambda-0x lambda-0x force-pushed the spr/main/5231a946 branch 2 times, most recently from fc56768 to 83ac6d1 Compare September 19, 2024 09:41
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: 3

Outside diff range and nitpick comments (5)
crates/torii/core/src/sql/test.rs (1)

48-52: Ohayo sensei! The code changes look good to me.

The shift from Arc::new to Box::new for wrapping the processors is a valid change in ownership semantics.

However, please consider the performance implications of using Box::new instead of Arc::new. While Box::new allocates on the heap, Arc::new provides reference counting, which may be more suitable in certain scenarios. Ensure that the chosen approach aligns with the performance requirements of the codebase.

crates/torii/core/src/engine.rs (3)

Line range hint 232-349: Ohayo sensei! The changes to fetch_range are looking great.

Fetching events concurrently for the world contract and ERC tokens using join_all is a significant performance improvement. The processing of fetched events to extract transactions and blocks is handled correctly.

One suggestion for improvement:

Consider collecting the results of each task and handling errors individually. This would allow the function to continue processing events from other contracts even if one task fails, making the engine more resilient to transient errors.


Line range hint 351-372: Ohayo sensei! The fetch_pending function looks good.

It correctly fetches the pending block data and handles the case when the pending block is not available.

Don't forget to address the TODO comment once the provider is updated to always return a pending block. Let me know if you need any help with that!


Line range hint 552-576: Ohayo sensei! The process_transaction_with_events function looks good.

It correctly processes each event associated with the transaction by calling the process_event function with the necessary parameters.

I noticed that the transaction processor is commented out due to performance reasons. If it is no longer needed, consider removing the commented-out code to keep the codebase clean.

crates/torii/core/src/sql/mod.rs (1)

Line range hint 68-98: Ohayo sensei! Offer assistance with unit tests for erc_contracts handling

The updated new method now accepts erc_contracts and processes them to insert contracts into the database. To ensure this new functionality is reliable, it's important to have appropriate unit tests. I can help by generating unit tests to cover different scenarios, such as inserting multiple contracts and handling duplicates.

Do you want me to generate the unit testing code or open a GitHub issue to track this task?

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between d53a2e4 and 83ac6d1.

Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
Files selected for processing (26)
  • bin/torii/src/main.rs (7 hunks)
  • bin/torii/torii.toml (1 hunks)
  • crates/torii/core/Cargo.toml (1 hunks)
  • crates/torii/core/src/engine.rs (24 hunks)
  • crates/torii/core/src/lib.rs (0 hunks)
  • crates/torii/core/src/processors/erc20_legacy_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/erc20_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/erc721_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/mod.rs (2 hunks)
  • crates/torii/core/src/processors/store_set_record.rs (1 hunks)
  • crates/torii/core/src/sql/erc.rs (1 hunks)
  • crates/torii/core/src/sql/mod.rs (9 hunks)
  • crates/torii/core/src/sql/query_queue.rs (1 hunks)
  • crates/torii/core/src/sql/test.rs (5 hunks)
  • crates/torii/core/src/sql/utils.rs (1 hunks)
  • crates/torii/core/src/types.rs (2 hunks)
  • crates/torii/graphql/src/tests/metadata_test.rs (3 hunks)
  • crates/torii/graphql/src/tests/mod.rs (3 hunks)
  • crates/torii/graphql/src/tests/subscription_test.rs (6 hunks)
  • crates/torii/grpc/src/server/tests/entities_test.rs (3 hunks)
  • crates/torii/libp2p/src/server/mod.rs (1 hunks)
  • crates/torii/libp2p/src/tests.rs (2 hunks)
  • crates/torii/migrations/20240913104418_add_erc.sql (1 hunks)
  • crates/torii/migrations/20240918200125_rename_column_contracts_table.sql (1 hunks)
  • scripts/deploy_erc20_katana.sh (1 hunks)
  • scripts/send_erc20_transfer.sh (1 hunks)
Files not reviewed due to no reviewable changes (1)
  • crates/torii/core/src/lib.rs
Files skipped from review due to trivial changes (3)
  • crates/torii/core/src/processors/store_set_record.rs
  • crates/torii/migrations/20240918200125_rename_column_contracts_table.sql
  • scripts/deploy_erc20_katana.sh
Files skipped from review as they are similar to previous changes (11)
  • bin/torii/src/main.rs
  • bin/torii/torii.toml
  • crates/torii/core/Cargo.toml
  • crates/torii/core/src/processors/erc20_transfer.rs
  • crates/torii/core/src/processors/erc721_transfer.rs
  • crates/torii/core/src/sql/erc.rs
  • crates/torii/core/src/sql/utils.rs
  • crates/torii/core/src/types.rs
  • crates/torii/libp2p/src/server/mod.rs
  • crates/torii/migrations/20240913104418_add_erc.sql
  • scripts/send_erc20_transfer.sh
Additional comments not posted (36)
crates/torii/core/src/processors/erc20_legacy_transfer.rs (5)

1-10: Ohayo sensei! The imports look good to me.

The imported dependencies are relevant and necessary for the functionality implemented in this file. No unused imports detected.


12-15: Ohayo sensei! The constant and struct definitions are on point.

The LOG_TARGET constant follows the naming convention and will be useful for logging. The Erc20LegacyTransferProcessor struct is derived with appropriate traits.


17-34: Ohayo sensei! The EventProcessor trait implementation looks solid.

The event_key method returns the correct key for ERC20 transfer events. The validate method properly checks the event structure to ensure it matches the expected format for ERC20 transfers.


36-57: Ohayo sensei! The process method implementation is top-notch.

The method correctly extracts relevant data from the event, handling the Cairo serialization format for the value. The interaction with the database and logging of transaction details are implemented properly.


58-58: Ohayo sensei! The closing brace is in the right spot.

The closing brace matches the opening brace of the Erc20LegacyTransferProcessor struct.

crates/torii/core/src/processors/mod.rs (4)

12-17: Ohayo sensei! The uncommented module declarations look good.

Making the erc20_legacy_transfer, erc20_transfer, and erc721_transfer modules publicly accessible will allow them to be utilized in the processing logic. This change aligns with the objective of expanding functionality related to ERC20 and ERC721 token transfers.


82-82: Ohayo sensei! The EventProcessors<P> type alias definition looks good.

Defining EventProcessors<P> as Vec<Box<dyn EventProcessor<P>>> aligns with the changes made to the generate_event_processors_map function. Using Box instead of Arc indicates a shift in ownership semantics, allowing the function to own the event processors rather than using shared references.


86-87: Ohayo sensei! The modifications to the generate_event_processors_map function look good.

Changing the parameter type to EventProcessors<P> and the return type to Result<HashMap<Felt, EventProcessors<P>>> allows multiple processors to be associated with a single event key. This enhances the flexibility of event handling and enables more complex event processing scenarios.


92-92: Ohayo sensei! The processor insertion logic looks good.

Using event_processors.entry(key).or_insert(vec![]).push(processor) ensures that a new vector is created for each event key if it doesn't already exist, and the processor is added to the vector. This allows multiple processors to be associated with a single event key, enhancing the flexibility of event handling.

crates/torii/graphql/src/tests/metadata_test.rs (3)

3-4: Ohayo sensei! The import statement looks good to me.

The HashMap import is valid and necessary for the code changes. Nice work!


106-106: Ohayo sensei! The modified Sql::new instantiation looks good here too.

The changes are consistent with the updated constructor signature. Please refer to the previous verification script to ensure all occurrences of Sql::new in the codebase match the new signature.


53-53: Ohayo sensei! The modified Sql::new instantiation looks good.

The changes are consistent with the updated constructor signature. Just make sure to update all other occurrences of Sql::new in the codebase to match the new signature.

Run the following script to verify the constructor usage:

Verification successful

Ohayo sensei! I've thoroughly examined the usage of Sql::new across the codebase, and I'm pleased to report some good news!

All instances of Sql::new are consistently using the new signature.

Here's a quick summary of my findings:

  • 13 occurrences of Sql::new were found across different files.
  • All instances use the new three-parameter signature: Sql::new(pool.clone(), <some_value>, &HashMap::new()).
  • The third parameter is consistently &HashMap::new(), which aligns perfectly with the change we're verifying.

No further action is required. The codebase appears to be in harmony with the new Sql::new signature. Excellent work, sensei!

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all occurrences of `Sql::new` match the new signature.

# Test: Search for the constructor usage. Expect: Only occurrences of the new signature.
rg --type rust -A 5 $'Sql::new'

Length of output: 7515

crates/torii/grpc/src/server/tests/entities_test.rs (4)

1-1: Ohayo sensei! The import statement looks good.

The HashMap import is necessary for the code changes in this file.


108-109: Ohayo sensei! The addition of new event processors looks good.

The RegisterModelProcessor and StoreSetRecordProcessor are added correctly to the list of event processors.


121-121: Ohayo sensei! The fetch_range method call looks good.

The additional HashMap parameter is consistent with the method signature change.

Run the following script to verify the method usage:

#!/bin/bash
# Description: Verify all method calls to `fetch_range` match the new signature.

# Test: Search for the method usage. Expect: Only occurrences of the new signature.
rg --type rust -A 5 $'fetch_range'

99-99: Ohayo sensei! The Sql::new function call looks good.

The additional HashMap parameter is consistent with the function signature change.

Run the following script to verify the function usage:

Verification successful

Ohayo sensei! It seems our previous attempt didn't quite hit the mark. Let's try again with a corrected script to find what we're looking for!


Ohayo sensei! I've got some good news for you about our Sql::new function!

The Sql::new function is being used correctly with the new signature throughout the codebase.

After a thorough investigation, I can confirm that:

  • All instances of Sql::new are called with three parameters: pool, world_address (or Felt::ZERO), and a HashMap.
  • The new HashMap parameter is consistently passed as &HashMap::new(), creating an empty HashMap in all cases.
  • There are no occurrences of the old signature (without the HashMap parameter) being used.

This consistency across the codebase indicates that the change has been properly implemented and there are no lingering issues with the function usage.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `Sql::new` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type rust -A 5 $'Sql::new'

Length of output: 2280


Script:

#!/bin/bash
# Description: Verify all function calls to `Sql::new` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type rust -A 5 'Sql::new'

Length of output: 7515

crates/torii/core/src/sql/query_queue.rs (1)

8-8: Ohayo sensei! The new import looks good.

The felt_to_sql_string function from the utils module will likely be used to convert Felt values, such as token IDs or addresses, into SQL-friendly string representations. This is a crucial step in indexing ERC20 and ERC721 tokens, as it allows for efficient storage and retrieval of token-related data in the database.

By converting Felt values to SQL strings, you can streamline the process of constructing SQL queries and managing data interactions with the database when dealing with token indexing. Keep up the great work, sensei!

crates/torii/graphql/src/tests/mod.rs (3)

1-1: Ohayo sensei! The import looks good to me.

The HashMap import from std::collections is valid and necessary for later usage.


354-354: Ohayo sensei! The Sql instantiation changes look good.

The additional parameter, a reference to a new HashMap, suggests improved configurability for the Sql instance. This could enable more flexible state management or data handling. The changes are valid and do not introduce any apparent issues.


363-365: Ohayo sensei! The processor and fetch_range changes look valid, but please verify the performance impact.

The shift from using Arc::new to Box::new for processor instances indicates a change in ownership semantics and memory management. While this is a valid approach, it's worth verifying if this change has any unintended performance implications, considering the trade-offs between reference counting and heap allocation.

Additionally, passing a new HashMap reference to engine.fetch_range aligns with the earlier modifications to Sql::new, maintaining consistency.

Overall, the changes appear correct, but it's prudent to assess the performance impact of the processor memory management change.

Also applies to: 373-373, 377-377

crates/torii/core/src/sql/test.rs (2)

131-131: Ohayo sensei! The code changes look good to me.

The update to the Sql::new function call, including the new parameter of a reference to an empty HashMap, is a valid change that ensures a consistent empty state is passed to the function during initialization.


291-291: Ohayo sensei! The code changes look good to me.

The updates to the Sql::new function calls in both test_load_from_remote_del and test_update_with_set_record functions, including the new parameter of a reference to an empty HashMap, are valid changes that ensure a consistent empty state is passed to the function during initialization.

Also applies to: 381-381

crates/torii/graphql/src/tests/subscription_test.rs (2)

3-3: Ohayo sensei! The HashMap import looks good to me.

The HashMap type is a useful data structure for storing key-value pairs and is commonly used in Rust projects. The import statement follows Rust's naming conventions and is valid.


25-25: Ohayo sensei! The Sql instantiation with the new HashMap parameter looks good.

The additional &HashMap::new() parameter allows for more flexibility in configuring the Sql object. This change suggests that the Sql object now supports additional configuration or metadata through the HashMap parameter.

To ensure consistency, please run the following script to verify that all instantiations of the Sql object have been updated with the new parameter:

Verification successful

Ohayo sensei! The Sql::new update is consistently applied across the codebase. Sugoi!

All instantiations of Sql::new now include the new HashMap parameter, either as &HashMap::new() in test files or as &erc_contracts in the main application. This consistency ensures that the change is properly implemented throughout the project.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all instantiations of the `Sql` object include the new `HashMap` parameter.

# Test: Search for the `Sql::new` method usage. Expect: All occurrences to include the `HashMap` parameter.
rg --type rust $'Sql::new\(' -A 1

Length of output: 2776

crates/torii/core/src/engine.rs (9)

Line range hint 204-226: Ohayo sensei! The changes to fetch_data look good to me.

The function correctly handles fetching data for different scenarios based on the cursor head and latest block number. The logic is sound and the implementation is clean.


Line range hint 374-388: Ohayo sensei! The process function looks good to me.

It correctly dispatches the processing based on the type of fetched data. The logic is straightforward and easy to understand.


Line range hint 390-452: Ohayo sensei! The process_pending function looks solid.

It correctly handles the processing of pending transactions, skipping the ones that have already been processed based on the cursor. The error handling for processing pending transactions is handled appropriately, with specific handling for the "TransactionHashNotFound" error.

The function also processes parallelized events and updates the database with the processed data.


Line range hint 454-493: Ohayo sensei! The process_range function looks great.

It correctly processes transactions and blocks for a given range, handling the associated events and updating the database accordingly. Processing parallelized events and updating the database with the processed data is also handled correctly.

The database is executed in batches, which is a good performance optimization.


Line range hint 495-534: Ohayo sensei! The process_tasks function is looking good.

Using a semaphore to limit the number of concurrent tasks based on the configuration is a great way to control the parallelization. Spawning a task for each batch of parallelized events and processing them concurrently significantly improves performance.

The error handling for processing parallelized events is handled correctly, with errors being logged. Merging the results from each task into the main database ensures data consistency.


Line range hint 585-621: Ohayo sensei! The process_transaction_with_receipt function looks solid.

It correctly processes each event associated with the transaction if it belongs to the world contract or ERC tokens. Updating the cursor map for each processed event ensures proper tracking of the event processing progress.

Calling the process_event function to process each event with the necessary parameters is handled correctly.


Line range hint 667-749: Ohayo sensei! The process_event function is looking great.

It correctly retrieves the appropriate event processors based on the event key and falls back to the catch-all event processor if no specific processor is found. This ensures that all events are handled, even if they don't have a dedicated processor.

Parallelizing the processing of certain events based on a task identifier is a smart optimization for improving performance for specific event types.

Processing the event using the retrieved event processors and handling errors with appropriate logging is implemented correctly.


752-777: Ohayo sensei! The get_all_events function looks great.

It correctly fetches events in chunks using pagination until all events are retrieved. Using a loop to continuously fetch event pages until the continuation token is None ensures that all events are fetched.

Returning the contract address and the list of fetched event pages provides the necessary data for further processing.


112-113: Ohayo sensei! The changes to the Engine struct look good.

Adding the tokens field to store the ERC tokens to index is a useful addition. It allows the engine to focus on specific tokens of interest.

The struct contains all the necessary fields and provides methods for the engine to function properly, including starting the engine, fetching data, processing data, and handling various types of events and transactions.

crates/torii/libp2p/src/tests.rs (1)

Line range hint 527-563: Ohayo sensei! The changes to the test_client_messaging function look great!

The test function thoroughly verifies the client messaging functionality by setting up the necessary components, registering the Message model, publishing a signed message, and waiting for it to be received within a timeout.

A few additional insights:

  • The use of an in-memory SQLite database ensures a clean and isolated testing environment.
  • The Katana sequencer and JSON-RPC client provide a realistic setup for testing the messaging system.
  • The test covers the essential aspects of message publishing, subscription, and reception.
  • The timeout mechanism ensures that the test fails if the message is not received within the expected time frame.

Overall, this test function enhances the reliability and correctness of the client messaging system. Keep up the great work, sensei!

crates/torii/core/src/sql/mod.rs (2)

37-37: Ohayo sensei! Test module path update is acceptable

Changing the test module's path to test.rs improves consistency. Ensure that all tests are still recognized and executed by the test runner.


125-132: Ohayo sensei! Update all calls to head() to match the new signature

The head method now requires a contract parameter. Ensure that all calls to this method throughout the codebase have been updated to include the new parameter to prevent potential runtime errors.

To ensure that all calls are updated, you can run the following script:

Verification successful

Ohayo sensei! Let's dig a bit deeper to make sure we're not missing anything. I'll run a couple more searches to verify the head() method calls.


Ohayo sensei! I've found some interesting information, but let's double-check to make sure we're not missing anything important.


Ohayo sensei! After our thorough investigation, I have some good news for you!

The head() method call has been correctly updated

We found one occurrence of the head() method being called in crates/torii/core/src/engine.rs, and it's already using the correct signature with a parameter:

let (head, _, _) = self.db.head(self.world.address).await?;

This call matches the new signature we were looking for. We didn't find any other calls to the head() method in the codebase that would need updating.

However, I couldn't locate the actual method definition for head(). While this is a bit unusual, it doesn't affect our conclusion about the method calls being up-to-date.

To be extra thorough, you might want to manually verify the head() method definition and check if there are any other calls to this method that our search might have missed. But based on our findings, it appears that the necessary updates have been made.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all calls to `head()` that need to be updated.

rg --type rust $'\.head\(\)'

Length of output: 29


Script:

#!/bin/bash
# Search for any occurrences of 'head' as a method call
rg --type rust '\w+\.head\b'

# Search for the 'head' method definition
ast-grep --lang rust --pattern 'fn head($$$) $$$'

Length of output: 605


Script:

#!/bin/bash
# Check the context of the head() call we found
rg --type rust -C 5 'self\.db\.head\(self\.world\.address\)'

# Search for the head method definition with a more specific pattern
ast-grep --lang rust --pattern 'pub async fn head(&self, contract: Felt) -> Result<$$$>'

Length of output: 966

crates/torii/core/src/sql/mod.rs Show resolved Hide resolved
crates/torii/core/src/sql/mod.rs Show resolved Hide resolved
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.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 83ac6d1 and 3414843.

Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
Files selected for processing (26)
  • bin/torii/src/main.rs (7 hunks)
  • bin/torii/torii.toml (1 hunks)
  • crates/torii/core/Cargo.toml (1 hunks)
  • crates/torii/core/src/engine.rs (24 hunks)
  • crates/torii/core/src/lib.rs (0 hunks)
  • crates/torii/core/src/processors/erc20_legacy_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/erc20_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/erc721_transfer.rs (1 hunks)
  • crates/torii/core/src/processors/mod.rs (2 hunks)
  • crates/torii/core/src/processors/store_set_record.rs (1 hunks)
  • crates/torii/core/src/sql/erc.rs (1 hunks)
  • crates/torii/core/src/sql/mod.rs (9 hunks)
  • crates/torii/core/src/sql/query_queue.rs (1 hunks)
  • crates/torii/core/src/sql/test.rs (5 hunks)
  • crates/torii/core/src/sql/utils.rs (1 hunks)
  • crates/torii/core/src/types.rs (2 hunks)
  • crates/torii/graphql/src/tests/metadata_test.rs (3 hunks)
  • crates/torii/graphql/src/tests/mod.rs (3 hunks)
  • crates/torii/graphql/src/tests/subscription_test.rs (6 hunks)
  • crates/torii/grpc/src/server/tests/entities_test.rs (3 hunks)
  • crates/torii/libp2p/src/server/mod.rs (1 hunks)
  • crates/torii/libp2p/src/tests.rs (2 hunks)
  • crates/torii/migrations/20240913104418_add_erc.sql (1 hunks)
  • crates/torii/migrations/20240918200125_rename_column_contracts_table.sql (1 hunks)
  • scripts/deploy_erc20_katana.sh (1 hunks)
  • scripts/send_erc20_transfer.sh (1 hunks)
Files not reviewed due to no reviewable changes (1)
  • crates/torii/core/src/lib.rs
Files skipped from review due to trivial changes (1)
  • bin/torii/torii.toml
Files skipped from review as they are similar to previous changes (22)
  • crates/torii/core/Cargo.toml
  • crates/torii/core/src/processors/erc20_legacy_transfer.rs
  • crates/torii/core/src/processors/erc20_transfer.rs
  • crates/torii/core/src/processors/erc721_transfer.rs
  • crates/torii/core/src/processors/mod.rs
  • crates/torii/core/src/processors/store_set_record.rs
  • crates/torii/core/src/sql/erc.rs
  • crates/torii/core/src/sql/mod.rs
  • crates/torii/core/src/sql/query_queue.rs
  • crates/torii/core/src/sql/test.rs
  • crates/torii/core/src/sql/utils.rs
  • crates/torii/core/src/types.rs
  • crates/torii/graphql/src/tests/metadata_test.rs
  • crates/torii/graphql/src/tests/mod.rs
  • crates/torii/graphql/src/tests/subscription_test.rs
  • crates/torii/grpc/src/server/tests/entities_test.rs
  • crates/torii/libp2p/src/server/mod.rs
  • crates/torii/libp2p/src/tests.rs
  • crates/torii/migrations/20240913104418_add_erc.sql
  • crates/torii/migrations/20240918200125_rename_column_contracts_table.sql
  • scripts/deploy_erc20_katana.sh
  • scripts/send_erc20_transfer.sh
Additional comments not posted (12)
crates/torii/core/src/engine.rs (12)

9-9: Ohayo sensei! The join_all import looks good to me.

This import is necessary for the changes made in the fetch_range function to concurrently fetch events from multiple contracts.


12-14: Ohayo sensei! The additional imports from starknet::core::types are looking good.

These imports are necessary for the changes made to the Engine struct and related functions to support indexing ERC tokens.


26-27: Ohayo sensei! The imports from crate::sql and crate::types are looking good.

These imports are necessary for the changes made to the Engine struct and related functions to support indexing ERC tokens and managing database cursors.


33-33: Ohayo sensei! The change to the event field in the Processors struct is a great enhancement.

Allowing multiple event processors to be associated with a single event key improves the flexibility of event handling. This enables more complex processing scenarios where different processors can handle the same event type in different ways.


82-82: Ohayo sensei! The comment about the LinkedList order is a helpful addition.

The comment clarifies that the blocks in the LinkedList might not be in a specific order. This information is valuable for developers working with the FetchRangeResult struct to set the right expectations about the block order.


112-113: Ohayo sensei! The addition of the tokens field to the Engine struct is a key change.

The tokens field allows the engine to store and manage the ERC tokens that need to be indexed. This is a fundamental requirement for the new functionality of indexing specific ERC tokens.


Line range hint 123-132: Ohayo sensei! The modification to the Engine constructor to accept the tokens parameter is a necessary change.

By accepting the tokens parameter, the constructor allows the caller to provide the ERC tokens that need to be indexed. This ensures that the engine is initialized with the correct set of tokens to index.


Line range hint 204-298: Ohayo sensei! The changes in the fetch_range function to fetch events concurrently are a significant performance improvement.

By creating separate tasks for fetching events from each contract and using join_all to execute them concurrently, the function can efficiently retrieve events from multiple contracts in parallel. This can greatly reduce the overall time required to fetch events, especially when dealing with a large number of contracts.

The code segment also handles the processing of the fetched events, ensuring that already processed events are filtered out based on the last processed transaction for each contract. This prevents duplicate processing of events.

Overall, these changes enhance the performance and correctness of the event fetching process.


Line range hint 397-448: Ohayo sensei! The modifications to the process_pending function enhance the processing of pending transactions and their events.

The function now iterates over the transactions in the pending block and processes each transaction using the process_transaction_with_receipt function. This ensures that each transaction is properly handled and its events are processed individually.

The last_pending_block_tx and cursor_map variables are updated based on the processed transactions, allowing the function to keep track of the last processed transaction and the cursor for each contract. This is important for maintaining the correct state and avoiding duplicate processing.

Error handling is also implemented to handle scenarios where a transaction receipt is not found. In such cases, the function sets the appropriate cursors and returns early, preventing the processing from being halted.

These changes improve the robustness and reliability of the pending transaction processing logic.


Line range hint 457-478: Ohayo sensei! The updates to the process_range function enhance the processing of blocks and their transactions.

The function now iterates over the transactions in the data.transactions map and processes each transaction using the process_transaction_with_events function. This ensures that each transaction and its associated events are properly handled.

Additionally, the function processes each block using the process_block function. To avoid processing the same block multiple times, it maintains a processed_blocks set. This optimization prevents unnecessary duplicate processing of blocks.

If the block_tx channel is provided, the function sends the block number through the channel. This allows other parts of the system to be notified about the processed blocks, enabling further actions or synchronization based on the processed blocks.

These changes improve the efficiency and correctness of the block and transaction processing logic.


489-489: Ohayo sensei! The modification to reset the cursors in the process_range function is a necessary update.

After processing a range of blocks, it is important to reset the cursors to reflect the latest processed block. By calling the reset_cursors method of the db object with the latest_block_number, the function ensures that the cursors are properly updated.

This change maintains the consistency between the actual progress of block processing and the cursors stored in the database. It prevents any discrepancies and keeps the system in a valid state.


512-521: Ohayo sensei! The updates to the process_tasks function for handling parallelized events are a great addition.

Processing parallelized events allows for efficient utilization of system resources by leveraging multiple event processors concurrently. This can significantly improve the throughput and performance of event processing.

The function iterates over the processors.event map to retrieve the event processors associated with each event key. This ensures that each event is processed by its corresponding event processors, enabling customized processing logic for different event types.

By calling the process method on each event processor, the function triggers the specific processing logic defined for each event type. This flexibility allows for tailored handling of events based on their characteristics.

Furthermore, the function logs any errors that occur during event processing using the error macro. This aids in identifying and debugging issues, making it easier to diagnose and fix problems in the event processing pipeline.

Overall, these changes enhance the efficiency, customization, and observability of parallelized event processing.

Comment on lines +359 to +360
let contract_address = Felt::from_str(address).unwrap();
let start_block = start_block.parse::<u64>()?;
Copy link

Choose a reason for hiding this comment

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

Ohayo sensei! Let's handle those parsing errors gracefully.

Using unwrap when parsing the contract address can cause the application to panic if an invalid address is provided. It's better to propagate the error using the ? operator for a smoother experience.

Here's a suggestion:

-                let contract_address = Felt::from_str(address).unwrap();
+                let contract_address = Felt::from_str(address)?;

Apply the same change to line 365 for consistency.

Also applies to: 365-366

@rsodre
Copy link

rsodre commented Sep 20, 2024

Although I am curious how does game use ERC1155, do they mainly need one ERC20 and multiplle ERC721, or just multiple ERC20s?

Usually, ERC1155 are used as consumables. A single token can have multiple copies owned by multiple accounts

Copy link
Collaborator

@glihm glihm left a comment

Choose a reason for hiding this comment

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

For now due to legacy format of the tokens, we don't know if it's ERC721 or ERC20 for the transfer as only the selector of the event is used.

We should see how complex it is to leverage the token type (world/erc20/erc721) to actually scope the map of processors.

@rsodre
Copy link

rsodre commented Sep 20, 2024

and don't forget that name() and symbol() can return a felt252 or a ByteArray

@lambda-0x
Copy link
Collaborator Author

@rsodre thanks for pointing this out, we already handle this.

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.

3 participants