Improve code style by removing duplicated code in the `pallas-validate` crate
This PR addresses code duplication in the pallas-validate crate by introducing generic traits and functions to unify similar operations across different Cardano eras.
Problem
The pallas-validate/src/utils.rs file contained significant code duplication, with separate implementations for similar operations across different eras (Alonzo, Babbage, Conway). Examples included:
-
aux_data_from_alonzo_tx,aux_data_from_babbage_tx,aux_data_from_conway_tx -
get_babbage_tx_size,get_conway_tx_size -
add_valuesvsconway_add_values -
find_policyvsconway_find_policy - And many more...
Solution
New Generic Traits
Introduced trait-based abstractions to unify operations across eras:
-
ValueOps: Abstracts value operations (getting lovelace, checking coin-only values, etc.) -
MultiassetOps: Abstracts multiasset operations (finding policies/assets, iteration) -
AuxDataAccess: Abstracts auxiliary data extraction from transactions -
TxSizeCalculator: Abstracts transaction size calculation
Generic Functions
Created reusable generic implementations:
// Before: 3 separate functions
pub fn aux_data_from_alonzo_tx<'a>(mtx: &'a AlonzoTx) -> Option<&'a [u8]>
pub fn aux_data_from_babbage_tx<'a>(mtx: &'a BabbageTx) -> Option<&'a [u8]>
pub fn aux_data_from_conway_tx<'a>(mtx: &'a ConwayTx) -> Option<&'a [u8]>
// After: 1 generic function + trait implementations
pub fn get_aux_data_from_tx<T: AuxDataAccess>(tx: &T) -> Option<&[u8]>
Improvements Made
- Auxiliary data extraction: 6 functions → 1 generic + 3 compatibility wrappers
- Transaction size calculation: 3 functions → 1 generic + 3 compatibility wrappers
- Value size calculation: 2 functions → 1 generic + 2 compatibility wrappers
- Lovelace extraction: 2 functions → 1 generic + 2 compatibility wrappers
- Asset/policy finding: 4 functions → 2 generic + 4 compatibility wrappers
- Multiasset manipulation: 4 functions → 2 generic + 4 compatibility wrappers
- Coercion functions: Refactored to use functional programming approach
Backward Compatibility
All existing public APIs are preserved through compatibility wrapper functions, ensuring no breaking changes. All 119 existing tests continue to pass without modification.
Benefits
- Reduced duplication: Eliminated redundant implementations across eras
- Improved maintainability: New eras can reuse existing generic implementations
- Better organization: Related functionality is grouped using traits
- Type safety: Generic constraints ensure correct usage patterns
- Functional approach: Cleaner, more readable implementations using iterators and functional programming
The refactoring maintains full backward compatibility while significantly improving code organization and reducing maintenance burden for future development.
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.