|
| 1 | +# Transaction Validity |
| 2 | + |
| 3 | +What does it mean for a transaction to be valid? The ledger specs define it |
| 4 | +quite simply: a transaction is valid if it may be applied to a valid ledger |
| 5 | +state to return another valid ledger state. We say that it is valid with regard |
| 6 | +to the initial ledger state. |
| 7 | + |
| 8 | +More prosaically, for a transaction to be valid with regards to a ledger state |
| 9 | +entails the things we would expect: its inputs must exist, the spender must have |
| 10 | +the right to spend those inputs, the transaction must balance etc. In the |
| 11 | +ledger specifications, these are all written as _predicates_ - assertions that |
| 12 | +one thing equals another, for example. A failing predicate means that the |
| 13 | +transition is invalid and hence that the transaction is invalid with regard |
| 14 | +to that ledger state. |
| 15 | + |
| 16 | +## Multi-phase Validity |
| 17 | + |
| 18 | +Invalid transactions do not end up on the chain. Consequently, invalid |
| 19 | +transactions do not pay fees. A trivial attack on a block producing node would |
| 20 | +be to bombard it with invalid transactions. The node must verify that each |
| 21 | +transaction is invalid, but gains no benefit for performing this work. |
| 22 | + |
| 23 | +In order that this not become an asymmetric resource attack, the work which |
| 24 | +must be done to validate a transaction needs be bounded. The introduction of |
| 25 | +Plutus in the Alonzo era, however, complicated this situation. Plutus scripts |
| 26 | +must necessarily be capable of performing a significant amount of work. Should |
| 27 | +this work result in the transaction being deemed invalid, that work would be |
| 28 | +uncompensated - an attacker could use relatively small amounts of their own |
| 29 | +resource (crafting a looping Plutus script is, after all, relatively easy) to |
| 30 | +force significantly larger resource expenditure from the network. |
| 31 | + |
| 32 | +In order to combat this, Alonzo introduced the concept of 2-phase validity: |
| 33 | + |
| 34 | +1. The first phase involves the regular checks of things such as transaction |
| 35 | + size, fee suitability, input validity etc. These checks are assumed to have |
| 36 | + bounded work. A failure in phase 1 indicates that the transaction will |
| 37 | + not be placed on chain. |
| 38 | +2. Phase 2 checks are only run if phase 1 succeeds. Phase 2 checks involve |
| 39 | + running Plutus scripts and validating that inputs locked by those scripts |
| 40 | + can be spent. A transaction failing a phase 2 check can still be put on |
| 41 | + chain. In this case, a special input called the 'collateral' is spent and |
| 42 | + donated to the fee pot. The collateral must be locked by a phase-1 |
| 43 | + verifiable input - i.e. an input locked by a VKey or native script. |
| 44 | + |
| 45 | +An important consideration is that phase-2 checks are _static_ (see below). |
| 46 | +Phase-2 checks are run always in the context only of the transaction and its |
| 47 | +resolved inputs (which, since we have a UTxO system, are determinstic if they |
| 48 | +exist). As such, a diligent transaction submitter should have no risk of their |
| 49 | +collateral being taken - they can validate that their script passes before |
| 50 | +submitting the transaction and then be assured that it will either pass when |
| 51 | +the transaction is included, or that the transaction will fail during phase 1 |
| 52 | +(for example, if an input has been spent).[^1] |
| 53 | + |
| 54 | +## Static vs Dynamic Checks |
| 55 | + |
| 56 | +Since transaction validity is defined with regard to a ledger state, a change |
| 57 | +to the ledger state may result in previously valid transactions now becoming |
| 58 | +invalid. For example, the time may have moved past the transaction's validity |
| 59 | +window, or one of the inputs may have been spent. |
| 60 | + |
| 61 | +Consequently, as the ledger state evolves due to new blocks being accepted, |
| 62 | +nodes need to revalidate transactions in their mempool against the new state. |
| 63 | +However, not everything needs to be revalidated. Cryptographic signatures, for |
| 64 | +example, are guaranteed to remain valid regardless of the ledger state. |
| 65 | + |
| 66 | +Formally, we call a check _static_ if it can be evaluated with regard only to |
| 67 | +the contents of the transaction and its resolved inputs. Examples |
| 68 | +(non-exhaustive) of static checks include: |
| 69 | + |
| 70 | +- Cryptographic signature checks |
| 71 | +- Native (multisig/timelock) scripts |
| 72 | +- Phase 2 checks (Plutus scripts) |
| 73 | + |
| 74 | +_Dynamic checks_, on the other hand, require access to the UTxO or other aspects |
| 75 | +of the ledger state to compute. As such, they need to be re-evaluated each time |
| 76 | +the ledger state is updated. Obvious examples of dynamic checks include |
| 77 | +verifying that inputs exist, checking that the transaction still sits within its |
| 78 | +validity window, and validating block transaction size against the protocol |
| 79 | +parameters. |
| 80 | + |
| 81 | +# Block Validity |
| 82 | + |
| 83 | +> This section is currently a stub |
| 84 | +
|
| 85 | +# Relevance for the node developer |
| 86 | + |
| 87 | +The above is mostly relevant for node developers in that it is useful to be able |
| 88 | +to run the ledger transitions with fine-grained control over which checks are |
| 89 | +computed. |
| 90 | + |
| 91 | +There are four main scenarios which come into consideration: |
| 92 | + |
| 93 | +1. Validating a transaction as it enters the mempool. In this case all checks |
| 94 | + must be computed. |
| 95 | +2. Re-validating a transaction after a new block has been adopted. In this case, |
| 96 | + we care only about re-running _dynamic_ checks. |
| 97 | +3. Validating a new block body downloaded from a peer. In this case all checks |
| 98 | + must be computed. |
| 99 | +4. Re-applying a block from our local storage in order to reconstruct the ledger |
| 100 | + state. Since local blocks are assumed to be trusted, we need run _no_ checks |
| 101 | + here and only apply the transition. |
| 102 | + |
| 103 | +Node developers should bear these scenarios in mind when considering how to |
| 104 | +structure their node transition function. |
| 105 | + |
| 106 | +[^1]: Note that there is a small addendum to this story. While theoretically |
| 107 | +anyone may validate their own Plutus scripts, many users do not run their own |
| 108 | +node and as such trust a third party to validate those scripts on their behalf. |
| 109 | +These users were concerned about accidentally losing collateral. Since |
| 110 | +collateral must be a single address, users in such a situation either had to |
| 111 | +assign precisely the 'minCollateral' to an address or put up another UTxO as |
| 112 | +collateral and risk losing more than the minimum. To assuage the fears of such |
| 113 | +folks, Babbage introduced a 'collateral return address' to which collateral in |
| 114 | +excess of the minimum required would be returned in the case of a failing |
| 115 | +script. |
0 commit comments