plutus
plutus copied to clipboard
What guarantees do we have about about the internal structure of the things in `ScriptContext`?
Describe the feature you'd like
I'm specifically wondering about:
- Internal ordering of entries in maps in
ScriptContext.- Both for things like
txInfoDatathat don't use theMapconstructor and also things likeValuethat do use it.
- Both for things like
- Is it possible for there to be
0of a token in a value? - Is it possible for there to be an empty
CurrencySymbolentry in a value? - Internal ordering of entries in sets.
- E.g.
txInfoDCert,txInfoSignatories, and similar.
- E.g.
I already know that inputs are lexicographically ordered as noted in https://github.com/input-output-hk/plutus/issues/4296#issuecomment-1004723515.
The questions about values are e.g. to know whether a naïve equality check represents "real" equality.
If you could have 0 of a token, then a Value with 0 of a token would not be equal to one that is otherwise the same
but does not include the same, even though they represent the same amount.
Describe alternatives you've considered
No response
Re: Value, see https://github.com/input-output-hk/plutus/issues/4258
The questions about values are e.g. to know whether a naïve equality check represents "real" equality.
What kind of naive equality check are you suggesting? Neither equality on the underlying Map representation nor on the Data representation are correct. You want equivalence of Values, which is what the Eq instance we provide does. Anything else isn't correct.
In principle we could require the representation of Value to be normalized, but then we'd have to be very careful to ensure that this property was always maintained.
Internal ordering of entries in maps in ScriptContext. Internal ordering of entries in sets. E.g. txInfoDCert, txInfoSignatories, and similar.
It depends on how they're represented in the ledger. For example, certificates are actually a sequence in the ledger, and so the order will be the same as what the user provided. It would be nice if we could make that clearer. Perhaps we just need a Set newtype to indicate that certain lists don't have a fixed order...
But for things that are set-like we don't provide any ordering guarantees, and I don't think we're likely to. Maybe in the future we will if something like https://github.com/cardano-foundation/CIPs/pull/231 gets accepted.
What kind of naive equality check are you suggesting? Neither equality on the underlying
Maprepresentation nor on theDatarepresentation are correct. You want equivalence ofValues, which is what theEqinstance we provide does. Anything else isn't correct.
Note that equality (and other relations, like <=) in the ledger semantics behave exactly like that, i.e. adding redundant zeros doesn't affect them (or, equivalently, everything that's not non-zero is zero). So if a relation were finer than that, it wouldn't match the ledger semantics.
So is it possible to construct a transaction where we control the order of the entries in txInfoMint? Can we also mint a zero amount?
There are no guarantees about the order. I think they are sorted (similar to inputs), but there are some potential subtleties in the implementation that may or may not screw you over if you try to rely on it. And yes, you can always mint zero of something (which of course does nothing but increase fees).
@WhatisRT Does minting 0 still run the script? If so, can you also Withdraw 0 ADA from a stake account, running a stake validator in the process?
I'd like to remind you all that this stuff is specified :) If you look in the Shelley formal spec, you will see that the set of minting policies which is run is the support of the Value considered as a finitely-supported-function; i.e. it does not include anything which maps to zero. This is consistent with 0 entries being equivalent to not being present.
Neither equality on the underlying Map representation nor on the Data representation are correct. You want equivalence of Values, which is what the Eq instance we provide does. Anything else isn't correct.
Doesn't the Cardano ledger impl and the CLI already normalize Values when building transactions though?
The CLI seems to do such a thing when building transaction here.
The Cardano ledger impl also seems to maintain sorted Values (and potentially even normalized via prune). I'd assume transforming such a Value (which is a real Map) into the Plutus Value (which is an assoc list) would indeed produce a normalized Value - but I'm not sure if there's more stuff going on in the middle.
Also tangentially related, but the CBOR spec seems to also suggest the encoding of maps be sorted. The Alonzo spec seems to suggest it maintain the "canonical" format, which is also given in the RFC. It seems odd that Plutus's Value (and Map I guess) doesn't maintain this canonical format upon serialization to CBOR. I think the Cardano API Value does maintain this format though. Does that specific section of the spec only apply to the Cardano API and its direct users ....?
I feel confused at the fact that some parts of the official Cardano code seem to consciously try and ensure normalization of Values, whereas other places don't.
In principle we could require the representation of Value to be normalized, but then we'd have to be very careful to ensure that this property was always maintained.
I think it'd be quite doable to maintain normalization, for Values at least, if what is being fed to the script is actually normalized. And from the code, it seems that if we limit ourselves to purely using the cardano-cli for building and submitting transactions, that invariant could potentially already be enforced.
You're mixing some things here. Just because the CLI outputs a certain format it doesn't mean that all transactions have to be of that format. The same goes for this canonical format: this is only used to compute the script integrity hash and doesn't even apply to Value.
Also, the restricting oneself to transactions produced by the cardano-cli is bad, since an attacker can then construct a transaction by hand and break your assumptions. So, be safe, don't peek at internals and interact with Value via the functions provided.
Something we observed is that the provided high-level functions are quite expensive in terms of memory and CPU, much more than working directly with the underlying Map representation. With current Plutus limitations, it may be necessary to break the Value abstraction in some complex scripts. I think this can be safe from attacks as long as the scripts are conservative enough to fail when the assumptions are not met.
https://github.com/input-output-hk/cardano-ledger/blob/master/eras/shelley-ma/impl/src/Cardano/Ledger/Mary/Value.hs#L382
It very much seems like the sortedness of values is part of the guarantees.
I believe we need an objective on coming up with a process to figure out
- what kinds of things are there to stay
- how to handle and report breaking changes (see also the discussion in #5408 and #4753)
The security of the whole system depends on these things, so it definitely should be prioritized.