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

Initial Transaction Validations #129

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

yHSJ
Copy link
Contributor

@yHSJ yHSJ commented Feb 27, 2025

This PR introduces some initial transaction validations for the block validation

Summary by CodeRabbit

  • New Features

    • Updated the public transaction interface with new utility types and refined output types.
    • Enhanced block validation by incorporating detailed transaction validation checks.
    • Organised transaction validations into modular components for improved error reporting.
    • Introduced new validation logic for transaction metadata and output sizes.
  • Chores

    • Added a new workspace dependency for better project management.

Copy link

coderabbitai bot commented Feb 27, 2025

Walkthrough

The changes introduce enhancements to transaction validation across several modules. In the kernel crate, new types such as Bytes, PseudoTransactionOutput, and TransactionBody are added to the public re-exports. The ledger crate sees the addition of a transaction module, which includes a new enum for transaction rule violations and functions for validating transactions. This integration improves the overall block validation process by ensuring that transactions meet specific criteria regarding inputs and outputs.

Changes

File(s) Change Summary
crates/amaru-kernel/src/lib.rs Updated re-exports: added Bytes, PseudoTransactionOutput, and TransactionBody.
crates/amaru-ledger/src/rules.rs Introduced new module transaction, added enum TransactionRuleViolation, and implemented validate_transaction function for transaction checks.
crates/amaru-ledger/src/rules/transaction/disjoint_ref_inputs.rs Added module with NonDisjointRefInputs struct, its conversion to TransactionRuleViolation, and function disjoint_ref_inputs for validating inputs.
crates/amaru-ledger/src/rules/transaction/mod.rs Registered new public modules: disjoint_ref_inputs, metadata, and output_size.
crates/amaru-ledger/src/rules/transaction/output_size.rs Added module defining OutputTooSmall struct with conversion to TransactionRuleViolation and implemented validate_output_size for output size validation.
crates/amaru-ledger/src/rules/transaction/metadata.rs Introduced InvalidTransactionMetadata enum for metadata validation errors and validate_metadata function for checking transaction metadata.
crates/amaru-kernel/Cargo.toml Added dependency: pallas-traverse.workspace = true.

Sequence Diagram(s)

sequenceDiagram
    participant BV as BlockValidator
    participant VT as validate_transaction
    participant DRI as disjoint_ref_inputs
    participant OS as validate_output_size
    participant MD as validate_metadata
    BV->>VT: validate_transaction(tx_body, witness_set, protocol_params)
    VT->>DRI: disjoint_ref_inputs(tx_body)
    DRI-->>VT: Return ok/error for disjoint inputs
    VT->>OS: validate_output_size(tx_body, protocol_params)
    OS-->>VT: Return ok/error for output size
    VT->>MD: validate_metadata(tx_body, auxiliary_data)
    MD-->>VT: Return ok/error for metadata
    VT-->>BV: Return Ok / TransactionRuleViolation (InvalidTransaction)
Loading

Suggested reviewers

  • KtorZ
  • abailly

Poem

In the land of code where logic flows,
New types and checks, oh how it grows!
Transactions validated, no more strife,
With rules in place, we dance through life!
Cheers to the changes, let’s raise a cheer,
For cleaner code and a brighter year!
🎉✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
crates/amaru-ledger/src/rules/transaction/disjoint_ref_inputs.rs (1)

9-13: Alternative Conversion Recommendation
Using impl From<NonDisjointRefInputs> for TransactionRuleViolation might be more idiomatic than impl Into. Consider turning that commented code back on, dear chum!

Here’s a potential tweak:

-impl Into<TransactionRuleViolation> for NonDisjointRefInputs {
+impl From<NonDisjointRefInputs> for TransactionRuleViolation {
     fn from(value: NonDisjointRefInputs) -> Self {
         TransactionRuleViolation::NonDisjointRefInputs(value)
     }
 }
crates/amaru-ledger/src/rules/transaction/output_size.rs (1)

17-53: Handle Serialization Error More Politely
The panic! on serialisation failure could rattle unsuspecting users if it’s triggered. Might be best to return a bespoke error. Otherwise, the rest is top-notch, especially the logic around coin size checks—cracking work!

Here’s a possible approach for gentler error handling:

 cbor::encode(output, &mut bytes)
-    .unwrap_or_else(|_| panic!("Failed to serialize output"));
+    .map_err(|_| {
+        // Return a descriptive error or perhaps wrap it in your custom type
+        OutputTooSmall { outputs_too_small: vec![output.clone()] }
+    })?;
crates/amaru-ledger/src/rules.rs (3)

59-59: Consider avoiding unnecessary data cloning.

You’re cloning block.transaction_witness_sets before de-structuring it. If the structure’s not massive or if you only need read access, you could reference it directly, saving a few bytes.


97-116: Check those TODOs to shore up the logic.

  1. If a witness set is missing for a transaction, you skip it—are you sure no error is needed? Might be worth verifying.
  2. The placeholder zeroed-out transaction_hash should eventually be replaced by the real McCoy to make error reports more helpful.

Happy to offer help implementing the transaction hash retrieval or refining the skip logic if needed—just let me know, mate.


121-131: Unused _is_valid parameter.

Since _is_valid is never used, it might puzzle future readers. You could remove it or incorporate a check to short-circuit on known invalid transactions.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between bf28513 and a511d4e.

📒 Files selected for processing (5)
  • crates/amaru-kernel/src/lib.rs (1 hunks)
  • crates/amaru-ledger/src/rules.rs (5 hunks)
  • crates/amaru-ledger/src/rules/transaction/disjoint_ref_inputs.rs (1 hunks)
  • crates/amaru-ledger/src/rules/transaction/mod.rs (1 hunks)
  • crates/amaru-ledger/src/rules/transaction/output_size.rs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • crates/amaru-ledger/src/rules/transaction/mod.rs
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build on windows-latest with target x86_64-pc-windows-msvc
  • GitHub Check: Build on ubuntu-latest with target riscv32im-risc0-zkvm-elf
🔇 Additional comments (16)
crates/amaru-kernel/src/lib.rs (1)

40-42: Spiffing Re-exports!
Bringing in PseudoTransactionOutput and TransactionBody in place of MintedTransactionOutput looks grand. It neatly aligns with the new transaction validation enhancements. Keep this approach up!

crates/amaru-ledger/src/rules/transaction/disjoint_ref_inputs.rs (3)

1-3: Imports Look Spot-On!
Everything is hunky-dory here. Nothing to quibble over. Move along confidently!


5-7: Nicely Named Struct
NonDisjointRefInputs may sound a tad negative, but it’s crystal clear in its intent. Good on you for clarity!


21-36: Intersection Detection Works a Treat
This function elegantly identifies intersecting inputs. Splendid job! Everything looks properly well-structured.

crates/amaru-ledger/src/rules/transaction/output_size.rs (3)

1-3: Importing the Essentials
The necessary items for transaction output checks are graciously gathered here. No fuss whatsoever!


7-9: A Spot-On Struct
OutputTooSmall clarifies its purpose in a jiffy. Good naming, mate!


11-15: Consistent Error Conversion
Your Into<TransactionRuleViolation> implementation deftly parallels the pattern from other rule violations. Jolly good!

crates/amaru-ledger/src/rules.rs (9)

2-2: Top-notch module separation, mate!

Introducing the transaction module here helps keep everything tidy and compartmentalised. No worries from my end.


6-6: Neat addition of these items from the kernel crate.

Pulling in MintedBlock, Redeemers, TransactionBody, WitnessSet is perfectly grand, as it sets the stage for your transaction logic.


15-16: Good on you for splitting up transaction checks into their own modules.

This modular approach for disjoint_ref_inputs and output_size is a beaut—makes the code a smidgen easier to organise and maintain.


18-22: Enum structure looks well-structured.

Lovely to see BlockValidationError enumerated so thoroughly. This is a pretty straightforward approach, helps keep error handling crisp.


28-32: Detailed error variant for invalid transactions.

Storing the transaction hash, index, and the specific violation in InvalidTransaction is a smashing idea. This will provide clarity in debugging.


35-37: Great approach to categorising transaction rule violations.

Defining each specific error type (NonDisjointRefInputs and OutputTooSmall) makes it practically impossible to mix them up. Right as rain!


79-82: Handy extraction of transactions.

Matching on MaybeIndefArray to unify data into a simple vector is quite neat. Crikey, no problems spotted here.


84-87: Witness sets neatly retrieved.

Again, the pattern matching approach is consistent, which keeps the code easy to follow.


89-95: Good fallback for when invalid transactions are absent.

Skipping gracefully to an empty list prevents blow-ups in your loop below. Spot on!

pub intersection: Vec<TransactionInput>,
}

