From 79072b64d86c1a8f8f66977f5c2c8cdcd9ce51d4 Mon Sep 17 00:00:00 2001 From: Gabriel Coutinho de Paula Date: Tue, 24 Mar 2026 08:56:08 -0300 Subject: [PATCH 1/5] fix: make canonical app build deterministic --- .github/workflows/ci.yml | 25 +- .github/workflows/release.yml | 14 +- .gitignore | 2 + Cargo.lock | 627 +++++++++++------- Cargo.toml | 10 +- examples/canonical-app/.gitignore | 1 + examples/canonical-app/Dockerfile | 7 +- examples/canonical-app/justfile | 20 +- .../canonical-app/scripts/sha256_files.py | 26 + justfile | 3 + 10 files changed, 488 insertions(+), 247 deletions(-) create mode 100644 examples/canonical-app/scripts/sha256_files.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index efdb1ff..b104d99 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,9 @@ on: push: pull_request: +env: + XGENEXT2FS_VERSION: v1.5.6 + jobs: rust: runs-on: ubuntu-latest @@ -71,14 +74,14 @@ jobs: run: | set -euo pipefail ARCH="$(dpkg --print-architecture)" - VERSION="v1.5.5" + VERSION="${XGENEXT2FS_VERSION}" case "${ARCH}" in amd64) - DEB_SHA256="e42857c454a772553e2bec5e73ac499b39d35dbf622bdb4cbb1b19fe98f62999" + ASSET_NAME="xgenext2fs_amd64.deb" ;; arm64) - DEB_SHA256="a9964903e9d4c1006dc9d88b4823be14d2eccaf66007c48e76c883e17db2880c" + ASSET_NAME="xgenext2fs_arm64.deb" ;; *) echo "unsupported arch for xgenext2fs: ${ARCH}" >&2 @@ -86,8 +89,9 @@ jobs: ;; esac - wget -O /tmp/xgenext2fs.deb "https://github.com/cartesi/genext2fs/releases/download/${VERSION}/xgenext2fs_${ARCH}.deb" - echo "${DEB_SHA256} /tmp/xgenext2fs.deb" | sha256sum --check + ASSET_URL="https://github.com/cartesi/genext2fs/releases/download/${VERSION}/${ASSET_NAME}" + wget -O /tmp/xgenext2fs.deb "${ASSET_URL}" + sha256sum /tmp/xgenext2fs.deb sudo apt-get update sudo apt-get install -y /tmp/xgenext2fs.deb @@ -170,14 +174,14 @@ jobs: run: | set -euo pipefail ARCH="$(dpkg --print-architecture)" - VERSION="v1.5.5" + VERSION="${XGENEXT2FS_VERSION}" case "${ARCH}" in amd64) - DEB_SHA256="e42857c454a772553e2bec5e73ac499b39d35dbf622bdb4cbb1b19fe98f62999" + ASSET_NAME="xgenext2fs_amd64.deb" ;; arm64) - DEB_SHA256="a9964903e9d4c1006dc9d88b4823be14d2eccaf66007c48e76c883e17db2880c" + ASSET_NAME="xgenext2fs_arm64.deb" ;; *) echo "unsupported arch for xgenext2fs: ${ARCH}" >&2 @@ -185,8 +189,9 @@ jobs: ;; esac - wget -O /tmp/xgenext2fs.deb "https://github.com/cartesi/genext2fs/releases/download/${VERSION}/xgenext2fs_${ARCH}.deb" - echo "${DEB_SHA256} /tmp/xgenext2fs.deb" | sha256sum --check + ASSET_URL="https://github.com/cartesi/genext2fs/releases/download/${VERSION}/${ASSET_NAME}" + wget -O /tmp/xgenext2fs.deb "${ASSET_URL}" + sha256sum /tmp/xgenext2fs.deb sudo apt-get update sudo apt-get install -y /tmp/xgenext2fs.deb diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ce4abf6..3351270 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,6 +19,9 @@ on: permissions: contents: write +env: + XGENEXT2FS_VERSION: v1.5.6 + jobs: build-sequencer: name: Build sequencer (${{ matrix.arch }}) @@ -122,14 +125,14 @@ jobs: run: | set -euo pipefail ARCH="$(dpkg --print-architecture)" - VERSION="v1.5.5" + VERSION="${XGENEXT2FS_VERSION}" case "${ARCH}" in amd64) - DEB_SHA256="e42857c454a772553e2bec5e73ac499b39d35dbf622bdb4cbb1b19fe98f62999" + ASSET_NAME="xgenext2fs_amd64.deb" ;; arm64) - DEB_SHA256="a9964903e9d4c1006dc9d88b4823be14d2eccaf66007c48e76c883e17db2880c" + ASSET_NAME="xgenext2fs_arm64.deb" ;; *) echo "unsupported arch for xgenext2fs: ${ARCH}" >&2 @@ -137,8 +140,9 @@ jobs: ;; esac - wget -O /tmp/xgenext2fs.deb "https://github.com/cartesi/genext2fs/releases/download/${VERSION}/xgenext2fs_${ARCH}.deb" - echo "${DEB_SHA256} /tmp/xgenext2fs.deb" | sha256sum --check + ASSET_URL="https://github.com/cartesi/genext2fs/releases/download/${VERSION}/${ASSET_NAME}" + wget -O /tmp/xgenext2fs.deb "${ASSET_URL}" + sha256sum /tmp/xgenext2fs.deb sudo apt-get update sudo apt-get install -y /tmp/xgenext2fs.deb diff --git a/.gitignore b/.gitignore index a175101..822d909 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /target +.env +.env.fish sequencer.db sequencer.db-shm sequencer.db-wal diff --git a/Cargo.lock b/Cargo.lock index ee45b58..272f74f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "alloy-chains" -version = "0.2.30" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f374d3c6d729268bbe2d0e0ff992bb97898b2df756691a62ee1d5f0506bc39" +checksum = "9247f0a399ef71aeb68f497b2b8fb348014f742b50d3b83b1e00dfe1b7d64b3d" dependencies = [ "alloy-primitives", "num_enum", @@ -141,7 +141,7 @@ dependencies = [ "itoa", "serde", "serde_json", - "winnow", + "winnow 0.7.15", ] [[package]] @@ -345,7 +345,7 @@ dependencies = [ "cfg-if", "const-hex", "derive_more", - "foldhash", + "foldhash 0.2.0", "hashbrown 0.16.1", "indexmap 2.13.0", "itoa", @@ -421,7 +421,7 @@ checksum = "ce8849c74c9ca0f5a03da1c865e3eb6f768df816e67dd3721a398a8a7e398011" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -557,7 +557,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -575,7 +575,7 @@ dependencies = [ "proc-macro2", "quote", "sha3", - "syn 2.0.114", + "syn 2.0.117", "syn-solidity", ] @@ -593,7 +593,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.114", + "syn 2.0.117", "syn-solidity", ] @@ -604,7 +604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6df77fea9d6a2a75c0ef8d2acbdfd92286cc599983d3175ccdc170d3433d249" dependencies = [ "serde", - "winnow", + "winnow 0.7.15", ] [[package]] @@ -660,13 +660,12 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d7fd448ab0a017de542de1dcca7a58e7019fe0e7a34ed3f9543ebddf6aceffa" +checksum = "3f14b5d9b2c2173980202c6ff470d96e7c5e202c65a9f67884ad565226df7fbb" dependencies = [ "alloy-primitives", "alloy-rlp", - "arrayvec", "derive_more", "nybbles", "serde", @@ -684,7 +683,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -698,9 +697,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -713,15 +712,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -746,6 +745,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + [[package]] name = "app-core" version = "0.1.0" @@ -850,7 +855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -888,7 +893,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -959,9 +964,6 @@ name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -dependencies = [ - "serde", -] [[package]] name = "async-recursion" @@ -971,7 +973,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -993,7 +995,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1004,7 +1006,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1021,7 +1023,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1142,7 +1144,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1178,9 +1180,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bitvec" @@ -1217,32 +1219,33 @@ dependencies = [ [[package]] name = "borsh" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" dependencies = [ "borsh-derive", + "bytes", "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "byte-slice-cast" @@ -1267,9 +1270,9 @@ dependencies = [ [[package]] name = "c-kzg" -version = "2.1.6" +version = "2.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a0f582957c24870b7bfd12bf562c40b4734b533cafbaf8ded31d6d85f462c01" +checksum = "6648ed1e4ea8e8a1a4a2c78e1cda29a3fd500bc622899c340d8525ea9a76b24a" dependencies = [ "blst", "cc", @@ -1310,7 +1313,7 @@ dependencies = [ [[package]] name = "cartesi-machine" version = "2.0.0" -source = "git+https://github.com/cartesi/dave?branch=feature%2Fbump-emulator-2-stephen#5d0560a04f623318af9ef5b7f193170b618b6ced" +source = "git+https://github.com/cartesi/dave?branch=feature%2Fbump-emulator-2-coutinho#317a88a32a1b4a6002d561f37bb833843df55cba" dependencies = [ "base64", "cartesi-machine-sys", @@ -1324,7 +1327,7 @@ dependencies = [ [[package]] name = "cartesi-machine-sys" version = "2.0.0" -source = "git+https://github.com/cartesi/dave?branch=feature%2Fbump-emulator-2-stephen#5d0560a04f623318af9ef5b7f193170b618b6ced" +source = "git+https://github.com/cartesi/dave?branch=feature%2Fbump-emulator-2-coutinho#317a88a32a1b4a6002d561f37bb833843df55cba" dependencies = [ "bindgen", "cfg-if", @@ -1345,9 +1348,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.55" +version = "1.2.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" dependencies = [ "find-msvc-tools", "shlex", @@ -1399,9 +1402,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.60" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", "clap_derive", @@ -1409,9 +1412,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.60" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -1421,33 +1424,33 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.55" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "clap_lex" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "const-hex" -version = "1.17.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" +checksum = "531185e432bb31db1ecda541e9e7ab21468d4d844ad7505e0546a49b4945d49b" dependencies = [ "cfg-if", "cpufeatures", @@ -1595,7 +1598,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1610,7 +1613,7 @@ dependencies = [ "quote", "serde", "strsim", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1623,7 +1626,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1634,7 +1637,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1645,7 +1648,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1656,7 +1659,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core 0.23.0", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1728,7 +1731,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1738,7 +1741,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1760,7 +1763,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.114", + "syn 2.0.117", "unicode-xid", ] @@ -1793,7 +1796,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1832,7 +1835,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1881,7 +1884,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1937,7 +1940,7 @@ dependencies = [ "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2025,6 +2028,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foldhash" version = "0.2.0" @@ -2048,9 +2057,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -2063,9 +2072,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -2073,15 +2082,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -2096,32 +2105,32 @@ checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -2131,7 +2140,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -2174,11 +2182,24 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + [[package]] name = "glob" version = "0.3.3" @@ -2208,6 +2229,15 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + [[package]] name = "hashbrown" version = "0.16.1" @@ -2216,7 +2246,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.2.0", "serde", "serde_core", ] @@ -2490,6 +2520,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -2534,7 +2570,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2571,15 +2607,15 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +checksum = "d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb" dependencies = [ "memchr", "serde", @@ -2620,15 +2656,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -2651,9 +2687,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ "cpufeatures", ] @@ -2674,16 +2710,22 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.180" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libcmt-sys" version = "0.1.0" -source = "git+https://github.com/GCdePaula/cartesi-tools-rs?rev=c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86#c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86" +source = "git+https://github.com/GCdePaula/cartesi-tools-rs?rev=ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22#ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22" dependencies = [ "ar", "bindgen", @@ -2713,9 +2755,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" dependencies = [ "bitflags", "libc", @@ -2756,9 +2798,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" @@ -2815,7 +2857,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2835,9 +2877,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mime" @@ -2928,9 +2970,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", "rustversion", @@ -2938,13 +2980,13 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2963,9 +3005,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" @@ -2998,7 +3040,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3063,14 +3105,14 @@ checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -3131,7 +3173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3147,9 +3189,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ "toml_edit", ] @@ -3173,7 +3215,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3187,9 +3229,9 @@ dependencies = [ [[package]] name = "proptest" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ "bit-set", "bit-vec", @@ -3232,9 +3274,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "bytes", "getrandom 0.3.4", @@ -3267,9 +3309,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.44" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -3280,6 +3322,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "radium" version = "0.7.0" @@ -3359,9 +3407,9 @@ dependencies = [ [[package]] name = "rapidhash" -version = "4.2.1" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8b5b858a440a0bc02625b62dd95131b9201aa9f69f411195dd4a7cfb1de3d7" +checksum = "b5e48930979c155e2f33aa36ab3119b5ee81332beb6482199a8ecd6029b80b59" dependencies = [ "rustversion", ] @@ -3401,7 +3449,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3429,9 +3477,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "reqwest" @@ -3649,9 +3697,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", @@ -3686,9 +3734,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.9" +version = "0.103.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" dependencies = [ "ring", "rustls-pki-types", @@ -3715,9 +3763,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "schemars" @@ -3892,7 +3940,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3933,9 +3981,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.17.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" +checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" dependencies = [ "base64", "chrono", @@ -3952,14 +4000,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.17.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0" +checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" dependencies = [ - "darling 0.21.3", + "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4031,10 +4079,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -4065,12 +4114,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4131,7 +4180,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4153,9 +4202,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -4171,7 +4220,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4191,7 +4240,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4202,9 +4251,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" dependencies = [ "filetime", "libc", @@ -4213,12 +4262,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.24.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", "rustix", "windows-sys 0.61.2", @@ -4236,7 +4285,7 @@ dependencies = [ [[package]] name = "testsi" version = "0.1.0" -source = "git+https://github.com/GCdePaula/cartesi-tools-rs?rev=c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86#c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86" +source = "git+https://github.com/GCdePaula/cartesi-tools-rs?rev=ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22#ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22" dependencies = [ "cartesi-machine", "inventory", @@ -4249,11 +4298,11 @@ dependencies = [ [[package]] name = "testsi-macros" version = "0.1.0" -source = "git+https://github.com/GCdePaula/cartesi-tools-rs?rev=c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86#c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86" +source = "git+https://github.com/GCdePaula/cartesi-tools-rs?rev=ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22#ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4282,7 +4331,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4293,7 +4342,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4357,9 +4406,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -4372,9 +4421,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.49.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ "bytes", "libc", @@ -4388,13 +4437,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4446,32 +4495,32 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.23.10+spec-1.0.0" +version = "0.25.8+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +checksum = "16bff38f1d86c47f9ff0647e6838d7bb362522bdf44006c7068c2b1e606f1f3c" dependencies = [ "indexmap 2.13.0", "toml_datetime", "toml_parser", - "winnow", + "winnow 1.0.0", ] [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" dependencies = [ - "winnow", + "winnow 1.0.0", ] [[package]] @@ -4541,7 +4590,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4567,9 +4616,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "nu-ansi-term", @@ -4586,7 +4635,7 @@ dependencies = [ [[package]] name = "trolley" version = "0.1.0" -source = "git+https://github.com/GCdePaula/cartesi-tools-rs?rev=c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86#c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86" +source = "git+https://github.com/GCdePaula/cartesi-tools-rs?rev=ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22#ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22" dependencies = [ "libcmt-sys", "types", @@ -4624,7 +4673,7 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "types" version = "0.1.0" -source = "git+https://github.com/GCdePaula/cartesi-tools-rs?rev=c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86#c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86" +source = "git+https://github.com/GCdePaula/cartesi-tools-rs?rev=ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22#ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -4656,15 +4705,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "a559e63b5d8004e12f9bce88af5c6d939c58de839b7532cfe9653846cedd2a9e" [[package]] name = "unicode-xid" @@ -4760,11 +4809,20 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -4775,9 +4833,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.58" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if", "futures-util", @@ -4789,9 +4847,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4799,26 +4857,60 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver 1.0.27", +] + [[package]] name = "wasmtimer" version = "0.4.3" @@ -4835,9 +4927,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.85" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", @@ -4892,7 +4984,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4903,7 +4995,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5088,9 +5180,18 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" dependencies = [ "memchr", ] @@ -5100,6 +5201,88 @@ name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver 1.0.27", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "writeable" @@ -5154,28 +5337,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.38" +version = "0.8.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cf3aa6855b23711ee9852dfc97dfaa51c45feaba5b645d0c777414d494a961" +checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.38" +version = "0.8.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a616990af1a287837c4fe6596ad77ef57948f787e46ce28e166facc0cc1cb75" +checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5195,7 +5378,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "synstructure", ] @@ -5216,7 +5399,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5249,11 +5432,11 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "zmij" -version = "1.0.19" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 90e10e8..9bcd353 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,8 +28,8 @@ authors = [ ] [workspace.dependencies] -libcmt-sys = { version = "0.1", git = "https://github.com/GCdePaula/cartesi-tools-rs", rev = "c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86" } -trolley = { version = "0.1", git = "https://github.com/GCdePaula/cartesi-tools-rs", rev = "c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86" } -testsi = { version = "0.1", git = "https://github.com/GCdePaula/cartesi-tools-rs", rev = "c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86" } -types = { version = "0.1", git = "https://github.com/GCdePaula/cartesi-tools-rs", rev = "c2b2f65bc6a3d4ddf80b3a0c5a1673fbf22e9f86" } -cartesi-machine = { version = "2", git = "https://github.com/cartesi/dave", rev = "5d0560a04f623318af9ef5b7f193170b618b6ced", features = ["download_uarch"] } +libcmt-sys = { version = "0.1", git = "https://github.com/GCdePaula/cartesi-tools-rs", rev = "ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22" } +trolley = { version = "0.1", git = "https://github.com/GCdePaula/cartesi-tools-rs", rev = "ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22" } +testsi = { version = "0.1", git = "https://github.com/GCdePaula/cartesi-tools-rs", rev = "ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22" } +types = { version = "0.1", git = "https://github.com/GCdePaula/cartesi-tools-rs", rev = "ed14b98ecfe9796dc3ca7c9b96bfdbf0ef9baf22" } +cartesi-machine = { version = "2", git = "https://github.com/cartesi/dave", rev = "317a88a32a1b4a6002d561f37bb833843df55cba", features = ["download_uarch"] } diff --git a/examples/canonical-app/.gitignore b/examples/canonical-app/.gitignore index 6a3417b..7e15350 100644 --- a/examples/canonical-app/.gitignore +++ b/examples/canonical-app/.gitignore @@ -1 +1,2 @@ /out/ +/scripts/__pycache__/ diff --git a/examples/canonical-app/Dockerfile b/examples/canonical-app/Dockerfile index d993874..f2f2069 100644 --- a/examples/canonical-app/Dockerfile +++ b/examples/canonical-app/Dockerfile @@ -16,8 +16,13 @@ RUN echo "${TOOLS_SHA512} /tmp/tools.deb" | sha512sum -c - \ # alpine:3.22.2 (riscv64/alpine) FROM riscv64/alpine@sha256:372839ff152f938e12282226fb5f9ddaef72f9662dcadbf9dd0de5ce287c694e +ARG ALPINE_MAIN_REPOSITORY=https://dl-cdn.alpinelinux.org/alpine/v3.22/main +ARG LIBGCC_VERSION=14.2.0-r6 + # Add libgcc for Rust -RUN apk add --no-cache libgcc +RUN apk add --no-cache \ + --repository="${ALPINE_MAIN_REPOSITORY}" \ + "libgcc=${LIBGCC_VERSION}" # Copy `cartesi-init` COPY --from=extractor --chmod=755 /tmp/out/usr/sbin/cartesi-init /usr/sbin/cartesi-init diff --git a/examples/canonical-app/justfile b/examples/canonical-app/justfile index 2554be0..10f08f0 100644 --- a/examples/canonical-app/justfile +++ b/examples/canonical-app/justfile @@ -1,6 +1,7 @@ set shell := ["bash", "-euo", "pipefail", "-c"] out_dir := "out" +source_date_epoch := "0" linux_kernel := out_dir + "/linux.bin" rootfs_tar := out_dir + "/canonical-rootfs.tar" rootfs_ext2 := out_dir + "/canonical-rootfs.ext2" @@ -18,13 +19,13 @@ build-dapp: build-dapp-devnet build-dapp-devnet: mkdir -p {{out_dir}} - CROSS_CONFIG=Cross.toml DOCKER_DEFAULT_PLATFORM=linux/amd64 cross build --package canonical-app --bin canonical-app-devnet --target riscv64gc-unknown-linux-musl --release + SOURCE_DATE_EPOCH={{source_date_epoch}} CARGO_PROFILE_RELEASE_STRIP=symbols CROSS_CONFIG=Cross.toml DOCKER_DEFAULT_PLATFORM=linux/amd64 cross build --package canonical-app --bin canonical-app-devnet --target riscv64gc-unknown-linux-musl --release cp ../../target/riscv64gc-unknown-linux-musl/release/canonical-app-devnet {{dapp_binary_devnet}} cp {{dapp_binary_devnet}} {{dapp_binary}} build-dapp-sepolia: mkdir -p {{out_dir}} - CROSS_CONFIG=Cross.toml DOCKER_DEFAULT_PLATFORM=linux/amd64 cross build --package canonical-app --bin canonical-app-sepolia --target riscv64gc-unknown-linux-musl --release + SOURCE_DATE_EPOCH={{source_date_epoch}} CARGO_PROFILE_RELEASE_STRIP=symbols CROSS_CONFIG=Cross.toml DOCKER_DEFAULT_PLATFORM=linux/amd64 cross build --package canonical-app --bin canonical-app-sepolia --target riscv64gc-unknown-linux-musl --release cp ../../target/riscv64gc-unknown-linux-musl/release/canonical-app-sepolia {{dapp_binary_sepolia}} cp {{dapp_binary_sepolia}} {{dapp_binary}} @@ -32,7 +33,7 @@ build-rootfs: build-rootfs-devnet build-rootfs-devnet: build-dapp-devnet mkdir -p {{out_dir}} - docker buildx build \ + SOURCE_DATE_EPOCH={{source_date_epoch}} docker buildx build \ --platform linux/riscv64 \ --output type=tar,dest={{rootfs_tar}} \ --file Dockerfile \ @@ -41,7 +42,7 @@ build-rootfs-devnet: build-dapp-devnet build-rootfs-sepolia: build-dapp-sepolia mkdir -p {{out_dir}} - docker buildx build \ + SOURCE_DATE_EPOCH={{source_date_epoch}} docker buildx build \ --platform linux/riscv64 \ --output type=tar,dest={{rootfs_tar}} \ --file Dockerfile \ @@ -81,3 +82,14 @@ build-machine-image-sepolia: clean-machine-image-sepolia build-rootfs-sepolia test-guest: build-machine-image cargo run -p canonical-test + +print-build-hashes: build-machine-image + echo "== tool versions ==" + cartesi-machine --version + xgenext2fs --version + cross --version || true + docker buildx version + echo + echo "== artifact hashes ==" + python3 scripts/sha256_files.py {{dapp_binary_devnet}} {{rootfs_tar}} {{rootfs_ext2}} + cartesi-machine --load={{machine_image}} --initial-hash diff --git a/examples/canonical-app/scripts/sha256_files.py b/examples/canonical-app/scripts/sha256_files.py new file mode 100644 index 0000000..8e8854e --- /dev/null +++ b/examples/canonical-app/scripts/sha256_files.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import hashlib +import sys +from pathlib import Path + + +def sha256_for_file(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as input_file: + for chunk in iter(lambda: input_file.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def main(argv: list[str]) -> int: + for raw_path in argv[1:]: + path = Path(raw_path) + print(f"{sha256_for_file(path)} {path}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main(sys.argv)) diff --git a/justfile b/justfile index efa2ab2..3f5a351 100644 --- a/justfile +++ b/justfile @@ -40,6 +40,9 @@ canonical-build-machine-image-sepolia: canonical-test-guest: just -f examples/canonical-app/justfile test-guest +canonical-print-build-hashes: + just -f examples/canonical-app/justfile print-build-hashes + clean: cargo clean rm -f sequencer.db sequencer.db-shm sequencer.db-wal From aaea7a8226faf73ec9fd3ffefa8de6d44ff2e0ca Mon Sep 17 00:00:00 2001 From: Gabriel Coutinho de Paula Date: Tue, 24 Mar 2026 19:53:09 -0300 Subject: [PATCH 2/5] feat: implement nicer batch limit and fees fix bach too large --- sequencer-core/src/batch.rs | 17 ++++ sequencer/src/inclusion_lane/config.rs | 19 +---- sequencer/src/inclusion_lane/lane.rs | 9 +-- sequencer/src/inclusion_lane/tests.rs | 11 ++- sequencer/src/runtime.rs | 2 +- sequencer/src/storage/db.rs | 81 ++++++++++++------- .../src/storage/migrations/0001_schema.sql | 69 ++++++++++++++-- sequencer/src/storage/mod.rs | 19 ++++- sequencer/src/storage/sql.rs | 69 +++++++++++----- sequencer/tests/e2e_sequencer.rs | 3 +- 10 files changed, 210 insertions(+), 89 deletions(-) diff --git a/sequencer-core/src/batch.rs b/sequencer-core/src/batch.rs index 1bd4725..d34182d 100644 --- a/sequencer-core/src/batch.rs +++ b/sequencer-core/src/batch.rs @@ -8,6 +8,23 @@ use ssz_derive::{Decode, Encode}; /// L1/app must post such inputs as `0x00 || body`. Only these are stored (body only) and executed. pub const INPUT_TAG_DIRECT_INPUT: u8 = 0x00; +// --------------------------------------------------------------------------- +// Gas-economics-derived batch sizing +// +// The InputBox contract charges roughly: +// total_gas ≈ base_gas + delta × payload_bytes +// +// We charge each user-op a DA fee of (1 + α) × δ per byte, where α amortizes +// the base cost across the batch: +// +// α × δ × n = base_gas ⟹ n = base_gas / (α × δ) +// +// Choosing α (the overhead fraction) determines the batch size n in bytes. +// All parameters live in the `batch_policy` SQLite singleton table so they +// can be hot-swapped at runtime (see 0001_schema.sql). A CHECK constraint +// on that table ensures batch_size_target < const_max_batch_bytes. +// --------------------------------------------------------------------------- + /// Batch submissions are sent as raw `ssz(Batch)` with no tag; classification at L1 is by /// attempting SSZ decode, and at the rollup by msg_sender. diff --git a/sequencer/src/inclusion_lane/config.rs b/sequencer/src/inclusion_lane/config.rs index 5ea70bc..6cb0414 100644 --- a/sequencer/src/inclusion_lane/config.rs +++ b/sequencer/src/inclusion_lane/config.rs @@ -4,13 +4,10 @@ use std::time::Duration; use alloy_primitives::Address; -use sequencer_core::application::Application; -use sequencer_core::user_op::SignedUserOp; -const DEFAULT_MAX_USER_OPS_PER_CHUNK: usize = 1024; +const DEFAULT_MAX_USER_OPS_PER_CHUNK: usize = 64; const DEFAULT_SAFE_INPUT_BUFFER_CAPACITY: usize = 2048; const DEFAULT_MAX_BATCH_OPEN: Duration = Duration::from_secs(2 * 60 * 60); -const DEFAULT_MAX_BATCH_USER_OP_BYTES: usize = 1_048_576; // 1 MiB const DEFAULT_IDLE_POLL_INTERVAL: Duration = Duration::from_millis(2); #[derive(Debug, Clone, Copy)] @@ -19,28 +16,16 @@ pub struct InclusionLaneConfig { pub max_user_ops_per_chunk: usize, pub safe_input_buffer_capacity: usize, pub max_batch_open: Duration, - - // Soft threshold for batch rotation. - // - // We intentionally check this between chunks (not per user-op) to keep the hot path - // simple and low-latency. This means batches can overshoot the threshold by at most - // one processed chunk. API ingress bounds each user-op size, so this overshoot is - // bounded by: - // max_user_ops_per_chunk * (SignedUserOp::max_batch_metadata() + A::MAX_METHOD_PAYLOAD_BYTES) - pub max_batch_user_op_bytes: usize, - pub idle_poll_interval: Duration, } impl InclusionLaneConfig { - pub fn for_app(batch_submitter_address: Address) -> Self { + pub fn new(batch_submitter_address: Address) -> Self { Self { batch_submitter_address, max_user_ops_per_chunk: DEFAULT_MAX_USER_OPS_PER_CHUNK, safe_input_buffer_capacity: DEFAULT_SAFE_INPUT_BUFFER_CAPACITY, max_batch_open: DEFAULT_MAX_BATCH_OPEN, - max_batch_user_op_bytes: DEFAULT_MAX_BATCH_USER_OP_BYTES - .max(SignedUserOp::max_batch_metadata() + A::MAX_METHOD_PAYLOAD_BYTES), idle_poll_interval: DEFAULT_IDLE_POLL_INTERVAL, } } diff --git a/sequencer/src/inclusion_lane/lane.rs b/sequencer/src/inclusion_lane/lane.rs index 87a42cb..ed61d2f 100644 --- a/sequencer/src/inclusion_lane/lane.rs +++ b/sequencer/src/inclusion_lane/lane.rs @@ -297,7 +297,7 @@ impl InclusionLane { } fn should_close_batch(head: &WriteHead, config: &InclusionLaneConfig) -> bool { - should_close_batch_by_time(head, config) || should_close_batch_by_size::(head, config) + should_close_batch_by_time(head, config) || should_close_batch_by_size::(head) } fn should_close_batch_by_time(head: &WriteHead, config: &InclusionLaneConfig) -> bool { @@ -307,11 +307,8 @@ fn should_close_batch_by_time(head: &WriteHead, config: &InclusionLaneConfig) -> age >= config.max_batch_open } -fn should_close_batch_by_size( - head: &WriteHead, - config: &InclusionLaneConfig, -) -> bool { - user_op_count_to_bytes::(head.batch_user_op_count) >= config.max_batch_user_op_bytes as u64 +fn should_close_batch_by_size(head: &WriteHead) -> bool { + user_op_count_to_bytes::(head.batch_user_op_count) >= head.max_batch_user_op_bytes } fn execute_user_op( diff --git a/sequencer/src/inclusion_lane/tests.rs b/sequencer/src/inclusion_lane/tests.rs index 7f96448..9c13e23 100644 --- a/sequencer/src/inclusion_lane/tests.rs +++ b/sequencer/src/inclusion_lane/tests.rs @@ -200,7 +200,6 @@ fn default_test_config() -> InclusionLaneConfig { max_user_ops_per_chunk: 16, safe_input_buffer_capacity: 16, max_batch_open: Duration::MAX, - max_batch_user_op_bytes: 1_000_000_000, idle_poll_interval: Duration::from_millis(2), } } @@ -634,9 +633,13 @@ async fn empty_batches_close_when_max_open_time_is_reached() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn batch_closes_when_max_user_op_bytes_is_reached() { let db = temp_db("batch-close-size"); - let mut config = default_test_config(); - config.max_batch_user_op_bytes = - SignedUserOp::max_batch_metadata() + ::MAX_METHOD_PAYLOAD_BYTES; + // Set alpha high enough that batch_size_target ≤ one user op (126 bytes). + // 55000*1000/(17000*26) = 124 bytes < 126. + { + let mut storage = Storage::open(db.path.as_str(), "NORMAL").expect("open storage"); + storage.set_alpha(17000, 1000).expect("set alpha"); + } + let config = default_test_config(); let (tx, shutdown, lane_handle) = start_lane(db.path.as_str(), config).await; let (pending, recv) = make_pending_user_op(0x33); diff --git a/sequencer/src/runtime.rs b/sequencer/src/runtime.rs index 246a26e..4294aef 100644 --- a/sequencer/src/runtime.rs +++ b/sequencer/src/runtime.rs @@ -147,7 +147,7 @@ where shutdown.clone(), app, storage, - InclusionLaneConfig::for_app::(l1_config.batch_submitter_address), + InclusionLaneConfig::new(l1_config.batch_submitter_address), ); let mut input_reader_handle = input_reader.start()?; diff --git a/sequencer/src/storage/db.rs b/sequencer/src/storage/db.rs index 7537a2c..082f963 100644 --- a/sequencer/src/storage/db.rs +++ b/sequencer/src/storage/db.rs @@ -9,17 +9,18 @@ use super::sql::{ sql_count_user_ops_for_frame, sql_insert_open_batch, sql_insert_open_batch_with_index, sql_insert_open_frame, sql_insert_safe_inputs_batch, sql_insert_sequenced_direct_inputs_for_frame, sql_insert_user_ops_and_sequenced_batch, - sql_select_frames_for_batch, sql_select_latest_batch_index, + sql_select_batch_policy, sql_select_frames_for_batch, sql_select_latest_batch_index, sql_select_latest_batch_with_user_op_count, sql_select_latest_frame_in_batch_for_batch, sql_select_max_safe_input_index, sql_select_ordered_l2_tx_count, sql_select_ordered_l2_txs_for_batch, sql_select_ordered_l2_txs_from_offset, - sql_select_ordered_l2_txs_page_from_offset, sql_select_recommended_fee, sql_select_safe_block, + sql_select_ordered_l2_txs_page_from_offset, sql_select_safe_block, sql_select_safe_input_payloads_for_sender, sql_select_safe_inputs_range, sql_select_total_drained_direct_inputs, sql_select_user_ops_for_frame, - sql_update_recommended_fee, sql_update_safe_block, + sql_update_batch_policy_alpha, sql_update_batch_policy_gas_price, sql_update_safe_block, }; use super::{ - FrameHeader, SafeFrontier, SafeInputRange, StorageOpenError, StoredSafeInput, WriteHead, + BatchPolicy, FrameHeader, SafeFrontier, SafeInputRange, StorageOpenError, StoredSafeInput, + WriteHead, }; use crate::inclusion_lane::PendingUserOp; use alloy_primitives::Address; @@ -247,30 +248,44 @@ impl Storage { ); let now_ms = now_unix_ms(); - let frame_fee = query_recommended_fee(&tx)?; + let policy = query_batch_policy(&tx)?; insert_open_batch_with_index(&tx, 0, now_ms)?; - insert_open_frame(&tx, 0, 0, now_ms, frame_fee, safe_block)?; + insert_open_frame(&tx, 0, 0, now_ms, policy.recommended_fee, safe_block)?; persist_frame_direct_sequence(&tx, 0, 0, leading_direct_range)?; tx.commit()?; Ok(WriteHead { batch_index: 0, batch_created_at: from_unix_ms(now_ms), - frame_fee, + frame_fee: policy.recommended_fee, safe_block, batch_user_op_count: 0, open_frame_user_op_count: 0, frame_in_batch: 0, + max_batch_user_op_bytes: policy.batch_size_target, }) } - pub fn recommended_fee(&mut self) -> Result { - let value = sql_select_recommended_fee(&self.conn)?; - Ok(i64_to_u64(value)) + pub fn batch_policy(&mut self) -> Result { + let (fee, target) = sql_select_batch_policy(&self.conn)?; + Ok(BatchPolicy { + recommended_fee: i64_to_u64(fee), + batch_size_target: i64_to_u64(target), + }) + } + + pub fn set_gas_price(&mut self, gas_price: u64) -> Result<()> { + let changed_rows = + sql_update_batch_policy_gas_price(&self.conn, u64_to_i64(gas_price))?; + if changed_rows != 1 { + return Err(rusqlite::Error::StatementChangedRows(changed_rows)); + } + Ok(()) } - pub fn set_recommended_fee(&mut self, fee: u64) -> Result<()> { - let changed_rows = sql_update_recommended_fee(&self.conn, u64_to_i64(fee))?; + pub fn set_alpha(&mut self, num: u64, denom: u64) -> Result<()> { + let changed_rows = + sql_update_batch_policy_alpha(&self.conn, u64_to_i64(num), u64_to_i64(denom))?; if changed_rows != 1 { return Err(rusqlite::Error::StatementChangedRows(changed_rows)); } @@ -317,14 +332,14 @@ impl Storage { .transaction_with_behavior(TransactionBehavior::Immediate)?; assert_write_head_matches_open_state(&tx, head)?; let now_ms = now_unix_ms(); - let next_frame_fee = query_recommended_fee(&tx)?; + let policy = query_batch_policy(&tx)?; let next_frame_in_batch = head.frame_in_batch.saturating_add(1); insert_open_frame( &tx, head.batch_index, next_frame_in_batch, now_ms, - next_frame_fee, + policy.recommended_fee, next_safe_block, )?; persist_frame_direct_sequence( @@ -334,7 +349,7 @@ impl Storage { leading_direct_range, )?; tx.commit()?; - head.advance_frame(next_frame_fee, next_safe_block); + head.advance_frame(policy, next_safe_block); Ok(()) } @@ -348,23 +363,23 @@ impl Storage { .transaction_with_behavior(TransactionBehavior::Immediate)?; assert_write_head_matches_open_state(&tx, head)?; let now_ms = now_unix_ms(); - // Frame fee is committed here: we sample the current recommendation once and - // assign it to the newly opened frame. - let next_frame_fee = query_recommended_fee(&tx)?; + // Batch policy is sampled here: the derived fee is committed to the newly + // opened frame, and the batch size target is stored on the write head. + let policy = query_batch_policy(&tx)?; let next_batch_index = insert_open_batch(&tx, now_ms)?; insert_open_frame( &tx, next_batch_index, 0, now_ms, - next_frame_fee, + policy.recommended_fee, next_safe_block, )?; tx.commit()?; head.move_to_next_batch( next_batch_index, from_unix_ms(now_ms), - next_frame_fee, + policy, next_safe_block, ); Ok(()) @@ -516,6 +531,7 @@ fn load_current_write_head(tx: &Transaction<'_>) -> Result> { }; let (frame_in_batch, frame_fee, safe_block) = query_latest_frame_in_batch(tx, batch_index)?; let open_frame_user_op_count = query_frame_user_op_count(tx, batch_index, frame_in_batch)?; + let policy = query_batch_policy(tx)?; Ok(Some(WriteHead { batch_index, batch_created_at, @@ -524,6 +540,7 @@ fn load_current_write_head(tx: &Transaction<'_>) -> Result> { batch_user_op_count, open_frame_user_op_count, frame_in_batch, + max_batch_user_op_bytes: policy.batch_size_target, })) } @@ -606,9 +623,12 @@ fn query_current_safe_block(tx: &Connection) -> Result { Ok(i64_to_u64(value)) } -fn query_recommended_fee(tx: &Transaction<'_>) -> Result { - let value = sql_select_recommended_fee(tx)?; - Ok(i64_to_u64(value)) +fn query_batch_policy(tx: &Transaction<'_>) -> Result { + let (fee, target) = sql_select_batch_policy(tx)?; + Ok(BatchPolicy { + recommended_fee: i64_to_u64(fee), + batch_size_target: i64_to_u64(target), + }) } fn persist_frame_direct_sequence( @@ -761,12 +781,13 @@ mod tests { } #[test] - fn next_frame_fee_comes_from_recommended_fee_singleton() { - let db = temp_db("recommended-fee"); + fn next_frame_fee_comes_from_batch_policy() { + let db = temp_db("batch-policy-fee"); let mut storage = Storage::open(db.path.as_str(), "NORMAL").expect("open storage"); - assert_eq!(storage.recommended_fee().expect("default recommended"), 0); + let policy = storage.batch_policy().expect("default policy"); + assert_eq!(policy.recommended_fee, 0); - storage.set_recommended_fee(7).expect("set recommended fee"); + storage.set_gas_price(100).expect("set gas price"); let mut head = storage .initialize_open_state(0, SafeInputRange::empty_at(0)) @@ -776,8 +797,10 @@ mod tests { .close_frame_and_batch(&mut head, next_safe_block) .expect("rotate batch"); - assert_eq!(head.frame_fee, 7); - assert_eq!(storage.recommended_fee().expect("read recommended"), 7); + let policy = storage.batch_policy().expect("read policy"); + assert!(head.frame_fee > 0, "frame fee should be derived from gas_price"); + assert_eq!(head.frame_fee, policy.recommended_fee); + assert!(head.max_batch_user_op_bytes > 0, "batch size target should be set"); } #[test] diff --git a/sequencer/src/storage/migrations/0001_schema.sql b/sequencer/src/storage/migrations/0001_schema.sql index 2be3b27..1a8fbdc 100644 --- a/sequencer/src/storage/migrations/0001_schema.sql +++ b/sequencer/src/storage/migrations/0001_schema.sql @@ -81,11 +81,68 @@ CREATE TABLE IF NOT EXISTS l1_safe_head ( INSERT OR IGNORE INTO l1_safe_head (singleton_id, block_number) VALUES (0, 0); -CREATE TABLE IF NOT EXISTS recommended_fees ( - singleton_id INTEGER PRIMARY KEY CHECK (singleton_id = 0), - -- Mutable recommendation consumed when opening the next frame. - fee INTEGER NOT NULL CHECK (fee >= 0) +-- --------------------------------------------------------------------------- +-- Batch policy singleton +-- +-- Contains operator-tunable knobs (alpha, gas_price) and on-chain constants +-- (delta, base_gas, etc.). A view derives `batch_size_target` and +-- `recommended_fee` from these columns, and a CHECK constraint prevents +-- updates that would violate the batch size limit. +-- +-- Gas economics: +-- batch_size_target = const_base_gas * alpha_denom / (alpha_num * const_delta) +-- recommended_fee = gas_price * (alpha_num + alpha_denom) +-- * const_delta * const_user_op_bytes / alpha_denom +-- --------------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS batch_policy ( + singleton_id INTEGER PRIMARY KEY CHECK (singleton_id = 0), + + -- Knobs (operator-tunable via sqlite3 CLI): + alpha_num INTEGER NOT NULL CHECK (alpha_num > 0), + alpha_denom INTEGER NOT NULL CHECK (alpha_denom > 0), + gas_price INTEGER NOT NULL CHECK (gas_price >= 0), + + -- Constants (in DB so the CHECK can reference them): + const_delta INTEGER NOT NULL CHECK (const_delta > 0), + const_base_gas INTEGER NOT NULL CHECK (const_base_gas > 0), + const_user_op_bytes INTEGER NOT NULL CHECK (const_user_op_bytes > 0), + -- Effective max batch payload. Already includes slack for chunk overshoot + -- and SSZ framing, so the CHECK is simply batch_size_target < this value. + const_max_batch_bytes INTEGER NOT NULL CHECK (const_max_batch_bytes > 0), + + -- Safety: batch_size_target < const_max_batch_bytes. + CHECK ( + const_base_gas * alpha_denom / (alpha_num * const_delta) + < const_max_batch_bytes + ) ); -INSERT OR IGNORE INTO recommended_fees (singleton_id, fee) -VALUES (0, 0); +INSERT OR IGNORE INTO batch_policy( + singleton_id, + + alpha_num, alpha_denom, gas_price, + + const_delta, const_base_gas, + const_user_op_bytes, const_max_batch_bytes +) +VALUES ( + -- Fixed id + 0, + + -- Knobs + 168, 1000, 0, + + -- Constants + 26, 55000, + 126, 32000 +); + +-- Derived view for reads. +CREATE VIEW IF NOT EXISTS batch_policy_derived AS +SELECT *, + const_base_gas * alpha_denom / (alpha_num * const_delta) + AS batch_size_target, + + gas_price * (alpha_num + alpha_denom) * const_delta * const_user_op_bytes / alpha_denom + AS recommended_fee +FROM batch_policy; diff --git a/sequencer/src/storage/mod.rs b/sequencer/src/storage/mod.rs index 31fc29f..65a48e6 100644 --- a/sequencer/src/storage/mod.rs +++ b/sequencer/src/storage/mod.rs @@ -69,6 +69,13 @@ pub enum StorageOpenError { Migration(#[from] rusqlite_migration::Error), } +/// Derived batch policy read from the `batch_policy_derived` view. +#[derive(Debug, Clone, Copy)] +pub struct BatchPolicy { + pub recommended_fee: u64, + pub batch_size_target: u64, +} + #[derive(Debug, Clone, Copy)] pub struct WriteHead { pub batch_index: u64, @@ -79,6 +86,8 @@ pub struct WriteHead { pub batch_user_op_count: u64, pub open_frame_user_op_count: u32, pub frame_in_batch: u32, + // Soft batch size threshold read from batch_policy at each frame/batch transition. + pub max_batch_user_op_bytes: u64, } impl WriteHead { @@ -91,26 +100,28 @@ impl WriteHead { self.open_frame_user_op_count > 0 } - pub fn advance_frame(&mut self, frame_fee: u64, safe_block: u64) { + pub fn advance_frame(&mut self, policy: BatchPolicy, safe_block: u64) { self.frame_in_batch = self.frame_in_batch.saturating_add(1); - self.frame_fee = frame_fee; + self.frame_fee = policy.recommended_fee; self.safe_block = safe_block; self.open_frame_user_op_count = 0; + self.max_batch_user_op_bytes = policy.batch_size_target; } pub fn move_to_next_batch( &mut self, batch_index: u64, batch_created_at: SystemTime, - frame_fee: u64, + policy: BatchPolicy, safe_block: u64, ) { self.batch_index = batch_index; self.batch_created_at = batch_created_at; - self.frame_fee = frame_fee; + self.frame_fee = policy.recommended_fee; self.safe_block = safe_block; self.batch_user_op_count = 0; self.open_frame_user_op_count = 0; self.frame_in_batch = 0; + self.max_batch_user_op_bytes = policy.batch_size_target; } } diff --git a/sequencer/src/storage/sql.rs b/sequencer/src/storage/sql.rs index 1710753..15d518e 100644 --- a/sequencer/src/storage/sql.rs +++ b/sequencer/src/storage/sql.rs @@ -26,8 +26,8 @@ const SQL_SELECT_LATEST_BATCH_INDEX: &str = "SELECT MAX(batch_index) FROM batche const SQL_SELECT_USER_OPS_FOR_FRAME: &str = "SELECT nonce, max_fee, data, sig FROM user_ops WHERE batch_index = ?1 AND frame_in_batch = ?2 ORDER BY pos_in_frame ASC"; const SQL_SELECT_MAX_SAFE_INPUT_INDEX: &str = "SELECT MAX(safe_input_index) FROM safe_inputs"; const SQL_SELECT_ORDERED_L2_TX_COUNT: &str = "SELECT COUNT(*) FROM sequenced_l2_txs"; -const SQL_SELECT_RECOMMENDED_FEE: &str = - "SELECT fee FROM recommended_fees WHERE singleton_id = 0 LIMIT 1"; +const SQL_SELECT_BATCH_POLICY: &str = + "SELECT recommended_fee, batch_size_target FROM batch_policy_derived WHERE singleton_id = 0 LIMIT 1"; const SQL_SELECT_SAFE_BLOCK: &str = "SELECT block_number FROM l1_safe_head WHERE singleton_id = 0 LIMIT 1"; const SQL_INSERT_SAFE_INPUT: &str = "INSERT INTO safe_inputs (safe_input_index, sender, payload, block_number) VALUES (?1, ?2, ?3, ?4)"; @@ -35,8 +35,10 @@ const SQL_INSERT_USER_OP: &str = include_str!("queries/insert_user_op.sql"); const SQL_INSERT_SEQUENCED_USER_OP: &str = include_str!("queries/insert_sequenced_user_op.sql"); const SQL_INSERT_SEQUENCED_DIRECT_INPUT: &str = include_str!("queries/insert_sequenced_direct_input.sql"); -const SQL_UPDATE_RECOMMENDED_FEE: &str = - "UPDATE recommended_fees SET fee = ?1 WHERE singleton_id = 0"; +const SQL_UPDATE_BATCH_POLICY_GAS_PRICE: &str = + "UPDATE batch_policy SET gas_price = ?1 WHERE singleton_id = 0"; +const SQL_UPDATE_BATCH_POLICY_ALPHA: &str = + "UPDATE batch_policy SET alpha_num = ?1, alpha_denom = ?2 WHERE singleton_id = 0"; const SQL_UPDATE_SAFE_BLOCK: &str = "UPDATE l1_safe_head SET block_number = ?1 WHERE singleton_id = 0"; #[derive(Debug, Clone)] @@ -93,12 +95,25 @@ pub(super) fn sql_select_latest_batch_index(conn: &Connection) -> Result Result { - conn.query_row(SQL_SELECT_RECOMMENDED_FEE, [], |row| row.get(0)) +pub(super) fn sql_select_batch_policy(conn: &Connection) -> Result<(i64, i64)> { + conn.query_row(SQL_SELECT_BATCH_POLICY, [], |row| { + Ok((row.get(0)?, row.get(1)?)) + }) } -pub(super) fn sql_update_recommended_fee(conn: &Connection, fee: i64) -> Result { - conn.execute(SQL_UPDATE_RECOMMENDED_FEE, params![fee]) +pub(super) fn sql_update_batch_policy_gas_price( + conn: &Connection, + gas_price: i64, +) -> Result { + conn.execute(SQL_UPDATE_BATCH_POLICY_GAS_PRICE, params![gas_price]) +} + +pub(super) fn sql_update_batch_policy_alpha( + conn: &Connection, + alpha_num: i64, + alpha_denom: i64, +) -> Result { + conn.execute(SQL_UPDATE_BATCH_POLICY_ALPHA, params![alpha_num, alpha_denom]) } pub(super) fn sql_select_safe_block(conn: &Connection) -> Result { @@ -399,13 +414,13 @@ mod tests { SQL_INSERT_SEQUENCED_USER_OP, SQL_INSERT_USER_OP, sql_insert_open_batch, sql_insert_open_batch_with_index, sql_insert_open_frame, sql_insert_safe_inputs_batch, sql_insert_sequenced_direct_inputs_for_frame, sql_insert_user_ops_and_sequenced_batch, - sql_select_frames_for_batch, sql_select_latest_batch_index, + sql_select_batch_policy, sql_select_frames_for_batch, sql_select_latest_batch_index, sql_select_latest_batch_with_user_op_count, sql_select_max_safe_input_index, sql_select_ordered_l2_tx_count, sql_select_ordered_l2_txs_from_offset, - sql_select_ordered_l2_txs_page_from_offset, sql_select_recommended_fee, - sql_select_safe_block, sql_select_safe_inputs_range, - sql_select_total_drained_direct_inputs, sql_select_user_ops_for_frame, - sql_update_recommended_fee, sql_update_safe_block, + sql_select_ordered_l2_txs_page_from_offset, sql_select_safe_block, + sql_select_safe_inputs_range, sql_select_total_drained_direct_inputs, + sql_select_user_ops_for_frame, sql_update_batch_policy_alpha, + sql_update_batch_policy_gas_price, sql_update_safe_block, }; use crate::inclusion_lane::PendingUserOp; use crate::storage::db::Storage; @@ -686,14 +701,28 @@ mod tests { } #[test] - fn recommended_fee_helpers_read_and_update_singleton() { + fn batch_policy_helpers_read_defaults_and_update_knobs() { let conn = setup_conn(); - assert_eq!( - sql_select_recommended_fee(&conn).expect("read recommended"), - 0 - ); - sql_update_recommended_fee(&conn, 9).expect("update recommended"); - assert_eq!(sql_select_recommended_fee(&conn).expect("read updated"), 9); + // Default: gas_price=0 → recommended_fee=0, alpha=168/1000 → batch_size_target=12591 + let (fee, target) = sql_select_batch_policy(&conn).expect("read policy"); + assert_eq!(fee, 0); + assert_eq!(target, 55000 * 1000 / (168 * 26)); // 12591 + + sql_update_batch_policy_gas_price(&conn, 100).expect("update gas price"); + let (fee, _) = sql_select_batch_policy(&conn).expect("read updated policy"); + assert!(fee > 0, "fee should be derived from gas_price"); + + sql_update_batch_policy_alpha(&conn, 200, 1000).expect("update alpha"); + let (_, target) = sql_select_batch_policy(&conn).expect("read updated target"); + assert_eq!(target, 55000 * 1000 / (200 * 26)); // 10576 + } + + #[test] + fn batch_policy_check_rejects_unsafe_alpha() { + let conn = setup_conn(); + // alpha_num=1 → batch_size_target = 55000*1000/(1*26) = 2_115_384 → way over 32000 + let err = sql_update_batch_policy_alpha(&conn, 1, 1000); + assert!(err.is_err(), "CHECK should reject unsafe alpha"); } #[test] diff --git a/sequencer/tests/e2e_sequencer.rs b/sequencer/tests/e2e_sequencer.rs index 4ec29a0..84c41fa 100644 --- a/sequencer/tests/e2e_sequencer.rs +++ b/sequencer/tests/e2e_sequencer.rs @@ -431,7 +431,6 @@ async fn start_full_server_with_max_body( max_user_ops_per_chunk: 32, safe_input_buffer_capacity: 32, max_batch_open: Duration::from_secs(60 * 60), - max_batch_user_op_bytes: 1_048_576, idle_poll_interval: Duration::from_millis(2), }, ); @@ -546,7 +545,7 @@ async fn shutdown_runtime(mut runtime: FullServerRuntime) { fn bootstrap_open_frame_fee_zero(db_path: &str) { let mut storage = Storage::open(db_path, "NORMAL").expect("open storage"); - storage.set_recommended_fee(0).expect("set recommended fee"); + // gas_price defaults to 0 → recommended_fee = 0. let head = storage .initialize_open_state(0, SafeInputRange::empty_at(0)) .expect("initialize open state"); From 612d2e89a64213e9737fdd70b08ffbd15a8976f5 Mon Sep 17 00:00:00 2001 From: Gabriel Coutinho de Paula Date: Tue, 24 Mar 2026 21:15:43 -0300 Subject: [PATCH 3/5] refactor: improve cli/env arguments, update CI --- .../actions/setup-guest-toolchain/action.yml | 131 ++++++++++++ .github/workflows/ci.yml | 201 +++--------------- .github/workflows/release.yml | 103 ++------- justfile | 8 +- sequencer/src/config.rs | 143 +++++++------ sequencer/src/runtime.rs | 45 ++-- tests/harness/src/sequencer.rs | 37 ++-- 7 files changed, 300 insertions(+), 368 deletions(-) create mode 100644 .github/actions/setup-guest-toolchain/action.yml diff --git a/.github/actions/setup-guest-toolchain/action.yml b/.github/actions/setup-guest-toolchain/action.yml new file mode 100644 index 0000000..127f7e5 --- /dev/null +++ b/.github/actions/setup-guest-toolchain/action.yml @@ -0,0 +1,131 @@ +name: "Setup guest toolchain" +description: "Install system deps, xgenext2fs, cartesi-machine, QEMU/Buildx, Rust, just, and cross." + +inputs: + xgenext2fs-version: + description: "xgenext2fs release tag" + required: true + cartesi-machine-version: + description: "cartesi-machine release tag" + required: true + cartesi-machine-sha256-amd64: + description: "SHA-256 for the amd64 .deb" + required: true + cartesi-machine-sha256-arm64: + description: "SHA-256 for the arm64 .deb" + required: true + xgenext2fs-sha256-amd64: + description: "SHA-256 for the amd64 xgenext2fs .deb" + required: true + xgenext2fs-sha256-arm64: + description: "SHA-256 for the arm64 xgenext2fs .deb" + required: true + install-foundry: + description: "Whether to install Foundry (for anvil)" + required: false + default: "false" + foundry-version: + description: "Foundry version tag" + required: false + default: "v1.4.3" + rust-components: + description: "Extra rustup components (comma-separated)" + required: false + default: "rustfmt" + +runs: + using: composite + steps: + - name: Install system dependencies + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y \ + lua5.4 \ + liblua5.4-dev \ + libslirp-dev \ + ca-certificates \ + wget \ + xz-utils + + - name: Install xgenext2fs + shell: bash + run: | + set -euo pipefail + ARCH="$(dpkg --print-architecture)" + VERSION="${{ inputs.xgenext2fs-version }}" + + case "${ARCH}" in + amd64) + ASSET_NAME="xgenext2fs_amd64.deb" + EXPECTED_SHA="${{ inputs.xgenext2fs-sha256-amd64 }}" + ;; + arm64) + ASSET_NAME="xgenext2fs_arm64.deb" + EXPECTED_SHA="${{ inputs.xgenext2fs-sha256-arm64 }}" + ;; + *) + echo "unsupported arch for xgenext2fs: ${ARCH}" >&2 + exit 1 + ;; + esac + + ASSET_URL="https://github.com/cartesi/genext2fs/releases/download/${VERSION}/${ASSET_NAME}" + wget -O /tmp/xgenext2fs.deb "${ASSET_URL}" + echo "${EXPECTED_SHA} /tmp/xgenext2fs.deb" | sha256sum --check + sudo apt-get install -y /tmp/xgenext2fs.deb + + - name: Install cartesi-machine + shell: bash + run: | + set -euo pipefail + ARCH="$(dpkg --print-architecture)" + VERSION="${{ inputs.cartesi-machine-version }}" + + case "${ARCH}" in + amd64) + DEB_SHA256="${{ inputs.cartesi-machine-sha256-amd64 }}" + ;; + arm64) + DEB_SHA256="${{ inputs.cartesi-machine-sha256-arm64 }}" + ;; + *) + echo "unsupported arch for machine-emulator: ${ARCH}" >&2 + exit 1 + ;; + esac + + wget -O /tmp/machine-emulator.deb "https://github.com/cartesi/machine-emulator/releases/download/${VERSION}/machine-emulator_${ARCH}.deb" + echo "${DEB_SHA256} /tmp/machine-emulator.deb" | sha256sum --check + sudo apt-get install -y /tmp/machine-emulator.deb + cartesi-machine --version + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + components: ${{ inputs.rust-components }} + + - name: Cache Rust artifacts + uses: Swatinem/rust-cache@v2 + + - name: Install Foundry + if: inputs.install-foundry == 'true' + uses: foundry-rs/foundry-toolchain@v1 + with: + version: ${{ inputs.foundry-version }} + + - name: Install just + uses: taiki-e/install-action@v2 + with: + tool: just + + - name: Install cross + uses: taiki-e/install-action@v2 + with: + tool: cross diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b104d99..f203d8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,11 @@ on: env: XGENEXT2FS_VERSION: v1.5.6 + XGENEXT2FS_SHA256_AMD64: 996e4e68a638b5dc5967d3410f92ecb8d2f41e32218bbe0f8b4c4474d7eebc59 + XGENEXT2FS_SHA256_ARM64: e5aca81164b762bbe5447bacef41e4fa9e357fd9c8f44e519c5206227d43144d + CARTESI_MACHINE_VERSION: v0.20.0-test2 + CARTESI_MACHINE_SHA256_AMD64: 39bbfc96a6cc6606307294b719df65f4f2725e8d200d062bcbd8c22355b99b56 + CARTESI_MACHINE_SHA256_ARM64: 787d823756000cdecd72da8a3494b4c08613087379035959e561bbaef7a220ba jobs: rust: @@ -27,7 +32,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: - components: rustfmt + components: rustfmt, clippy - name: Cache Rust artifacts uses: Swatinem/rust-cache@v2 @@ -37,15 +42,15 @@ jobs: with: version: v1.4.3 - - name: Check - run: cargo check --workspace --all-targets --locked - - name: Build run: cargo build --workspace --all-targets --locked - name: Format run: cargo fmt --all -- --check + - name: Clippy + run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings + - name: Test timeout-minutes: 15 run: RUN_ANVIL_TESTS=1 cargo test --workspace --all-targets --all-features --locked @@ -59,90 +64,15 @@ jobs: - name: Checkout uses: actions/checkout@v5 - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y \ - lua5.4 \ - liblua5.4-dev \ - libslirp-dev \ - ca-certificates \ - wget \ - xz-utils - - - name: Install xgenext2fs - run: | - set -euo pipefail - ARCH="$(dpkg --print-architecture)" - VERSION="${XGENEXT2FS_VERSION}" - - case "${ARCH}" in - amd64) - ASSET_NAME="xgenext2fs_amd64.deb" - ;; - arm64) - ASSET_NAME="xgenext2fs_arm64.deb" - ;; - *) - echo "unsupported arch for xgenext2fs: ${ARCH}" >&2 - exit 1 - ;; - esac - - ASSET_URL="https://github.com/cartesi/genext2fs/releases/download/${VERSION}/${ASSET_NAME}" - wget -O /tmp/xgenext2fs.deb "${ASSET_URL}" - sha256sum /tmp/xgenext2fs.deb - sudo apt-get update - sudo apt-get install -y /tmp/xgenext2fs.deb - - - name: Install cartesi-machine (machine emulator CLI) - run: | - set -euo pipefail - ARCH="$(dpkg --print-architecture)" - VERSION="v0.20.0-test2" - - case "${ARCH}" in - amd64) - DEB_SHA256="39bbfc96a6cc6606307294b719df65f4f2725e8d200d062bcbd8c22355b99b56" - ;; - arm64) - DEB_SHA256="787d823756000cdecd72da8a3494b4c08613087379035959e561bbaef7a220ba" - ;; - *) - echo "unsupported arch for machine-emulator: ${ARCH}" >&2 - exit 1 - ;; - esac - - wget -O /tmp/machine-emulator.deb "https://github.com/cartesi/machine-emulator/releases/download/${VERSION}/machine-emulator_${ARCH}.deb" - echo "${DEB_SHA256} /tmp/machine-emulator.deb" | sha256sum --check - sudo apt-get update - sudo apt-get install -y /tmp/machine-emulator.deb - cartesi-machine --version - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt - - - name: Cache Rust artifacts - uses: Swatinem/rust-cache@v2 - - - name: Install just - uses: taiki-e/install-action@v2 + - name: Setup guest toolchain + uses: ./.github/actions/setup-guest-toolchain with: - tool: just - - - name: Install cross - uses: taiki-e/install-action@v2 - with: - tool: cross + xgenext2fs-version: ${{ env.XGENEXT2FS_VERSION }} + xgenext2fs-sha256-amd64: ${{ env.XGENEXT2FS_SHA256_AMD64 }} + xgenext2fs-sha256-arm64: ${{ env.XGENEXT2FS_SHA256_ARM64 }} + cartesi-machine-version: ${{ env.CARTESI_MACHINE_VERSION }} + cartesi-machine-sha256-amd64: ${{ env.CARTESI_MACHINE_SHA256_AMD64 }} + cartesi-machine-sha256-arm64: ${{ env.CARTESI_MACHINE_SHA256_ARM64 }} - name: Download canonical app deps run: just -f examples/canonical-app/justfile download-deps @@ -159,95 +89,16 @@ jobs: - name: Checkout uses: actions/checkout@v5 - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y \ - lua5.4 \ - liblua5.4-dev \ - libslirp-dev \ - ca-certificates \ - wget \ - xz-utils - - - name: Install xgenext2fs - run: | - set -euo pipefail - ARCH="$(dpkg --print-architecture)" - VERSION="${XGENEXT2FS_VERSION}" - - case "${ARCH}" in - amd64) - ASSET_NAME="xgenext2fs_amd64.deb" - ;; - arm64) - ASSET_NAME="xgenext2fs_arm64.deb" - ;; - *) - echo "unsupported arch for xgenext2fs: ${ARCH}" >&2 - exit 1 - ;; - esac - - ASSET_URL="https://github.com/cartesi/genext2fs/releases/download/${VERSION}/${ASSET_NAME}" - wget -O /tmp/xgenext2fs.deb "${ASSET_URL}" - sha256sum /tmp/xgenext2fs.deb - sudo apt-get update - sudo apt-get install -y /tmp/xgenext2fs.deb - - - name: Install cartesi-machine (machine emulator CLI) - run: | - set -euo pipefail - ARCH="$(dpkg --print-architecture)" - VERSION="v0.20.0-test2" - - case "${ARCH}" in - amd64) - DEB_SHA256="39bbfc96a6cc6606307294b719df65f4f2725e8d200d062bcbd8c22355b99b56" - ;; - arm64) - DEB_SHA256="787d823756000cdecd72da8a3494b4c08613087379035959e561bbaef7a220ba" - ;; - *) - echo "unsupported arch for machine-emulator: ${ARCH}" >&2 - exit 1 - ;; - esac - - wget -O /tmp/machine-emulator.deb "https://github.com/cartesi/machine-emulator/releases/download/${VERSION}/machine-emulator_${ARCH}.deb" - echo "${DEB_SHA256} /tmp/machine-emulator.deb" | sha256sum --check - sudo apt-get update - sudo apt-get install -y /tmp/machine-emulator.deb - cartesi-machine --version - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt - - - name: Cache Rust artifacts - uses: Swatinem/rust-cache@v2 - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: v1.4.3 - - - name: Install just - uses: taiki-e/install-action@v2 - with: - tool: just - - - name: Install cross - uses: taiki-e/install-action@v2 + - name: Setup guest toolchain + uses: ./.github/actions/setup-guest-toolchain with: - tool: cross + xgenext2fs-version: ${{ env.XGENEXT2FS_VERSION }} + xgenext2fs-sha256-amd64: ${{ env.XGENEXT2FS_SHA256_AMD64 }} + xgenext2fs-sha256-arm64: ${{ env.XGENEXT2FS_SHA256_ARM64 }} + cartesi-machine-version: ${{ env.CARTESI_MACHINE_VERSION }} + cartesi-machine-sha256-amd64: ${{ env.CARTESI_MACHINE_SHA256_AMD64 }} + cartesi-machine-sha256-arm64: ${{ env.CARTESI_MACHINE_SHA256_ARM64 }} + install-foundry: "true" - name: Run rollups E2E tests run: just test-rollups-e2e diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3351270..a561bcf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,6 +21,11 @@ permissions: env: XGENEXT2FS_VERSION: v1.5.6 + XGENEXT2FS_SHA256_AMD64: 996e4e68a638b5dc5967d3410f92ecb8d2f41e32218bbe0f8b4c4474d7eebc59 + XGENEXT2FS_SHA256_ARM64: e5aca81164b762bbe5447bacef41e4fa9e357fd9c8f44e519c5206227d43144d + CARTESI_MACHINE_VERSION: v0.20.0-test2 + CARTESI_MACHINE_SHA256_AMD64: 39bbfc96a6cc6606307294b719df65f4f2725e8d200d062bcbd8c22355b99b56 + CARTESI_MACHINE_SHA256_ARM64: 787d823756000cdecd72da8a3494b4c08613087379035959e561bbaef7a220ba jobs: build-sequencer: @@ -85,15 +90,17 @@ jobs: Required environment variables: - `SEQ_ETH_RPC_URL` - - `SEQ_DOMAIN_CHAIN_ID` - - `SEQ_DOMAIN_VERIFYING_CONTRACT` + - `SEQ_CHAIN_ID` + - `SEQ_APP_ADDRESS` + - `SEQ_BATCH_SUBMITTER_PRIVATE_KEY` (or `SEQ_BATCH_SUBMITTER_PRIVATE_KEY_FILE`) Example: ```bash SEQ_ETH_RPC_URL=http://127.0.0.1:8545 \ - SEQ_DOMAIN_CHAIN_ID=31337 \ - SEQ_DOMAIN_VERIFYING_CONTRACT=0x1111111111111111111111111111111111111111 \ + SEQ_CHAIN_ID=31337 \ + SEQ_APP_ADDRESS=0x1111111111111111111111111111111111111111 \ + SEQ_BATCH_SUBMITTER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ ./sequencer ``` EOF @@ -113,85 +120,15 @@ jobs: - name: Checkout uses: actions/checkout@v5 - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y \ - ca-certificates \ - wget \ - xz-utils - - - name: Install xgenext2fs - run: | - set -euo pipefail - ARCH="$(dpkg --print-architecture)" - VERSION="${XGENEXT2FS_VERSION}" - - case "${ARCH}" in - amd64) - ASSET_NAME="xgenext2fs_amd64.deb" - ;; - arm64) - ASSET_NAME="xgenext2fs_arm64.deb" - ;; - *) - echo "unsupported arch for xgenext2fs: ${ARCH}" >&2 - exit 1 - ;; - esac - - ASSET_URL="https://github.com/cartesi/genext2fs/releases/download/${VERSION}/${ASSET_NAME}" - wget -O /tmp/xgenext2fs.deb "${ASSET_URL}" - sha256sum /tmp/xgenext2fs.deb - sudo apt-get update - sudo apt-get install -y /tmp/xgenext2fs.deb - - - name: Install cartesi-machine (machine emulator CLI) - run: | - set -euo pipefail - ARCH="$(dpkg --print-architecture)" - VERSION="v0.20.0-test2" - - case "${ARCH}" in - amd64) - DEB_SHA256="39bbfc96a6cc6606307294b719df65f4f2725e8d200d062bcbd8c22355b99b56" - ;; - arm64) - DEB_SHA256="787d823756000cdecd72da8a3494b4c08613087379035959e561bbaef7a220ba" - ;; - *) - echo "unsupported arch for machine-emulator: ${ARCH}" >&2 - exit 1 - ;; - esac - - wget -O /tmp/machine-emulator.deb "https://github.com/cartesi/machine-emulator/releases/download/${VERSION}/machine-emulator_${ARCH}.deb" - echo "${DEB_SHA256} /tmp/machine-emulator.deb" | sha256sum --check - sudo apt-get update - sudo apt-get install -y /tmp/machine-emulator.deb - cartesi-machine --version - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - - - name: Cache Rust artifacts - uses: Swatinem/rust-cache@v2 - - - name: Install just - uses: taiki-e/install-action@v2 + - name: Setup guest toolchain + uses: ./.github/actions/setup-guest-toolchain with: - tool: just - - - name: Install cross - uses: taiki-e/install-action@v2 - with: - tool: cross + xgenext2fs-version: ${{ env.XGENEXT2FS_VERSION }} + xgenext2fs-sha256-amd64: ${{ env.XGENEXT2FS_SHA256_AMD64 }} + xgenext2fs-sha256-arm64: ${{ env.XGENEXT2FS_SHA256_ARM64 }} + cartesi-machine-version: ${{ env.CARTESI_MACHINE_VERSION }} + cartesi-machine-sha256-amd64: ${{ env.CARTESI_MACHINE_SHA256_AMD64 }} + cartesi-machine-sha256-arm64: ${{ env.CARTESI_MACHINE_SHA256_ARM64 }} - name: Download canonical app deps run: just -f examples/canonical-app/justfile download-deps @@ -227,7 +164,7 @@ jobs: - build-canonical-machine-image steps: - name: Download build artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: path: dist diff --git a/justfile b/justfile index 3f5a351..e223c56 100644 --- a/justfile +++ b/justfile @@ -45,7 +45,7 @@ canonical-print-build-hashes: clean: cargo clean - rm -f sequencer.db sequencer.db-shm sequencer.db-wal + rm -rf sequencer-data just -f examples/canonical-app/justfile clean just -f tests/benchmarks/justfile clean @@ -66,6 +66,6 @@ ci: cargo fmt --all -- --check cargo test --workspace --all-targets --all-features --locked -run addr="127.0.0.1:3000" db="sequencer.db": - rm -f {{db}} {{db}}-shm {{db}}-wal - SEQ_HTTP_ADDR={{addr}} SEQ_DB_PATH={{db}} cargo run -p sequencer --release +run addr="127.0.0.1:3000" data_dir="sequencer-data": + rm -rf {{data_dir}} + SEQ_HTTP_ADDR={{addr}} SEQ_DATA_DIR={{data_dir}} cargo run -p sequencer --release diff --git a/sequencer/src/config.rs b/sequencer/src/config.rs index 05956b5..9ce5496 100644 --- a/sequencer/src/config.rs +++ b/sequencer/src/config.rs @@ -9,52 +9,42 @@ pub const DOMAIN_NAME: &str = "CartesiAppSequencer"; pub const DOMAIN_VERSION: &str = "1"; const DEFAULT_HTTP_ADDR: &str = "127.0.0.1:3000"; -const DEFAULT_DB_PATH: &str = "sequencer.db"; +const DEFAULT_DATA_DIR: &str = "sequencer-data"; +const DB_FILENAME: &str = "sequencer.db"; /// Shared L1 / InputBox configuration used by both the input reader and the batch submitter. /// /// Built once at startup from `RunConfig` plus the discovered InputBox address, so RPC URL, -/// InputBox address, and app (verifying contract) address are defined in a single place and -/// not duplicated across component configs. +/// InputBox address, and app address are defined in a single place and not duplicated across +/// component configs. #[derive(Debug, Clone)] pub struct L1Config { - /// L1 Ethereum RPC URL (e.g. for reading safe blocks and posting batch inputs). pub eth_rpc_url: String, - /// InputBox contract address (same contract for ingesting direct inputs and for submitting batches). pub input_box_address: Address, - /// Application / verifying contract address (used to discover InputBox and filter inputs). pub app_address: Address, - /// Hex-encoded private key used by the batch submitter for posting batches to L1. - /// - /// `RunConfig` is responsible for resolving whether this comes from an inline - /// value or a key file; by the time `L1Config` is constructed this is always - /// the fully resolved private key. pub batch_submitter_private_key: String, - /// EOA address of the batch submitter (derived from `batch_submitter_private_key`). - /// Inputs from this sender are batch submissions; all others are direct inputs. pub batch_submitter_address: Address, } #[derive(Debug, Clone, Parser)] #[command( name = "sequencer", - about = "Deterministic sequencer prototype with low-latency soft confirmations", + about = "Deterministic sequencer prototype with low-latency soft confirmations.\n\n\ + All options can also be set via environment variables (shown in brackets).", version, after_help = "\ Examples: sequencer \\ --eth-rpc-url http://127.0.0.1:8545 \\ - --domain-chain-id 31337 \\ - --domain-verifying-contract 0x1111111111111111111111111111111111111111 \\ - --batch-submitter-private-key 0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef - - sequencer \\ - --http-addr 0.0.0.0:3000 \\ - --db-path ./sequencer.db \\ - --eth-rpc-url https://eth.example \\ - --domain-chain-id 1 \\ - --domain-verifying-contract 0x4444444444444444444444444444444444444444 \\ - --batch-submitter-private-key 0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\ + --chain-id 31337 \\ + --app-address 0x1111111111111111111111111111111111111111 \\ + --batch-submitter-private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 + + SEQ_ETH_RPC_URL=http://127.0.0.1:8545 \\ + SEQ_CHAIN_ID=31337 \\ + SEQ_APP_ADDRESS=0x1111111111111111111111111111111111111111 \\ + SEQ_BATCH_SUBMITTER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \\ + sequencer\ ", group( ArgGroup::new("batch_submitter_key_source") @@ -66,34 +56,33 @@ Examples: pub struct RunConfig { #[arg(long, env = "SEQ_HTTP_ADDR", default_value = DEFAULT_HTTP_ADDR, value_parser = parse_non_empty_string)] pub http_addr: String, - #[arg(long, env = "SEQ_DB_PATH", default_value = DEFAULT_DB_PATH, value_parser = parse_non_empty_string)] - pub db_path: String, + #[arg(long, env = "SEQ_DATA_DIR", default_value = DEFAULT_DATA_DIR, value_parser = parse_non_empty_string)] + pub data_dir: String, #[arg(long, env = "SEQ_ETH_RPC_URL", value_parser = parse_non_empty_string)] pub eth_rpc_url: String, /// Error codes that trigger `get_logs` retries with a shorter block range. #[arg(long, env = "SEQ_LONG_BLOCK_RANGE_ERROR_CODES", value_delimiter = ',', default_values = crate::partition::DEFAULT_LONG_BLOCK_RANGE_ERROR_CODES)] pub long_block_range_error_codes: Vec, - #[arg(long, env = "SEQ_DOMAIN_CHAIN_ID")] - pub domain_chain_id: u64, - #[arg(long, env = "SEQ_DOMAIN_VERIFYING_CONTRACT", value_parser = parse_address)] - pub domain_verifying_contract: Address, - /// Hex-encoded private key used by the batch submitter for posting batches to L1. - /// Exactly one of this or `batch_submitter_private_key_file` must be set when a signer - /// is desired. + /// Expected chain ID. Validated against the RPC at startup. + #[arg(long, env = "SEQ_CHAIN_ID")] + pub chain_id: u64, + /// Application (EIP-712 verifying contract) address. + #[arg(long, env = "SEQ_APP_ADDRESS", value_parser = parse_address)] + pub app_address: Address, + /// Hex-encoded private key for the batch submitter. #[arg( long, env = "SEQ_BATCH_SUBMITTER_PRIVATE_KEY", group = "batch_submitter_key_source" )] - pub batch_submitter_private_key: Option, - /// Path to a file whose first line contains the batch submitter private key. Takes - /// precedence over `batch_submitter_private_key` if both are set (checked by clap group). + batch_submitter_private_key: Option, + /// Path to a file whose first line contains the batch submitter private key. #[arg( long, env = "SEQ_BATCH_SUBMITTER_PRIVATE_KEY_FILE", group = "batch_submitter_key_source" )] - pub batch_submitter_private_key_file: Option, + batch_submitter_private_key_file: Option, /// How often the batch submitter polls for new work when idle. #[arg( @@ -104,7 +93,6 @@ pub struct RunConfig { pub batch_submitter_idle_poll_interval_ms: u64, /// Number of blocks behind Latest that the batch submitter treats as confirmed. - /// The submitter scans only up to `Latest - depth`, and waits for the same depth after posting. #[arg( long, env = "SEQ_BATCH_SUBMITTER_CONFIRMATION_DEPTH", @@ -118,11 +106,32 @@ impl RunConfig { Eip712Domain { name: Some(DOMAIN_NAME.into()), version: Some(DOMAIN_VERSION.into()), - chain_id: Some(U256::from(self.domain_chain_id)), - verifying_contract: Some(self.domain_verifying_contract), + chain_id: Some(U256::from(self.chain_id)), + verifying_contract: Some(self.app_address), salt: None, } } + + /// Full path to the SQLite database file inside `data_dir`. + pub fn db_path(&self) -> String { + std::path::Path::new(&self.data_dir) + .join(DB_FILENAME) + .to_string_lossy() + .into_owned() + } + + /// Resolve the batch submitter private key from either the inline value or a key file. + pub fn resolve_private_key(&self) -> Result { + if let Some(file) = &self.batch_submitter_private_key_file { + let contents = std::fs::read_to_string(file)?; + Ok(contents.lines().next().unwrap_or("").trim().to_string()) + } else { + Ok(self + .batch_submitter_private_key + .clone() + .expect("batch submitter private key is required by CLI arg group")) + } + } } fn parse_non_empty_string(raw: &str) -> Result { @@ -135,13 +144,13 @@ fn parse_non_empty_string(raw: &str) -> Result { fn parse_address(raw: &str) -> Result { if !raw.starts_with("0x") { - return Err("verifying contract must be 0x-prefixed".to_string()); + return Err("address must be 0x-prefixed".to_string()); } let bytes = alloy_primitives::hex::decode(raw) - .map_err(|err| format!("invalid verifying contract hex: {err}"))?; + .map_err(|err| format!("invalid address hex: {err}"))?; if bytes.len() != 20 { - return Err("verifying contract must be 20 bytes".to_string()); + return Err("address must be 20 bytes".to_string()); } Ok(Address::from_slice(&bytes)) } @@ -152,35 +161,36 @@ mod tests { use alloy_primitives::{Address, U256}; use clap::Parser; + const TEST_ARGS: [&str; 9] = [ + "sequencer", + "--eth-rpc-url", + "http://127.0.0.1:8545", + "--chain-id", + "31337", + "--app-address", + "0x1111111111111111111111111111111111111111", + "--batch-submitter-private-key", + "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + ]; + #[test] - fn run_config_requires_deployment_domain_inputs() { + fn run_config_requires_essential_inputs() { let err = RunConfig::try_parse_from([ "sequencer", "--batch-submitter-private-key", "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", ]) - .expect_err("domain inputs are required"); + .expect_err("essential inputs are required"); let message = err.to_string(); assert!(message.contains("--eth-rpc-url")); - assert!(message.contains("--domain-chain-id")); - assert!(message.contains("--domain-verifying-contract")); + assert!(message.contains("--chain-id")); + assert!(message.contains("--app-address")); } #[test] fn run_config_uses_default_block_range_retry_codes() { - let config = RunConfig::try_parse_from([ - "sequencer", - "--eth-rpc-url", - "http://127.0.0.1:8545", - "--domain-chain-id", - "31337", - "--domain-verifying-contract", - "0x1111111111111111111111111111111111111111", - "--batch-submitter-private-key", - "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", - ]) - .expect("parse run config"); + let config = RunConfig::try_parse_from(TEST_ARGS).expect("parse run config"); assert_eq!( config.long_block_range_error_codes, @@ -195,18 +205,7 @@ mod tests { #[test] fn run_config_builds_domain_with_fixed_name_and_version() { - let config = RunConfig::try_parse_from([ - "sequencer", - "--eth-rpc-url", - "http://127.0.0.1:8545", - "--domain-chain-id", - "31337", - "--domain-verifying-contract", - "0x1111111111111111111111111111111111111111", - "--batch-submitter-private-key", - "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", - ]) - .expect("parse run config"); + let config = RunConfig::try_parse_from(TEST_ARGS).expect("parse run config"); let domain = config.build_domain(); assert_eq!(domain.name.as_deref(), Some(DOMAIN_NAME)); diff --git a/sequencer/src/runtime.rs b/sequencer/src/runtime.rs index 4294aef..75c8aff 100644 --- a/sequencer/src/runtime.rs +++ b/sequencer/src/runtime.rs @@ -85,18 +85,12 @@ where let domain = config.build_domain(); let shutdown = ShutdownSignal::default(); + // Ensure the data directory exists before any component tries to open the DB. + std::fs::create_dir_all(&config.data_dir)?; + let db_path = config.db_path(); + // Single L1/InputBox config shared by input reader and batch submitter (no duplicate RPC URL or addresses). - // Resolve batch-submitter private key (exactly one of inline or file is required at the CLI layer). - let batch_submitter_private_key = if let Some(file) = &config.batch_submitter_private_key_file { - let contents = - std::fs::read_to_string(file).map_err(|e| RunError::Io(std::io::Error::other(e)))?; - contents.lines().next().unwrap_or("").trim().to_string() - } else { - config - .batch_submitter_private_key - .clone() - .expect("batch submitter private key is required by CLI arg group") - }; + let batch_submitter_private_key = config.resolve_private_key()?; let batch_submitter_address = { use alloy::signers::local::PrivateKeySigner; @@ -106,11 +100,11 @@ where .address() }; let mut input_reader = InputReader::new( - config.db_path.clone(), + db_path.clone(), shutdown.clone(), InputReaderConfig { rpc_url: config.eth_rpc_url.clone(), - app_address: config.domain_verifying_contract, + app_address: config.app_address, poll_interval: INPUT_READER_POLL_INTERVAL, long_block_range_error_codes: config.long_block_range_error_codes.clone(), }, @@ -121,7 +115,7 @@ where let l1_config = L1Config { eth_rpc_url: config.eth_rpc_url.clone(), input_box_address: input_reader.input_box_address(), - app_address: config.domain_verifying_contract, + app_address: config.app_address, batch_submitter_private_key, batch_submitter_address, }; @@ -132,16 +126,16 @@ where tracing::info!( http_addr = %config.http_addr, - db_path = %config.db_path, + data_dir = %config.data_dir, eth_rpc_url = %l1_config.eth_rpc_url, input_box_address = %l1_config.input_box_address, input_reader_genesis_block, - domain_chain_id = config.domain_chain_id, - domain_verifying_contract = %l1_config.app_address, + chain_id = config.chain_id, + app_address = %l1_config.app_address, "starting sequencer" ); - let storage = storage::Storage::open(&config.db_path, SQLITE_SYNCHRONOUS_PRAGMA)?; + let storage = storage::Storage::open(&db_path, SQLITE_SYNCHRONOUS_PRAGMA)?; let (tx, mut inclusion_lane_handle) = InclusionLane::start( QUEUE_CAPACITY, shutdown.clone(), @@ -164,9 +158,20 @@ where long_block_range_error_codes: config.long_block_range_error_codes, }; let provider = build_batch_submitter_provider(&l1_config).await?; + + // Validate that the RPC chain ID matches --chain-id. + use alloy::providers::Provider; + let rpc_chain_id = provider.get_chain_id().await + .map_err(|e| std::io::Error::other(format!("failed to query RPC chain ID: {e}")))?; + assert_eq!( + rpc_chain_id, config.chain_id, + "RPC chain ID {rpc_chain_id} does not match --chain-id {}", + config.chain_id + ); + let poster = std::sync::Arc::new(EthereumBatchPoster::new(provider, poster_config)); let submitter = BatchSubmitter::new( - config.db_path.clone(), + db_path.clone(), l1_config.batch_submitter_address, poster, shutdown.clone(), @@ -175,7 +180,7 @@ where let mut batch_submitter_handle = submitter.start().map_err(RunError::OpenStorage)?; let tx_feed = L2TxFeed::new( - config.db_path.clone(), + db_path.clone(), shutdown.clone(), L2TxFeedConfig { batch_submitter_address: Some(l1_config.batch_submitter_address), diff --git a/tests/harness/src/sequencer.rs b/tests/harness/src/sequencer.rs index 54c6c64..6041db2 100644 --- a/tests/harness/src/sequencer.rs +++ b/tests/harness/src/sequencer.rs @@ -41,7 +41,7 @@ pub struct ManagedSequencer { sequencer_bin: PathBuf, log_prefix: String, logs_dir: PathBuf, - db_path: PathBuf, + data_dir: PathBuf, endpoint: String, log_path: PathBuf, } @@ -61,6 +61,16 @@ pub fn teardown_sqlite_artifacts(logs_dir: &Path) -> HarnessResult<()> { for entry in fs::read_dir(logs_dir)? { let entry = entry?; + let path = entry.path(); + // Remove sequencer data directories (contain sequencer.db). + if path.is_dir() && path.join("sequencer.db").exists() { + match fs::remove_dir_all(&path) { + Ok(()) => {} + Err(err) if err.kind() == io::ErrorKind::NotFound => {} + Err(err) => return Err(err.into()), + } + continue; + } let file_name = entry.file_name(); let Some(file_name) = file_name.to_str() else { continue; @@ -68,7 +78,7 @@ pub fn teardown_sqlite_artifacts(logs_dir: &Path) -> HarnessResult<()> { if !matches_sqlite_artifact(file_name) { continue; } - match fs::remove_file(entry.path()) { + match fs::remove_file(&path) { Ok(()) => {} Err(err) if err.kind() == io::ErrorKind::NotFound => {} Err(err) => return Err(err.into()), @@ -86,8 +96,7 @@ impl ManagedSequencer { let rollups = DevnetRollupsStack::spawn(log_prefix.as_str(), logs_dir.as_path()).await?; fs::create_dir_all(logs_dir.as_path())?; - let db_path = timestamped_log_path(logs_dir.as_path(), &format!("{log_prefix}-db")) - .with_extension("sqlite"); + let data_dir = timestamped_log_path(logs_dir.as_path(), &format!("{log_prefix}-data")); let SpawnedSequencerProcess { child, endpoint, @@ -96,7 +105,7 @@ impl ManagedSequencer { sequencer_bin.as_path(), log_prefix.as_str(), logs_dir.as_path(), - db_path.as_path(), + data_dir.as_path(), &rollups, ) .await?; @@ -108,7 +117,7 @@ impl ManagedSequencer { sequencer_bin, log_prefix, logs_dir, - db_path, + data_dir, endpoint, log_path, }) @@ -126,8 +135,8 @@ impl ManagedSequencer { self.log_path.as_path() } - pub fn db_path(&self) -> &Path { - self.db_path.as_path() + pub fn data_dir(&self) -> &Path { + self.data_dir.as_path() } pub fn domain_chain_id(&self) -> u64 { @@ -172,7 +181,7 @@ impl ManagedSequencer { self.sequencer_bin.as_path(), self.log_prefix.as_str(), self.logs_dir.as_path(), - self.db_path.as_path(), + self.data_dir.as_path(), &self.rollups, ) .await?; @@ -247,7 +256,7 @@ async fn spawn_sequencer_process( sequencer_bin: &Path, log_prefix: &str, logs_dir: &Path, - db_path: &Path, + data_dir: &Path, rollups: &DevnetRollupsStack, ) -> HarnessResult { let (endpoint, http_addr) = build_local_endpoint()?; @@ -265,13 +274,13 @@ async fn spawn_sequencer_process( let mut child = Command::new(path_as_str(sequencer_bin)?) .arg("--http-addr") .arg(http_addr) - .arg("--db-path") - .arg(path_as_str(db_path)?) + .arg("--data-dir") + .arg(path_as_str(data_dir)?) .arg("--eth-rpc-url") .arg(rollups.l1_endpoint()) - .arg("--domain-chain-id") + .arg("--chain-id") .arg(DEVNET_CHAIN_ID.to_string()) - .arg("--domain-verifying-contract") + .arg("--app-address") .arg(rollups.app_address().to_string()) .arg("--batch-submitter-private-key") .arg(&batch_submitter_key) From 553aee7afa06dd2479b85f8426679ca13ddfdab6 Mon Sep 17 00:00:00 2001 From: Gabriel Coutinho de Paula Date: Tue, 24 Mar 2026 21:28:48 -0300 Subject: [PATCH 4/5] refactor: move sequenced user op insertion inside sqlite --- sequencer/src/config.rs | 4 +-- sequencer/src/runtime.rs | 4 ++- sequencer/src/storage/db.rs | 17 +++++---- .../src/storage/migrations/0001_schema.sql | 8 +++++ .../queries/insert_sequenced_user_op.sql | 6 ---- sequencer/src/storage/sql.rs | 35 +++++++++---------- 6 files changed, 40 insertions(+), 34 deletions(-) delete mode 100644 sequencer/src/storage/queries/insert_sequenced_user_op.sql diff --git a/sequencer/src/config.rs b/sequencer/src/config.rs index 9ce5496..1e4e1ad 100644 --- a/sequencer/src/config.rs +++ b/sequencer/src/config.rs @@ -147,8 +147,8 @@ fn parse_address(raw: &str) -> Result { return Err("address must be 0x-prefixed".to_string()); } - let bytes = alloy_primitives::hex::decode(raw) - .map_err(|err| format!("invalid address hex: {err}"))?; + let bytes = + alloy_primitives::hex::decode(raw).map_err(|err| format!("invalid address hex: {err}"))?; if bytes.len() != 20 { return Err("address must be 20 bytes".to_string()); } diff --git a/sequencer/src/runtime.rs b/sequencer/src/runtime.rs index 75c8aff..f9b4492 100644 --- a/sequencer/src/runtime.rs +++ b/sequencer/src/runtime.rs @@ -161,7 +161,9 @@ where // Validate that the RPC chain ID matches --chain-id. use alloy::providers::Provider; - let rpc_chain_id = provider.get_chain_id().await + let rpc_chain_id = provider + .get_chain_id() + .await .map_err(|e| std::io::Error::other(format!("failed to query RPC chain ID: {e}")))?; assert_eq!( rpc_chain_id, config.chain_id, diff --git a/sequencer/src/storage/db.rs b/sequencer/src/storage/db.rs index 082f963..321bf65 100644 --- a/sequencer/src/storage/db.rs +++ b/sequencer/src/storage/db.rs @@ -8,7 +8,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH}; use super::sql::{ sql_count_user_ops_for_frame, sql_insert_open_batch, sql_insert_open_batch_with_index, sql_insert_open_frame, sql_insert_safe_inputs_batch, - sql_insert_sequenced_direct_inputs_for_frame, sql_insert_user_ops_and_sequenced_batch, + sql_insert_sequenced_direct_inputs_for_frame, sql_insert_user_ops_batch, sql_select_batch_policy, sql_select_frames_for_batch, sql_select_latest_batch_index, sql_select_latest_batch_with_user_op_count, sql_select_latest_frame_in_batch_for_batch, sql_select_max_safe_input_index, sql_select_ordered_l2_tx_count, @@ -275,8 +275,7 @@ impl Storage { } pub fn set_gas_price(&mut self, gas_price: u64) -> Result<()> { - let changed_rows = - sql_update_batch_policy_gas_price(&self.conn, u64_to_i64(gas_price))?; + let changed_rows = sql_update_batch_policy_gas_price(&self.conn, u64_to_i64(gas_price))?; if changed_rows != 1 { return Err(rusqlite::Error::StatementChangedRows(changed_rows)); } @@ -308,7 +307,7 @@ impl Storage { // observe the same database snapshot. assert_write_head_matches_open_state(&tx, head)?; - sql_insert_user_ops_and_sequenced_batch( + sql_insert_user_ops_batch( &tx, u64_to_i64(head.batch_index), i64::from(head.frame_in_batch), @@ -798,9 +797,15 @@ mod tests { .expect("rotate batch"); let policy = storage.batch_policy().expect("read policy"); - assert!(head.frame_fee > 0, "frame fee should be derived from gas_price"); + assert!( + head.frame_fee > 0, + "frame fee should be derived from gas_price" + ); assert_eq!(head.frame_fee, policy.recommended_fee); - assert!(head.max_batch_user_op_bytes > 0, "batch size target should be set"); + assert!( + head.max_batch_user_op_bytes > 0, + "batch size target should be set" + ); } #[test] diff --git a/sequencer/src/storage/migrations/0001_schema.sql b/sequencer/src/storage/migrations/0001_schema.sql index 1a8fbdc..2b2cdc3 100644 --- a/sequencer/src/storage/migrations/0001_schema.sql +++ b/sequencer/src/storage/migrations/0001_schema.sql @@ -29,6 +29,14 @@ CREATE TABLE IF NOT EXISTS user_ops ( UNIQUE(sender, nonce) ); +-- Automatically sequence every user-op into the global replay order on insert. +CREATE TRIGGER IF NOT EXISTS trg_sequence_user_op AFTER INSERT ON user_ops +BEGIN + INSERT INTO sequenced_l2_txs ( + batch_index, frame_in_batch, user_op_pos_in_frame, safe_input_index + ) VALUES (NEW.batch_index, NEW.frame_in_batch, NEW.pos_in_frame, NULL); +END; + CREATE TABLE IF NOT EXISTS safe_inputs ( safe_input_index INTEGER PRIMARY KEY, sender BLOB NOT NULL CHECK (length(sender) = 20), diff --git a/sequencer/src/storage/queries/insert_sequenced_user_op.sql b/sequencer/src/storage/queries/insert_sequenced_user_op.sql deleted file mode 100644 index 1f9e485..0000000 --- a/sequencer/src/storage/queries/insert_sequenced_user_op.sql +++ /dev/null @@ -1,6 +0,0 @@ -INSERT INTO sequenced_l2_txs ( - batch_index, - frame_in_batch, - user_op_pos_in_frame, - safe_input_index -) VALUES (?1, ?2, ?3, NULL) diff --git a/sequencer/src/storage/sql.rs b/sequencer/src/storage/sql.rs index 15d518e..1775b8a 100644 --- a/sequencer/src/storage/sql.rs +++ b/sequencer/src/storage/sql.rs @@ -26,13 +26,11 @@ const SQL_SELECT_LATEST_BATCH_INDEX: &str = "SELECT MAX(batch_index) FROM batche const SQL_SELECT_USER_OPS_FOR_FRAME: &str = "SELECT nonce, max_fee, data, sig FROM user_ops WHERE batch_index = ?1 AND frame_in_batch = ?2 ORDER BY pos_in_frame ASC"; const SQL_SELECT_MAX_SAFE_INPUT_INDEX: &str = "SELECT MAX(safe_input_index) FROM safe_inputs"; const SQL_SELECT_ORDERED_L2_TX_COUNT: &str = "SELECT COUNT(*) FROM sequenced_l2_txs"; -const SQL_SELECT_BATCH_POLICY: &str = - "SELECT recommended_fee, batch_size_target FROM batch_policy_derived WHERE singleton_id = 0 LIMIT 1"; +const SQL_SELECT_BATCH_POLICY: &str = "SELECT recommended_fee, batch_size_target FROM batch_policy_derived WHERE singleton_id = 0 LIMIT 1"; const SQL_SELECT_SAFE_BLOCK: &str = "SELECT block_number FROM l1_safe_head WHERE singleton_id = 0 LIMIT 1"; const SQL_INSERT_SAFE_INPUT: &str = "INSERT INTO safe_inputs (safe_input_index, sender, payload, block_number) VALUES (?1, ?2, ?3, ?4)"; const SQL_INSERT_USER_OP: &str = include_str!("queries/insert_user_op.sql"); -const SQL_INSERT_SEQUENCED_USER_OP: &str = include_str!("queries/insert_sequenced_user_op.sql"); const SQL_INSERT_SEQUENCED_DIRECT_INPUT: &str = include_str!("queries/insert_sequenced_direct_input.sql"); const SQL_UPDATE_BATCH_POLICY_GAS_PRICE: &str = @@ -113,7 +111,10 @@ pub(super) fn sql_update_batch_policy_alpha( alpha_num: i64, alpha_denom: i64, ) -> Result { - conn.execute(SQL_UPDATE_BATCH_POLICY_ALPHA, params![alpha_num, alpha_denom]) + conn.execute( + SQL_UPDATE_BATCH_POLICY_ALPHA, + params![alpha_num, alpha_denom], + ) } pub(super) fn sql_select_safe_block(conn: &Connection) -> Result { @@ -190,7 +191,10 @@ pub(super) fn sql_insert_safe_inputs_batch( Ok(()) } -pub(super) fn sql_insert_user_ops_and_sequenced_batch( +/// Insert user-ops into the `user_ops` table. +/// The `trg_sequence_user_op` trigger automatically appends a corresponding row +/// to `sequenced_l2_txs` for each inserted user-op. +pub(super) fn sql_insert_user_ops_batch( tx: &Transaction<'_>, batch_index: i64, frame_in_batch: i64, @@ -201,12 +205,11 @@ pub(super) fn sql_insert_user_ops_and_sequenced_batch( return Ok(()); } - let mut user_ops_stmt = tx.prepare_cached(SQL_INSERT_USER_OP)?; - let mut sequenced_stmt = tx.prepare_cached(SQL_INSERT_SEQUENCED_USER_OP)?; + let mut stmt = tx.prepare_cached(SQL_INSERT_USER_OP)?; for (offset, item) in user_ops.iter().enumerate() { let pos_in_frame = frame_pos_start.saturating_add(offset as u32); let sig = item.signed.signature.as_bytes(); - user_ops_stmt.execute(params![ + stmt.execute(params![ batch_index, frame_in_batch, i64::from(pos_in_frame), @@ -217,11 +220,6 @@ pub(super) fn sql_insert_user_ops_and_sequenced_batch( &sig[..], to_unix_ms(item.received_at), ])?; - sequenced_stmt.execute(params![ - batch_index, - frame_in_batch, - i64::from(pos_in_frame), - ])?; } Ok(()) } @@ -411,9 +409,9 @@ fn u64_to_i64(value: u64) -> i64 { mod tests { use super::{ FrameHeaderRow, SQL_INSERT_SAFE_INPUT, SQL_INSERT_SEQUENCED_DIRECT_INPUT, - SQL_INSERT_SEQUENCED_USER_OP, SQL_INSERT_USER_OP, sql_insert_open_batch, - sql_insert_open_batch_with_index, sql_insert_open_frame, sql_insert_safe_inputs_batch, - sql_insert_sequenced_direct_inputs_for_frame, sql_insert_user_ops_and_sequenced_batch, + SQL_INSERT_USER_OP, sql_insert_open_batch, sql_insert_open_batch_with_index, + sql_insert_open_frame, sql_insert_safe_inputs_batch, + sql_insert_sequenced_direct_inputs_for_frame, sql_insert_user_ops_batch, sql_select_batch_policy, sql_select_frames_for_batch, sql_select_latest_batch_index, sql_select_latest_batch_with_user_op_count, sql_select_max_safe_input_index, sql_select_ordered_l2_tx_count, sql_select_ordered_l2_txs_from_offset, @@ -561,13 +559,12 @@ mod tests { ], ) .expect("insert user op"); + // The trg_sequence_user_op trigger automatically inserts the sequenced row. conn.execute( SQL_INSERT_SAFE_INPUT, params![0_i64, vec![0x11_u8; 20], vec![0xaa_u8], 10_i64], ) .expect("insert direct input"); - conn.execute(SQL_INSERT_SEQUENCED_USER_OP, params![0_i64, 0_i64, 0_i64]) - .expect("insert sequenced user op"); conn.execute( SQL_INSERT_SEQUENCED_DIRECT_INPUT, params![0_i64, 0_i64, 0_i64], @@ -758,7 +755,7 @@ mod tests { sample_pending_user_op(0x20, 0, 1), sample_pending_user_op(0x21, 1, 1), ]; - sql_insert_user_ops_and_sequenced_batch(&tx, 0, 0, 0, user_ops.as_slice()) + sql_insert_user_ops_batch(&tx, 0, 0, 0, user_ops.as_slice()) .expect("insert user ops + sequenced batch"); sql_insert_sequenced_direct_inputs_for_frame( From 725d6f92e0ee1c7a3c6b8816152c798cb61c8755 Mon Sep 17 00:00:00 2001 From: Stephen Chen <20940639+stephenctw@users.noreply.github.com> Date: Wed, 25 Mar 2026 10:45:39 +0800 Subject: [PATCH 5/5] doc: update docs --- AGENTS.md | 18 +++++++++++------- README.md | 28 ++++++++++++++++++---------- TODO.md | 2 +- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index cd9d785..2550874 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -57,11 +57,11 @@ Primary objective in this phase: make sequencer behavior, safety checks, and per - Rejections (`InvalidNonce`, fee cap too low, insufficient gas balance) produce no state mutation and are not persisted. - Included txs are persisted as frame/batch data in `batches`, `frames`, `user_ops`, `direct_inputs`, and `sequenced_l2_txs`. - Frame fee is persisted in `frames.fee` and is fixed for the lifetime of that frame. -- The next frame fee is sampled from `recommended_fees` when rotating to a new frame (default bootstrap value is `0`). +- The next frame fee is sampled from `batch_policy_derived.recommended_fee` when rotating to a new frame (defaults follow `batch_policy` bootstrap rows; tune `gas_price` / `alpha` via SQLite if needed). - `/ws/subscribe` currently has internal guardrails: subscriber cap `64`, catch-up cap `50000`. - When that catch-up window is exceeded, `/ws/subscribe` upgrades and then closes with websocket close code `1008` (`POLICY`) and reason `catch-up window exceeded`. - Wallet state (balances/nonces) is in-memory right now (not persisted). -- EIP-712 domain name/version are fixed in code; chain ID and verifying contract are deployment-specific inputs. +- EIP-712 domain name/version are fixed in code; chain ID and verifying contract come from `SEQ_CHAIN_ID` and `SEQ_APP_ADDRESS` (validated against the RPC chain id at startup). ## Hot-Path Invariants @@ -113,20 +113,24 @@ Run server: ```bash SEQ_ETH_RPC_URL=http://127.0.0.1:8545 \ -SEQ_DOMAIN_CHAIN_ID=31337 \ -SEQ_DOMAIN_VERIFYING_CONTRACT=0x1111111111111111111111111111111111111111 \ +SEQ_CHAIN_ID=31337 \ +SEQ_APP_ADDRESS=0x1111111111111111111111111111111111111111 \ +SEQ_BATCH_SUBMITTER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ cargo run -p sequencer ``` Optional env vars: - `SEQ_HTTP_ADDR` -- `SEQ_DB_PATH` +- `SEQ_DATA_DIR` (default `sequencer-data`; DB file `sequencer.db` inside it) - `SEQ_LONG_BLOCK_RANGE_ERROR_CODES` +- `SEQ_BATCH_SUBMITTER_PRIVATE_KEY_FILE` (alternative to `SEQ_BATCH_SUBMITTER_PRIVATE_KEY`) +- `SEQ_BATCH_SUBMITTER_IDLE_POLL_INTERVAL_MS`, `SEQ_BATCH_SUBMITTER_CONFIRMATION_DEPTH` Required env vars: - `SEQ_ETH_RPC_URL` -- `SEQ_DOMAIN_CHAIN_ID` -- `SEQ_DOMAIN_VERIFYING_CONTRACT` +- `SEQ_CHAIN_ID` +- `SEQ_APP_ADDRESS` +- `SEQ_BATCH_SUBMITTER_PRIVATE_KEY` or `SEQ_BATCH_SUBMITTER_PRIVATE_KEY_FILE` ## Always / Ask First / Never diff --git a/README.md b/README.md index 4152050..f59779c 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,8 @@ Current focus is reliability of sequencing, persistence, and replay semantics. - users sign `max_fee` - inclusion validates `max_fee >= current_frame_fee` - execution charges `current_frame_fee` - - the next frame fee is sampled from `recommended_fees` when rotating to a new frame + - when opening a new frame or batch, the sequencer samples **`recommended_fee`** from the `batch_policy_derived` SQLite view (derived from `gas_price`, amortization `alpha`, and on-chain DA constants in `batch_policy`) +- **Batch closure by size** uses **`batch_size_target`** from the same view (stored on `WriteHead` as `max_batch_user_op_bytes`). The inclusion lane compares it to a **worst-case estimate** of in-batch user-op bytes (`batch_user_op_count × (per-op metadata cap + max method payload)`), not the exact SSZ-encoded batch size. A **time-based** max open duration also closes batches. ## Quick Start @@ -36,31 +37,38 @@ cargo fmt --all cargo clippy --all-targets --all-features -- -D warnings ``` -Run the server with a local deployment domain: +Run the server (example uses Anvil account #0 as batch submitter; use your own key in production): ```bash SEQ_ETH_RPC_URL=http://127.0.0.1:8545 \ -SEQ_DOMAIN_CHAIN_ID=31337 \ -SEQ_DOMAIN_VERIFYING_CONTRACT=0x1111111111111111111111111111111111111111 \ +SEQ_CHAIN_ID=31337 \ +SEQ_APP_ADDRESS=0x1111111111111111111111111111111111111111 \ +SEQ_BATCH_SUBMITTER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ cargo run -p sequencer ``` +At startup the process checks that the RPC `eth_chainId` matches `SEQ_CHAIN_ID`. + Optional runtime inputs: - `SEQ_HTTP_ADDR` defaults to `127.0.0.1:3000` -- `SEQ_DB_PATH` defaults to `sequencer.db` +- `SEQ_DATA_DIR` defaults to `sequencer-data` (SQLite file is `sequencer.db` inside that directory; the directory is created if missing) - `SEQ_LONG_BLOCK_RANGE_ERROR_CODES` defaults to `-32005,-32600,-32602,-32616` +- `SEQ_BATCH_SUBMITTER_PRIVATE_KEY_FILE` instead of `SEQ_BATCH_SUBMITTER_PRIVATE_KEY` (first line of the file is the key) +- `SEQ_BATCH_SUBMITTER_IDLE_POLL_INTERVAL_MS`, `SEQ_BATCH_SUBMITTER_CONFIRMATION_DEPTH` Required runtime inputs: - `SEQ_ETH_RPC_URL` -- `SEQ_DOMAIN_CHAIN_ID` -- `SEQ_DOMAIN_VERIFYING_CONTRACT` +- `SEQ_CHAIN_ID` +- `SEQ_APP_ADDRESS` +- `SEQ_BATCH_SUBMITTER_PRIVATE_KEY` or `SEQ_BATCH_SUBMITTER_PRIVATE_KEY_FILE` -Fixed protocol identity: +Fixed protocol identity (EIP-712): - domain name: `CartesiAppSequencer` - domain version: `1` +- `chain_id` and `verifying_contract` come from `SEQ_CHAIN_ID` and `SEQ_APP_ADDRESS` Most queue sizes, polling intervals, and safety limits are now internal runtime constants instead of public launch-time configuration. @@ -129,9 +137,9 @@ Success response: - `frames`: frame boundaries within each batch - `frames.fee`: committed fee for each frame - `user_ops`: included user operations +- `sequenced_l2_txs`: append-only ordered replay rows (`UserOp` xor `DirectInput`); inserting into `user_ops` also appends the corresponding replay row via trigger `trg_sequence_user_op` - `direct_inputs`: direct-input payload stream -- `sequenced_l2_txs`: append-only ordered replay rows (`UserOp` xor `DirectInput`) -- `recommended_fees`: singleton mutable recommendation for the next frame fee +- `batch_policy`: singleton knobs and constants for DA-style batch sizing and fee derivation; `batch_policy_derived` view exposes `recommended_fee` and `batch_size_target` ## Project Layout diff --git a/TODO.md b/TODO.md index 4df6b3f..4255ec4 100644 --- a/TODO.md +++ b/TODO.md @@ -33,7 +33,7 @@ Build a robust sequencer prototype for a future DeFi stack, with deterministic o - Implement direct-input reader from blockchain (ingests into `direct_inputs`). - Implement batch submitter (reads closed batches and submits on-chain). -- Implement inclusion fee estimator module that updates the suggested fee in DB (`recommended_fees`). +- Implement inclusion fee estimator module that updates the suggested fee in DB (`batch_policy`, e.g. `gas_price` or related knobs). - Add paginated historical `L2Tx` sync endpoint so lagging readers can backfill over HTTP before switching to `/ws/subscribe` for live updates. - Keep storage/replay semantics deterministic and catch-up-safe as direct-input ingestion, batch submission, and recovery flows land.