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-???? | On-chain Transaction Chaining #508

Closed
wants to merge 7 commits into from

Conversation

michele-nuzzi
Copy link

Once in a while, I see people raising issues that could be solved with transaction chaining if there where the possibility to have some additional guarantees on it.

There is no strict need for this proposal at the current state but I think it might prevent something more complex in the future.

(see rendered proposal in branch)

@L-as
Copy link
Contributor

L-as commented Apr 21, 2023

Seems like this is basically batched transactions as described in IntersectMBO/cardano-ledger#768

@michele-nuzzi
Copy link
Author

The goal/problem they try to solve is the same; however, I would say this is a different implementation if compared to do the description of the cited issue

@Ryun1 Ryun1 changed the title on-chain transaction chaining CIP-???? | On-chain Transaction Chaining Apr 21, 2023
We can distinguish the two types of inputs based on the type of the first element of the array;

if it is an unsigned integer it should be interpreted as a pointer to a previous transaction (`chained_tx_input` first element)
(`0` being the transaction immediately before the current chained one)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is too vague: you are suggesting we index backwards from a transaction in what? The mempool? The chain? Both of those are created non-deterministically, so that seems extremely unlikely to work.

Copy link
Author

Choose a reason for hiding this comment

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

I'm not really sure where this should happen if you have any suggestions that would be great.

regarding both being not deterministic the pointer to the previous transaction only makes sense if there is a previous transaction pointing to the current one.

If none is present the transaction should be considered invalid (or at least wait to be processed until some other transaction includes the current as chained).

In this sense transactions are referencing chained ones forwards; UTxO is referencing backward.

Copy link

Choose a reason for hiding this comment

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

Then prev_tx_pointer is not needed. Output index is sufficient if we rely on the fact there is another transaction referening this one.

@michaelpj
Copy link
Contributor

Yes, this is quite different to the proposals there. I would like to see some analysis of the requirements and comparison with other solutions, since the various solutions all differ in terms of what they offer.

Some requirements questions:

  1. What's the batch creation process?
    • Both this and the simple "signed batches" proposal in the linked issue require all the transactions to be constructed together
  2. What's visible to scripts?
    • This proposal adds some information about other transactions in the batch to scripts
  3. Other things?

Copy link
Contributor

@michaelpj michaelpj left a comment

Choose a reason for hiding this comment

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

It seems to me that the main difference between this and batch transactions is that this lets scripts "see" that other transactions will happen, which is a major power increase and I'm not sure what I think about it.

I think we could probably add that to batch transactions too, though: include a field like "otherTransactionsInBatch :: [TxIx]` to the script context. I don't think that gives us a hashing problem although it might make fee calculation annoying.

## Motivation: why is this CIP necessary?
<!-- A clear explanation that introduces the reason for a proposal, its use cases and stakeholders. If the CIP changes an established design then it must outline design issues that motivate a rework. For complex proposals, authors must write a Cardano Problem Statement (CPS) as defined in CIP-9999 and link to it as the `Motivation`. -->

The changes proposed in this CIP are implemented would allow for composability between transactions while preserving the deterministic behaviour.
Copy link
Contributor

Choose a reason for hiding this comment

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

Please provide some actual usecases!

Copy link
Member

Choose a reason for hiding this comment

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

I concur with @michaelpj here, the motivation is a bit short. It's not clear to me "how is this a useful thing". Or more exactly, how is that different from chaining UTxO the way it's already possible?


phase 1 validation can also fail if some transaction input is defined using only an unsigned integer but no other transaction specifies the current transaction as chained.

DApp developers can check on-chain for eventual chained transaction by exposing the `txInfoChainedTxId` `ScriptContext` field in the output datum going to be used in the chained transaciton.
Copy link
Contributor

Choose a reason for hiding this comment

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

It would really help to have some usecases to see how this is useful. I think I can guess, but please just explain!

@dcoutts
Copy link
Contributor

dcoutts commented Apr 24, 2023

Doesn't this imply that the chain of transactions must all be within one block? I can't see how to enforce the guarantee otherwise. And if so, doesn't this end up being much the same as batched transactions?

@michele-nuzzi
Copy link
Author

Doesn't this imply that the chain of transactions must all be within one block? I can't see how to enforce the guarantee otherwise. And if so, doesn't this end up being much the same as batched transactions?

