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

[Fix] Relax ordering checks for futures #2356

Merged
merged 9 commits into from
Mar 3, 2024
Merged

Conversation

evan-schott
Copy link
Contributor

@evan-schott evan-schott commented Feb 15, 2024

TLDR - The enforcement that futures must be consumed in the order they are produced is too strict. It forces developers to commit in advance to the order in which on-chain code is finalized and eliminates any opportunity to react dynamically to on-chain state. This ability to conditionally order external function calls is assumed on all standard programmable blockchains. By allowing the user to await futures in an arbitrary order, we can restore feature parity in this domain with other ecosystems, reduce developer experience friction and provide more intuitive syntax, all while preserving the existing intended security assumptions.

Motivation

Background

The functions in Aleo programs are split into two categories: offline and online. Offline functions are executed offline and are subsequently represented by a proof of the executions correctness. Online finalize functions must be re-executed and are subject to change depending on the state of the ledger. Although offline and online functions are linked in the sense that they share a name (think "function foo()" and the "finalize foo()" that follows), the offline function can never interact with the online state, whereas the online function receives input parameters from the offline call.

Earlier this year, the implementation of the asyncs feature made calls to external transitions produce futures, which must in turn be awaited inside the current function's corresponding finalize block. The intention of this feature was to give a more intuitive depiction of how the online and offline state interact by leveraging familiar async-await-future syntax. Additionally the feature allowed users to interleave additional instructions between the awaiting of external futures, which was impossible to do beforehand.

Problem 1: Conceptual

One constraint imposed in this feature was that the order in which external transition functions are called must be equivalent to the order in which the corresponding external finalize functions are awaited. This is problematic, as it gives the illusion that the ordering of asynchronous execution can be governed inside a synchronous block of code, when by definition, it is impossible to control the ordering in which asynchronous queries are executed.

Consider a simple example in which a developer wants to query the state of the same website twice in a row. Since the internet is asynchronous, if they use a protocol like UDP, there is no guarantee that the first request captures an earlier state of the website than the second request. The only way for the developer to ensure that the first one viewed the state before the second one is if they block in between the queries. This is not an option in Aleo programs because as soon as we block to wait for an on-chain execution to happen, we can no longer do more offline execution and subsequently generate a proof. We would have to wait for the asynchronous code to execute, attest to it, and then proceed. But this is also impossible as our attestation would not necessarily be correct as someone else could have modified the state in between our first finalize execution and our second finalize execution.

Problem 2: Loss of functionality

Under the current model, a developer is unable to re-order the awaiting of futures in a finalize block. In this way they are unable to write code that reacts to on-chain state, and conditionally choose the order to await futures. This functionality is a default assumption on all existing programmable blockchains.

Consider the abstract case in which program A.aleo imports B.aleo and C.aleo, and B.aleo imports C.aleo. Now suppose A.aleo/foo() externally calls B.aleo/boo() which in turn externally calls C.aleo/woo(). It is now impossible to write finalize logic for A.aleo/foo in which it first reads some on-chain state from C.aleo and depending on the result chooses whether to await B.aleo/boo.future or C.aleo/woo.future first. This would be beneficial in a case where C.aleo/woo() modifies on-chain state, such as its own mappings.

Testing

In addition to passing CI, I have added a new more complicated test to make sure nothing funny happens when futures are re-ordered. Also the tests asserting that all futures must be awaited, and that all futures must be propagated to an async call both still pass.

@evan-schott evan-schott changed the title Fix/future checks [Fix] Relax ordering checks for futures Feb 15, 2024
@vicsn
Copy link
Contributor

vicsn commented Feb 16, 2024

The ordering checks for futures are too strict, forcing developers to commit to offline to the order that on-chain execution will be finalized.

To make sure I understand, could this perhaps say: The ordering checks for futures are too strict, forcing developers to consume all of them in the order they were produced. Instead, we should let the user commit to an arbitrary order in which the on-chain futures will be consumed.

@evan-schott
Copy link
Contributor Author

@vicsn Thank you. I have revised it to make it more clear.

Copy link
Contributor

@d0cd d0cd left a comment

Choose a reason for hiding this comment

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

Left some some comments.

@howardwu howardwu merged commit 31684ee into mainnet Mar 3, 2024
76 of 78 checks passed
@howardwu howardwu deleted the fix/future-checks branch March 3, 2024 03:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants