Skip to content

283 keep order of chain specific outputs#285

Open
nicolasLuduena wants to merge 15 commits intomainfrom
283-keep-order-of-chain-specific-outputs
Open

283 keep order of chain specific outputs#285
nicolasLuduena wants to merge 15 commits intomainfrom
283-keep-order-of-chain-specific-outputs

Conversation

@nicolasLuduena
Copy link
Contributor

This pull request introduces the concept of a "declared index" for transaction outputs and Cardano publish directives, ensuring their original order is preserved throughout parsing, lowering, compilation, and serialization. The declared index is now tracked in the AST, IR, and final output structures, and is included in all relevant test fixtures and example files. This change enables deterministic ordering of outputs, which is critical for correct transaction construction and downstream processing.

Core logic and data model changes:

  • Added a declared_index field to OutputBlock and CardanoPublishBlock in the AST, and ensured it is set during parsing to reflect the order in which outputs and directives are declared.
  • Updated the compilation pipeline to use the declared_index for sorting outputs, ensuring the final transaction outputs are in the correct order.

Parsing and lowering enhancements:

  • Modified the AST parsing logic for outputs and Cardano-specific blocks to assign and increment declared_index as each output or directive is encountered.

  • Ensured that the lowering phase includes the declared_index in the IR representations.
    Test and example updates:

  • Updated all relevant test cases and example files to include the new declared_index field, ensuring consistency and coverage for the new behavior.

These changes collectively ensure that output and directive ordering is explicit and robust throughout the transaction lifecycle.

@nicolasLuduena nicolasLuduena linked an issue Jan 20, 2026 that may be closed by this pull request
pub optional: bool,
pub fields: Vec<OutputBlockField>,
pub span: Span,
pub declared_index: Option<usize>,
Copy link
Contributor

Choose a reason for hiding this comment

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

why declared_index instead of index?
is there a conflicting index which is not declared?

if not, rename it to just index

Comment on lines +742 to +750
data.insert(
"declared_index".to_string(),
ir::Expression::Number(
self.declared_index
.map(|x| x as i128)
.expect("Publish block must have a declaration index"),
),
);

Copy link
Contributor

Choose a reason for hiding this comment

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

The lowering phase should not be used for enforcing invariants.

If the user should be aware of the rule, then the analyze phase should check the rule.

The assertion of the rule should be applied when needed. In this case, the compiler should be then one erroring when the value is missing.

datum,
amount,
optional: self.optional,
declared_index: ir::Expression::Number(declared_ix as i128),
Copy link
Contributor

Choose a reason for hiding this comment

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

why do we use an explicit expression type?
Why can't we rely on the into_lower method as we do with the rest of the fields?

Comment on lines +218 to +222
Rule::output_block => {
let mut ob = OutputBlock::parse(item)?;
ob.declared_index = Some(declared_index);
declared_index += 1;
outputs.push(ob);
Copy link
Contributor

Choose a reason for hiding this comment

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

this shouldn't be here. We're coupling the rules of a specifc type of AST in the parsing logic of a totally unrelated block.

On top of that, the AST is not in charge of defining the indexes of the outputs. The AST describes the intent of the user that typed the code. The index expression should remain as an optional expression all the way down until the compiler is forced to add a value.

Comment on lines +227 to +235
Rule::chain_specific_block => {
let mut csb = ChainSpecificBlock::parse(item)?;
let ChainSpecificBlock::Cardano(cardano_block) = &mut csb;
if let crate::cardano::CardanoBlock::Publish(pb) = cardano_block {
pb.declared_index = Some(declared_index);
declared_index += 1;
}

adhoc.push(csb);
Copy link
Contributor

Choose a reason for hiding this comment

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

same as previous comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Keep order of chain specific outputs

2 participants