In the EUTXO model as in Plutus, validator scripts carry the role of validating transactions which spend inputs locked to a script address.
A simple example
In the above example, the validator can correctly validate the spending of an EUTXO locking currency amounts, with a Datum representing an accounting model.
We can confirm the validity of any UTXO at the script address if and only if the transaction which created it spends an input from the script address, running the validator.
Datum Spam
The problem with the above example is that the validator only checks transactions which spend from the script address.
So a transaction can bypass the validator and submit spam Datums to the script address:
In essence, validators control the input but not the output of transactions.
State-Thread Tokens
To validate the output of transactions, we have a trick up our sleeves -
Native token Minting Policies will check any transaction which mints their associated token, so we can create a token which we attach to an initial Datum output at the script address.
Other policies may be used, such as deferring to a “parent” validator (such as governance) but the simplest way to do this is with a ‘one-shot’ minting policy which uses a unique TxOut to mint an NFT-like token which may only be minted oncce.
If desired, the policy can also be used to validate the initial value of the Datum output.
This token can then be used to represent a unique state-thread which the validator can ensure never leaves the script.
stateThreadPolicy :: TxOutRef -> () -> ScriptContext -> Bool
stateThreadPolicy spend _ ctx@ScriptContext {scriptContextTxInfo = txInfo@TxInfo { txInfoInputs } } =
(fmap txInInfoOutRef txInfoInputs) == [spend]
&& ... -- check initial datum
Now, the validator ensures that the state-thread token remains attached to a valid datum at the script address.