Skip to content

mel-project/mil

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mel Intermediate Lisp

A simple Lisp to write low-level programs for the MelVM.

Some example programs can be seen here.

Build

With stable Rust installed:

cargo build

Use the Nix shell environment

# Reads the flake.nix/.lock files to get the specified rust version
nix develop

Compiling a Mil program

Provide the path to a *.mil file to compile.

mil examples/hellohash.mil

# Alternatively
cargo run -- examples/hellohash.mil

By default, only the hash of the script is printed to stdout upon successful compilation.

To get the binary, tell the compiler to write it to a file.

mil examples/hellohash.mil --output hh.mvm

Generate a test-transactions file

To test that a covenant script executes properly, you need to define the context in which you want to test the script. The context is everything a covenant would have access to when used in a real-world transaction. That is, the transaction it is a part of, and the transaction spending it.

The mil compiler accepts a json file with a list of environment contexts which it will execute the compiled script in and display the results (script returned true or false) when you pass the flag --test-txs <file.json>.

Writing all this context manually would be cumbersome, so we've written a tool in racket, mel-types-rkt to generate the json for you. In the simplest use case, we just want a dummy environment and don't care what the "self" and spending transactions really look like.

TODO: package a binary for mel-types-rkt With racket and mel-types-rkt installed, generate the test-txs.json file as follows:

mil hello.mil --out hello.out | racket <path-to-mel-types-rkt>/main.rkt -f hello.out > test-txs.json

The mil compiler will output the hash of the hello.mil script. The main entrypoint of mel-types-rkt uses that hash to generate a valid context for the script.

Execute tests

The mil compiler also provides an environment for executing scripts on user-configured scenarios. In the MelVM, a script is associated with a UTXO, and executed only when a transaction attempts to spend it. Therefore, this test environment takes a json file consisting of a list of (UTXO, spender-transaction) values to execute. The json file specifically is of type [(CoinID, CoinDataHeight, Transaction)]. See the mil binary search tree configuration for an example.

To execute a script on a test tx file,

mil bst.mil --test-txs test-txs.json

The results of each tx pair is printed. Indicating whether execution succeeded, and displaying the final state of the MelVM stack, which if Int(0) indicates that the spend is not allowed, and any other value means it is.

tx#0 - Successful execution.

Final stack
--------
[Int(1)]

tx#1 - Successful execution.

Final stack
--------
[Int(0)]

Debugging

To see the entire execution, one instruction at a time, and the evolution of the stack and heap, attach the --debug flag to compilation.

You can also disassemble a program after its been compiled to see its opcodes as interpreted by the MelVM. Use the --show-disassembly flag to get the disassembly on stdout.