IntersectMBO / plutus

The Plutus language implementation and tools

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

One more change is needed for ScriptPurpose

lehins opened this issue · comments

Describe the feature you'd like

@zliu41 Sorry for not catching this earlier. Instead of an Integer here we need to specify ProposalProcedure

Describe alternatives you've considered

No response

@lehins What's the reason for needing the full ProposalProcedure instead of the index of it?

@zliu41 This is how we've always done the ScriptPurpose and this is the way it is in the spec.

In my opinion it makes no sense and it should always have been an Integer in all of the type constructors of ScriptPurpose. But while discussing this topic with @WhatisRT today, he said that this decision was mostly done for Plutus Scripts, so the script knows which thing actually triggered the script. It is always possible to lookup the thing that triggered the script in the appropriate field of TxInfo using the index, so I am not sure why it was done this way.

If you don't think this is useful information, maybe we should switch the rest Integer instead in Conway?

data ScriptPurpose
  = Minting Haskell.Integer
  | Spending Haskell.Integer
  | Rewarding Haskell.Integer
  | Certifying Haskell.Integer
  | Voting Haskell.Integer
  | Proposing Haskell.Integer

I really don't know how ScriptPurpose is used in Plutus scripts, so it is really hard for me to tell what's best here.

Among the other script purposes I think only Certifying is analogous and can be switched to Integer. However ProposalProcedure, which can contain many parameters, can be bigger than TxCert, which has a fixed size.

Using ProposalProcedure means the ScriptContext will be bigger; on the other hand it makes the constitution script cheaper. Not a big deal either way; we can go with ProposalProcedure. cc @michaelpj

Among the other script purposes I think only Certifying is analogous

They are actually all analogous. Redeemer pointers are specified as Int in the transaction. We resolve them into actual elements in the ledger rules. The only reason why they are not an Int is for the ScriptPurpose in the PlutusContext.

One way or another, whichever way you decide it to be it should be consistent: either all Integer or all actual elements.

Given that we're changing a bunch of stuff for V3, I wouldn't be totally averse to just switching to Integers (or perhaps newtypes around integers so we can provide a bit of help in picking the right lookup function) for the pointers.

I think my argument before was that we might as well give people the "resolved" value. But I'm not sure this is actually useful, and in some cases people then go and match it up against the inputs to figure out the index 🙈 It would mean that you would have to do a linear lookup to find the value, so that's wasted work if you just care about what it is and not where it is 🤷

Unclear! I do agree it should be consistent. And nobody has complained about it, so maybe the current version is good?

I wouldn't be totally averse to just switching to Integers (or perhaps newtypes around integers so we can provide a bit of help in picking the right lookup function) for the pointers.

What if we include both? The index and the element? I think that would provide the best of both of worlds 🙂

Well, it doesn't give us the advantage of being able to shrink the script context. An interesting idea, though 🤔

Providing just the element can be ambiguous in some cases. For example if one transaction contains two different proposals for TreasuryWithdrawal that have the same amount but different anchors. Then the script will not know which is which, because they both will be identical in the list of proposals, despite being two totally separate proposals on the ledger side.

Proving just the index requires an O(n) lookup, so it is also not ideal.

Oh yeah. Also having an index available would allow the plutus programmer to construct TxIn and GovernanceActionId easily. Because the only thing that is required is the transaction body hash (txInfoId) and the index in the list of inputs and proposals respectively.

So, after having a long discussion with @WhatisRT about this issue we came to a consensus that we really need to supply the index for Certifying and Proposing:

data ScriptPurpose
  = Minting V2.CurrencySymbol
  | Spending V2.TxOutRef
  | Rewarding V2.Credential
  | Certifying Haskell.Integer TxCert
  | Voting Voter
  | Proposing Haskell.Integer Proposal

If we don't do this then the script purpose can be ambiguous. The alternative is bring back the translation of Anchor, which I suspect Plutus team would not want to do in order to avoid bloating up the ScriptContext.

The reason for ambiguity is I could submit a transaction with certificates and proposals that will look identical to plutus, while being distinct in reality:

Tx {
  ...
  certs = [RegDRepTxCert c1 100 Nothing, UpdateDRepTxCert c1 (Just drepAnchor), UpdateDRepTxCert c1 Nothing]
  ...
  proposals =
    let w = TreasuryWithdrawals [ra1] (Just policyHash) in
      [ProposalProcedure 200 ra1 w (Just gaAnchor), ProposalProcedure 200 ra1 w Nothing]
  ...
}

