Skip to content

Releases: wmendes/caravel

Caravel v0.4.3

Choose a tag to compare

@github-actions github-actions released this 06 Oct 22:28
3fea52f

Testnet only, not audited. Install: curl -fsSL https://raw.githubusercontent.com/wmendes/caravel/v0.4.3/scripts/install.sh | bash

Signed releases, and GHOSTSIG on testnet. Caravel Perps on testnet runs it.

What changed

Releases are signed. This finishes the follow-up the #145 audit asked for: one signed manifest covering the archives, IMAGES, the commit and the platforms.

  • The release workflow attests every file in SHA256SUMS, through GitHub artifact attestations and Sigstore. That covers each platform's archive and IMAGES, and through IMAGES' digests, the container images. The attestation names this repository, its release workflow, the tag and the commit. No key is kept anywhere.
  • The bundle is caravel.sigstore.json, attached to the release.
  • When the GitHub CLI is installed, the installer checks the archive and IMAGES against it, and stops if anything doesn't match. No GitHub login is needed.
  • Without gh, the checksums still hold, and the installer says how to check. CARAVEL_REQUIRE_SIGNATURE=1 turns a missing check into an error.

To check a download yourself:

gh attestation verify caravel-0.4.3-x86_64-linux.tar.gz --repo wmendes/caravel \
  --signer-workflow wmendes/caravel/.github/workflows/release.yml --source-ref refs/tags/v0.4.3

GHOSTSIG connects on testnet.

  • Stellar Wallets Kit's GHOSTSIG module starts on Stellar's public network unless it is given a network, and the kit's default list gives it none.
  • So connecting asked GHOSTSIG for an account on the public network, and the trading app refused it.
  • The app now gives GHOSTSIG the lane's network.

Upgrading

  • Nodes: apply the release as usual. Nothing in the nodes, formats or contracts changed.
  • Installing 0.4.2 or earlier with this installer works as before: they have no signature to check, unless CARAVEL_REQUIRE_SIGNATURE=1 is set.

Caravel v0.4.2

Choose a tag to compare

@github-actions github-actions released this 06 Oct 21:21
a6a7c6d

Testnet only, not audited. Install: curl -fsSL https://raw.githubusercontent.com/wmendes/caravel/v0.4.2/scripts/install.sh | bash

Fixes from a security review. An AI agent's defensive source audit of 0.4.1 (#145) reported eight problems. We checked each one against the code, and all eight hold, so this release fixes all of them. Every fix comes with a test that fails on 0.4.1. Caravel Perps on testnet runs it.

This is not a professional audit, and Caravel stays testnet-only.

What changed

An escape claim always pays what it should (S-01, high).

  • The payout is equity × payout_num / payout_den. The settlement contract multiplied before dividing in 128 bits. Once the product passed i128::MAX, the arithmetic error became a payout of 0, and the claim was marked used for good.
  • The product passes i128::MAX at about 1.3e19 base units on each side. That is 13 tokens at 18 decimals, or 1.3 trillion at 7.
  • New lanes' contract now divides a 256-bit product. A payout that doesn't compute fails the call with PayoutOverflow (error 64) and the claim stays open.
  • The new build of record is 603a413d….

A wipe only after every node has stopped (O-01, high).

  • destroy --wipe stopped each node and then emptied data/, but every host type could hide a failed stop. On ssh hosts a systemctl failure was ignored; in Docker, a failed docker ps or docker rm; locally, a failed kill.
  • Now systemd must report the unit stopped, no container may be left, and the process must be gone.

A host's root must be a plain directory of its own (O-04).

  • root = "/." passed the check and resolves to /.
  • A root must now be an absolute path at least two levels deep, with no . or .. part, outside /bin, /etc, /usr and the other system directories.
  • The wipe also refuses a root that resolves to /, or a data/ that is a link.

A crash keeps all of a block or none of it (R-01, R-02, R-03).

  • A block, its checkpoint and a validator's live-check flags are now one transaction.
  • Before, a crash between them left a node that failed every restart with Corrupt("last checkpoint"). Or it lost a flag, so a restarted validator could sign a checkpoint it had refused.

destroy checks exit.json against the freeze (O-03).

  • A checkpoint already sent could land after destroy exported the exits, and become the frozen one.
  • After the freeze, destroy now compares exit.json with Stellar's last checkpoint. It exports again if needed, and pays out or wipes nothing until they match. A second destroy on a frozen lane does the same check.
  • caravel escape already refused a stale file.

The release's image list is checksummed (O-02).

  • SHA256SUMS now lists IMAGES, and the installer checks it.
  • An image ref that names a registry must carry its digest.
  • Signed release manifests are a follow-up.

Upgrading

  • Nodes: apply the release as usual. Store layouts, formats and consensus are unchanged.
  • Existing lanes keep their settlement contract. A lane on a token with many decimals, created with 0.4.1 or earlier, runs the old payout. Recreate it to get the fix. Caravel Perps settles in 7-decimal USDC, out of the bug's reach.
  • Host roots: a lane file whose root is one level deep (/opt) or under a system directory is now refused. Move it to something like /opt/caravel.
  • Installing 0.4.1 or earlier with this installer prints a note that their IMAGES is unchecked, since their SHA256SUMS doesn't list it.

Caravel v0.4.1

Choose a tag to compare

@github-actions github-actions released this 05 Oct 09:37
6f40b83

Testnet only, not audited. Install: curl -fsSL https://raw.githubusercontent.com/wmendes/caravel/v0.4.1/scripts/install.sh | bash

Checkpoints when they're needed, and much cheaper ones. This release also carries 0.4.0, which was not published separately. Caravel Perps on testnet runs it.

Why

A checkpoint is one Stellar transaction. Lanes used to seal one every so many blocks, busy or idle. On testnet each cost about 0.34 XLM, and 97% of that was rent for a record the settlement contract kept of every checkpoint for 120 days. One a minute came to about 490 XLM a day, and a withdrawal could wait a minute to become claimable.

Numbers

Before Now
A withdrawal claimable on Stellar (Caravel Perps, testnet) up to ~66 s ~7 s
caravel withdraw, from the command to claimed up to ~110 s ~18 s
An idle lane's checkpoints every 60 s every ~4.5 min (288 a day)
A checkpoint without withdrawals, new lanes (testnet) ~0.34 XLM ~0.002 XLM
A checkpoint with withdrawals ~0.34 XLM ~0.335 XLM (unchanged)

Full tables are in docs/RESULTS.md.

What changed

Checkpoints by time and content. Three [node] settings, set all three or none:

checkpoint_urgent_ms = 5000      # a deposit, forced withdrawal or withdrawal is waiting
checkpoint_busy_ms = 60000       # user transactions are waiting
checkpoint_idle_ms = 3600000     # nothing is waiting
  • A checkpoint ends once the oldest thing in it has waited that long, or when its batch is full. With the settings unset, checkpoint_every_blocks decides as before; with them set, it is only a cap.
  • At 500 ms blocks an idle batch fills in about 4.5 minutes, because empty blocks and oracle updates still add bytes, so idle lanes checkpoint about that often.
  • caravel validate says when a deployment's checkpoints will come. It refuses settings that could let the contract freeze an idle lane, or let a deposit miss the force-inclusion window.
  • /v1/status reports the rules, the open batch, and why each batch ended.

A cheaper settlement contract for new lanes.

  • It keeps its record only for checkpoints with withdrawals, which the claims need. All other checkpoints cost the transaction alone.
  • Every check, claim, escape and freeze rule is unchanged.
  • The new build of record is ffddd99e…. Existing lanes keep their contract (Caravel Perps: 8a2fafbd…).
  • Replay and the relayer read checkpoints without a record from their ckpt events and LastCkpt.

Faster caravel withdraw. It no longer reads every block of its checkpoint to find its own withdrawal, and it polls four times as often.

Fees you can see. The relayer's metrics now record each checkpoint's rent, refundable and non-refundable fee.

Upgrading

  • Nodes: apply the release as usual. The new settings are optional.
  • Lane files: a 0.3.0 node refuses a lane file that uses the new settings, so upgrade the nodes first.
  • Withdrawal cost: a checkpoint that carries withdrawals still pays the record's rent, on either contract. Under steady withdrawal traffic, checkpoint_urgent_ms sets how many of those you pay for: one every 5 s is about 5,800 XLM a day on testnet, and one every 30 s about 970.

Caravel v0.3.0

Choose a tag to compare

@github-actions github-actions released this 05 Oct 06:09
2d4315a

Testnet only, not audited. Install: curl -fsSL https://raw.githubusercontent.com/wmendes/caravel/v0.3.0/scripts/install.sh | bash

A performance release: lanes store less, settle sooner and say where their time goes. Nothing in consensus changed. The engines, the settlement contract and the frozen formats are byte for byte the same as in 0.2.0, so existing lanes upgrade in place. Caravel Perps on testnet runs 0.3.0.

Numbers

Measured with the new full-stack soak (sequencer, 3 validators, relayer, a local Stellar network), 10 minutes per run, before and after this release:

0.2.0 0.3.0
Time from a transaction to its checkpoint on Stellar, 100 tx/s, p50 / p99 5.6 / 8.9 s 3.1 / 5.2 s
From sealing a checkpoint to its signatures 2.0 s 9 to 15 ms (144 ms on the testnet VM)
A validator's store, 100 tx/s grows ~2.3 GB a day stays near 1 to 2 MB
The sequencer's store, 100 tx/s ~2.3 GB a day ~0.95 GB a day
All four stores of an idle lane at 200 ms blocks ~410 MB a day ~83 MB a day

Full tables are in docs/RESULTS.md.

What changed

Storage

  • Validators drop the blocks of old accepted checkpoints. They keep the ones after their oldest kept snapshot, and Stellar keeps every checkpoint. Asked for a dropped block, /v1/blocks/{h} answers 410 PRUNED.
  • The sequencer still keeps every block, now compressed: each old checkpoint's blocks become one deflated row, read back transparently.
  • Nodes write the full state at checkpoints and about every 10 s, not with every block. After a restart they re-execute the few blocks since and check each against its recorded state hash.
  • Validators commit blocks with synchronous=NORMAL. What they sign is still on disk before the signature leaves. The sequencer keeps full sync, so it never forgets a block it has served.
  • New stores give pages back as they prune. caravel-perps-node compact converts an older store and shrinks it.
  • Log caps: containers use Docker's local driver (3 × 10 MB), the process runtime rotates a node's log past 10 MB, and the relayer's checkpoint metrics move aside past 10 MB. Logs carry colors only on a terminal.

Latency

  • The sequencer retries signatures after 150 ms instead of sleeping 2 s, and a validator waits briefly for the last block instead of refusing.
  • Validators fetch raw block bytes on a long poll (/v1/blocks/{h}/raw?wait_ms=), outside the sequencer's core lock.
  • The relayer is told as soon as a checkpoint is signed, skips a redundant read before each submission, keeps its account between sends, polls for inclusion every 250 ms, and sends a dropped request again.
  • Every request that takes the sequencer's core lock runs off the async workers. The mempool indexes queued nonces per account. The WebSocket builds each block's shared messages once, not once per subscriber.

Visibility and tools

  • Per-phase timings (p50 / p99 / max) in /v1/status under perf, on the sequencer and validators, and in caravel status --json.
  • scripts/soak-lane.sh: the whole lane under load on a local network, reporting timings, CPU, memory, storage per day and latency. loadgen goes past 255 accounts, keeps several requests in flight and writes CSV.
  • caravel validate points out a deployment off the local network that checkpoints more often than every 30 s. The docs explain choosing checkpoint_every_blocks by time.

CI: about 3 minutes for a code change with a warm cache, against about 10. Jobs run in parallel and both parity gates use every core.

Upgrading

  • Apply the new release as usual (caravel plan, then caravel apply). Stores open as they are and gain the new table on first start.
  • An existing store prunes in the background, 8 checkpoints every 30 s, so a long-lived lane takes a few hours to slim down. Its files keep their size until you run compact with the nodes stopped.
  • Anything that read old blocks from a validator should read them from the sequencer, or replay from Stellar.

Known limits

  • On testnet the relayer still lands one checkpoint per ledger (about 5 s), which caps sustained load near 85 to 90 transactions a second whatever the block time. Two checkpoints in flight need hand-built transaction footprints, and bigger batches are a contract change; both are left for later.
  • 200 ms blocks work and cost little storage now, but four nodes on a 2-vCPU e2-small leave no CPU headroom at that pace. Caravel Perps stays at 500 ms.

Caravel v0.2.0

Choose a tag to compare

@github-actions github-actions released this 04 Oct 12:06
5d9ffbd

Testnet only, not audited. Install: curl -fsSL https://raw.githubusercontent.com/wmendes/caravel/v0.2.0/scripts/install.sh | bash

Caravel v0.1.0

Choose a tag to compare

@github-actions github-actions released this 03 Oct 19:26
0b3dd60

Testnet only, not audited. Install: curl -fsSL https://raw.githubusercontent.com/wmendes/caravel/v0.1.0/scripts/install.sh | bash