Closed savaki closed 1 year ago
On investigating further, Delay
and Force
are only used to help the interpreter manage environments around polymorphic values (see the comment whose start is linked below).
https://github.com/input-output-hk/plutus/blob/cc953b36ec9681cc28edf1accf08f48a31238e69/plutus-core/untyped-plutus-core/src/UntypedPlutusCore/Core/Type.hs#L34
I also tried to just stop emitting Delay
and Force
, which broke the interpreter, as obviously they're there for a reason. I don't know what that reason is, but the mention of the value restriction confuses me. From what I know, there is no need for a value restriction in a language without mutation. Anyway, it dropped about 3K as the issue mentions.
Even so, we're way above the maximum transaction size, with a very simple contract. I'd have to ask if we can show you the contract in private, if you're interested. Regardless, my calculations seem to show that the Plutus code being generated is way too big for a 16KB limit:
A state machine contract with a trivial transition function (operating on PlutusTx.Data as redeemer and data to cut out serialization) is ~9KB. A minting script which does nothing but defer to a validation script is ~5KB. This leaves 2KB. The generated IsData
instances for any other type of redeemer and datum are likely to be larger than that. For us, they're 4KB. This brings us 2KB over the limit without any actual logic (hand-written serialization saves us 2KB, still bringing us to the limit).
I noticed something similar with two much simpler scripts: the AlwaysFails and AlwaysSucceeds scripts in the chris-moreton/plutus-scripts repo.
AlwaysSucceeds seems to decompile into:
(program 1.0.0 [[(Λ (Λ (Λ (Λ (Λ x5))))) (force (Λ x1))] (Λ x1)])
whereas I was expecting:
(program 1.0.0 (Λ (Λ (Λ ()))))
AlwaysFails seems to decompile into:
(program 1.0.0 [[(Λ (Λ [(Λ [(Λ (Λ (Λ (Λ [(force x4) x7])))) (force (Λ [(force x2) [(force [x3 x1]) ()]]))]) (force (Λ (error)))])) (force (Λ x1))] (Λ x1)])
whereas I was expecting:
(program 1.0.0 (Λ (Λ (Λ (error)))))
Maybe my understanding of Plutus-Core is lacking, but in that case the Plutus-Core documentation is also lacking.
I've removed the bug
label, because since 2021 we've done a lot to reduce the size of the compiled scripts.
We do however recognize that sizes are still far from being ideal. It is one of our objectives to further reduce script sizes, hence I've added the status: objective
label.
... actually, five minutes later I've found another issue that is about script sizes and has more discussion and up-to-date information, so I'm going to make that one have the status: objective
label and close this one after we create two tests out of @christianschmitz's snippet.
@christianschmitz thanks a lot for reporting, those are great tests to have!
close this one after we create two tests out of @christianschmitz's snippet.
The tests were added in #5394, both the cases compile as efficiently as possible when optimizations are turned on.
Area
[x] Plutus Foundation Related to the GHC plugin, Haskell-to-Plutus compiler, on-chain code [] Plutus Application Framework Related to the Plutus application backend (PAB), emulator, Plutus libraries [] Marlowe Related to Marlowe [] Other Any other topic (Playgrounds, etc.)
Summary
Compiling to Plutus generates code that is significantly larger than the current 16k transaction size limit. The code itself has only modest responsibilities: initializing a few state values and minting tokens.
Expected behavior
Given the limited logic of the contract, our expectation was the code size would fit well within the 16k transaction size limit.
System info (please complete the following information):
Additional context
The team has had a working version of the protocol running in the PAB and was looking to transition to the testnet. The issue we ran into almost immediately was the compiled size of the script. The following is a rough history of our efforts to get the script down to size:
Initial size was roughly 28k
ExceptT String
and replaced witherror ()
- saved 3.5kIsData
instances with hand written serialization - saved 3kStateMachine
with hand written checks - saved 1.5kAt this point, it became clear to the team that something was not right. We decompiled the script to attempt to understand what was going on. Here are some observations:
delay
orforce
. And while they're only 1 byte a pop, this adds up.Just these two issues alone would represent over 6k or close to 40% of the entire transaction size budget.
One of our engineers came across this while scanning the plutus repo which appears seems to indicate this is a known issue, https://github.com/input-output-hk/plutus/blob/cc953b36ec9681cc28edf1accf08f48a31238e69/plutus-core/plutus-ir/src/PlutusIR/Transform/NonStrict.hs#L54
Our hope would be either the compiler be changed to generate far more efficient code or the 16k transaction size limit be raised to 32k.