which will be translated to PlutusContext as

Tx {
  ...
  certs = [RegDRepTxCert c1 100, UpdateDRepTxCert c1, UpdateDRepTxCert c1]
  ...
  proposals =
    let w = TreasuryWithdrawals [ra1] (Just policyHash) in
      [ProposalProcedure 200 ra1 w, ProposalProcedure 200 ra1 w]
  ...
}

in which case script purpose will be identical for both proposals and it will also be identical for the last two UpdateDRepTxCert certificates. Adding an index to the script purpose for Certifying and Proposing should solve this problem.

I assumed we'd also remove the TxCert and Proposal parts, but I don't mind either way.

Again for consistency I'd prefer adding it everywhere if we're going to do it somewhere.

The main issue is that this really ties in with a bunch of other stuff. @lehins really wants to optionally support indexing redeemers in the order in which they are mentioned on the wire. If we do that, when we show the indices to Plutus we now either need to substitute everything back into the original order (which would mean the index supplied is different from the one Plutus sees), or we'd need to implement our old friend, but not just for inputs, also for multi-asset (the horror!) and everything else.

I think it's also important to recognize that these two types of script purposes are different, since these are the ones where the ordering has actual semantic meaning in the ledger, while everything else can be freely reorganized without changing the semantics of the transaction. So it makes sense that these two would get information that reflects that.

They are actually all analogous.

Again for consistency I'd prefer adding it everywhere if we're going to do it somewhere.

I still don't know what the indexes mean for Minting, Rewarding and Voting. What would they be indexing into? I'm not seeing [CurrencySymbol], [Credential] or [Voter] in the script context.

@zliu41 That is very good question.

Map in plutus is just an assoc list, right? So the index would be the element in the Map starting from the beginning.

This is how redeemer pointers implemented on the wire. When a user supplies Data and Execution Units in transaction they supply it through an index into the Map, rather than the actual Key in the Map. Presumably, that was done for efficiency reasons, in order to reduce transaction size.

It is a bit of a mess, to be honest with you. In this PR, however, we definitely need to solve the issue of ambiguity for Proposals and Certificates, neither of which have an issue with ordering.

What would they be indexing into? I'm not seeing [CurrencySymbol], [Credential] or [Voter] in the script context.

@zliu41 Sorry, I misunderstood your question. These are the fields that can contain script hashes as such they can be locked by scripts and need a script purpose. All three are maps, not lists, that's why you are not seeing them:

PlutusTx's map API is not exactly assocation list, it's a mess - it is a weird and confusing hybrid of an association list and a map. But even if it is an association list, I don't think integer indexing is an operation that makes sense on association lists - they are supposed to be accessed by keys. Indeed PlutusTx's map API doesn't provide an indexing operation: you need to convert it to a regular list via Map.toList first.

If integer indexing is indeed useful for Minting, Rewarding and Voting, I would suggest changing the corresponding maps to regular lists in the script context.

Fortunately you guys prefer having the indexes only on Proposing and Certifying anyway, so we don't really have a problem then. I also think it makes sense to supply both the index and the other argument, since it makes the script easier to write and cheaper. So I'll update the PR accordingly.

PlutusTx's map API is not exactly assocation list, it's a mess - it is a weird and confusing hybrid of an association list and a map. But even if it is an association list, I don't think integer indexing is an operation that makes sense on association lists - they are supposed to be accessed by keys. Indeed PlutusTx's map API doesn't provide an indexing operation: you need to convert it to a regular list via Map.toList first.

If integer indexing is indeed useful for Minting, Rewarding and Voting, I would suggest changing the corresponding maps to regular lists in the script context.

Fortunately you guys prefer having the indexes only on Proposing and Certifying anyway, so we don't really have a problem then. I also think it makes sense to supply both the index and the other argument, since it makes the script easier to write and cheaper. So I'll update the PR accordingly.

Is this both the index and other argument for all purposes or just new ones? Preferably I know a lot of users would prefer having both since the index can be extremely helpful for quickly looking up inputs. If needed I can provide more specific use cases.

Is this both the index and other argument for all purposes or just new ones?

Yes, both index and argument. However, we aren't quite sure if it is safe yet to add an index for inputs. Reason for this is in the fact that inputs are a Set in Ledger and it depends on the Ord instance. There is a much more complicated issue at hand here with regards to inputs, which we probably won't have enough time to address for Conway and PlutusV3

Proposals and certificates, on the other hand, preserve the order in which they were provided on the wire, thus index is stable.