-
Notifications
You must be signed in to change notification settings - Fork 483
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
docusaurus: plutus exe #6743
Draft
bezirg
wants to merge
4
commits into
master
Choose a base branch
from
bezirg/plutus-exe-doc
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
docusaurus: plutus exe #6743
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,347 @@ | ||
--- | ||
sidebar_position: 40 | ||
--- | ||
|
||
# CLI tool for Plutus | ||
|
||
You can locally (without starting a Cardano Node) [run](#running) or [debug](#debugging) compiled code | ||
by using the `plutus` CLI tool. This tool allows you also to [optimise](#converting) compiled code, [convert](#converting) between code formats, | ||
and [check](#checking) code for common issues. A pre-built version of the `plutus` CLI executable | ||
can be found on the [Latest release](https://github.com/IntersectMBO/plutus/releases/latest) page in the repository. Alternatively, you can build the tool | ||
using Nix, specifically for your platform: | ||
|
||
``` shell | ||
$ nix build .#cabalProject.$(nix eval nixpkgs#stdenv.buildPlatform.system).hsPkgs.plutus-core.components.exes.plutus | ||
``` | ||
|
||
To consult the tool's usage you can invoke `plutus --help` in a command line: | ||
|
||
``` shell | ||
$ plutus --help | ||
USAGE: plutus [FILES...] [--stdin] [-o FILE | --stdout] [--run|--bench|--debug]... | ||
-h --help Show usage | ||
-V --version Show version | ||
-q --quiet Don't print text (error) output; rely only on exit codes | ||
-v --verbose Print more than than the default | ||
--print-builtins Print the Default universe & builtins | ||
--print-cost-model Print the cost model of latest Plutus Version as JSON | ||
--stdin Use stdin | ||
-e[NAME] --example[=NAME] Use example NAME as input. Leave out NAME to see the list of examples' names | ||
-p STYLE --pretty=STYLE Make program's textual-output&error output pretty. Ignored for non-textual output (flat/cbor). Values: `classic`, `readable, `classic-simple`, `readable-simple` | ||
-o FILE Write compiled program to file | ||
--stdout Write compiled program to stdout | ||
-O[INT] Set optimisation level; default: 0 , safe optimisations: 1, >=2: unsafe optimisations | ||
--whole-opt Run an extra optimisation pass after all inputs are applied together. Ignored if only 1 input given. | ||
-x SUFFIX Causes all files following this option on the command line to be processed as if they had the suffix SUFFIX | ||
-n NAMING --nam=NAMING Change naming to `name` (default), `debruijn` or `named-debruijn` | ||
-a ANNOTATION --ann=ANNOTATION Change annotation to `unit` (default) or `srcspan` | ||
--run Compile and run | ||
--bench[=SECS] Compile then run repeatedly up to these number of seconds (default:10) and print statistics | ||
--debug[=INTERFACE] Compile then Debug program after compilation. Uses a `tui` (default) or a `cli` interface. | ||
--debug-dir[=DIR] When `--debug`, try to search for PlutusTx source files in given DIR (default: .) | ||
--budget=INT,INT Set CPU,MEM budget limit. The default is no limit. Only if --run, --bench, or --debug is given | ||
``` | ||
|
||
Two interesting sub-commands which can aid during Plutus-based script development (e.g. Aiken, Plutarch, Plutus Tx) are `--print-builtins` and `--print-cost-model` which as their name suggest print detailed lists of currently recognized builtin functions and cost model parameters, respectively. | ||
|
||
## Converting Code with the CLI {#converting} | ||
|
||
Before you can even run or debug your code, you first need to compile and extract the plutus code from the high-level source code. | ||
The steps for extracting plutus code vary depending on the source language you are using (Plutus Tx, Aiken, ...); | ||
if your are using Plutus Tx as source, you can follow the instructions on [how to inspect compiled code](./inspecting.md#inspecting-the-compiled-code). | ||
|
||
Although the CLI tool cannot help with compiling high-level code (e.g. Plutus Tx), it can aid with compiling and converting | ||
between formats and intermediate representations of lower-level plutus code (PIR, TPLC, UPLC). | ||
|
||
In the following example we check a program written in the PIR (Plutus Intermediate Representation) language: | ||
|
||
``` shell | ||
$ echo '(program 1.1.0 (lam x (con integer) (lam y (con integer) x)))' > const.pir | ||
$ plutus const.pir | ||
Program passed all static checks. If you want the output result, use -o FILE or --stdout. | ||
``` | ||
|
||
Or as a single command: | ||
|
||
``` shell | ||
$ echo '(program 1.1.0 (lam x (con integer) (lam y (con integer) x)))' | plutus -x pir --stdin | ||
Program passed all static checks. If you want the output result, use -o FILE or --stdout. | ||
``` | ||
|
||
In the command above, the `-x pir` option is necessary for letting the CLI tool know | ||
the format/language of the supplied input. If the `-x` option is not passed, the CLI tool will try to guess the input's format/language | ||
by looking at its filename extension `.SUFFIX` — will default to `uplc` for `--stdin` or missing/other suffix. | ||
What the `-x SUFFIX` option does is instructing the CLI tool to treat subsequent filenames | ||
as if they had a `.SUFFIX` file extension. | ||
The following table lists some recognized suffixes and corresponding `-x` values: | ||
|
||
|Filename Suffix|-x Option|Format Type|Description| | ||
|---|---|---|---| | ||
|.uplc|-x uplc|Textual|Untyped Plutus Core with Names| | ||
|.tplc|-x tplc|Textual|Typed Plutus Core with Names| | ||
|.pir|-x pir|Textual|PIR with Names| | ||
|.data|-x data|Binary|Values of `Data` serialised in CBOR| | ||
|.data-txt|-x data-txt|Textual|Values of `Data` in Haskell's `Show` format| | ||
|.uplc-flat|-x uplc-flat|Binary|Untyped PlutusCore with NamedDeBruijn serialised in Flat| | ||
|.uplc-cbor|-x uplc-cbor|Binary|Untyped PlutusCore with DeBruijn serialised in CBOR| | ||
|
||
In case the input format is more complex (contains a non-default variable-naming scheme or annotations), | ||
the `-n NAMING` and `-a ANNOTATION` options can be used respectively to override the defaults. | ||
|
||
|-n Short Option|-n Long Option|Description| | ||
|---|---|---| | ||
|-n n|-n name|Use descriptive textual names for variables| | ||
|-n d|-n debruijn|Use debruijn indices for variables| | ||
|-n nd|-n named-debruijn|Use name with debruijn index for variables: "name-index"| | ||
|
||
|-a Option|Description| | ||
|---|---| | ||
|-a unit|Code does not contain any annotations (default)| | ||
|-a srcspan|Code is annotated with source spans| | ||
|
||
Note that the `-x`,`-n`,`-a` options are *positional*: if | ||
there are multiple input filenames, multiple calls to these options can be used | ||
to override previous occurrences so that you can combine code of different formats. For example: | ||
|
||
``` shell | ||
# plutus -x pir FILE_PIR FILE_ALSO_PIR -x tplc FILE_NOW_TPLC -a srcspan FILE_TPLC_BUT_WITH_ANNOTATIONS | ||
``` | ||
|
||
Positioning the input files one after the other (juxtaposing) as such, acts | ||
like Haskell's function application: | ||
it compiles individually each plutus snippet to a common *output target* and combines left-to-right | ||
their compilation result with plutus' function application. Both inputs and final compiled output are (type-)checked. | ||
|
||
``` shell | ||
# plutus FUNC_FILE ARG1 ARG2 ... | ||
$ echo '(program 1.1.0 (lam x (lam y [(builtin appendString) x y])))' > append.uplc | ||
$ echo '(program 1.1.0 (con string "Hello, "))' > hello.uplc | ||
|
||
# "Hello, world" | ||
$ echo '(program 1.1.0 (con string "world"))' | plutus append.uplc hello.uplc --stdin --stdout | ||
(program | ||
1.1.0 | ||
[ | ||
[ | ||
(lam x-0 (lam y-1 [ [ (builtin appendString) x-0 ] y-1 ])) | ||
(con string "Hello, ") | ||
] | ||
(con string "world") | ||
] | ||
) | ||
# "worldHello, " Note the flip of stdin and hello arguments | ||
$ echo '(program 1.1.0 (con string "world"))' | plutus append.uplc --stdin hello.uplc --stdout | ||
(program | ||
1.1.0 | ||
[ | ||
[ | ||
(lam x-0 (lam y-1 [ [ (builtin appendString) x-0 ] y-1 ])) | ||
(con string "world") | ||
] | ||
(con string "Hello, ") | ||
] | ||
) | ||
``` | ||
|
||
To override the output's target format the `-x`,`-n`,`-a` options are again used; | ||
note that the *last occurrence* of `-x`,`-n`,`-a` will be the one that dictates the output format. | ||
|
||
``` shell | ||
# Checks and compiles PIR to UPLC (the default) | ||
$ plutus const.pir --stdout | ||
(program 1.1.0 (lam x-256 (lam y-257 x-256))) | ||
# Overrides to pir for both input&output. Can be used for pretty-printing or self-optimising (--whole-opt). | ||
$ plutus -x pir const.pir --stdout | ||
(program 1.1.0 (lam x-0 (con integer) (lam y-1 (con integer) x-0))) | ||
# Overrides input to be tplc instead of guessed pir (example still works because pir is superset of tplc) | ||
# Overrides output to uplc with debruijn naming | ||
$ plutus -x tplc const.pir -x uplc -n debruijn --stdout | ||
(program 1.1.0 (lam !0 (lam !0 !2))) | ||
``` | ||
|
||
If the output's format type is *textual* (see table above) the compiled code | ||
will be printed to the designated output (file or stdout) in a "pretty" format. | ||
You can change how this output looks by specifying a different `-p STYLE` style (defaults to `classic`). | ||
Note that *textual output* with pretty style other than the default may not be recognized | ||
back again as *textual input* to the CLI. | ||
|
||
``` shell | ||
$ plutus sub.pir -x pir --stdout | ||
(program | ||
1.1.0 | ||
(lam | ||
x-0 | ||
(con integer) | ||
(lam y-1 (con integer) [ [ (builtin subtractInteger) x-0 ] y-1 ]) | ||
) | ||
) | ||
$ plutus sub.pir -x pir --stdout --pretty=readable-simple | ||
program 1.1.0 (\(x : integer) (y : integer) -> subtractInteger x y) | ||
``` | ||
|
||
|-p Option|Description| | ||
|---|---| | ||
|-p classic|Lisp-like syntax with unique variable names (default)| | ||
|-p classic-simple|Lisp-like syntax with ambiguous (no unique) variable names| | ||
|-p readable|Succinct syntax with unique variable names| | ||
|-p readable-simple|Succinct syntax with ambiguous (no unique) variable names| | ||
|
||
## Checking Code with the CLI {#checking} | ||
|
||
Depending on the input and output formats, certain checks will be run by the tool (syntax check, type checking). | ||
Any errors during these checks will be reported to `stderr`: | ||
|
||
``` shell | ||
$ echo "(program 1.1.0 (lam x (con integer) [(builtin addIntege) x (con integer 1)]))" | plutus -x tplc --stdin | ||
<stdin>:1:56: | ||
| | ||
1 | (program 1.1.0 (lam x (con integer) [(builtin addIntege) x (con integer 1)])) | ||
| ^ | ||
Unknown built-in function 'addIntege' at <stdin>:1:56. | ||
Parsable functions are [ addInteger, ...] | ||
``` | ||
|
||
The tool can be made more `--verbose` about the checking/compilation process, or | ||
more `--quiet` if you prefer to rely solely on the tool's exit status. | ||
|
||
Fixing the typo in the example above, then applying it to an argument using the CLI's juxtaposition: | ||
|
||
``` shell | ||
$ echo "(program 1.1.0 (lam x (con integer) [(builtin addInteger) x (con integer 1)]))" | plutus -x tplc --stdin -x uplc -o inc.uplc | ||
$ echo "(program 1.1.0 (con bool True))" | plutus inc.uplc --stdin --stdout | ||
(program | ||
1.1.0 | ||
[ | ||
(lam x-21 [ [ (builtin addInteger) x-21 ] (con integer 1) ]) (con bool True) | ||
] | ||
) | ||
``` | ||
|
||
There is a type error above (expected type: integer, actual type: bool), | ||
however all static checks pass and the compiled code is successfully returned. This is | ||
because our compilation target (output format) is `uplc`, a.k.a. untyped plutus core. | ||
Although the 2 input snippets are written in `tplc` (a.k.a. typed plutus core) and thus type-checked by the tool, | ||
they are only typechecked *separately*; their combined, compiled output is in `uplc`, a.k.a untyped plutus core, | ||
which means no type-checking will be done statically. We could however change the output format to be tplc, which would | ||
raise the type error: | ||
|
||
``` shell | ||
$ echo "(program 1.1.0 (lam x (con integer) [(builtin addInteger) x (con integer 1)]))" | plutus -x tplc --stdin -o inc.tplc | ||
$ echo "(program 1.1.0 (con bool True))" | plutus -x tplc inc.tplc --stdin --stdout | ||
Failed to typecheck fully-applied program. The error was: | ||
Error from the PLC compiler: | ||
Type mismatch at () | ||
Expected a term of type | ||
'(con integer)' | ||
But found one of type | ||
'(con bool)' | ||
Namely, | ||
'(con bool True)' | ||
``` | ||
|
||
## Running Code with the CLI {#running} | ||
|
||
We saw earlier that certain type errors cannot be caught statically for `uplc` | ||
since the language is untyped. We do have the option, however, to run | ||
the compiled code using the interpreter and look for runtime type errors. | ||
Running the program locally using the CLI tool is simply an extra step which is executed | ||
after [checking](#checking) and [compilation](#converting) have been completed, simply by adding the `--run` option: | ||
|
||
``` shell | ||
$ echo "(program 1.1.0 (con bool True))" | plutus inc.uplc --stdin --run | ||
Program passed all static checks. If you want the output result, use -o FILE or --stdout. | ||
Running the program: An error has occurred: | ||
Could not unlift a value: | ||
Type mismatch: expected: integer; actual: bool | ||
Caused by: addInteger True 1 | ||
``` | ||
|
||
Other times catching such "type errors" at runtime is not even possible; consider for example: | ||
|
||
``` shell | ||
# if True then "" else 5 | ||
$ echo '(program 1.1.0 [(force (builtin ifThenElse)) (con bool True) (con string "") (con integer 5)])' | plutus --stdin --run | ||
Program passed all static checks. If you want the output result, use -o FILE or --stdout. | ||
Running the program: Execution succeeded. Final Term: | ||
(con string "") | ||
Used budget: ExBudget {exBudgetCPU = ExCPU 204149, exBudgetMemory = ExMemory 901} | ||
``` | ||
|
||
> :pushpin: **NOTE** | ||
> The above example shows that `uplc` -- the language which actually *runs on the chain* -- | ||
> is lower-level and more akin to assembly. Users that are concerned about the safety of their smart contracts | ||
> are advised instead to develop in a higher-level typed language (e.g. Plutus Tx) which compiles down to `uplc`. | ||
|
||
After plutus program's execution is completed (succeeded or failed), the final used budget will be printed to `stderr`. | ||
Because the CLI tool employs the same `uplc` interpreter as the one that the Cardano node runs, we can be sure | ||
that the program's execution result&budget match *precisely* — assuming same program | ||
and cost model — the result&budget computed by the chain. | ||
|
||
You can pass a maximum CPU and/or Memory budget that is allowed to be spent with the `--budget=CPU` or `-budget=,MEM` or `--budget=CPU,MEM` options; if given budget runs out, the execution will fail and stop earlier. | ||
If there is no CPU and/or MEM limit given, the budget is practically unlimited. | ||
|
||
``` shell | ||
$ echo "(program 1.1.0 (con integer 1))" | $plutus inc.uplc --stdin --run --budget=229307,903 | ||
Program passed all checks. No output file was written, use -o or --stdout. | ||
An error has occurred: | ||
The machine terminated part way through evaluation due to overspending the budget. | ||
The budget when the machine terminated was: | ||
({cpu: -1 | ||
| mem: 1}) | ||
Negative numbers indicate the overspent budget; note that this only indicates the budget that was needed for the next step, not to run the program to completion. | ||
|
||
$ echo "(program 1.1.0 (con integer 1))" | $plutus inc.uplc --stdin --run --budget=,903 | ||
Program passed all checks. No output file was written, use -o or --stdout. | ||
Execution succeeded. Final Term: | ||
(con integer 2) | ||
Remaining budget: ExBudget {exBudgetCPU = ExCPU 9223372036854546499, exBudgetMemory = ExMemory 1} | ||
Used budget: ExBudget {exBudgetCPU = ExCPU 229308, exBudgetMemory = ExMemory 902} | ||
``` | ||
|
||
As shown in [compilation](#converting) section, you are free to mix and match | ||
different input languages (pir/tplc/uplc); as long as the output target at the CLI | ||
is set to `uplc`, their compiled output will be `--run` through the | ||
the local `uplc` interpreter (same interpreter as that on chain). | ||
|
||
> :pushpin: **NOTE** | ||
> Attempting to run a `tplc` target will use a `tplc` interpreter. Although | ||
> the `tplc` interpreter behaves the same as the default `uplc` interpreter (for *type correct* programs), | ||
> it comes with caveats: cannot execute `uplc` code, | ||
> cannot have budget accounting and budget limits, runs way slower and your program must be fully type correct. | ||
> The last point is not necessarily a caveat, but it diverges from the on-chain behavior: | ||
> the `tplc` interpreter accepts less programs than the chain (and the default `uplc` interpreter) would accept. | ||
|
||
## Debugging Code with the CLI *(Experimental)* | ||
|
||
The `plutus` tool's built-in debugger provides a different way to | ||
to execute compiled plutus code (only if you are targeting untyped plutus core, a.k.a `uplc`). | ||
The `--debug` option starts a TUI (Terminal User Interface) in your console: | ||
|
||
``` shell | ||
$ plutus inc.uplc --debug | ||
``` | ||
|
||
The debugger will load the program, display its text code on a window, | ||
and wait for a user command to start executing it using the `uplc` interpreter. | ||
The commands available to the user are: | ||
|
||
|Keyboard Shortcut|Command| | ||
|-----|-----| | ||
|?|Show help dialog| | ||
|Esc|Quit help dialog or debugger| | ||
|Ctrl+up/down/left/right|Resize window| | ||
|Tab|Switch focus to other window| | ||
|s|Step once the interpreter| | ||
|
||
Unlike the `--run` option, the `step` command does not execute the program | ||
to completion. Instead, the `uplc` interpreter is moved one "budgeting" step forward — | ||
the smallest step possible that gets accounted for and subtracted from the current budget — | ||
and the screen will be updated to show the remaining budget. | ||
You can still combine `--debug` with the `--budget=CPU,MEM` option to limit the initial total budget given. | ||
|
||
Every time an interactive step is taken, the debugger | ||
highlights the code region (sub-term) that the `uplc` interpreter | ||
is about to "step into" (execute) next, in the program's text window. A separate | ||
"Logs" window is kept up-to-date with any printed plutus' `trace`s and debugger's messages. | ||
|
||
FIXME: add screenshot |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 can copy-paste this line easier.zsh
mis-interpreting it as a comment.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 suspect that without the
shell
specifier this fenced code block will also have the "Copy To Clipboard" button.