Not necessarily; transactions can still be included in multiple blocks; the only thing needed for a chain of transactions is the existence of an output of a previous one

@michaelpj
Copy link
Contributor

Not necessarily; transactions can still be included in multiple blocks; the only thing needed for a chain of transactions is the existence of an output of a previous one

So this doesn't ensure that the following transaction is ever made? It's much less clear what the point is, then. I thought this would allow scripts to ensure that another transaction happens, but in this case it wouldn't.

@michele-nuzzi
Copy link
Author

michele-nuzzi commented Apr 24, 2023

It seems to me that the main difference between this and batch transactions is that this lets scripts "see" that other transactions will happen, which is a major power increase and I'm not sure what I think about it.

That is the main idea of the proposal. The main use case (that I will add as soon as I edit the proposal) is the composability of transactions; keeping every transaction atomic on its own but under all aspects provides a way to be sure some other action took place (based on the output of the current).

In general this would give scripts the possibility to act like active entities.

This, as an example, allows for datum validation when creating a brand new UTxO in a script; where the first transaction creates the UTxO and the second spends that UTxO only to be sure that the datum is valid; if the second fails the first fails too, so the UTxO is never created.

Another use case, also based on the "acting like active entities" thing, is smart contract interaction; where a smart contract first performs an action (even expansive ones) and then forwards the validation to a script in a successive transaction that checks for the result of the previous and the presence of the target (external) contract; under all aspects emulating a contract call.

NOTE: thanks to the Acyclic structure of UTxOs there's no danger for reentrant calls

@michele-nuzzi
Copy link
Author

michele-nuzzi commented Apr 24, 2023

Not necessarily; transactions can still be included in multiple blocks; the only thing needed for a chain of transactions is the existence of an output of a previous one

So this doesn't ensure that the following transaction is ever made? It's much less clear what the point is, then. I thought this would allow scripts to ensure that another transaction happens, but in this case it wouldn't.

In order to be included in a block all the chained transactions have to be submitted an all have to be validated; if any of the transactions fails none is included; if all succeed then can be included as a normal transaction.

If the above doesn't make sense then is likely I'm missing something so please let me know how can I improve there.


Despite being extremly powerful this process as currently some limitations:
- it gives no guarantees that all of the multiple transactions are valid
- the process happens entrierly offchain; without the possibility for a plutus script to be aware of it
Copy link
Member

Choose a reason for hiding this comment

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

This last paragraph shall actually be part of the "Motivation" section IMO as it gives some clear justification for why is this CIP necessary.

Copy link
Author

Choose a reason for hiding this comment

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

Will do!

Copy link
Member

@KtorZ KtorZ left a comment

Choose a reason for hiding this comment

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

Little suggestion: I'd welcome some extra proof-reading on the document as there are many little typos 🤓

@rphair
Copy link
Collaborator

rphair commented May 3, 2023

@KtorZ: ... proof-reading on the document as there are many little typos 🤓

@michele-nuzzi after you've given this your best effort let us know & I'll give it a good editing review. 😇

@michele-nuzzi
Copy link
Author

Little suggestion: I'd welcome some extra proof-reading on the document as there are many little typos nerd_face

That is my signature; at least we are sure I wrote it.

Will go over it by tomorrow.

@rphair
Copy link
Collaborator

rphair commented May 30, 2023

@michele-nuzzi marking Waiting for Author as per #518.

@rphair rphair added the State: Waiting for Author Proposal showing lack of documented progress by authors. label May 30, 2023
@fallen-icarus
Copy link

@michele-nuzzi Why can't you just use minting policies for this? That is what I have been using for my applications.

The main use case (that I will add as soon as I edit the proposal) is the composability of transactions; keeping every transaction atomic on its own but under all aspects provides a way to be sure some other action took place (based on the output of the current).

This, as an example, allows for datum validation when creating a brand new UTxO in a script; where the first transaction creates the UTxO and the second spends that UTxO only to be sure that the datum is valid; if the second fails the first fails too, so the UTxO is never created.

