Overview
Cartesi's reference off-chain implementation of Cartesi Machines is based on software emulation.
The emulator is written in C/C++ with POSIX dependencies restricted to the terminal, process, and memory-mapping facilities.
The emulator/
directory in the Emulator SDK can be used to build and install the Cartesi Machine emulator.
It is written as a C++ class, but can be accessed in a variety of different ways.
When linked to a C++ application, the emulator can be controlled directly via the interface of the cartesi::machine
class.
C applications can control the emulator in a similar way, by means of a matching C API.
The emulator can also be accessed from the Lua programming language, via a cartesi
module that exposes a cartesi.machine
interface to Lua programs.
Additionally, Cartesi provides a gRPC server that can run a Cartesi Machine instance that is controlled remotely.
Finally, there is a command-line utility (written in Lua) that can configure and run Cartesi Machines for rapid prototyping.
The C, C++, Lua APIs as well as the command-line utility can seamlessly instantiate local emulators or connect to remote gRPC servers.
The documentation starts from the command-line utility, cartesi-machine
.
This utility is used for most prototyping tasks.
The documentation then covers the Lua interface of cartesi.machine
.
The C/C++/gRPC interfaces are very similar, and are covered only within their reference manuals.
Machine playground
The setup of a new development environment is often a time-consuming task.
This is particularly true in case of cross-development environments (i.e., when the development happens in a host platform but software runs in a different target platform).
With this in mind, the Cartesi team provides the cartesi/playground
Docker image for use while reading this documentation.
The Docker image enables immediate experimentation with Cartesi Machines.
It comes with a pre-built emulator and Lua interpreter accessible within the command-line, as well as a pre-built ROM image, RAM image, and root file-system.
It also comes with the cross-compiler for the RISC-V architecture on which the Cartesi Machine is based.
To enter the playground, open a terminal, download the Docker image from Cartesi's repository, and run it adequately mapping the current user and group information, as well as making the host's current directory available inside the container:
docker pull cartesi/playground:0.5.0
docker run -it --rm -h playground \
-e USER=$(id -u -n) \
-e GROUP=$(id -g -n) \
-e UID=$(id -u) \
-e GID=$(id -g) \
-v `pwd`:/home/$(id -u -n) \
-w /home/$(id -u -n) \
cartesi/playground:0.5.0 /bin/bash
Once inside, you can execute the cartesi-machine
utility as follows:
cartesi-machine --help
Usage:
/opt/cartesi/bin/cartesi-machine.lua [options] [command] [arguments]
where options are:
--remote-address=<address>
use a remote cartesi machine listenning to <address> instead of
running a local cartesi machine.
(requires --checkin-address)
--checkin-address=<address>
address of the local checkin server to run.
--remote-shutdown
shutdown the remote cartesi machine after the execution.
--no-remote-create
use existing cartesi machine in the remote server instead of creating a new one.
--no-remote-destroy
do not destroy the cartesi machine in the remote server after the execution.
--ram-image=<filename>
name of file containing RAM image (default: "linux.bin").
--no-ram-image
forget settings for RAM image.
--ram-length=<number>
set RAM length.
--rom-image=<filename>
name of file containing ROM image (default: "rom.bin").
--no-rom-bootargs
clear default bootargs.
--append-rom-bootargs=<string>
append <string> to bootargs.
--no-root-flash-drive
clear default root flash drive and associated bootargs parameters.
--flash-drive=<key>:<value>[,<key>:<value>[,...]...]
defines a new flash drive, or modify an existing flash drive definition
flash drives appear as /dev/mtdblock[1-7].
<key>:<value> is one of
label:<label>
filename:<filename>
start:<number>
length:<number>
shared
label (mandatory)
identifies the flash drive. init attempts to mount it as /mnt/<label>.
filename (optional)
gives the name of the file containing the image for the flash drive.
when omitted or set to the empty, the drive starts filled with 0.
start (optional)
sets the starting physical memory offset for flash drive in bytes.
when omitted, drives start at 2 << 63 and are spaced by 2 << 60.
if any start offset is set, all of them must be set.
length (optional)
gives the length of the flash drive in bytes (must be multiple of 4Ki).
if omitted, the length is computed from the image in filename.
if length and filename are set, the image file size must match length.
shared (optional)
target modifications to flash drive modify image file as well.
by default, image files are not modified and changes are lost.
(an option "--flash-drive=label:root,filename:rootfs.ext2" is implicit)
--replace-flash-drive=<key>:<value>[,<key>:<value>[,...]...]
--replace-memory-range=<key>:<value>[,<key>:<value>[,...]...]
replaces an existing flash drive or rollup memory range right after
machine instantiation.
(typically used in conjunction with the --load=<directory> option.)
<key>:<value> is one of
filename:<filename>
start:<number>
length:<number>
shared
semantics are the same as for the --flash-drive option with the following
difference: start and length are mandatory, and must match those of a
previously existing flash drive or rollup memory memory range.
--dhd=<key>:<value>[,<key>:<value>[,...]...]
configures the dehashing device.
by default, the device is not present.
<key>:<value> is one of
filename:<filename>
tstart:<number>
tlength:<number>
filename (optional)
gives the name of the file containing the initial dehashed data.
when omitted or set to the empty, the data starts filled with 0.
tstart (mandatory when device present)
sets the start of target physical memory range for output data.
must be aligned to tlength.
tlength (mandatory when device present)
gives the length of target physical memory range for output data.
must be a power of 2 greater than 4Ki, or 0 when device not present.
--dhd-source=<address>
address of server acting as source for dehashed data.
--rollup-rx-buffer=<key>:<value>[,<key>:<value>[,...]...]
--rollup-tx-buffer=<key>:<value>[,<key>:<value>[,...]...]
--rollup-input-metadata=<key>:<value>[,<key>:<value>[,...]...]
--rollup-voucher-hashes=<key>:<value>[,<key>:<value>[,...]...]
--rollup-notice-hashes=<key>:<value>[,<key>:<value>[,...]...]
defines the individual the memory ranges used by rollups.
<key>:<value> is one of
filename:<filename>
start:<number>
length:<number>
shared
semantics are the same as for the --flash-drive option with the following
difference: start and length are mandatory.
--rollup
defines appropriate values for rollup-rx-buffer, rollup-tx-buffer,
rollup-input-metadata, rollup-voucher-hashes, rollup-notice hashes,
and htif yield for use with rollups.
equivalent to the following options:
--rollup-rx-buffer=start:0x60000000,length:2<<20
--rollup-tx-buffer=start:0x60200000,length:2<<20
--rollup-input-metadata=start:0x60400000,length:4096
--rollup-voucher-hashes=start:0x60600000,length:2<<20
--rollup-notice-hashes=start:0x60800000,length:2<<20
--htif-yield-manual
--htif-yield-automatic
--rollup-advance-state=<key>:<value>[,<key>:<value>[,...]...]
advances the state of the machine through a number of inputs in an epoch
<key>:<value> is one of
epoch_index:<number>
input:<filename-pattern>
input_metadata:<filename-pattern>
input_index_begin:<number>
input_index_end:<number>
voucher:<filename-pattern>
voucher_hashes: <filename>
notice:<filename-pattern>
notice_hashes: <filename>
report:<filename-pattern>
hashes
epoch_index
the index of the epoch (the value of %e).
input (default: "epoch-%e-input-%i.bin")
the pattern that derives the name of the file read for input %i
of epoch index %e.
input_index_begin (default: 0)
index of first input to advance (the first value of %i).
input_index_end (default: 0)
one past index of last input to advance (one past last value of %i).
input_metadata (default: "epoch-%e-input-metadata-%i.bin")
the pattern that derives the name of the file read for
input metadata %i of epoch index %e.
voucher (default: "epoch-%e-input-%i-voucher-%o.bin")
the pattern that derives the name of the file written for voucher %o
of input %i of epoch %e.
voucher_hashes (default: "epoch-%e-input-%i-voucher-hashes.bin")
the pattern that derives the name of the file written for the voucher
hashes of input %i of epoch %e.
notice (default: "epoch-%e-input-%i-notice-%o.bin")
the pattern that derives the name of the file written for notice %o
of input %i of epoch %e.
notice_hashes (default: "epoch-%e-input-%i-notice-hashes.bin")
the pattern that derives the name of the file written for the notice
hashes of input %i of epoch %e.
report (default: "epoch-%e-input-%i-report-%o.bin")
the pattern that derives the name of the file written for report %o
of input %i of epoch %e.
hashes
print out hashes before every input.
the input index ranges in {input_index_begin, ..., input_index_end-1}.
for each input, "%e" is replaced by the epoch index, "%i" by the
input index, and "%o" by the voucher, notice, or report index.
--rollup-inspect-state=<key>:<value>[,<key>:<value>[,...]...]
inspect the state of the machine with a query.
the query happens after the end of --rollup-advance-state.
<key>:<value> is one of
query:<filename>
report:<filename-pattern>
query (default: "query.bin")
the name of the file from which to read the query.
report (default: "query-report-%o.bin")
the pattern that derives the name of the file written for report %o
of the query.
while the query is processed, "%o" is replaced by the current report index.
--concurrency=<key>:<value>[,<key>:<value>[,...]...]
configures the number of threads used in some implementation parts.
<key>:<value> is one of
update_merkle_tree:<number>
update_merkle_tree (optional)
defines the number of threads to use while calculating the merkle tree.
when ommited or defined as 0, the number of hardware threads is used if
it can be identified or else a single thread is used.
--max-mcycle=<number>
stop at a given mcycle (default: 2305843009213693952).
-i or --htif-console-getchar
run in interactive mode.
--htif-yield-manual
honor yield requests with manual reset by target.
--htif-yield-automatic
honor yield requests with automatic reset by target.
--store=<directory>
store machine to <directory>, where "%h" is substituted by the
state hash in the directory name.
--load=<directory>
load machine previously stored in <directory>.
--initial-hash
print initial state hash before running machine.
--final-hash
print final state hash when done.
--periodic-hashes=<number-period>[,<number-start>]
prints root hash every <number-period> cycles. If <number-start> is given,
the periodic hashing will start at that mcycle. This option implies
--initial-hash and --final-hash.
(default: none)
--step
print step log for 1 additional cycle when done.
--json-steps=<filename>
output json with step logs for all cycles to <filename>.
--store-config[=<filename>]
store initial machine config to <filename>. If <filename> is omitted,
print the initial machine config to stderr.
--load-config=<filename>
load initial machine config from <filename>. If a field is omitted on
machine_config table, it will fall back into the respective command-line
argument or into the default value.
--dump-pmas
dump all PMA ranges to disk when done.
and command and arguments:
command
the full path to the program inside the target system.
(default: /bin/sh)
arguments
the given command arguments.
<number> can be specified in decimal (e.g., 16) or hexadeximal (e.g., 0x10),
with a suffix multiplier (i.e., Ki, Mi, Gi for 2^10, 2^20, 2^30, respectively),
or a left shift (e.g., 2 << 20).
<address> is one of the following formats:
<host>:<port>
unix:<path>
<host> can be a host name, IPv4 or IPv6 address.
A final check can also be performed to verify if the contents inside the container are as expected:
sha256sum /opt/cartesi/share/images/linux.bin
76d90cd7eb6c66a76c192fefdc7bb236637f2f9f0eb4f0c5eb44f2f82240fcdd /opt/cartesi/share/images/linux.bin
sha256sum /opt/cartesi/share/images/rom.bin
ed73b33741fb6ebb61a7e4d00ba23d30712ccb47e888b2b5ad3245d6928b8cfe /opt/cartesi/share/images/rom.bin
sha256sum /opt/cartesi/share/images/rootfs.ext2
485f12ffd1a6df386f8be4e5e1695ecc220fd90d3a606f8ab3c0f2877199a1a3 /opt/cartesi/share/images/rootfs.ext2
Note that, if the hashes of the files you are using do not match the ones above, then when you attempt to replicate the examples in the documentation, you will obtain different hashes. Moreover, the cycle counts and outputs may also differ.