Skip to content

Invalid transactions missing inputs and outputs (collateral operations) #602

@linconvidal

Description

@linconvidal

Context & versions

  • rosetta-java v1.3.2
  • Network: preprod
  • Transaction example: 2bb415e28c4bbc81b3be24499ba8fa216fe728b1e828ebc35b5a58c079f9fec8 (Block 3422820)
  • Issue: rosetta-java only shows invalid operations (failed script attempts), missing the valid collateral operations that actually succeeded

Steps to reproduce

  1. Start rosetta-java on preprod
  2. Query invalid transaction via /block/transaction:
    curl -X POST http://localhost:8083/block/transaction \
      -H "Content-Type: application/json" \
      -d '{
        "network_identifier": {"blockchain": "cardano", "network": "preprod"},
        "block_identifier": {"index": 3422820, "hash": "5d8c7e399374b40693ec8c05e5003dc3b7c3ef7c7e04d68507371a1e262281be"},
        "transaction_identifier": {"hash": "2bb415e28c4bbc81b3be24499ba8fa216fe728b1e828ebc35b5a58c079f9fec8"}
      }'
  3. Observe response shows only invalid script input operation
  4. Verify script UTXO still exists using cardano-cli (wasn't actually consumed)
  5. Note collateral operations are completely missing

Actual behavior

rosetta-java response (INCOMPLETE)

{
  "operations": [
    {
      "type": "input",
      "status": "invalid",  // ✓ Correct status - this operation failed
      "account": {"address": "addr_test1wr3cmj7uzdl89zkrgdqk55sn9ka3368stgaky3xm59elfrg49uvlm"},
      "amount": {"value": "-5000000"},  // ✓ Shows attempted amount
      "coin_change": {
        "coin_identifier": {"identifier": "39bdb7ca1f83ab998811a1b29c57e3bb24336e8c8e10a6fd19e662c2c4a0f29f:0"},
        "coin_action": "coin_spent"
      }
    }
  ]
}

Problem: Only shows invalid operations. Missing the VALID collateral operations that succeeded.

UTXO Search for 39bdb7ca...#0 (the script input shown with invalid status):

curl -X POST http://localhost:8083/search/transactions \
  -H "Content-Type: application/json" \
  -d '{"network_identifier": {"blockchain": "cardano", "network": "preprod"}, 
       "coin_identifier": {"identifier": "39bdb7ca1f83ab998811a1b29c57e3bb24336e8c8e10a6fd19e662c2c4a0f29f:0"}}'

Response:

{
  "total_count": 1,  // ONLY ONE TRANSACTION - THE CREATION!
  "transactions": [
    {
      "block_identifier": {"index": 3413492},
      "transaction": {
        "transaction_identifier": {"hash": "39bdb7ca1f83ab998811a1b29c57e3bb24336e8c8e10a6fd19e662c2c4a0f29f"},
        "operations": [
          // ... shows this UTXO being CREATED as output #0 with 5 ADA
        ]
      }
    }
  ]
}

But via cardano-cli:

cardano-cli query utxo --address addr_test1wr3cmj7uzdl89zkrgdqk55sn9ka3368stgaky3xm59elfrg49uvlm --testnet-magic 1

Result:

                           TxHash                                 TxIx        Amount
--------------------------------------------------------------------------------------
39bdb7ca1f83ab998811a1b29c57e3bb24336e8c8e10a6fd19e662c2c4a0f29f     0        5000000 lovelace + TxOutDatumInline

THIS UTXO STILL EXISTS! Confirms the operation correctly has status="invalid" (wasn't consumed).

Collateral UTXO fe079cee...#2 (what rosetta-ts shows but rosetta-java misses):

curl -X POST http://localhost:8083/search/transactions \
  -H "Content-Type: application/json" \
  -d '{"network_identifier": {"blockchain": "cardano", "network": "preprod"},
       "coin_identifier": {"identifier": "fe079ceee24e55afccdb6662c8b22ea228348f56b57587fb8e95a867969d31c3:2"}}'

Response:

{
  "total_count": 2,  // TWO TRANSACTIONS - CREATED AND SPENT!
  "transactions": [
    "2bb415e28c4bbc81b3be24499ba8fa216fe728b1e828ebc35b5a58c079f9fec8",  // SPENT HERE (our invalid tx)
    "fe079ceee24e55afccdb6662c8b22ea228348f56b57587fb8e95a867969d31c3"   // CREATED HERE
  ]
}

Collateral return verification via cardano-cli:

cardano-cli query utxo --address addr_test1vz8dlkd8zg4rxzs26fq95fheupph8mmgpf78rh3c5nyalsq5rgkvr --testnet-magic 1

Result:

                           TxHash                                 TxIx        Amount
--------------------------------------------------------------------------------------
2bb415e28c4bbc81b3be24499ba8fa216fe728b1e828ebc35b5a58c079f9fec8     2        13165743 lovelace

Collateral was consumed and returned! This is what rosetta should show.

rosetta-ts response (partially correct)

{
  "operations": [
    {
      "type": "input", 
      "status": "invalid",  // ❌ Should be "success" - this WAS consumed!
      "account": {"address": "addr_test1vz8dlkd8zg4rxzs26fq95fheupph8mmgpf78rh3c5nyalsq5rgkvr"},
      "amount": {"value": "-13720235"},  // 13.72 ADA - COLLATERAL
      "coin_change": {
        "coin_identifier": {"identifier": "fe079ceee24e55afccdb6662c8b22ea228348f56b57587fb8e95a867969d31c3:2"},
        "coin_action": "coin_spent"
      }
    },
    {
      "type": "output",
      "status": "invalid",  // ❌ Should be "success" - this WAS created!
      "account": {"address": "addr_test1vz8dlkd8zg4rxzs26fq95fheupph8mmgpf78rh3c5nyalsq5rgkvr"},
      "amount": {"value": "13165743"},  // 13.16 ADA - COLLATERAL RETURN  
      "coin_change": {
        "coin_identifier": {"identifier": "2bb415e28c4bbc81b3be24499ba8fa216fe728b1e828ebc35b5a58c079f9fec8:2"},
        "coin_action": "coin_created"
      }
    }
    // ❌ MISSING: Script input operation with status "invalid" (the actual failed operation)
  ]
}

Problems with rosetta-ts:

  • Shows the RIGHT UTXOs (collateral) but WRONG status (should be "success" for collateral ops)
  • Missing the actual invalid operation (script input that failed to be consumed)

What Actually Happened

graph LR
    subgraph "BEFORE Transaction"
        U1["Contract Wallet<br/>addr_test1wr3cmj7..."] 
        U1 --> UTXO1["39bdb7ca...#0<br/>5 ADA<br/>(script input)"]
        
        U2["User Wallet<br/>addr_test1vz8dlkd..."] 
        U2 --> UTXO3["fe079cee...#2<br/>13.72 ADA<br/>(COLLATERAL)"]
    end
    
    subgraph "Transaction Attempt"
        TX["TX: 2bb415e...<br/>Script Execution FAILS<br/>Phase 2 Validation ❌"]
        UTXO1 -.->|"TRIED to spend<br/>(but failed)"|TX
        UTXO3 ==>|"ACTUALLY SPENT<br/>(collateral)"|TX
    end
    
    subgraph "AFTER Transaction"
        TX ==>|"Collateral Return<br/>13.16 ADA"|UTXO4["2bb415e...#2<br/>13.16 ADA<br/>(collateral return)"]
        TX ==>|"Fee to Network<br/>0.554 ADA"|FEE["Network Fee Pot"]
        
        UTXO1 -->|"STILL EXISTS<br/>(unspent)"|U1B["Contract Wallet<br/>addr_test1wr3cmj7..."]
        UTXO4 -->|"NEW UTXO"|U2B["User Wallet<br/>addr_test1vz8dlkd..."]
    end
    
    style UTXO1 fill:#f5f5f5,stroke:#666,stroke-width:1px
    style UTXO3 fill:#fff,stroke:#000,stroke-width:2px
    style UTXO4 fill:#fff,stroke:#000,stroke-width:2px
    style FEE fill:#fff,stroke:#333,stroke-width:1px
    style TX fill:#fafafa,stroke:#000,stroke-width:2px
    style U1 fill:#fff,stroke:#333,stroke-width:1px
    style U2 fill:#fff,stroke:#333,stroke-width:1px
    style U1B fill:#fff,stroke:#333,stroke-width:1px
    style U2B fill:#fff,stroke:#333,stroke-width:1px
