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

CIP-0051? | Preserve submitter's ordering of transaction inputs #231

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions cip-gege251-reliably-ordered-tx-inputs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
CIP: ?
Title: Preserve submitter's ordering of transaction inputs
Authors: Gergely Szabo <gergely@mlabs.city>
Discussions-To:
Comments-Summary:
Comments-URI:
Status: Draft
Type: Standards Track
Created: 2022-02-25
License: Apache-2.0
---

# Preserve submitter's ordering of transaction inputs

## Abstract

This CIP proposes a way to improve efficiency of handling transaction inputs in Plutus scripts by changing the way they are representend in the ledger.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
This CIP proposes a way to improve efficiency of handling transaction inputs in Plutus scripts by changing the way they are representend in the ledger.
This CIP proposes a way to improve efficiency of handling transaction inputs in Plutus scripts by changing the way they are representend in the ledger.represented


## Motivation

The current implementation of the transaction body stores transaction inputs as a set. When interacting with transaction inputs inside a validator script, this representation changes to a linked list, but the ordering of the transaction inputs is different than that of the originally submitted transaction's. In the case when we want to find a certain transaction input on chain, we need to do a costly filtering on the input list with the worst case of O(n).
However if the transaction inputs would be stored as an array, preserving the original ordering, we could better optimise our scripts by determining the order of inputs off-chain and simplifying the search to a pattern match.
For example, for a script needing transaction inputs for two purposes: one for updating the datum of the script, and one or more for supplying the funds. We could order these inputs such that the one including the datum comes first, and then we can use a pattern match `txWithDatum : txWithFunds = txInfoInputs`.

## Specification

In the CDDL definiotion of the transaction body, transaction inputs will need to be changed from Set to Array:

```
transaction_body =
{ 0 : [* transaction_input] ; inputs
, 1 : [* transaction_output]
, 2 : coin ; fee
, ? 3 : uint ; time to live
, ? 4 : [* certificate]
, ? 5 : withdrawals
, ? 6 : update
, ? 7 : auxiliary_data_hash
, ? 8 : uint ; validity interval start
, ? 9 : mint
, ? 11 : script_data_hash ; New
, ? 13 : set<transaction_input> ; Collateral ; new
, ? 14 : required_signers ; New
, ? 15 : network_id ; New
}
```

Note that the Set is defined in the cardano-ledger specification as an Array of zero or more elements `set = [* a]`, so this would only cause a semantic change, without the actual change of the underlying data structure.

## Rationale

In theory we could pre-calculate the index of the searched transaction input off-chain, by relying on the ordering of transaction inputs (lexicographic ordering on `(TransactionID, TransactionIndex)`). But then, to pass this information to the script, we would need to use a redeemer, which could defeat the purpose of this optimisation with it's own fees. Also, we could only reliably do this after transaction balancing, but changing the transaction after balancing could affect fees, rendering the transaction unbalanced again. This method also introduces unnecessary complexity.
Copy link
Member

Choose a reason for hiding this comment

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

which could defeat the purpose of this optimization with it's own fees.

I am not sure that framing this as an optimization to save on fees is the best justification. Surely, it improves the developer experience and makes easier to work with transaction inputs. I think one of the most common problem with that is calculation of redeemer pointers and how it conflicts with transaction balancing (adding new inputs to cover for fee may invalid all existing pointers on inputs). If the argument is made about saving on fees, then it should come backed with numbers showing how much to help weigh whether the change is worth it or not.


## Security considerations

We considered the possibility of a man-in-the-middle attack, where the adversary could change the transaction input ordering, and altering the behaviour of a script. However the existing ledger rules for deriving txid are sufficient to guarantee the integrity of transactions, because the inputs (whether a set or a list) are included in the transaction body that gets hashed to a txid. Therefore, no changes would be required to txid derivation.
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure to understand the point being made here and in particular, why transaction integrity is something that helps mitigating an adversary changing the order of inputs?


## Backward Compatibility

For ledger transactions before this CIP is implemented, the underlying CBOR data structure only changes semantically, and the difference between input order at submission and at script evaluation is irrelevant for the ledger. However, because scripts could rely on pattern matching by position, a new Plutus version is required.

## Test Cases

We need regression tests to assert that no utxo appears twice in the transaction input list.

## Implementations

The ledger implementation currently represents transaction inputs as a Map with the key of `(TransactionID, TransactionIndex)`.

## Copyright

This CIP is licensed under Apache-2.0