Skip to content

Persistent mode for saya using mock of SNOS - #2253

Merged
glihm merged 61 commits into
dojoengine:mainfrom
neotheprogramist:saya/settle-katana
Oct 9, 2024
Merged

Persistent mode for saya using mock of SNOS#2253
glihm merged 61 commits into
dojoengine:mainfrom
neotheprogramist:saya/settle-katana

Conversation

@matzayonc

@matzayonc matzayonc commented Aug 2, 2024

Copy link
Copy Markdown
Collaborator

Description

I added a Cairo 1 program simulating SNOS, committing to piltover.

Related issue

Tests

The full development flow is in this script: bin/saya/saya.sh.

  • Yes
  • No, because they aren't needed
  • No, because I need help

Added to documentation?

  • README.md
  • Dojo Book
  • No documentation needed

Checklist

  • I've formatted my code (scripts/prettier.sh, scripts/rust_fmt.sh, scripts/cairo_fmt.sh)
  • I've linted my code (scripts/clippy.sh, scripts/docs.sh)
  • I've commented my code
  • I've requested a review after addressing the comments

Summary by CodeRabbit

  • New Features

    • Introduced flexible dependency management for improved maintenance and future updates.
    • Enhanced command-line interface with new and modified flags for better clarity and usability, including options for settlement modes.
    • Implemented structured options for operational modes and contract addresses.
    • Added batch processing capabilities and improved transaction handling for StarkNet interactions.
    • Introduced new configuration parameters for block processing and proof generation.
    • Streamlined deployment process with updated manifest files reflecting new deployment addresses.
    • Added support for new proving programs and enhanced handling of Cairo versions.
    • Introduced a new error handling structure for better reporting and debugging.
    • Added a new method for publishing checkpoints to the data availability layer.
    • Enhanced documentation for Saya CLI, detailing usage and setup instructions.
    • Added a new asynchronous function for monitoring transaction status until completion.
  • Bug Fixes

    • Resolved previous workaround regarding world_address, enhancing deployment instructions.
  • Documentation

    • Updated README with expanded deployment instructions and command-line options.
    • Revised configuration files to reflect new operational parameters and batch processing settings.
  • Chores

    • Cleaned up unused imports and improved code readability across various modules.
    • Restructured and clarified documentation for better user guidance.

@matzayonc
matzayonc requested a review from glihm August 2, 2024 11:43
Comment thread bin/saya/README.md Outdated
Comment thread bin/saya/src/args/shard.rs Outdated
pub struct SayaModeArg(pub SayaMode);

