-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SCP-4107 MIP for universal validator #1
Conversation
When used for minting role tokens, this "universal validator" must enforce the following constraints: | ||
1. The validator is parameterized by a `TxOut` that it consumes when minting tokens. | ||
2. The `Redeemer` for the validator is the list of roles (i.e., token names) that will be minted, along with the number of tokens minted on a role-by-role basis. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should allow the monetary policy script to burn tokens, without constraint. This would be a simple change to Alex's validator. This doesn't decrease the security of Marlowe contracts because owners are always at risk of losing their private keys to the wallet where the token resides, sending the token into oblivion, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that sounds better than not allowing burning at all. Maybe eventually we can think of a way of requiring the contract to be closed for burning
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd need to leave the contract on the chain (just with Close
as its continuation) and modify the monetary policy so that it could burn tokens when the contract is in this Close
quiescent state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess leaving the contract on-chain is pretty similar to not burning the tokens
Thus, having the `MarloweParams` parameterize the universal validator via that `TxOut` consumed in the minting process, rather than the `CurrencySymbol`, inexorably ties the minting validator to the spending validator. The present Marlowe validator's use of `CurrencySymbol` in its `MarloweParams` allows it to accept *any* currency symbol for role tokens, but this MIP's use of the `TxOut` in the `MarloweParams` for the *universal* validator ensures that the spending validator can only use tokens minted by minting validator because both these validators are *one and the same*. | ||
|
||
Note that the MIP forbids three potentiallly important and presently possible use cases: | ||
1. Customized monetary policies. *Some Marlowe dApps (e.g., DAOs or centrally administered applications) would benefit from supervisory control via a sophisticated minting policy.* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is my only reservation about this MIP. It will eliminate novel use of custom monetary policies in conjunction with Marlowe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking the same thing, some of Marlowe's limitations due to its static nature could be overcome by using custom monetary policies.
At the same time, even if we only maintain/support one particular validator, it doesn't mean that someone could write/fork a validator that follows Marlowe's semantics with a custom monetary policy (although it would be much harder than using the official one)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a potential solution, though I think it's far more likely that we would do this ourselves as part of delivering a system to a large client. This would be expensive though, as we would need to get the forked validator audited and certified separately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and if we make a version of the validator we will need a corresponding supporting version of the runtime, etc. From the point of view of the audit, I don't think it makes a difference, because the audit results will at best be subject to the monetary policy (independently of whether it is in or outside of the validator).
But from the security point of view, not having the monetary policy fixed by the version of the validator would open the door for attacks that would be pretty tricky to communicate to the user, since the monetary policy can be anything, the best we can do is tell the user it is not standard if its hash doesn't belong to a list (or something like this, I guess).
On the other hand, if we extend the validator to be cleverer and handle the monetary policy, we could manually add support in the future for specific behaviours like the ones you suggest, and then we can explain them to the user easily
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, the increase in security is probably worth the loss of flexibility (no custom monetary policies or reuse of role tokens among multiple contracts).
|
||
## Path to Active | ||
|
||
In implementation is proposed in [marlowe-cardano PR#117](https://github.com/input-output-hk/marlowe-cardano/pull/117). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've merged the Language.Marlowe.Scripts
from PR#117 into the SCP-4107 branch, which is derived from the sprint-61
branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure but maybe it would be valuable to include some summary about the implementation here?
From my perspective it is worth mentioning that we are doing here a "unification" of miniting policy script and spending script which have completely different types! We should ask ourselves - is this proper usage of this technology which should provide as guarantees through types?
From my perspective this solution requires a lot of "low level hackery" and makes our on chain code pretty hard to understand but of course I'm not proficient plutus coder so my point may be invalid.
I wonder how spread this idiom is in the larger plutus community. Are there any other idioms which we can adopt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Are we bypassing any checks by doing this?
One thing related to this to consider too is that we may be using an "unintended feature", so maybe in the future, a new version of Plutus or the ledger could prevent us from continuing doing this? We could have this as a temporary hack and liaise with Plutus to potentially get a less hacky way of doing this same thing, or at least making sure it doesn't get disabled
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we bypassing any checks by doing this?
I carefully reviewed the proposed implementation, and it doesn't by bypass any checks. It may tie the validator to Plutus V1 or V2, because we don't know what Plutus V3+ will contain.
|
||
## Backwards Compatibility | ||
|
||
This alteration to the validator is not backward compatible with the following Marlowe components: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we both maintain backwards compatibility and support custom minting policies if we change MarloweParams
to the sum type
data MarloweParams =
MarloweParams -- Previously.
{
rolePayoutValidatorHash :: ValidatorHash
, rolesCurrency :: CurrencySymbol
}
| MarloweUniversalParams -- This MIP.
{
rolePayoutValidatorHash :: ValidatorHash
, uniqueTxOutRef :: (TxId, Integer)
}
and make some minor adjustments where uniqueTxOutRef
is used and where rolesCurrency
is used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we care that much about backward compatibility? We do have the advantage that Marlowe isn't currently used in real-world solutions (can we verify this assumption?) which means we can afford to break backwards compatibility without causing significant disruption. I would just make this a clean break at this point, essentially invalidating all legacy Marlowe contracts, as they are all 100% test contracts anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If at some point in the future we want to do this, we could use GADTs and type parameters to carry a witness of validator versions at the type level (like the hard-fork combinator does in Cardano Node):
data MarloweParams (version :: ValidatorVersion) where
MarloweParamsV0
:: ValidatorHash
-> CurrencySymbol
-> MarloweParams ValidatorV0
MarloweParamsV1
:: ValidatorHash
-> TxOutRef
-> MarloweParams ValidatorV1
But at least for now, I don't think the added complexity is worth it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I much prefer the GADT approach, though we'd have to make sure this is compatible with the Plutus compiler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the discussion so far, I propose we not include this flexibility to the old-style MarloweParams
.
1. Customized monetary policies. *Some Marlowe dApps (e.g., DAOs or centrally administered applications) would benefit from supervisory control via a sophisticated minting policy.* | ||
2. Minting of additional role tokens after the original minting. *There may be certain crowd-oriented Marlowe dApps where this is desirable.* | ||
3. Burning of role tokens after a contract completes. *This makes it impossible ever to recover the minimum Ada associated with a role token, thus effectively increasing the up-front cost of Marlowe contracts.* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m not completely sure that moving MarloweParams
into MarloweData
(to maximize the use of reference scripts, SCP-4174) is compatible with the universal validator. We’d have to make sure that the minting script depends upon MarloweParams
but the spending script doesn’t, even though these two scripts must be the same Plutus code.
Perhaps we should implement SCP-4107 and SCP-4174 at the same time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain why the spending script could not depend on the MarloweParams
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain why the spending script could not depend on the MarloweParams?
It currently does, but it is desirable for the spending script not to depend upon any parameters because then it could be used as a reference script for every Marlowe contract. If the spending script depends upon a parameters, then we'd need one reference script for each parameter set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see having a single Marlowe interpreter (per version) across the whole chain a really huge possible optimization strategy. We are now struggling with transaction size limits and this clearly impacts further development of the Language itself.
I want to strongly emphasize that we possibly lose a huge benefit of our architecture which is based on a constant language interpreter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add MarloweParams
to the spending script or something like that? It does sounds like having a single Marlowe validator per version would be very beneficial
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m not completely sure that moving
MarloweParams
intoMarloweData
. . . is compatible with the universal validator.
This method is indeed compatible with a single Marlowe interpreter across the whole chain, if the monetary policy enforces that the Datum
send to the Marlowe script contains the MarloweParams
. This could be enforced with a minor change to https://github.com/input-output-hk/marlowe-cardano/blob/f51252d682238932a412f0f6baaf3f354309e2bc/marlowe/src/Language/Marlowe/Scripts.hs#L315
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in principle this LGTM, my main question is if this is a pre-requisite of the universal script or if it's something to avoid attack vectors.
This document describes a modification to the token-minting process for Marlowe and the unification of the minting of role tokens and the operation of the Marlowe application or payout validators. Although it requires a change to the `Language.Marlowe.Core.V1.Semantics.MarloweParams` datatype that will eliminate some use cases for role tokens, it will enforce certain new guarantees on the role-token usage. | ||
|
||
|
||
## Motivation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this MIP a requirement for having Universal Validator and being able to utilize reference scripts to reduce the transaction size or is that independent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This MIP is independent of reference scripts, but we could modify this MIP to better support reference scripts by moving MarloweParams
into the Datum
.
Thus, having the `MarloweParams` parameterize the universal validator via that `TxOut` consumed in the minting process, rather than the `CurrencySymbol`, inexorably ties the minting validator to the spending validator. The present Marlowe validator's use of `CurrencySymbol` in its `MarloweParams` allows it to accept *any* currency symbol for role tokens, but this MIP's use of the `TxOut` in the `MarloweParams` for the *universal* validator ensures that the spending validator can only use tokens minted by minting validator because both these validators are *one and the same*. | ||
|
||
Note that the MIP forbids three potentiallly important and presently possible use cases: | ||
1. Customized monetary policies. *Some Marlowe dApps (e.g., DAOs or centrally administered applications) would benefit from supervisory control via a sophisticated minting policy.* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking the same thing, some of Marlowe's limitations due to its static nature could be overcome by using custom monetary policies.
At the same time, even if we only maintain/support one particular validator, it doesn't mean that someone could write/fork a validator that follows Marlowe's semantics with a custom monetary policy (although it would be much harder than using the official one)
Note that the MIP forbids three potentiallly important and presently possible use cases: | ||
1. Customized monetary policies. *Some Marlowe dApps (e.g., DAOs or centrally administered applications) would benefit from supervisory control via a sophisticated minting policy.* | ||
2. Minting of additional role tokens after the original minting. *There may be certain crowd-oriented Marlowe dApps where this is desirable.* | ||
3. Burning of role tokens after a contract completes. *This makes it impossible ever to recover the minimum Ada associated with a role token, thus effectively increasing the up-front cost of Marlowe contracts.* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to burn tokens after a contract complete?
Is this something that the applyInput
does when it reaches a close?
could we pay the min-ada to the token owner when burning?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unburnable tokens are a waste of ADA.
* Marlowe backend, `Language.Marlowe.Client` | ||
* Marlowe CLI, `marlowe-cli` | ||
* Marlowe Run, `marlowe-dashboard-server` | ||
* Marlowe history, `Language.Marlowe.Client.History` | ||
* Marlowe test cases | ||
* Marlowe Pioneer Program lectures |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of these components are soon going to be superseded by runtime-based versions anyway. And we can still run the legacy code if we need to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. I think the proposal is reasonable, and the concerns that have been raised seem to either be non-issues (backwards compatibility) or have feasible workarounds (supporting custom monetary policies).
#### Minting | ||
|
||
When used for minting role tokens, this "universal validator" must enforce the following constraints: | ||
1. The validator is parameterized by a `TxOut` that it consumes when minting tokens. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also consider a hybrid which takes Maybe TxOut
. In the case of Nothing
we get a constant validator which checks the datum
for a policy id. I know it is not particularly pretty encoding but it covers both scenarios - more secure universal with sever space limitation (only referencing a script from a single contract thread - unique script per contract) or full script referencing (one script to rule them all per Marlowe version).
1. Customized monetary policies. *Some Marlowe dApps (e.g., DAOs or centrally administered applications) would benefit from supervisory control via a sophisticated minting policy.* | ||
2. Minting of additional role tokens after the original minting. *There may be certain crowd-oriented Marlowe dApps where this is desirable.* | ||
3. Burning of role tokens after a contract completes. *This makes it impossible ever to recover the minimum Ada associated with a role token, thus effectively increasing the up-front cost of Marlowe contracts.* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see having a single Marlowe interpreter (per version) across the whole chain a really huge possible optimization strategy. We are now struggling with transaction size limits and this clearly impacts further development of the Language itself.
I want to strongly emphasize that we possibly lose a huge benefit of our architecture which is based on a constant language interpreter.
|
||
## Path to Active | ||
|
||
In implementation is proposed in [marlowe-cardano PR#117](https://github.com/input-output-hk/marlowe-cardano/pull/117). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure but maybe it would be valuable to include some summary about the implementation here?
From my perspective it is worth mentioning that we are doing here a "unification" of miniting policy script and spending script which have completely different types! We should ask ourselves - is this proper usage of this technology which should provide as guarantees through types?
From my perspective this solution requires a lot of "low level hackery" and makes our on chain code pretty hard to understand but of course I'm not proficient plutus coder so my point may be invalid.
I wonder how spread this idiom is in the larger plutus community. Are there any other idioms which we can adopt?
The lack of an on-chain guarantee for the role-token monetary policy opens Marlowe to several off-chain vulnerabilities: For example, a Marlowe contract might be created for role tokens having an open monetary policy that allows additional role tokens to be created after the contract commences. The controller of that monetary policy could mint duplicate role tokens for parties in the contract and impersonate them, authorizing without consent transactions using the duplicate tokens. | ||
|
||
Thus, enforcing that each role tokens be a minted only once provides a security guarantee that duplicate role tokens will not be later minted and those duplicates used for role-based authorization of Marlowe choices and deposits. It also provides an option for minting true non-fungible native role tokens (that there is provably only ever one minted) if minting is limited to exactly one token per role. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we take a step back and consider what these "on chain" guarantees mean for the Marlowe users?
-
In the current situation how do we validate that a given transaction really represents a safe Marlowe contract "deployment"?
It seems that we have to perform few steps to gain confidence that we deal with safe Marlowe setup (
n
- is contract thread length on the chain; I assume separate query per transaction):-
We have to check if proper spending validator was used (
O(1)
) -
We have to check if proper/safe miniting policy was used to mint the tokens (
O(n)
). -
We have to check initial state and the initial contract itself (
O(n)
)...
or we can skip traversing history and only analyze the current continuation or hash and state (O(1)
). -
We can check role distribution if this is also important to us (
O(n)
).
-
-
How does this proposal improves the current situation?
It seems that we can skip miniting script verification step and possibly have constant time of verification without quering the blockchain (
O(1)
) (Is this really the case in real scenarios - don't we want to usually gain the whole picture on the contract anyway? IsO(n)
verification complexity a problem in real scenarios?).
Additionally to perform this verification step we don't have to use two parameters (Marlowe validator script + Mniting policy script) but only Marlowe validator script is required. -
Can we reduce the above verification flow without introducing universal validator?
I think so. In the next comment I sketch a verification schema which allows us
to doO(1)
verification ofMarlowe Tx
and proves that proper minting policy
was used together with proper Marlowe validator.
Verification step requires only a proper minting policy as an input and the
transaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's try to sketch a possible "Marlowe policy tracking" schema. It is a replacement for a unified validator which preserves O(1)
characteristic of script(s) verification step.
This approach uses constant Marlowe validator and relies only on a small modifications of the Marlowe validator itself. It moves most of the invariant checks to the policy script.
Scope limit
I focus here on the policy tracking so I skipped details regarding MarloweParams
handling as well as validatorToken
burning. I want to only indicate that in this architecture we are going to have MarloweParams
which consists of just a single value - roleCurrency
. We are going to have a constant rolePayoutScript
hash (role policy script gonna pick currency symbol from its datum) and a bit modified Marlowe validator check for the payout script and bit different constant payout script itself.
It is worth mentioning that we want to keep roleCurrency
and minting of thread token
even in the case of contracts without roles so we can mark PK
payouts using datum
with roleCurrency
to prevent double spending.
I'm going to expand on that if we want to really consider these schema.
Types
data PolicyParams = PolicyParams
{ ppTxOutRef :: TxOutRef
, ppRoles :: List TokeName -- Left for simplicity.
-- We can probably replace this list by just a `hash`.
}
data MarloweEnv = MarloweEnv
{ marloweData :: MarloweData
, marloweParams :: MarloweParams
, policyParams :: PolicyParams
}
Verification flow:
Inputs
-
Our correct minting policy script function.
-
Transaction which we want to verify.
Verification procedure
-
Pick
UTxO
of interest (which possibly contains a Marlowe contract validator). -
Check its
datum
forpolicyParams :: PolicyParams
value (the whole datum should be value of typeMarloweEnv
). -
Apply our policy script to the above
policyParams
to getcurrencySymbol :: CurrencySymbol
from that. -
Check if in the
Value
part of theUTxO
we find a token of this currency with empty token name{ currencySymbol -> { "" -> 1 }}
(we call itvalidadatorToken
from this point forward). -
If that is the case then the check is done and we should be sure (we still lack proper proof ;-)) that a given transaction is a possible last element on the "Marlowe Contract thread" which was properly initialized and executed:
-
It uses proper Marlowe validator.
-
It used a proper policy script to mint role tokens.
-
The policy was correctly initialized so the currency is unique and only proper role tokens were minted and it is impossible to mint any more tokens of this currency.
-
Implementation
Minting policy
Constant:
marlowe :: Address
- Marlowe Validator script address
Parameters:
PolicyParams { ppTxOutRef, ppRoles }
Checks:
-
Check if this transaction consumes
ppTxOutRef
. -
Check if there is exactly one
TxOut
to an address of desired spending validatormarlowe
(uniqueness can be relaxed in the future - we can replace by strongerdatum
checks I think). -
Check if the value attached to this
TxOut
containsvalidatorToken
- one coin ofownCurrencySymbol
with empty token name. -
Check that there is not an empty string between
ppRoles
(not $ "" `elem` ppRoles
). -
Check if transaction mints set of tokens consisting of
ppRoles
andvalidatorToken
([""] <> ppRoles
). -
Check if datum for
marlowe
TxOut
contains a value ofMarloweEnv
and (using pseudo notation to distinguishdatum
and values from script parameters):-
datum.policyParams.ppTxOutRef == parameters.ppTxOutRef
-
extractRoles datum.marloweData.marloweContract == parameters.ppRoles
-
datum.marloweParams.roleCurrency == ownCurrencySymbol
-
Marlowe validator
Checks related to "policy tracking"
-
Check if a possible singleton continuation (
txOut
atmarlowe
address):-
Is associated with
datum
in whichpolicyParams
is preserved. -
roleCurrency
references correctvalidatorToken
inValue
. -
Preserves
validatorToken
in itsValue
.
-
-
If there is no continuation
txOut
check ifvalidatorToken
is burned in the transaction.
Execution
-
Marlowe validator uses
marloweData
to store its state. -
Marlowe validator uses
marloweParams.roleCurrency
when authenticating parties. -
Marlowe validator uses
marloweParams.roleCurrency
together with some constantpayoutScript
address to check payouts handling. -
Marlowe validator uses
marloweParams.roleCurrency
to check ifPK
payouts are marked using this value indatum
correctly.
Sketch of the proof
A proper proof should be provided but the sketch of the reasoning could look like this:
-
Correct minting policy => unique currency symbol because of
ppTxOutRef
check. -
Correct minting policy => single and correct Marlowe validator output exists.
-
Correct minting policy => role tokens are minted correctly for a given Marlowe validator contract.
-
Correct Marlowe validator => Marlowe validator is preserved during contract execution.
-
Correct Marlowe validator =>
policyParams
is preserved during contract execution. -
Correct minting policy => unique
validatorToken
is assigned to correct Marlowe validator. -
Correct Marlowe validator =>
validatorToken
is preserved and witnesses a unique trace to to the initial transaction. -
Correct Marlowe validator =>
validatorToken
is burned at the end of the contract execution. -
validatorToken
which contains correctcurrencySymbol
attached to an UTxO => Correct minting policy was used during initial transaction for minting.
Pros / Cons
Comming soon... ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it uses one special token that the validator never lets go of and burns at the end. And we know the special token is unique because that is enforced by the minting policy, and we know that a validator that has it necessarily comes from the minting policy cause that is the only way of getting the token. Very clever :)
I cannot see any problems with the idea at the moment, but yes it is going to be tricky to make sure there really aren't subtleties
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if it has any practical meaning or sens what I'm going to write now so please just ignore it if it doesn't ;-)
In merkleized case if we would like to merkleize role distribution as well we probably wanted to have a bit different strategy because roles would be minted throughout the execution of the contract.
In this case we can treat validatorToken
value as a "counter" which should be increased on every step. This counter would be increased necessarily by our policy script - we should branch on the pcTxOutRef
check and if we are in the middle of the thread we should just grab validatorToken
from the input and increase the value. Policy script would also check at every step and output role tokens if necessary.
In such a case Marlowe validator should all the time check if the continuation contains counter increased by one.
In this scenario validatorToken
witnesses that we used correct policy script at every step in the Marlowe contract thread back to the initial transaction and it handled all contract tokens minting.
This strategy is in some sens generalization of the previous one and can be used in the simpler case as well.
Side note: I think that this policy driven execution stepper could be generalized further. It can be a base for "a library" of composable constant functions on the chain. Composition would be done through a minting policy which takes a "plan" of the execution as parameter (ordered list of functions representing fun3 . fun2 . fun1
) and initial value as parameter as well (and some TxOutRef
of course as well ;-)). It should check at every step if we proceed accordingly to the plan. "Library functions" should only check the step counter growth and then they should perform their job.
Maybe we can change plan into DAG and start doing some concurrency by using token names as threadId
's or something ;-)
I'm not sure if this idea has any real value though... but maybe if we are able to split some huge interpreter into small and fast composable parts then who knows ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a viable approach that solves the same currency-lookup problem that the universal validator does. However, in increase the transaction size (larger validator and extra token) and execute cost (more logic) and memory (larger script context). Is that worth it?
The spending validator probably doesn't a need "singleton continuation" check because validatorToken
is a singleton that cannot be sent simultaneously to two continuations.
A variation of this approach (and the DSL) could open possibilities for minting additional role tokens while a contract is running. As you point out, something along these lines could
BTW, if we had used a validatorToken
approach like this previously, then the validator wouldn't have been subject to double satisfaction.
I'm a little concerned about the use of a blank token name ""
for validatorToken
because it is a special value and because it means that a blank token name that is valid in Marlowe semantics is not valid on chain. This is probably okay, however, because the Semantics don't enforce the 32-byte maximum on token names, either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course verification schema gonna change. In such a case we have to just grab the whole history to discover that "non minting policy" was a valid choice. Unfortunately we also need info now about the actual validator address etc. so maybe it is just better to mint the thread token - it is not a significant overhead.
Under the table I put few comments. I would like to have really focused discussion which properties from the table are seriously meaningful and estimate more precisely what are the differences for this meaningful properties.
I would also like to have some perspective and evaluation of the flexibility and ease of reasoning regarding different approaches. I sketched above on demand minting schema for merkleized role distribution... it would be nice to have a set of solutions to this kind of variations and evaluate them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@palas At the end I think that having uniform thread token based architecture (validatorToken
) is really beneficial for Marlowe handling in general. runtime
can just assume that we use constant validators and thread tokens and that is the way to discover a particular contract history. Even if it means a slight overhead (impact should be measured - we lower the throughput by the size of minting policy) in the initial transaction it provides a clear on chain interface. This approach doesn't affect spending validator so it size stays the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't necessarily think that tracking PolicyParams
makes sens because verification can be done through direct check of the initial transaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding validatorToken
name - if we consider any surface language to the Marlowe
I would rather imagine that ""
wasn't a role valid identifier ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In principle we can reserve for validatorToken
any identifier which is invalid for the Role
value.
When used for minting role tokens, this "universal validator" must enforce the following constraints: | ||
1. The validator is parameterized by a `TxOut` that it consumes when minting tokens. | ||
2. The `Redeemer` for the validator is the list of roles (i.e., token names) that will be minted, along with the number of tokens minted on a role-by-role basis. | ||
3. Minting can only occur if there is output to a the Marlowe script address: i.e., the minting transaction must also create a new Marlowe contract. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this clarification that the minting must create a new Marlowe contract.
1. Customized monetary policies. *Some Marlowe dApps (e.g., DAOs or centrally administered applications) would benefit from supervisory control via a sophisticated minting policy.* | ||
2. Minting of additional role tokens after the original minting. *There may be certain crowd-oriented Marlowe dApps where this is desirable.* | ||
3. Burning of role tokens after a contract completes. *This makes it impossible ever to recover the minimum Ada associated with a role token, thus effectively increasing the up-front cost of Marlowe contracts.* | ||
4. Reuse of role tokens among multiple contracts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this clarification that role tokens cannot be used among multiple contracts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this isn't correct. The current implementation would allow the reuse of role tokens. I believe that it is impossible to forbid the reuse of role tokens. (We'd have to switch to "smart" tokens in order to forbid this.)
What problems are we trying to solve here, and at what cost?
Here are properites of the three validators that we've been discussing, plus a fourth ("Resulable") that simple moves
|
Let me rephrase this to:
EDIT: Reference scripts gives us a flexibility to separate script deployment and Marlowe contract transaction settlement. If we use all the scripts by reference then we can assume that all the rest of the transaction size can be used by Marlowe contract. Here are my rough estimates:
It is a bit speculative to compare these two but seems like in general between all options the difference won't be significant. It requires testing:
Brian please let me know if I can update the table with the above estimations. |
Few more comments / questions regarding semantics of properties listed in the table.
Maybe that is not best example but I sketched above a generalization which can handle incremental minting in merkleized contracts for example but requires a slight change in the spending validator check and minting policy usage on every transaction.
I'm not sure what that means. Do we mean if we can change minting policy easily? |
@paluh , yes, please updated the table. I think the memory impact is more important than the transaction-size impact. The transaction size can be alleviated by CIP-33 reference scripts, but that doesn't save memory. We have seen cases where a large |
@paluh, |
My opinion about the universal validator has vacillated over the past two weeks, so I thought I'd summarize my current thoughts.
|
@bwbush Should I iterate over |
@bwbush I think that we can drop |
This document describes a modification to the token-minting process for Marlowe and the unification of the minting of role tokens and the operation of the Marlowe application or payout validators. Although it requires a change to the
Language.Marlowe.Core.V1.Semantics.MarloweParams
datatype that will eliminate some use cases for role tokens, it will enforce certain new guarantees on the role-token usage.