-
-
Save jhbertra/2537036687ac003a4cb1597b4af77f3b to your computer and use it in GitHub Desktop.
{ | |
"contract": { | |
"timeout": 1655663503000, | |
"timeout_continuation": "close", | |
"when": [ | |
{ | |
"case": { | |
"deposits": 12000000, | |
"into_account": { | |
"address": "addr_test1vq9prvx8ufwutkwxx9cmmuuajaqmjqwujqlp9d8pvg6gupczgtm9j" | |
}, | |
"of_token": { | |
"currency_symbol": "", | |
"token_name": "" | |
}, | |
"party": { | |
"address": "addr_test1vq9prvx8ufwutkwxx9cmmuuajaqmjqwujqlp9d8pvg6gupczgtm9j" | |
} | |
}, | |
"merkleized_then": "30032ba38696e2a2c9f0f37fef7fa8cc7e2063ed4511420939be0ecfa95c0587" | |
} | |
] | |
}, | |
"continuations": { | |
"30032ba38696e2a2c9f0f37fef7fa8cc7e2063ed4511420939be0ecfa95c0587": "https://gist.githubusercontent.com/jhbertra/2537036687ac003a4cb1597b4af77f3b/raw/34b9c0725b3ee49aa85c859d2ccfdeaf49a96cd6/30032ba38696e2a2c9f0f37fef7fa8cc7e2063ed4511420939be0ecfa95c0587.json" | |
} | |
} |
{ | |
"contract": { | |
"timeout": 1655663504000, | |
"timeout_continuation": "close", | |
"when": [ | |
{ | |
"case": { | |
"notify_if": true | |
}, | |
"merkleized_then": "f9232556d1ec9d7bb7d767468336985f350fd3bdeb3360c10f38e620cc8b200c" | |
} | |
] | |
}, | |
"continuations": { | |
"f9232556d1ec9d7bb7d767468336985f350fd3bdeb3360c10f38e620cc8b200c": "https://gist.githubusercontent.com/jhbertra/2537036687ac003a4cb1597b4af77f3b/raw/b426969d33167b27eb87647c8cde1e16de7788a5/f9232556d1ec9d7bb7d767468336985f350fd3bdeb3360c10f38e620cc8b200c.json" | |
} | |
} |
{ | |
"contract": { | |
"from_account": { | |
"address": "addr_test1vq9prvx8ufwutkwxx9cmmuuajaqmjqwujqlp9d8pvg6gupczgtm9j" | |
}, | |
"pay": 5000000, | |
"then": { | |
"timeout": 1655663505000, | |
"timeout_continuation": "close", | |
"when": [ | |
{ | |
"case": { | |
"notify_if": true | |
}, | |
"then": "close" | |
} | |
] | |
}, | |
"to": { | |
"party": { | |
"address": "addr_test1vq9prvx8ufwutkwxx9cmmuuajaqmjqwujqlp9d8pvg6gupczgtm9j" | |
} | |
}, | |
"token": { | |
"currency_symbol": "", | |
"token_name": "" | |
} | |
}, | |
"continuations": {} | |
} |
Alternatives:
One problem with this setup is that loading the actual continuation requires loading two files: 1. The continuations file for the previous contract, then 2. The appropriate continuations file provided as a link within the first file.
We could instead have a URI convention such that:
The client provides a URI root for the contract, upon creation e.g. https://my.example.domain/marlowe-contracts
with the expectation that if we make a GET https://my.example.domain/marlowe-contracts/<contract-hash>
request, it will return the contract JSON for that hash. This would mean that we only need to provide 1 URI in the creation transaction: the base URI for performing lookups. This would save transaction size at the cost of always needing to fetch the creation transaction to load the URI. Alternatively, this could be propagated through the transactions and live in the metadata for each of them.
Under this design, the following would hold:
GET https://my.example.domain/marlowe-contracts/30032ba38696e2a2c9f0f37fef7fa8cc7e2063ed4511420939be0ecfa95c0587
<server responds with body>
{
"timeout": 1655663504000,
"timeout_continuation": "close",
"when": [
{
"case": {
"notify_if": true
},
"merkleized_then": "f9232556d1ec9d7bb7d767468336985f350fd3bdeb3360c10f38e620cc8b200c"
}
]
}
GET https://my.example.domain/marlowe-contracts/f9232556d1ec9d7bb7d767468336985f350fd3bdeb3360c10f38e620cc8b200c
<server responds with body>
{
"from_account": {
"address": "addr_test1vq9prvx8ufwutkwxx9cmmuuajaqmjqwujqlp9d8pvg6gupczgtm9j"
},
"pay": 5000000,
"then": {
"timeout": 1655663505000,
"timeout_continuation": "close",
"when": [
{
"case": {
"notify_if": true
},
"then": "close"
}
]
},
"to": {
"party": {
"address": "addr_test1vq9prvx8ufwutkwxx9cmmuuajaqmjqwujqlp9d8pvg6gupczgtm9j"
}
},
"token": {
"currency_symbol": "",
"token_name": ""
}
}
Side note: This mechanism could be useful for more than just contract continuations, the file could also include other metadata for the contract.
Alternatives:
One problem with this setup is that loading the actual continuation requires loading two files: 1. The continuations file for the previous contract, then 2. The appropriate continuations file provided as a link within the first file.
We could instead have a URI convention such that:
I don't think that the inconvenience of loading two files justifies imposing a URI convention. The original proposal makes no assumption about URIs other than that they can be dereferenced. However, we may want to tag the URI convention with a version number so that we can someday have more sophisticated continuation management. I'm not sure where the version tag would go, however.
Step 3 - Create contract via runtime
When we have a metadata standard for the creation transaction, it would be nice if it included a pointer to this index of all continuations.
Step 1 - Merkleizing the contract
We need to not assume that a contract will ever exist in an unmerkleized form. Some realistic contracts would be many GB of JSON if they were unmerkleized. I don't believe this proposed design assumes an unmerkleized instantiation, but I just wanted to highlight this issue.
Step 1 - Merkleizing the contract
We need to not assume that a contract will ever exist in an unmerkleized form. Some realistic contracts would be many GB of JSON if they were unmerkleized. I don't believe this proposed design assumes an unmerkleized instantiation, but I just wanted to highlight this issue.
That is a good point - and yes in this proposal, since Merkleization happens outside the Runtime, in some sense, it doesn't matter how this happens.
Management of Merkleized Marlowe Contracts on Chain
Step 1 - Merkleizing the contract
Here is the full contract:
After merkleizing, we get 3 fragments with their associated hashes:
Fragment 1 (hash
0x09c2691c3b3bd949c811b111f99389925e3fe474abaca283bad617341f1e6e42
)Fragment 2 (hash
0x30032ba38696e2a2c9f0f37fef7fa8cc7e2063ed4511420939be0ecfa95c0587
)Fragment 3 (hash
0xf9232556d1ec9d7bb7d767468336985f350fd3bdeb3360c10f38e620cc8b200c
)Step 2 - Publishing the linked files
In a depth-first traversal, publish a continuations file for each fragment in the Merkle DAG. This is performed depth-first so that leaf contracts are published first, and URIs are obtained for all dependencies before building the files that depend on those URIs. Here is the structure of a continuations file:
For all terminal contracts (ones without hashed continuations), the
continuations
object will be empty.Step 3 - Create contract via runtime
Provide the merkleized contract and the contract continuations file URI for that contract to the Marlowe Runtime. The Marlowe Runtime will pull the continuations file and verify its contents, failing with an error if it cannot. When the Runtime creates the Tx, it will add the following metadata fragment to the transaction body:
Step 4 - Apply First Input via runtime
The owner of address
addr_test1vq9prvx8ufwutkwxx9cmmuuajaqmjqwujqlp9d8pvg6gupczgtm9j
will deposit 12,000,000 ADA into their account in the contract. To do this, they can either provide an explicitMerkleizedInput
with the appropriate hash and continuation contract, or they can provide aNormalInput
(as if the contract weren't merkleized).Regardless, the runtime will look up the continuations file for the previous contract and determine which continuation it needs to follow. It will then load the continuations file for that continuation (in this case,
https://gist.githubusercontent.com/jhbertra/2537036687ac003a4cb1597b4af77f3b/raw/34b9c0725b3ee49aa85c859d2ccfdeaf49a96cd6/30032ba38696e2a2c9f0f37fef7fa8cc7e2063ed4511420939be0ecfa95c0587.json
). If the user explicitly provides the continuation, this is simply a way to aid the runtime in determining which continuation file to lookup. Otherwise, the runtime will add the correct continuation to the input automatically.When the Runtime creates the Tx for applying the inputs, it will add the following metadata fragment to the transaction body:
Step 5 - Apply Second Input via runtime
Step 5 is done in the same way as step 4. An
INotify
is given as the input for the contract, and this time the Runtime will add the following metadata fragment: