Plutus Tx gets a makeover: meet Plinth
Plutus Tx is now Plinth, with new capabilities. The renaming clarifies the distinction between high-level smart contract development and the Plutus Core execution layer on Cardano
20 February 2025 7 mins read
In the evolving landscape of Cardano’s smart contract capabilities, clarity and precision are key. The recent rebranding of Plutus Tx to Plinth represents a step in this direction. This change, approved during the recent Plutus working group meeting, aims to clarify the distinction between Plutus Tx and Plutus Core, addressing a common source of confusion in the ecosystem.
What is Plinth?
Plinth, formerly known as Plutus Tx, is a high-level language for writing smart contracts on Cardano. It allows developers to write their contracts in a subset of Haskell, which then gets compiled into Untyped Plutus Core (UPLC) – the language that Cardano nodes use to execute scripts. This makes Cardano approachable for developers familiar with Haskell, as well as those interested in learning it.
Why was Plutus Tx renamed to Plinth?
The renaming aims to eliminate confusion around the term ‘Plutus’, which has been ambiguously used to refer to both Plutus Tx and Plutus Core. This often led to misunderstandings – particularly the incorrect assumption that Cardano’s on-chain execution language is Haskell-based.
In reality, Cardano executes smart contracts using UPLC, a low-level language based on lambda calculus. Plinth is one of several high-level languages that compile to UPLC, alongside Aiken, OpShin, plu-ts, Plutarch, and Scalus. For more details, see an overview of languages compiling to UPLC in the Plinth user guide.
To avoid ambiguity, ‘Plutus’ should either be avoided on its own or used exclusively to refer to Untyped Plutus Core.
What’s new in Plinth beyond its name change?
Plinth’s original appeal lies in its simplicity – it is a subset of Haskell rather than a standalone language or embedded domain-specific language (DSL). This makes it accessible even to those without prior Haskell experience, especially with modern AI tools, which can effectively generate and explain simple Haskell code. Additionally, Plinth is fully compatible with existing Haskell tooling and frameworks, including Cabal, GHCi, the language server, and Template Haskell for metaprogramming.
However, efficiency has been a key concern. Since transaction fees depend on script execution costs and sizes – and Cardano imposes strict limits on both – optimization is essential. To address this, Plinth has recently gained several enhancements to improve script efficiency. Below is a brief overview.
Data-encoded ScriptContext
Previously, Plinth introduced a third way to encode data types, alongside Scott encoding and sums-of-products (SOP): encoding data types using Data
, a built-in type in Plutus Core. In most alternatives to Plinth, this is the only available encoding method, as Scott and SOP encodings are not supported. More recently, a new Plutus ledger API based on Data
encoding has been introduced. This API extends support to ScriptContext
, Map
, List
, and various other types.
Data encoding comes with trade-offs. It is generally slower to process – except for equality checks, which benefit from the equalsData
primitive – and less expressive, as Data
objects cannot contain functions. However, its key advantage is efficiency in script execution: since scripts receive arguments (notably ScriptContext
) as Data
, and the output datum is also a Data
object, using Data
directly eliminates the need for conversions between Data
and Scott/SOP encodings.
The conventional approach in Plinth has been to use unsafeFromBuiltinData
to convert all script arguments to Scott/SOP encoding. This has led to concerns that even a trivial ‘always succeed’ script in Plinth is significantly more expensive than some alternatives. While avoiding this overhead by working directly with Data
has always been possible, doing so required low-level, type-unsafe code.
Now, Plinth allows developers to choose the most efficient encoding scheme for each data type in their scripts:
- To use the
Data
-encodedScriptContext
, import fromPlutusLedgerApi.Data.V3
(or V1/V2) instead ofPlutusLedgerApi.V3
(or V1/V2) - To apply
Data
encoding to custom types, wrap the definition inasData
.
The process of constructing and inspecting these data types remains largely unchanged. For more details, see Optimizing scripts with asData
in the Plinth user guide.
More inlining controls
Inlining involves a trade-off between script cost and size. More inlining reduces script execution costs but may increase script size – though inlining can also enable further optimizations, mitigating size growth. Traditionally, the Plinth compiler has taken a conservative approach, prioritizing script size constraints. However, many users prefer faster execution, as lower script costs can reduce transaction fees, particularly with reference scripts.
To provide more control over inlining, Plinth now includes the following features:
inline-fix
compiler flag – instructs the compiler to inline all fixed-point combinators, which are inserted automatically when compiling recursive bindings. Benchmarking indicates that enabling this flag reduces script costs, with only a mild increase in script size when applicable. As a result,inline-fix
is enabled by default.PlutusTx.Optimize.Inline.inline
function – instructs the Plinth compiler to inline a binding at a specific callsite, regardless of size, as long as the binding is not recursive. This function serves as Plinth’s equivalent ofGHC.Magic.inline
. To inline a binding at all callsites, use theINLINE
pragma instead.
Other compiler flags that impact script costs include inline-constants
and preserve-logging
. For a full list of flags, see Plinth compiler options in the user guide.
Recursion unrolling
Beyond inlining, another approach to balancing script cost and size is recursion unrolling, similar to loop unrolling in imperative languages. While this optimization could be handled by the compiler in the future, Plinth currently provides utilities for recursion unrolling at the language level using Template Haskell.
Specifically, the PlutusTx.Optimize.SpaceTime
module introduces two functions:
peel
– removes a specified number of recursion layersunroll
– repeatedly peels a set number of layers until the recursion is fully unrolled, mimicking traditional loop unrolling.
As an example, one can use peel
to peel off three layers of the length
function:
lengthPeeled :: [Integer] -> Integer
lengthPeeled =
$$( peel 3 $ \self ->
[||
\case
[] -> 0
_ : xs -> 1 + $$self xs
||]
)
This approach requires Template Haskell, which can be a challenging concept in Haskell. However, the usage here is relatively straightforward.
There are plans to introduce recursion unrolling directly in the compiler, allowing developers to write standard recursive functions – such as length
– without additional transformations.
That said, understanding this technique can be valuable. If a similar optimization is needed, developers can implement it themselves using peel
and unroll
, rather than waiting for compiler support.
What's next for Plinth?
High Assurance: automated smart contract verification
The Plutus team is developing an automated formal verification tool for Cardano smart contracts. The tool ensures correctness and security by utilizing SMT solving and the Lean theorem prover. It introduces an annotation language that allows developers to formally specify contract properties in surface languages, including Plinth.
The expressive power of the annotation language will enable users to describe both global properties related to the blockchain state and transaction-related or temporal properties. This capability will allow the formal verification of individual smart contracts, as well as entire DApp protocols.
Certified compilation
The team is working on enhancing the Plinth compiler with a translation certification framework formalized in Agda. When compiling a Plinth program, the compiler generates translation certificates – Agda proof objects – corresponding to the transformations applied to the code. This provides additional assurance that the compiler has accurately translated the Plinth source code to UPLC.
The final word
The rebranding of Plutus Tx to Plinth is more than just a name change. It is a move towards greater clarity on the languages available to developers across the Cardano ecosystem. As Cardano grows, tools like Plinth will play a vital role in enabling developers to build sophisticated, high-assurance applications on the blockchain.
This blog post has been written in collaboration with Lars Brünjes and Olga Hryniuk. We also thank Philip DiSarro for the valuable perspectives he shared.
Recent posts
Plutus Tx gets a makeover: meet Plinth by Ziyang Liu
20 February 2025
IO Research’s vision for Cardano submitted to community for feedback by the Intersect Product Committee by Fergie Miller
5 February 2025
What’s next for Cardano? by Mike Ward
29 January 2025