This guide runs the watchdog against a local devnet: Anvil with the rollups
contracts, and wallet-sequencer-devnet. The watchdog README owns
how the watchdog works and its configuration;
deployment covers live chains.
The Nix/direnv development shell provides the tools. Without it, install:
- Lua 5.4 with its headers, a C compiler, and libcurl development files that
pkg-configfinds, for the native modules; cartesi-machineatCARTESI_MACHINE_VERSIONfromtoolchain-pins.env, with itscartesiLua module;flock(util-linux), which thesequencer-watchdogwrapper takes its lock with;- Foundry and the pinned Rust toolchain (shell and commands) for the devnet;
cross, Docker buildx able to buildlinux/riscv64, andxgenext2fs, to build machine images.
Then, from the repository root:
just setup # Anvil state, test contracts, kernel, native modules
just canonical-build-machine-image # devnet canonical image
just canonical-build-machine-image-sepolia # Sepolia canonical image
just doctor # Lua, the emulator, the native modules, the devnet imagejust watchdog-lua-deps, which just setup and the watchdog test recipes run,
compiles lua-curl (lcurl.so) and LuaFileSystem (lfs.so) from the vendored
sources into .deps/lua.
just test-watchdog-e2e needs the Sepolia canonical image and the test guest
image (watchdog/test-guest/out/test-machine-image), which it builds on first
use; the test guest README explains the
guest and how to rebuild it. just test-watchdog-compare-harness and
just test-rollups-e2e build missing canonical images themselves but reuse
existing ones, so rebuild an image after changing the wallet or its guest. The
README's Tests table says what each recipe exercises.
just test-watchdog-compare-harnessThe recipe runs just setup, builds the devnet image if it is missing, builds
wallet-sequencer-devnet and the e2e runner, and runs
watchdog_genesis_compare_test against a fresh Anvil and sequencer. The
scenario checks genesis parity and the watchdog's start through its production
wrapper:
- The sequencer's
/finalized_stateat genesis equals the devnet wallet's genesis SSZ state. - The devnet image answers the inspect query
state, run through thecartesi-machineCLI, with the same bytes. initaccepts the image against the application's on-chain template hash.- Two ticks are idle at the genesis block, and
statusreports it.
It replays no inputs. just test-rollups-e2e runs the comparisons after the
sequencer accepts batches, through both the Rust and the C-engine host, and
watchdog_divergence_drill_test, which walks the
incident runbook with the real commands.
In one terminal:
just devnet-for-watchdogIt starts Anvil and wallet-sequencer-devnet on ephemeral ports and prints
export CARTESI_WATCHDOG_*=… lines: the sequencer and L1 URLs, chain id
31337, the application address, a state directory under the
system temporary directory, the devnet image as the bootstrap at block 0,
CARTESI_WATCHDOG_STATE_SOURCE=inspect, and the native modules. Leave it
running; Ctrl+C stops both processes. If either exits on its own, the command
prints its log path and the log's tail, then exits.
In a second terminal, from the repository root, paste the exports, then:
export CARTESI_WATCHDOG_LUA_ROOT="$PWD"
curl -s "$CARTESI_WATCHDOG_SEQUENCER_URL/finalized_state/digest"
./watchdog/sequencer-watchdog init
./watchdog/sequencer-watchdog tick
./watchdog/sequencer-watchdog statusOn a fresh devnet the digest route answers for block 0. init logs
watchdog: init: initialized; head at block 0 (0 inputs), tick logs
watchdog: tick: idle at block 0 and exits 0, and status prints the head and
the last tick as JSON. Ticks stay idle until the sequencer accepts a batch
past genesis; the next tick then replays the new inputs and logs
watchdog: tick: sequencer agrees at block <B> (from block 0).
prepare_non_genesis_watchdog_state in
tests/e2e/src/test_cases.rs drives the
deposits and transfers that get there.
Restarting just devnet-for-watchdog starts a new chain on new ports. Paste
the new exports: tick reads both endpoints from the environment. The printed
state directory is the same path every time, and a head from the old chain
does not describe the new one: remove $CARTESI_WATCHDOG_STATE_DIR and run
init again.
| Message | Fix |
|---|---|
watchdog-lua-deps: libcurl dev package not found (libcurl4-openssl-dev or similar) |
Install libcurl development files that pkg-config finds |
watchdog-lua-deps: Lua headers not found; install the Lua 5.4 headers (liblua5.4-dev) or set LUA_INC |
Install the Lua 5.4 headers (liblua5.4-dev on Debian), or set LUA_INC to the directory holding lua.h |
watchdog-lua-deps: built lcurl.so but <lua> cannot load it (Lua version mismatch?) |
The headers and the interpreter belong to different Lua versions |
doctor: cartesi-machine not on PATH |
Install the pinned emulator, or enter the development shell |
missing the sepolia canonical image; run: just canonical-build-machine-image-sepolia |
just test-watchdog-e2e needs it |
CM inspect bytes mismatch (len <N> vs expected <M>) |
The devnet image is older than the wallet code; rebuild it with just canonical-build-machine-image |
watchdog state is already locked: <dir>/run.lock |
Another init, tick, or clear is running |
flock is required (util-linux) |
Use the devshell, or install util-linux |
sequencer /finalized_state/inclusion_block: GET <url> failed: … |
The devnet stack stopped, or the exports come from an earlier run |
divergence inclusion_block_regressed latched at block 0 |
The state directory comes from an earlier devnet run; remove it and run init again |