#[derive(Debug, Args, Clone)]
pub struct ShardOptions {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should think how the terminology will be separated, as shard is mostly for ephemeral execution and persistent execution is done in a different manner at some point.
Or the name shouldn't be piltover but settlement_contract which can be the world for shards and piltover for persistency.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Sure, that makes sense.

Comment thread bin/saya/src/args/shard.rs Outdated
&[
SayaModeArg(SayaMode::Ephemeral),
SayaModeArg(SayaMode::Persistent),
SayaModeArg(SayaMode::PersistentMerging),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What is this one? sovereign?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

So the one using the merger program recursively should be soverein?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hum, then no. It's something unrelated. I wasn't sure why we had a persistent and persistent merging. Seems to be only at provable program layer, right?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It changes the program flow in both merging and updating state. It is a different program, so it produces a different output. I think at this point PersistentMerging should be treated as a sort of legacy program, as it is still useful, but Persistent is a newer, "sounder" way to prove state.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's remove PersistentMerging if it's not used anymore?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Removed

Comment thread bin/saya/src/main.rs

// Wait until Ctrl + C is pressed, then shutdown
ctrl_c().await?;
// ctrl_c().await?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not required anymore to be able to kill the program? Or it's handled by the .start() function?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Not required, as the ephemeral shard will shut itself down after reaching the shutdown event.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah but we may want to kill saya. :) In this case it would be better keeping it to ensure graceful shutdown in case of manual interruption.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It is the opposite, this line simply prevents saya from closing until ctrl+c is pressed. Now we do the same thing by simply not returning from the start function until all the blocks are prover (for ephemeral shard).
A graceful shutdown would have to be implemented there.

use crate::{SayaStarknetAccount, LOG_TARGET};

#[derive(Debug, Serialize)]
pub struct PiltoverCalldata {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure if the cainome bindgen is already integrated to piltover. But if yes, we should use it to already have concrete types in rust that are automatically serializable in cairo.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Looks to me like it is integrated, will use it as a dependcy.

By the way those are automatically serializable, as they use serde_felt from this PR: cartridge-gg/cairo-proof-parser#10.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It doesn't seem to be working at the moment. Create a bug report here: keep-starknet-strange/piltover#39

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for that, I'll have a look at it to ensure it works as it will be better to rely on generated code.

Are we using a fork of piltover or the original contract?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Comment thread crates/saya/core/src/lib.rs Outdated
to: c.to,
selector: c.selector,
calldata: c.calldata,
starknet_messages: Vec::new(), // TODO: Fill messages.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This should be done in a subsequent PR, or could be done in this one? The messages are or L1HandlerTransaction or available into the receipts.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Should be trivial to implement, but might be less so to test it, that why I left it for now to avoid a false positive.
This PR is quite big already so I would leave it for the following out, unless you think otherwise.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sounds great in a follow up PR. 👍

cairo_version: Felt,
account: &SayaStarknetAccount,
) -> anyhow::Result<(String, Felt)> {
if serialized_proof.len() > 2000 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

isn't 4000 the limit?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I exprienced that some transactions failed when greater than 3000, but can test further now that it's in a more mature state.

let mut nonce = account.get_nonce().await?;
let mut hashes = Vec::new();

for fragment in serialized_proof.into_iter().chunks(2000).into_iter() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If a fragment upload fail, do we have a way that saya can make a call on the chain to resume from where it was?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Not at the moment, but should be pretty straight forward to implement.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same then let's keep that in the track for a follow up PR to be implemented to ensure more reliable settlement.

@codecov

codecov Bot commented Aug 29, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 19.20821% with 551 lines in your changes missing coverage. Please review.

Project coverage is 68.54%. Comparing base (e591364) to head (e47f0d1).
Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
crates/saya/core/src/lib.rs 0.00% 189 Missing ⚠️
crates/saya/core/src/prover/client.rs 0.00% 56 Missing ⚠️
crates/saya/core/src/verifier/starknet.rs 0.00% 52 Missing ⚠️
crates/saya/core/src/prover/mod.rs 0.00% 41 Missing ⚠️
crates/saya/core/src/verifier/utils.rs 0.00% 30 Missing ⚠️
bin/saya/src/args/mod.rs 75.47% 26 Missing ⚠️
...es/saya/core/src/data_availability/celestia/mod.rs 0.00% 25 Missing ⚠️
bin/saya/src/args/settlement.rs 0.00% 24 Missing ⚠️
crates/saya/core/src/dojo_os/piltover.rs 0.00% 24 Missing ⚠️
crates/saya/core/src/dojo_os/mod.rs 0.00% 22 Missing ⚠️
... and 7 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2253      +/-   ##
==========================================
+ Coverage   67.73%   68.54%   +0.80%     
==========================================
  Files         388      387       -1     
  Lines       50421    49902     -519     
==========================================
+ Hits        34153    34203      +50     
+ Misses      16268    15699     -569     

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

@matzayonc
matzayonc requested a review from glihm August 29, 2024 16:31
@matzayonc matzayonc self-assigned this Aug 29, 2024

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (4)
crates/saya/core/src/lib.rs (4)

14-14: Ohayo, sensei! The new imports look great!

The additions from itertools, prover, and starknet crates align well with the new functionality. The public re-export of ProverAccessKey is a nice touch for API usability.

Consider grouping related imports together for better readability. For example, you could group all starknet-related imports.

Also applies to: 19-22, 26-32


60-63: Ohayo, sensei! The SayaConfig struct has evolved nicely!

The new mode and settlement_contract fields, along with the more flexible block_range, align well with the PR objectives. These changes enhance the configurability of the Saya system.

Consider adding documentation comments for the new fields to explain their purpose and expected values. This will help users understand how to configure Saya correctly.


93-96: Ohayo, sensei! The Saya struct has gained some new superpowers!

The addition of prover_identifier, prev_commitment, and prev_height fields enhances Saya's capabilities for proving and state tracking. The initialization in the new method looks good.

Consider adding comments to explain the purpose of prev_commitment and prev_height, as their roles might not be immediately clear to newcomers.

Also applies to: 126-139


Line range hint 151-279: Ohayo, sensei! The start method has become a true master of ceremonies!

The refactoring to support different modes of operation and batch processing is impressive. The error handling and logging improvements are also great additions.

However, the method has grown quite complex. Consider breaking it down into smaller, more focused methods to improve readability and maintainability. For example:

  1. Extract the mode-specific logic into separate methods.
  2. Create a helper method for block fetching and processing.
  3. Move the proof generation and processing logic into a separate method.

This refactoring would make the start method easier to understand and maintain.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between a65bb40 and 5356d15.

📒 Files selected for processing (1)
  • crates/saya/core/src/lib.rs (13 hunks)
🧰 Additional context used
🔇 Additional comments (1)
crates/saya/core/src/lib.rs (1)

Line range hint 1-573: Ohayo, sensei! Overall, the changes to the Saya core library are impressive!

The introduction of different operational modes, enhanced StarkNet integration, and improved block processing align well with the PR objectives. The code structure and new functionality demonstrate a significant step forward for the Saya system.

However, there are a few areas that could benefit from further attention:

  1. The start method has become quite complex and could be refactored for better maintainability.
  2. There are some TODOs and commented-out code that need to be addressed.
  3. The StarknetAccountData struct could be improved for better security.
  4. Some methods could benefit from additional error handling and documentation.

Addressing these points will further enhance the quality and robustness of the codebase. Great work on this substantial update, sensei!

Comment on lines +426 to +522
async fn process_proven(
&mut self,
proof: ProverResult,
state_diff: Vec<Felt>,
last_block: u64,
state_roots: (Felt, Felt),
) -> SayaResult<()> {
trace!(target: LOG_TARGET, last_block, "Processing proven blocks.");

if self.config.store_proofs {
let filename = format!("proof_{}.json", last_block);
let mut file = File::create(filename).await.context("Failed to create proof file.")?;
file.write_all(proof.as_bytes()).await.context("Failed to write proof.")?;
}

let serialized_proof: Vec<Felt> = parse(&proof)?.into();
let world_da = state_diff.world_da.unwrap();

// Publish state difference if DA client is available
let serialized_proof = proof.serialized_proof;
// Publish state difference if DA client is available.
if let Some(da) = &self.da_client {
trace!(target: LOG_TARGET, last_block, "Publishing DA.");

if self.config.skip_publishing_proof {
da.publish_state_diff_felts(&world_da).await?;
let checkpoint = PublishedStateDiff {
prev_state_root: state_roots.0,
state_root: state_roots.1,
prev_height: self.prev_height,
prev_commitment: self.prev_commitment,
proof: serde_json::to_value(&proof.proof).unwrap(),
};
// let ns = Namespace::new_v0(b"saya-dev").unwrap();
// let commitment = Commitment::from_blob(ns, 0, &serialized_proof.iter().map(|felt|
// felt.to_bytes()).collect::<Vec<_>>());
let (commitment, height) = if self.config.mode != SayaMode::Ephemeral {
da.publish_checkpoint(checkpoint).await?
} else if self.config.skip_publishing_proof {
da.publish_state_diff_felts(&state_diff).await?
} else {
da.publish_state_diff_and_proof_felts(&world_da, &serialized_proof).await?;
}
da.publish_state_diff_and_proof_felts(&state_diff, &serialized_proof).await?
};
self.prev_commitment = Some(commitment);
self.prev_height = Some(height);

info!(target: LOG_TARGET,"commitment: {:?}, height: {:?}", commitment.0, height);
}

let program_hash = proof.program_hash;
let program_output_hash = proof.program_output_hash;
let program_output = proof.program_output;

let program_hash_string = program_hash;
let program_output_hash_string = program_output_hash;

info!(target: LOG_TARGET,"Extracted program hash and output hash. {:?} {:?}", program_hash_string, program_output_hash_string);
let expected_fact = poseidon_hash_many(&[program_hash, program_output_hash]).to_string();
let program = program_hash.to_string();
info!(target: LOG_TARGET, expected_fact, program, "Expected fact.");

let starknet_account = self.config.starknet_account.get_starknet_account()?;

// Verify the proof and register fact.
trace!(target: LOG_TARGET, last_block, "Verifying block.");
let (transaction_hash, nonce_after) = verifier::verify(
let (transaction_hash, _nonce) = verifier::verify(
VerifierIdentifier::HerodotusStarknetSepolia(self.config.fact_registry_address),
serialized_proof,
self.config.starknet_account.clone(),
&starknet_account,
self.config.mode.to_program().cairo_version(),
)
.await?;
info!(target: LOG_TARGET, last_block, transaction_hash, "Block verified.");

let ExtractProgramResult { program: _, program_hash } = extract_program(&proof)?;
let ExtractOutputResult { program_output, program_output_hash } = extract_output(&proof)?;
let expected_fact = poseidon_hash_many(&[program_hash, program_output_hash]).to_string();
info!(target: LOG_TARGET, expected_fact, "Expected fact.");

// When not waiting for couple of second `apply_diffs` will sometimes fail due to reliance
// on registered fact
tokio::time::sleep(std::time::Duration::from_secs(2)).await;

trace!(target: LOG_TARGET, last_block, "Applying diffs.");
let transaction_hash = dojo_os::starknet_apply_diffs(
self.config.world_address,
world_da,
program_output,
program_hash,
nonce_after + Felt::ONE,
self.config.starknet_account.clone(),
)
.await?;
info!(target: LOG_TARGET, last_block, transaction_hash, "Diffs applied.");

// Apply the diffs to the world state.
match self.config.mode {
SayaMode::Ephemeral => {
// Needs checker program to be verified, and set as the upgrade_state authority
todo!("Ephemeral mode does not support publishing updated state yet.");
}
SayaMode::Persistent => {
let serialized_output = program_output.iter().copied().collect_vec();
println!("serialized_output: {:?}", serialized_output);

// todo!("Persistent mode does not support publishing updated state with SNOS
// yet.");

let deduplicated_output =
serialized_output[1..serialized_output.len() / 2].to_vec();
let batcher_output = from_felts::<StarknetOsOutput>(&deduplicated_output).unwrap();
let piltover_calldata = PiltoverCalldata {
program_output: serialized_output,
// onchain_data_hash: batcher_output.new_state_root,
onchain_data_hash: batcher_output.new_block_hash,
onchain_data_size: (Felt::ZERO, Felt::ZERO),
};

let expected_state_root = batcher_output.new_block_hash.to_string();
let expected_block_number =
(batcher_output.new_block_number - Felt::ONE).to_string();
info!(target: LOG_TARGET, last_block, expected_state_root, expected_block_number, "Applying snos to piltover.");

starknet_apply_piltover(
piltover_calldata,
self.config.settlement_contract,
&starknet_account,
)
.await?;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo, sensei! The process_proven method is a true proof master!

The implementation for publishing state differences and verifying proofs looks solid. Great job on supporting different modes of operation!

However, there are a few areas that need attention:

  1. There's a TODO comment for the Ephemeral mode (line 491). This needs to be implemented.
  2. There's a commented-out line for onchain_data_hash (line 505). Decide whether to use this or remove it.
  3. The error handling for from_felts (line 502) uses unwrap(), which could lead to panics. Consider using ? or proper error handling.

Please address these issues to ensure the robustness of the process_proven method.

Comment on lines +548 to +573
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct StarknetAccountData {
pub starknet_url: Url,
#[serde(deserialize_with = "felt_string_deserializer")]
pub chain_id: Felt,
pub signer_address: Felt,
pub signer_key: Felt,
}

impl StarknetAccountData {
pub fn get_starknet_account(&self) -> anyhow::Result<SayaStarknetAccount> {
let provider = JsonRpcClient::new(HttpTransport::new(self.starknet_url.clone()));
let signer = LocalWallet::from(SigningKey::from_secret_scalar(self.signer_key));

let mut account = SingleOwnerAccount::new(
provider,
signer,
self.signer_address,
self.chain_id,
ExecutionEncoding::New,
);

account.set_block_id(BlockId::Tag(BlockTag::Pending));
Ok(account)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo, sensei! The StarknetAccountData struct is a nice addition, but let's talk security!

The implementation of StarknetAccountData and its get_starknet_account method improves the handling of StarkNet account information. However, there's a potential security concern:

Storing the signer_key directly in the struct might expose sensitive information. Consider using a more secure method for handling the signer key, such as:

  1. Using a separate, encrypted storage for the key.
  2. Implementing a method to securely retrieve the key when needed, possibly requiring user input for decryption.

Here's a conceptual example:

pub struct StarknetAccountData {
    pub starknet_url: Url,
    #[serde(deserialize_with = "felt_string_deserializer")]
    pub chain_id: Felt,
    pub signer_address: Felt,
    // Remove the signer_key field
}

impl StarknetAccountData {
    pub fn get_starknet_account(&self, key_provider: &dyn SecureKeyProvider) -> anyhow::Result<SayaStarknetAccount> {
        let provider = JsonRpcClient::new(HttpTransport::new(self.starknet_url.clone()));
        let signer_key = key_provider.get_signer_key()?; // Securely retrieve the key
        let signer = LocalWallet::from(SigningKey::from_secret_scalar(signer_key));

        // ... rest of the method ...
    }
}

This approach would enhance the security of the sensitive signer key.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (4)
bin/saya/src/args/mod.rs (4)

49-50: Ohayo! The SayaArgs struct is leveling up, sensei!

The new end_block field and the settlement options are great additions that provide more flexibility in controlling block processing and settlement. The conflict between batch_size and end_block is a smart move to prevent inconsistencies.

One small suggestion:

Consider adding a comment explaining why batch_size and end_block are mutually exclusive. This will help future developers understand the reasoning behind this constraint.

/// The number of blocks to be merged into a single proof.
/// This option conflicts with `end_block` to ensure consistent batch processing.
#[arg(conflicts_with = "end_block")]
pub batch_size: usize,

Also applies to: 54-60


100-193: Ohayo, sensei! The try_from implementation is looking sharp!

The new logic for handling DataAvailabilityConfig, private keys, and settlement options is well-implemented. The validation for batch_size in persistent mode is a crucial addition to ensure correct behavior.

However, I have a small suggestion to improve error handling consistency:

Consider using a custom error type instead of Box<dyn std::error::Error> for more specific error handling. This would make it easier to handle different error cases and provide more informative error messages to users.

For example:

#[derive(thiserror::Error, Debug)]
enum SayaConfigError {
    #[error("Celestia config: {0}")]
    CelestiaConfig(String),
    #[error("Invalid input: {0}")]
    InvalidInput(String),
    // Add more error variants as needed
}

impl TryFrom<SayaArgs> for SayaConfig {
    type Error = SayaConfigError;

    fn try_from(args: SayaArgs) -> Result<Self, Self::Error> {
        // Use the custom error type in your implementation
        // For example:
        // Err(SayaConfigError::CelestiaConfig("Node url is required".to_string()))
    }
}

This approach would make error handling more robust and easier to maintain as the codebase grows.


Line range hint 199-297: Ohayo! The test case is looking good, sensei!

The updates to the test case accurately reflect the changes in the structs and implementation. Good job on maintaining test coverage!

To make your tests even more robust, consider adding these additional test cases:

  1. Test the validation of batch_size in persistent mode:
#[test]
fn test_batch_size_validation_in_persistent_mode() {
    let args = SayaArgs {
        // ... other fields ...
        batch_size: 2,
        settlement: SettlementOptions {
            saya_mode: settlement::SayaModeArg(SayaMode::Persistent),
            // ... other fields ...
        },
        // ... other fields ...
    };

    let result: Result<SayaConfig, _> = args.try_into();
    assert!(result.is_err());
    assert!(result.unwrap_err().to_string().contains("Batch size must be 1 for persistent mode"));
}
  1. Test the mutual exclusivity of batch_size and end_block:
#[test]
fn test_batch_size_and_end_block_conflict() {
    let args = SayaArgs {
        // ... other fields ...
        batch_size: 10,
        end_block: Some(100),
        // ... other fields ...
    };

    let result: Result<SayaConfig, _> = args.try_into();
    assert!(result.is_err());
    assert!(result.unwrap_err().to_string().contains("The argument '--batch-size <BATCH_SIZE>' cannot be used with '--end-block <END_BLOCK>'"));
}

These additional tests will help ensure that the new constraints and validations are working as expected.


169-177: Ohayo, sensei! The settlement_contract validation is on point!

The addition of the settlement_contract field and its validation for persistent mode is crucial. Great job on ensuring this important requirement is met!

To make the error message even more helpful:

Consider updating the error message to be more specific about the requirement:

return Err(SayaConfigError::InvalidInput(
    "A `settlement_contract` must be specified when using persistent mode.".to_string()
));

This more detailed message will help users understand exactly what they need to provide when using persistent mode.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 3d6be35 and 9ac3bdf.

📒 Files selected for processing (1)
  • bin/saya/src/args/mod.rs (6 hunks)
🧰 Additional context used
🔇 Additional comments (2)
bin/saya/src/args/mod.rs (2)

6-7: Ohayo, sensei! The new imports and module look good!

The addition of SayaMode and SettlementOptions imports, along with the new settlement module, aligns well with the introduction of settlement-related functionality. Nice work on keeping the code structure organized!

Also applies to: 21-21


Line range hint 1-297: Ohayo, sensei! Your code is evolving beautifully!

Overall, the changes to this file significantly enhance the Saya configuration process. The new settlement options, block range controls, and data availability configurations provide great flexibility for users. The added validations, especially for the persistent mode and settlement_contract, help prevent misconfigurations.

Here's a summary of the improvements:

  1. Enhanced SayaArgs struct with new options
  2. Improved try_from implementation with robust error checking
  3. Updated test cases to cover new functionality

To take your code to the next level, consider:

  1. Implementing a custom error type for more specific error handling
  2. Adding a few more test cases to cover edge cases
  3. Improving some error messages for clarity

Great work on evolving the Saya tool, sensei! These changes will definitely improve the user experience and make the tool more powerful.

Comment thread bin/saya/src/args/mod.rs
Comment on lines +49 to +50
#[arg(short, long)]
pub end_block: Option<u64>,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo, sensei! Let's add a quick check for end_block!

The addition of the end_block field is a great improvement for flexibility. However, to prevent potential issues, we should ensure that end_block is greater than or equal to start_block when it's provided.

Consider adding this validation in the try_from implementation:

if let Some(end_block) = args.end_block {
    if end_block < args.start_block {
        return Err(SayaConfigError::InvalidInput(
            "`end_block` must be greater than or equal to `start_block`".to_string()
        ));
    }
}

This check will help prevent invalid block ranges and potential runtime errors.

Also applies to: 184-184

@glihm
glihm merged commit 4fb8f3f into dojoengine:main Oct 9, 2024
@coderabbitai coderabbitai Bot mentioned this pull request Oct 23, 2024
10 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Jul 8, 2025
10 tasks
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.

5 participants