I want to run a statemachine on testnet.

The SM runs in the emulator, and I can initialize on testnet, but if I try to make a new client it throws an error. The error comes from transition failure, but this is due to the PAB not being able to re-establish state.

I find this pretty hard to debug, but as far as I can see we have the following:

  • The SM has the function getState function (here)
  • This calls typeScriptTxOut (here) which expects a value Right Datum or else errors.
  • The ChainIndexTxOut (Here) has the value type Either DatumHash Datum
  • the PAB ask the relies on the chain-index for this data.
  • The chain-index seems to return only Left DatumHash (here)

The chain index does know the datum from the hash. However this requires an additional query to the datum table or equivalent join.

Has anyone else had this problem / solved this problem/ able to explain how I've got it wrong, and there's no problem here?

(plutus-apps tag:7ed28bd67d7653b3ffe08b45848134380a738148)

  • Maybe a bit obvious but what constraints did you use in the endpoints? Did you use MustHashDatum or MustIncludeDatum in the construction of the transactions? The former only adds the hash of the datum to the output (and thus results in a Left DatumHash. The latter actually adds the datum to the transaction which creates the utxo (and thus results in a Right Datum).
    – Fermat
    May 6, 2022 at 11:24
  • Don't think I understand the comment. Constraints for SM datums are handled by the SM framework (github.com/input-output-hk/plutus-apps/blob/…). The problem above has now been fixed. (Checkout the issue linked below and the referenced PR)
    – waalge
    May 6, 2022 at 15:26

2 Answers 2


85% sure this is a bug introduced by changes to the chain index.

A work around is to mod the StateMachine.hs file

getDatum ::
    ( AsSMContractError e)
    => Tx.ChainIndexTxOut
    -> Contract w schema e Tx.ChainIndexTxOut
getDatum tx = mapError (review _SMContractError) $ do
    case Tx._ciTxOutDatum tx of
         Left dh -> do
            dM <- datumFromHash dh
            case dM of
                 Just d -> return (set Tx.ciTxOutDatum (Right d) tx)
                 Nothing -> return tx
         Right _ -> return tx

{-| Get the current on-chain state of the state machine instance.
    Return Nothing if there is no state on chain.
    Throws an @SMContractError@ if the number of outputs at the machine address is greater than one.
getOnChainState ::
    ( AsSMContractError e
    , PlutusTx.FromData state
    , PlutusTx.ToData state
    => StateMachineClient state i
    -> Contract w schema e (Maybe (OnChainState state i, Map TxOutRef Tx.ChainIndexTxOut))
getOnChainState StateMachineClient{scInstance, scChooser} = mapError (review _SMContractError) $ do
    utxoTx_ <- utxosAt (SM.machineAddress scInstance)
    utxoTx <- sequence (Map.map getDatum utxoTx_) -- FETCH DATUMS
    let states = getStates scInstance utxoTx
    case states of
        [] -> pure Nothing
        _  -> case scChooser states of
                Left err    -> throwing _SMContractError err
                Right state -> pure $ Just (state, utxoTx)

Not pretty but I think it works. Alternative is to mod the chain index code emulating the old behavior.



My first sugestion would be to avoid using the out-of-the box statemachine from the plutus library at the moment. In it's current form it is highly inneficient and you will quickly run into maxTx size limits on testnet. If you want to run a state machine, it is best to build your own so it can be as efficient as possible. Also, chain index and pab is a nightmare when trying to test on testnet, so it is probably best to use a service like blockfrost.

I have just release The Open Source Cardano Lottery project, which has source code that implements a state machine as well as how to test on testnet (and devnent). It is a beta non-prod release, so there is room for improvements, but it is fully functional on the testnet.

You can find the source code here:


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.