This is literally how I use the minting policy. For example, when a borrower creates a UTxO to ask for a loan, they must mint an Ask token and store it in the UTxO. This Ask token can only be minted if the datum in the UTxO is valid (among other things). A lender who then wants to offer a loan must create a UTxO with an Offer token. The Offer token can only be minted if the offer is valid (datum, value, etc must all be valid). To accept a loan, the borrower must match up an ask UTxO with an offer UTxO with the added requirement that they contain an Ask token and Offer token, respectively. The very fact that the tokens exist means the UTxOs are valid. To use the terminology here, the presence of the tokens is proof that a previous transaction occured. I have successfully been able to compose my applications using this approach. For example, you can safely compose my dex, options trading protocol, and secondary market in a single transaction. They either all succeed or the transaction fails.

In order to be included in a block all the chained transactions have to be submitted an all have to be validated; if any of the transactions fails none is included; if all succeed then can be included as a normal transaction.

The approach I mention above has this property already. Why is this approach not sufficient?

@michele-nuzzi
Copy link
Author

@michele-nuzzi Why can't you just use minting policies for this? That is what I have been using for my applications.

The main use case (that I will add as soon as I edit the proposal) is the composability of transactions; keeping every transaction atomic on its own but under all aspects provides a way to be sure some other action took place (based on the output of the current).

This, as an example, allows for datum validation when creating a brand new UTxO in a script; where the first transaction creates the UTxO and the second spends that UTxO only to be sure that the datum is valid; if the second fails the first fails too, so the UTxO is never created.

This is literally how I use the minting policy. For example, when a borrower creates a UTxO to ask for a loan, they must mint an Ask token and store it in the UTxO. This Ask token can only be minted if the datum in the UTxO is valid (among other things). A lender who then wants to offer a loan must create a UTxO with an Offer token. The Offer token can only be minted if the offer is valid (datum, value, etc must all be valid). To accept a loan, the borrower must match up an ask UTxO with an offer UTxO with the added requirement that they contain an Ask token and Offer token, respectively. The very fact that the tokens exist means the UTxOs are valid. To use the terminology here, the presence of the tokens is proof that a previous transaction occured. I have successfully been able to compose my applications using this approach. For example, you can safely compose my dex, options trading protocol, and secondary market in a single transaction. They either all succeed or the transaction fails.

In order to be included in a block all the chained transactions have to be submitted an all have to be validated; if any of the transactions fails none is included; if all succeed then can be included as a normal transaction.

The approach I mention above has this property already. Why is this approach not sufficient?

yes that particular scenario is already possible without chaining transactions; as an example, I used a similar technique in this yield contract;

however, the contract tends to be more complicated because

in that particular case, I had a mutual dependency between the minting policy and the validator (policy checks for the asset to be sent to the validator and the validator checks for the policy to assert the validity of an utxo)

that implies "unsafe" type coercion and ad-hoc data design.

while the CIP won't remove the pattern (mutual dependencies are more common than I wish they were) it definitely makes the process much smoother and requires less mental gymnastic to achieve something like datum validation.

There are also many advantages in chaining transactions and having the guarantee that there is some transaction happening after yours.

In particular "batching" (but without third parties signing transactions)
where a bunch of different users would send a single witness transaction to some contract and then that contract would be a single witness to a chained transaction.

The above is also possible without third parties but that would imply having multiple users from all around the world having to sign the same exact transaction.

If that was easy we wouldn't have batchers at all today, but of course, that is not the case.

chaining transactions and having a guarantee of that on-chain allows contracts to act like active entities; without requiring an indefinite amount of users to sign the same exact transaction (they would sign theirs and then leave the contract to do its things)

@rphair
Copy link
Collaborator

rphair commented Aug 20, 2024

@michele-nuzzi we are trying to trim the abandoned proposals from the CIP PR queue but it looks like this one is still relevant... despite being in Waiting for Author state for about a year... due to the mention in #880 (comment) (cc @fallen-icarus @WhatisRT), so could you please look this over and let us know what we're waiting for here?

If you're standing by your proposal, and intend to carry it forward, please update the header & format according to the new CIP-0001 (I believe you are familiar with those specifics but please post if not). Then based on your posting whatever's happened in the last year, we can change the status to something other than (potentially) Abandoned... until then, this tag marks it for closure if there are no further updates.

@rphair rphair removed the State: Waiting for Author Proposal showing lack of documented progress by authors. label Aug 20, 2024
@rphair rphair added the State: Likely Abandoned Close if confirmed abandoned (long waiting). label Aug 20, 2024
@rphair rphair closed this Sep 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
State: Likely Abandoned Close if confirmed abandoned (long waiting).
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants