Off-Narrative-Labs / Tuxedo

Write UTXO-based Substrate Runtimes
https://off-narrative-labs.github.io/Tuxedo/
Apache License 2.0
55 stars 16 forks source link

Named UTXOs #193

Open JoshOrndorff opened 5 months ago

JoshOrndorff commented 5 months ago

Aka Storage items. Aka UTXOs indexed on-chain.

This issue captures my thoughts about the core differences between the Account vs UTXO models, and the times when I've found myself wanting account-like storage access. Throughout the writeup I'll have the example of a DEX and on-chain price oracle in mind. I'm assuming background understanding about how AMM dexes work in account systems, why AMMs don't work so well in UTXO systems, and why order books have the opposite characteristics (good in utxo, bad in accounts).


Storage Layout in Accounts and UTXOs

I think the biggest difference between accounts and UTXOs is how state is arranged in storage. In the Account model, you know where to store data based on what kind of data it is. If it is a gonvernace vote there is a storage item for that. If it is some coins, there is a storage item for that. But in the UTXO model, data is stored at pseudorandom locations based on the hash of the transaction that created it. I argue that this is a more important difference that the actual structure of accounts with balances vs collection of coins.

In a UTXO model the transaction specifies exactly which input state it is expecting to consume by specifying the UTXO IDs (storage locations) of its inputs. The execution is not able to interact with any other state than what was supplied by the inputs. This is a strength in many ways, for example, there is no risk of a transaction being applied on different pre-state than the transactor expected. But it can also be a weakness as you can see in AMMs. In the UTXO model, every time a user tries to use the AMM, they have to specify the pre-state and if any other user beats them to it, the transaction is invalid and they have to try again, perhaps many times.

In the account model the transaction does not need to specify the exact prestate. It only needs to specify that it wants to interact with the AMM, and the current state, whatever it may be, is fetched from the known location. On one hand this is excellent because users no longer have to race with other users to interact with the AMM. On the other hand, this is exactly what creates the ability for an MEV bot to run up the AMM price right before they include your transaction. (also sux for privacy, but that's another topic.) The good news is that there are some engineering solutions such as max-slippage parameters etc that make this pretty workable. This is good because users love AMMs and also the on-chain price oracle they provide.

A Hybrid Approach.

Several times, I've wanted something like a storage item. For storing the relay parent number in a parachain for example. Or tracking whether an inherent has been called. Or tallying up the total tip over the course of a block. So far all of these have some kind of alternate appraoch that is workable enough, but the point is that I've found myself thinking there may be a time and place for something like storage items.

I think that we can indeed achieve a hybrid naturally in the UTXO model. Consider two different kinds of UTXOs. The normal ones that are created based on tx hash. And a new kind called IndexedUtxos (or something). The indexed ones are unlike normal ones because they have well-known and stable names. Whereas normal UTXOs need to specify which specific UTXO ids they consume and therefore the exact associated state, these new extended transactions may also specify indexed utxos by name, consuming them regardless of what actual state is present. One hesitation is that every n00b will use these like storage items at every chance and not get how UTXOs really work.

Another Degree of Indirection

As a way to implement the above, I think we should basically have a small on-chain index of well-known UTXOs. Every time one such UTXO is updated, the index can also be updated. Basically the named UTXO just contains the UtxoRef of the underlying current state.

AltiMario commented 5 months ago

I think you can take inspiration from the work done on Cardano. This is the official IOG solution https://github.com/IntersectMBO/cardano-db-sync which will soon be replaced by the coming https://github.com/input-output-hk/marconi However, the community built additional solutions to face different challenges https://dcspark.github.io/carp/docs/intro/ https://github.com/txpipe/oura https://github.com/txpipe/scrolls https://github.com/CardanoSolutions/kupo

Here is a nice explanation with key differences https://github.com/CardanoSolutions/kupo?tab=readme-ov-file#alternatives

JoshOrndorff commented 5 months ago

@AltiMario Thanks for these very useful links. I will indeed learn a lot from them. However, this issue is about a potential small on-chain index. #192 is more relevant for off-chain indexers.