Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
2618: Multi-Asset Migration Algorithm r=jonathanknowles a=jonathanknowles # Issue Number ADP-839 # Overview This PR adds an algorithm for performing migrations of multi-asset UTxO sets from one wallet to another. It consists of four main parts: 1. Module `Migration`, which provides a top-level public API, defined in terms of concrete wallet types. 2. Module `Migration.Planning`, which contains an algorithm for planning migrations at a high level. It determines how to partition a UTxO set into entries of different types, and in which order to add UTxO entries to selections. 3. Module `Migration.Selection`, which provides functions for incrementally constructing a selection to be included in a migration plan. (A selection is the basis for an individual transaction.) 4. The `TxConstraints` type, which provides an abstract cost model for transactions, allowing parts of a transaction can be costed individually. This allows the incremental cost of extending a selection to be calculated without having to recalculate the cost of the entire selection. # Performance For pure ada wallets, we can process around 30,000 UTxO entries per second. We can process around 3,000 UTxO entries per second with wallets of the following composition: | Percentage | UTxO Entry Type | | -- | -- | | 10% | Pure ada entries below the minimum ada quantity | | 40% | Pure ada entries with at least the minimum ada quantity | | 40% | Multi-asset token bundles with precisely the minimum ada quantity | | 10% | Multi-asset token bundles with more than the minimum ada quantity | # Design ## UTxO partitioning The algorithm starts by partitioning the UTxO set into three types of UTxO entry: | Type | Definition | | -- | -- | | **_supporter_** | an entry that is capable of paying for itself | | **_freerider_** | an entry that is **not** capable of paying for itself | | **_ignorable_** | a dust ada entry that should not be included because its value is less than the marginal cost of an input. | ## Adding entries to transactions The algorithm uses a **supporter** entry to initialize each transaction, but then gives priority to adding **freerider** entries until the transaction is full. It adds a **supporter** entry only when there's not enough ada available to pay for an additional **freerider** entry. <img src="https://user-images.githubusercontent.com/206319/115514178-6c521b80-a2b6-11eb-808f-92b4c679b99a.png" alt="extending a selection" width="300px"> ## Creating outputs within transactions The algorithm minimizes the number of outputs for each transaction (and thus minimizes the fee required) by merging together all value provided by the inputs. Due to the nature of our transaction constraints (which limit the size of an output), the algorithm usually produces transactions with between 1 and 4 outputs. # Requirements The algorithm in this PR is designed to satisfy the following requirements: - **REQ-1** The algorithm _must_ succeed at selecting all pure ada entries greater than `txBaseFee` + `minAdaQuantity` + `marginalFeeForInputAndOutput`. - **REQ-2** The algorithm _must_ succeed at selecting all multi-asset entries whose ada quantities are greater than or equal to `txBaseFee` + `minAdaQuantity` + `marginalFeeForInputAndOutput`. - **REQ-3** The algorithm _should_ make a best effort to select entries whose ada quantities are less than `txBaseFee` + `minAdaQuantity` + `marginalFeeForInputAndOutput`, but is permitted to omit such entries if it cannot find a viable strategy to select them. - **REQ-4** The algorithm _must_ produce **T**: a set of transactions for which fees are balanced, and **R**: the remainder of the UTxO set that could not be selected, such that the inputs of **T** and the entries in **R** are disjoint, and such that the union of inputs in **T** and entries in **R** is equal to the original UTxO set. - **REQ-5** The algorithm _must_ preserve the balance of every non-ada asset, so that for any given asset **a**, the total quantity of asset **a** in the selected inputs is exactly equal to the total quantity of asset **a** in the generated outputs. - **REQ-6** The algorithm _must not_ produce transactions with dependencies between them; it should be possible to broadcast the generated transactions in any order. - **REQ-7** The algorithm _must not_ produce outputs with token quantities that exceed the maximum allowed in an output `(2^64 − 1)`. - **REQ-8** The algorithm _must not_ produce outputs whose serialized length exceeds the maximum allowed length (`4000` bytes). - **REQ-9** The algorithm _must not_ produce transactions that exceed the transaction size limit (`16384` bytes). - **REQ-10** The algorithm _must_ move the reward balance in its entirety. - **REQ-11** The algorithm _must_ be deterministic: if run twice on the same UTxO set, it must generate exactly the same migration plan. (This is necessary to support an API where a non-hardware wallet user can generate a plan, inspect the plan, and then initiate a migration without having to resubmit the plan.) # Non-Requirements - **NON-REQ-1** Preserving the UTxO distribution. Co-authored-by: Jonathan Knowles <[email protected]>
- Loading branch information