impl Into<TransactionRuleViolation> for NonDisjointRefInputs {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I attempted to implement the From trait here instead, but I ran into a strange rustc error I'm still working on debugging.

@yHSJ yHSJ force-pushed the jshy/block-validation branch from 5fd7757 to 0f70c7e Compare February 28, 2025 15: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: 0

🧹 Nitpick comments (2)
crates/amaru-ledger/src/rules.rs (2)

105-109: Consider error handling for missing witness sets

The current implementation simply skips transactions without a witness set. Is this the intended behavior? If a transaction is expected to have a witness set but doesn't, this might indicate a problem that should be reported rather than silently skipped.

Consider whether this warrants an error or at least a warning log.

- let witness_set = match witness_sets.get(i as usize) {
-     Some(witness_set) => witness_set,
-     None => continue,
- };
+ let witness_set = match witness_sets.get(i as usize) {
+     Some(witness_set) => witness_set,
+     None => {
+         // Only skip if this is expected behavior, otherwise consider returning an error
+         tracing::warn!("Transaction at index {} has no witness set", i);
+         continue;
+     }
+ };

106-106: Address TODO comment for type conversion

This TODO comment flagging the as cast suggests potential issues with the type conversion. Worth addressing this to ensure proper error handling for potential overflows if i becomes a large value.

This could potentially lead to an integer overflow if the transaction index exceeds usize::MAX, though that's unlikely in practice.

- // TODO handle `as` correctly
- let witness_set = match witness_sets.get(i as usize) {
+ let witness_set = match usize::try_from(i).map_err(|_| {
+     BlockValidationError::RuleViolations(vec![RuleViolation::InvalidTransaction {
+         transaction_hash: raw_transaction.original_hash(),
+         transaction_index: i,
+         violation: TransactionRuleViolation::IndexOutOfRange, // Would need to add this variant
+     }])
+ }).and_then(|idx| Ok(witness_sets.get(idx))) {
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5fd7757 and 0f70c7e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • crates/amaru-kernel/Cargo.toml (1 hunks)
  • crates/amaru-kernel/src/lib.rs (1 hunks)
  • crates/amaru-ledger/src/rules.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/amaru-kernel/Cargo.toml
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build on ubuntu-latest with target riscv32im-risc0-zkvm-elf
  • GitHub Check: Build on windows-latest with target x86_64-pc-windows-msvc
🔇 Additional comments (10)
crates/amaru-kernel/src/lib.rs (2)

40-42: Updated the re-exports to support transaction validation

Good job on updating the public re-exports to include PseudoTransactionOutput and replace MintedTransactionOutput with TransactionBody. This is a sensible change that aligns with the PR objectives of introducing transaction validations.

Just make sure all existing code that was using MintedTransactionOutput has been properly migrated to use TransactionBody instead. This change will ripple through anywhere that imported the old type.


46-47: Added OriginalHash from pallas_traverse

Nice addition of the OriginalHash trait which will be useful for getting transaction hashes in the validation logic. Good to see this being properly exported through the anti-corruption layer.

crates/amaru-ledger/src/rules.rs (8)

2-2: Added new transaction module

Good addition of the transaction module. This is a nice clean way to organize the new transaction validation functionality.


15-16: Imported transaction validation functions

Great job importing the specific validation functions from the transaction submodules. This approach keeps the code organized while making the validation functions directly accessible in the rules module.


28-32: Added InvalidTransaction variant to RuleViolation

Nice implementation of the InvalidTransaction variant which captures all the necessary context (hash, index, and specific violation). This gives you plenty of information for debugging when validation fails.


35-38: Added TransactionRuleViolation enum

Good job creating a specific enum for transaction rule violations. This gives you a nice extensible structure to add more validation rules in the future while keeping error reporting clean and specific.


79-101: Enhanced block validation with transaction processing

Well-structured code to extract the relevant transaction information from the block. The pattern matching approach is consistent with the rest of the codebase.


127-137: New validate_transaction function

The validate_transaction function is a good start for transaction validation. The unused parameters (_witness_set and _is_valid) with leading underscores indicate planned future enhancements, which is fine for initial transaction validations.

As you expand the validation rules in the future, you'll likely make use of these parameters. For now, it's clear these are intentionally unused.


113-122: Good error handling for transaction validation

Well done on the comprehensive error handling that includes the transaction hash and index in the error. This will make debugging much easier when validation fails on a specific transaction.


133-134: Initial transaction validation rules

Nice implementation of the first two transaction validation rules. You've created a good foundation to easily add more validation rules in the future. The implementation is clean and follows a consistent pattern.

For debugging purposes, you might want to consider adding a bit more context like specific values in the error types, but this is a solid start.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
crates/amaru-ledger/src/rules/transaction/metadata.rs (2)

20-24: Remove or document the commented-out From implementation

You've already got the Into trait implementation, which makes this commented-out From implementation redundant. Better to either remove it entirely or add a comment explaining why it's being kept for future reference.

-// impl From<InvalidTransactionMetadata> for TransactionRuleViolation {
-//     fn from(value: InvalidTransactionMetadata) -> Self {
-//         TransactionRuleViolation::InvalidTransactionMetadata(value)
-//     }
-// }

28-28: Fix typo in parameter name: "auxilary_data" → "auxiliary_data"

There's a wee spelling mistake in the parameter name - missing an "i" in "auxiliary". Small thing, but worth fixing for consistency.

-    auxilary_data: Option<AuxiliaryData>,
+    auxiliary_data: Option<AuxiliaryData>,
crates/amaru-ledger/src/rules.rs (2)

132-139: Add documentation for the validate_transaction function

This function would benefit from some documentation explaining its purpose, parameters, and return value. Especially since some parameters have leading underscores indicating they're not currently used.

Consider adding documentation like:

+/// Validates a transaction against the ledger rules.
+///
+/// # Parameters
+/// * `transaction_body` - The transaction body to validate
+/// * `_witness_set` - The witness set (currently unused)
+/// * `auxiliary_data` - Optional auxiliary data for the transaction
+/// * `_is_valid` - Flag indicating if the transaction is valid (currently unused)
+/// * `protocol_params` - Protocol parameters to validate against
+///
+/// # Returns
+/// * `Ok(())` if the transaction is valid
+/// * `Err(TransactionRuleViolation)` with the specific violation otherwise
 pub fn validate_transaction(
     transaction_body: &TransactionBody,
     _witness_set: &WitnessSet,
     auxiliary_data: Option<AuxiliaryData>,
     _is_valid: bool,
     protocol_params: &ProtocolParameters,
 ) -> Result<(), TransactionRuleViolation> {

139-142: Simplify error mapping with the ? operator

The error mapping pattern of .map_err(|err| err.into())? can be simplified by implementing the From trait for each error type and using the ? operator directly.

-    validate_metadata(transaction_body, auxiliary_data).map_err(|err| err.into())?;
+    validate_metadata(transaction_body, auxiliary_data)?;
-    disjoint_ref_inputs(transaction_body).map_err(|err| err.into())?;
+    disjoint_ref_inputs(transaction_body)?;
-    validate_output_size(transaction_body, protocol_params).map_err(|err| err.into())?;
+    validate_output_size(transaction_body, protocol_params)?;

This would require implementing From traits instead of Into:

impl From<InvalidTransactionMetadata> for TransactionRuleViolation {
    fn from(value: InvalidTransactionMetadata) -> Self {
        TransactionRuleViolation::InvalidTransactionMetadata(value)
    }
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0f70c7e and 5027f51.

📒 Files selected for processing (4)
  • crates/amaru-kernel/src/lib.rs (1 hunks)
  • crates/amaru-ledger/src/rules.rs (3 hunks)
  • crates/amaru-ledger/src/rules/transaction/metadata.rs (1 hunks)
  • crates/amaru-ledger/src/rules/transaction/mod.rs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build on ubuntu-latest with target riscv32im-risc0-zkvm-elf
  • GitHub Check: Build on windows-latest with target x86_64-pc-windows-msvc
🔇 Additional comments (9)
crates/amaru-ledger/src/rules/transaction/mod.rs (1)

1-3: Nicely structured modular approach to transaction validation!

Good job breaking down the transaction rules into logical modules. This modular approach will make maintenance and testing a piece of cake down the road.

crates/amaru-kernel/src/lib.rs (3)

32-32: Good addition of the Bytes type to public exports

Sensibly exposed for the transaction validation work. Keep the exports tidy!


39-42: Well-organized type exports for transaction validation

Nice job adding these necessary Conway types to the public interface. Particularly TransactionBody and PseudoTransactionOutput which are essential for the new validation logic.


46-46: Good addition of OriginalHash

This will be useful for transaction hash tracking in the validation process.

crates/amaru-ledger/src/rules/transaction/metadata.rs (1)

48-49: Clarify the TODO comment about validateMetadata

The comment mentions that some validation logic is implemented during deserialization instead of here. It would be helpful to add a bit more detail about what specific validation is missing and perhaps create a tracking issue to ensure it doesn't get forgotten.

Could you clarify the specific validation that's pending implementation during deserialization? Is there a tracking issue for this TODO?

crates/amaru-ledger/src/rules.rs (4)

2-2: Good modular organization with the new transaction module

Nice addition of the transaction module - keeping things well-organized!


41-45: Well-structured transaction rule violation enum

Good job creating a dedicated enum for transaction validation errors. This clear categorization will make error handling and reporting much more straightforward.


86-127: Well-integrated transaction validation in the block validation process

Excellent work incorporating transaction validation into the block validation process. The code retrieves all necessary components (transaction bodies, witness sets, auxiliary data), performs validation on each transaction, and properly maps errors to the block validation context.


134-137:

❓ Verification inconclusive

Plans for unused parameters in validate_transaction

I notice there are several parameters with leading underscores indicating they're currently unused. Do you have plans to utilize these in future implementations? Including a TODO comment might be helpful if there are specific enhancements planned.


🏁 Script executed:

#!/bin/bash
# Check for any existing TODOs related to these parameters
rg "validate_transaction.*witness_set|is_valid" -A 5 -B 5

Length of output: 2290


Clarify Future Plans for Unused Parameters in validate_transaction

I’ve noticed that the parameters _witness_set and _is_valid in the validate_transaction function (in crates/amaru-ledger/src/rules.rs around lines 134–137) are currently unused. If these parameters are earmarked for future enhancements, could you add a TODO comment to indicate their intended use? Otherwise, if they're no longer required, it might be best to consider removing them to keep the code tidy.

Cheers, and looking forward to your thoughts on this!


for (i, (transaction, raw_transaction)) in
(0u32..).zip(transactions.iter().zip(raw_transactions))
{
Copy link
Contributor

Choose a reason for hiding this comment

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

First zip might be replaced with transactions.iter().enumerate ?

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.

2 participants