Loading
  • Script input (39bdb7ca...#0): ATTEMPTED but FAILED - rosetta-java correctly shows this as invalid ✓
  • Collateral (fe079cee...#2): SUCCESSFULLY consumed, 13.16 ADA returned - rosetta-java doesn't show this ✗
  • Fee: 0.554 ADA taken from collateral
  • Core problem: Incomplete representation showing only failures, not successes

Expected behavior

For phase 2 validation failures, should show ALL operations (both intended and actual) with correct statuses, network_index, and related_operations:

{
  "operations": [
    {
      "operation_identifier": {"index": 0, "network_index": 0},
      "type": "input",
      "status": "invalid",  // Script execution failed - UTXO NOT consumed
      "account": {"address": "addr_test1wr3cmj7uzdl89zkrgdqk55sn9ka3368stgaky3xm59elfrg49uvlm"},
      "amount": {"value": "-5000000"},
      "coin_change": {
        "coin_identifier": {"identifier": "39bdb7ca1f83ab998811a1b29c57e3bb24336e8c8e10a6fd19e662c2c4a0f29f:0"},
        "coin_action": "coin_spent"
      }
    },
    {
      "operation_identifier": {"index": 1, "network_index": 0},
      "related_operations": [{"index": 0}],  // References the script input that would have funded it
      "type": "output",
      "status": "invalid",  // Intended output NOT created (script failed)
      "account": {"address": "addr_test1wr3cmj7uzdl89zkrgdqk55sn9ka3368stgaky3xm59elfrg49uvlm"},
      "amount": {"value": "1611940"}  // 1.61 ADA
    },
    {
      "operation_identifier": {"index": 2, "network_index": 1},
      "related_operations": [{"index": 0}],  // References the script input that would have funded it
      "type": "output",
      "status": "invalid",  // Intended output NOT created (script failed)
      "account": {"address": "addr_test1vz8dlkd8zg4rxzs26fq95fheupph8mmgpf78rh3c5nyalsq5rgkvr"},
      "amount": {"value": "3018399"}  // 3.01 ADA
    },
    {
      "operation_identifier": {"index": 3, "network_index": 0},  // Position in body.collateralInputs[]
      "type": "collateralInput",  // Different type for collateral!
      "status": "success",  // Collateral WAS consumed
      "account": {"address": "addr_test1vz8dlkd8zg4rxzs26fq95fheupph8mmgpf78rh3c5nyalsq5rgkvr"},
      "amount": {"value": "-13720235"},
      "coin_change": {
        "coin_identifier": {"identifier": "fe079ceee24e55afccdb6662c8b22ea228348f56b57587fb8e95a867969d31c3:2"},
        "coin_action": "coin_spent"
      }
    },
    {
      "operation_identifier": {"index": 4, "network_index": 0},  // network_index=0 for consistency
      "related_operations": [{"index": 3}],  // References the collateral input that funded it
      "type": "collateralReturn",  // Different type for collateral return!
      "status": "success",  // Collateral return WAS created
      "account": {"address": "addr_test1vz8dlkd8zg4rxzs26fq95fheupph8mmgpf78rh3c5nyalsq5rgkvr"},
      "amount": {"value": "13165743"},
      "coin_change": {
        "coin_identifier": {"identifier": "2bb415e28c4bbc81b3be24499ba8fa216fe728b1e828ebc35b5a58c079f9fec8:2"},
        "coin_action": "coin_created"
      }
    }
  ]
}

Note on implementation: The complete fix with correct network_index values ideally requires implementing separate operation types for collateral operations (collateralInput and collateralReturn), as detailed in the sub-issue proposal. This ensures each operation's network_index correctly represents its position within its respective transaction body array.

Sub-issues

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    Status

    Ready

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions