See the Best Practices for Marlowe on Cardano for guidelines on verifying that a Marlowe contract will execute correctly on the Cardano blockchain. Use Marlowe Playground or marlowe-cli run prepare
to simulate the execution of the contract. Use the marlowe-cli run analyze
tool to check for Cardano-specific problems in the contract, or run the contract itself on one of the Cardano testnets. In general, one should not participate in a smart contract whose execution paths one does not understand.
The spending of a UTxO for a Marlowe contract or a payout is validated by a Plutus script, either the semantics validator or the payout validator. For maximum security, one should not sign a transaction unless one has reviewed and understood the contents and implications of the unsigned transaction. For Marlowe, this means verifying the Marlowe contract and its input.
Before signing a Marlowe transaction, one should understand the following:
- Does the transaction operate a Marlowe contract?
- What is the current contract and its state?
- What input is being applied to the contract?
- What else is occurring in the transaction?
Because Marlowe's Plutus validator script is a universal interpreter for all Marlowe contracts of a specified version, the UTxO for a Marlowe contract resides at a well-known script hash. If one verifies that a transaction spends from an address that has the Marlowe script hash as its payment part, then one knows that the true Marlowe validator will run to validate the spending of that UTxO.
One can compute the script hash of the Marlowe validator from first principles by compiling the validator and computing its hash, assuming that one trusts the Marlowe script source code in this repository. Here is a recipe:
nix run 'github:input-output-hk/marlowe-cardano#marlowe-cli' -- contract validator --mainnet --out-file /dev/null --print-hash
addr1w94f8ywk4fg672xasahtk4t9k6w3aql943uxz5rt62d4dvq8evxaf
Validator hash: "6a9391d6aa51af28dd876ebb5565b69d1e83e5ac7861506bd29b56b0"
Here addr1w94f8ywk4fg672xasahtk4t9k6w3aql943uxz5rt62d4dvq8evxaf
is the address of the unstaked Marlowe validator and 6a9391d6aa51af28dd876ebb5565b69d1e83e5ac7861506bd29b56b0
is the well-known script hash of the Marlowe V1 validator.
A staking credential may be associated with the Marlowe validator so that any Ada residing in Marlowe contracts there accrues staking rewards. Thus, the same Marlowe validator might have many different addresses. For example, here are several addresses associated with the same validator hash:
$ nix run 'github:input-output-hk/marlowe-cardano#marlowe-cli' -- contract address --mainnet
addr1w94f8ywk4fg672xasahtk4t9k6w3aql943uxz5rt62d4dvq8evxaf
$ nix run 'github:input-output-hk/marlowe-cardano#marlowe-cli' -- contract address --mainnet --stake-address stake1u8plvp2a7dythh6yxutd0qlzzkncr3gy5ftvxj02d3etafq4kz6s2
addr1z94f8ywk4fg672xasahtk4t9k6w3aql943uxz5rt62d4dvxr7cz4mu6gh005gdck67p7y9d8s8zsfgjkcdy75mrjh6jqe7ks37
$ nix run 'github:input-output-hk/marlowe-cardano#marlowe-cli' -- contract address --mainnet --stake-address stake1u8f6d2307veldu24l0u8gck9yp2f0mvxjqtja9ras2wzacss7utvx
addr1z94f8ywk4fg672xasahtk4t9k6w3aql943uxz5rt62d4dvxn564zluen7mc4t7lcw33v2gz5jlkcdyqh9628mq5u9m3qfuhp8s
Representing an address as base 16 bytes reveals the payment script hash, starting at the second byte:
$ cardano-cli address info --address addr1w94f8ywk4fg672xasahtk4t9k6w3aql943uxz5rt62d4dvq8evxaf | jq -r .base16
716a9391d6aa51af28dd876ebb5565b69d1e83e5ac7861506bd29b56b0
$ cardano-cli address info --address addr1z94f8ywk4fg672xasahtk4t9k6w3aql943uxz5rt62d4dvxr7cz4mu6gh005gdck67p7y9d8s8zsfgjkcdy75mrjh6jqe7ks37 | jq -r .base16
116a9391d6aa51af28dd876ebb5565b69d1e83e5ac7861506bd29b56b0c3f6055df348bbdf443716d783e215a781c504a256c349ea6c72bea4
$ cardano-cli address info --address addr1z94f8ywk4fg672xasahtk4t9k6w3aql943uxz5rt62d4dvxn564zluen7mc4t7lcw33v2gz5jlkcdyqh9628mq5u9m3qfuhp8s | jq -r .base16
116a9391d6aa51af28dd876ebb5565b69d1e83e5ac7861506bd29b56b0d3a6aa2ff333f6f155fbf87462c5205497ed8690172e947d829c2ee2
Below are the version hashes as of January 20, 2024.
Version | Technical Notes | Hash for Semantics Validator | Hash for Role-Payout Validator | Hash for Open-Role Validator |
---|---|---|---|---|
v5 | Optimized using PlutusTx.asData |
377325ad84a55ba0282d844dff2d5f0f18c33fd4a28a0a9d73c6f60d |
fcb8885eb5e4f9a5cfca3c75e8c7280e482af32dcdf2d13e47d05d27 |
2722e12a53dfb4fe3742b8a2c0534bd16b0b5ae492a3d76554bbe8a5 |
v4 | Optimized using PlutusTx 1.15 | 6027a8010c555a4dd6b08882b899f4b3167c6e4524047132202dd984 |
fdade3b86107bc715037b468574dd8d3f884a0da8c9956086b9a1a51 |
36a5c7e49a6b11c7fb65fb61db69ed5ceaa35326af9d952fd30185c0 |
v3 | Recompiled with Node 8.1.2 dependencies | d85fa9bc2bdfd97d5ebdbc5e3fc66f7476213c40c21b73b41257f09d |
10ec7e02d25f5836b3e1098e0d4d8389e71d7a97a57aa737adc1d1fa |
b1d61d0c8a3c0f081a7ccebf0050e3f2c9751e82a4f3953a769dddfb |
v2 | Changes in response to audit | 2ed2631dbb277c84334453c5c437b86325d371f0835a28b910a91a6e |
e165610232235bbbbeff5b998b233daae42979dec92a6722d9cda989 |
|
v1 | Audited | 6a9391d6aa51af28dd876ebb5565b69d1e83e5ac7861506bd29b56b0 |
49076eab20243dc9462511fb98a9cfb719f86e9692288139b7c91df3 |
The pre-transaction state of the contract is defined in the Plutus Datum
associated with the UTxO being spent from the Marlowe script address, and this datum must be provided in the transaction. This datum contains the following:
- the balances of the accounts internal to the contract,
- the history of choices previously made up to this point in the contract's execution,
- the current values of the contract's bound variables, and
- the part of the contract that remains to be executed.
The Datum
can be extracted from the unsigned transaction body and deserialized to Language.Marlowe.Core.V1.Semantics.MarloweData
using the function PlutusLedgerApi.V2.fromData
. Alternatively, the command-line tool marlowe log --show contract
will display the on-chain history of the contract.
The input being applied to the contract in the transaction is defined in the Plutus Redeemer
associated with spending the UTxO from the Marlowe script address, along with the slot validity interval for the transaction specified in the transaction body. The input is a sequence of zero or more deposits, choices, and notifications. The consequences of applying this input to the contract can be studied using a tool like Marlowe Playground or marlowe-cli run prepare
.
The Redeemer
can be extracted from the unsigned transaction body and deserialized to Language.Marlowe.Scripts.MarloweInput
using the function PlutusLedgerApi.V2.fromData
. The command-line tool marlowe-cli util slotting
will compute the relationship between the slots mentioned in the validity interval to the POSIX times in the contract.
The unsigned transaction may contain other spending and payments beyond that specified for the Marlowe contract. This can be examined with the tool cardano-cli transaction view
.
In addition to the semantics validator discussed above, Marlowe has a payout validator. The same security considerations hold for it. Its script hash can be computed as follows:
nix run 'github:input-output-hk/marlowe-cardano#marlowe-cli' -- role validator --mainnet --out-file /dev/null --print-hash
addr1w9yswm4tyqjrmj2xy5glhx9fe7m3n7rwj6fz3qfekly3mucd3rynq
addr1w9yswm4tyqjrmj2xy5glhx9fe7m3n7rwj6fz3qfekly3mucd3rynq
Validator hash: "49076eab20243dc9462511fb98a9cfb719f86e9692288139b7c91df3"
Deserialization of the Datum
and Redeemer
should target (PlutusLedgerApi.V2.CurrencySymbol, PlutusLedgerApi.V2.TokenName)
and ()
, respectively.
The Marlowe validator does not enforce a particular monetary policy for role tokens, in order to make possible novel use cases using role tokens. However, the security of authorizations in a role-based Marlowe contract depends critically upon the role-token monetary policy. Thus, one should carefully scrutinize both the monetary policy and the on-chain disbursement of the tokens before participating in a Marlowe contract. Verifying the monetary policy of a simple script just involves retrieving the script off of the blockchain and studying it; verifying the monetary policy of a Plutus script involves obtaining and studying the Plutus source code for the script and hashing the source code to check the monetary policy ID.
One typically uses a monetary policy (like that supported in Marlowe Runtime) that enforces a single minting event and single tokens for each role: such a monetary policy ensures that the role tokens are true non-fungible tokens (NFTs) so that the holders of the role tokens are provably the only ones who can act as the parties in the contract.
Nevertheless, monetary policies that mint multiple copies of a particular role token or ones with an open minting policy support non-standard use cases. For instance, minting two copies of each role token and distributing them to the same party allows that party to place one token in cold storage as a backup if their wallet containing the "hot" role token becomes inaccessible. Some novel crowdsourcing contracts might involve assigning the role (via identical role tokens that may be minted even after the contract commences) to many participants. Finally, a Plutus contract's minting policy for role tokens can coordinate with the operation of one or more Marlowe contracts.
Marlowe Runtime provides off-chain services that discover Marlowe contract history and build transactions that apply input to Marlowe contracts. The Marlowe Runtime deployment does not have to be trusted if one carefully examines the Marlowe transactions it produces, as discussed in the previous section. If Marlowe Runtime is deployed as part of a web service, then one needs to be aware of the possibility of person-in-the-middle, cross-site scripting, and other attacks.
Marlowe Runtime contains a registry of known Marlowe script versions that it uses to create new Marlowe transactions. One should only use Marlowe Runtime to create contracts if one trusts the script hashes in that registry. The Marlowe test suite verifies that the script registry has not been inadvertently or maliciously altered. (Of course, this does not guarantee that the test itself has not been altered.
Marlowe CLI provides utilities for running and managing Marlowe contracts, including simulating and analyzing them. Transactions constructed with marlowe-cli
can be examined using the same techniques as for studying any other Marlowe transaction.