Test Lantern with Curio PDP
Run the stock Curio-PDP storage provider with Lantern as its only chain node, prove data on the Filecoin calibration network, and tell us where it hurt.
One chain node, and it is Lantern
Curio-PDP needs a Lotus-compatible chain API. The upstream Docker stack ships Forest for that, which needs a chain snapshot and tens of GB of disk. In this test the unmodified filecoin/curio-pdp:calibnet image talks only to Lantern: no Lotus, no Forest, no RPC bridge. Lantern anchors to the head with a multi-operator quorum, follows it over libp2p, and verifies every block, state read and FEVM eth_call locally. Curio signs its own messages; Lantern publishes them and holds no keys.
Before you begin
A Linux host, x86_64 or arm64, for the Curio-PDP stack (the walkthrough uses systemd and the docker0 bridge). Building Lantern and running the client script also work on macOS.
Docker Engine with Compose v2.24.4 or newer, plus git and curl. Node.js 20+ on any machine for the client test.
A few GB of RAM for the whole stack and about 20 GB of fast disk. Piece storage needs at least 100 GiB free (registration declares it); it may be HDD.
A hostname for the PDP API: a domain you control, or a domain on a free Cloudflare account for a Cloudflare Tunnel (works behind NAT).
About 10 tFIL across two wallets (at least about 6 tFIL for the PDP wallet, the rest for client gas) plus test USDFC for the client. Faucets: the official list or faucet.reiers.io.
Plan for about half a day. Most of it is waiting: the first proof lands about one proving period (about 2 h on calibration) after your data set is created.
Twelve steps, clean machine to proofs
A skimmable summary with the key commands. The canonical, detailed walkthrough is RUN-PDP.md on GitHub, with every step linked below. Replace placeholders in angle brackets; pdp.example.com stands for your public hostname.
-
01
Install Docker Engine and Compose v2.24.4 or newer
The Lantern overlay uses the Compose
!overridetag, so distribution packages are often too old. Note yourdocker0address: the commands below use Docker's default bridge address172.17.0.1, replace it if yours differs.curl -fsSL https://get.docker.com | sudo sh sudo usermod -aG docker "$USER" # then log out and back in docker version docker compose version # must print v2.24.4 or newer ip -4 addr show docker0 # note the inet address, typically 172.17.0.1 -
02
Get Lantern v1.10.1-rc1 and verify it
Download the release binary and check it against the published manifest (Linux x86_64 shown,
lantern-linux-arm64also exists):Option A: downloadTAG=v1.10.1-rc1 # or a newer release curl -fsSLO "https://github.com/Reiers/lantern/releases/download/$TAG/lantern-linux-amd64" curl -fsSLO "https://github.com/Reiers/lantern/releases/download/$TAG/lantern-linux-amd64.sha256" sha256sum -c lantern-linux-amd64.sha256 # lantern-linux-amd64: OK mkdir -p "$HOME/.local/bin" install -m 0755 lantern-linux-amd64 "$HOME/.local/bin/lantern" export PATH="$HOME/.local/bin:$PATH" # add to ~/.bashrc if neededOr build from source with Go 1.26.4 (about 85 s on a clean machine, no C compiler, no Rust):
Option B: buildgit clone https://github.com/Reiers/lantern.git cd lantern TAG=v1.10.1-rc1 # or a newer release git checkout "$TAG" CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.versionTag=$TAG" -o lantern ./cmd/lanternReleases from v1.10.1 on are byte-reproducible. To check that the published bytes come from the tagged source, rebuild them in the pinned container (needs Docker, no local Go):
./scripts/repro-build.sh "$TAG" linux/amd64 # or linux/arm64, darwin/arm64; omit for all lantern version # lantern v1.10.1 (<commit>) Lantern+mainnet, or newerLantern+mainnetis only the compiled-in default. Every command takes--network calibrationat run time. -
03
Initialise Lantern for calibration
initwrites a trust anchor only when at least 3 distinct operators agree on the current finalized head, and any conflicting answer fails it.node-type pdpselects the PDP tier (persistent 3 GiB block cache plus a one-day transaction index). KeepLANTERN_HOMEidentical for every command and for the service.export LANTERN_HOME="$HOME/.lantern" export LANTERN_PASS='' # explicit empty: no keystore passphrase (Lantern holds no keys here) lantern init --network calibration --no-wallet lantern node-type pdp --network calibration -
04
Run the daemon on the Docker bridge
Curio runs in a container, so Lantern binds the host's
docker0address: reachable from local containers, not routed from your LAN or the internet.--allow-remote-rpcis an acknowledgement, not an open door: write, sign and admin methods still need the token. Never use--listen 0.0.0.0:1234on a host with a public interface.lantern service install --network calibration --listen 172.17.0.1:1234 -- --allow-remote-rpc --metrics 127.0.0.1:9092 sudo loginctl enable-linger "$USER" curl -s http://172.17.0.1:1234/healthz # ok lantern info --network calibrationlantern infoprints theFULLNODE_API_INFOvalue Curio needs.Filecoin.StateNetworkVersionmust return 29: anything lower means a build that predates the NV29 upgrade. Treat the token like a password. -
05
Start stock Curio-PDP against Lantern
Use the upstream
filecoin-project/curiostack unchanged, plus one overlay file from the Lantern repo that removes Forest.git clone --depth 1 https://github.com/filecoin-project/curio.git cd curio/docker/skiff cp /path/to/lantern/deploy/curio-pdp/docker-compose.lantern.yaml . cp .env .env.upstream cp /path/to/lantern/deploy/curio-pdp/env.lantern.example .envThe three
.envlines that matter. Set the domain before the first start, and use an IP literal after/ip4/:.envSKIFF_IMAGE=filecoin/curio-pdp:calibnet SKIFF_HTTP_DOMAIN=pdp.example.com FULLNODE_API_INFO=<token from lantern info>:/ip4/172.17.0.1/tcp/1234/httpStart Yugabyte and Curio-PDP only, naming both services every time (otherwise Compose also starts Forest). First start runs database migrations for a few minutes.
C="docker compose -f docker-compose.yaml -f docker-compose.calibnet.yaml -f docker-compose.lantern.yaml" $C pull yugabyte skiff $C up -d --no-build yugabyte skiff $C ps $C logs -f skiff -
06
Open the admin GUI over an SSH tunnel
The GUI listens on
127.0.0.1:4701and has no login, so never publish port 4701. The Chain page should show your Lantern with Reachability and Sync Statusok. The PDP Guide page is your checklist for steps 7 to 10.ssh -fN -L 4701:127.0.0.1:4701 <user>@<host> -
07
Attach storage
Create a piece directory, then attach
/data/pdp-piecesunder Storage in the GUI. The PDP Guide checks for at least 100 GiB free.docker exec skiff mkdir -p /data/pdp-pieces -
08
Create and fund the PDP wallet
In Wallets (or the PDP Guide) click Create. Curio shows the private key once: save it before closing the dialog. Fund the
0xaddress with at least about 6 tFIL (5 FIL registry fee plus gas) from a calibration faucet: the official faucet list or faucet.reiers.io (tFIL and USDFC, run by the Lantern maintainer). -
09
Expose the PDP API over public HTTPS
Clients and FWSS need
https://pdp.example.com. Behind NAT, a free Cloudflare Tunnel works (the PDP Guide can start the connector for you); with your own domain, terminate TLS in front of port 80 or let Curio fetch a Let's Encrypt certificate. Open only 80 and 443, never 4701 or 1234.curl -i https://pdp.example.com/pdp/ping503 PDP wallet not configuredbefore step 8 is expected (the path from the internet works).200once the wallet exists. -
10
Register with FWSS
Open PDP (tools section), then Register Provider in the Filecoin Service Registry section. Description: at most 128 characters. Capacity: at least 100 GiB. The registry charges a 5 FIL fee. Curio signs, Lantern publishes from its local message pool. Note your provider ID once the transaction lands.
-
11
Create a test data set as a client
Use a separate client wallet (never the PDP key) funded with tFIL and USDFC, and Node.js 20+ on any machine. The script uploads a 4 MiB random piece and waits for your provider to create the data set through Lantern; expect a data set ID within roughly 5 to 10 minutes.
cd deploy/curio-pdp npm install CLIENT_PRIVATE_KEY=0x<client key> PROVIDER_ID=<your provider id> node upload-test.mjs -
12
Watch proofs land
A calibration proving period is 240 epochs, about 2 hours. The first proof lands about one period after the data set is created, then once per period.
last proven epochabove 0 means a proof landed.node upload-test.mjs status <dataSetId> # read through your own Lantern instead of Glif: RPC_URL=http://172.17.0.1:1234/rpc/v1 node upload-test.mjs status <dataSetId>
From registration to steady proving
- 01 · Registration
The PDP page shows your provider ID; the registration transaction has status
1. - 02 · Data set creation
After the client upload, Curio sends the create transaction through Lantern and logs
Successfully processed data set create. The data set appears under DataSets. - 03 · PDPv0_InitPP
Runs once for the new data set and sends a
nextProvingPeriodtransaction (status1). - 04 · PDPv0_Prove
Runs in every challenge window (every 240 epochs on calibration) and sends a
provePossessiontransaction, followed byPDPv0_ProvPeriodscheduling the next period. The script'sstatusmode shows the last proven epoch advancing. - 05 · No manual intervention
In the maintainers' 24 hour run, two data sets went through 13 consecutive proving windows each, every transaction landed with status
1, and the Lantern daemon never restarted.
Once registered, third-party clients may pick your provider on their own; that is normal. Full details: RUN-PDP.md 13.
The errors we hit, so you do not
/ip4/ needs an IP literal
/ip4/host.docker.internal/... (as in the upstream .env) makes Curio exit with unknown url scheme '' in a loop. Use your docker0 IP, for example <token>:/ip4/172.17.0.1/tcp/1234/http.
Set SKIFF_HTTP_DOMAIN before the first start
It is seeded into the database once. If you started with localhost, edit HTTP.DomainName in Configuration (base layer) and restart skiff; changing .env later has no effect.
The daemon refuses to start without a trust anchor
no trust anchor at .../bootstrap-anchor.json means init never completed for this network and LANTERN_HOME. Run lantern init --network calibration --no-wallet (or lantern repair --network calibration) with the same LANTERN_HOME as the service.
Every command needs --network calibration
A command without it means mainnet: the daemon syncs mainnet or lantern info says "not initialised". Add the flag everywhere, including the service.
Compose older than v2.24.4, or unnamed services
Old Compose rejects the overlay's !override tag. Always run $C up -d --no-build yugabyte skiff; a bare up -d also starts Forest and downloads a snapshot.
Client create reverts on Filecoin Pay lockup
insufficient funds to cover lockup after function execution: each data set locks funds and the client already owns others. Deposit more, for example EXTRA_DEPOSIT_USDFC=5, and run the script again.
Provider description is limited to 128 characters
Longer descriptions fail with description is too long, max 128 characters allowed. Nothing is sent and no fee is charged: shorten it and submit again.
More symptoms and fixes: RUN-PDP.md troubleshooting. Seeing no contract code at given address? Your Lantern predates NV29: upgrade to v1.10.1-rc1 or later.
Tell us how it went
A full run that worked end to end is as valuable as a bug report. Every friction point, however small, makes the guide better for the next operator.
What to include
- Hardware: CPU and threads, RAM, disk, VM or bare metal
- OS: distribution, version and kernel
- Lantern version (
lantern version) and how you got it: built, downloaded or installer - Build time, if you built from source
- Time to first proof, from data set creation
- Pass or fail for each step you reached
- Every friction point, with the exact command and output
Never paste API tokens, private keys or the contents of secrets/. Redact them.
Credit where it is due
Testers are credited in the verification report if they want to be. Say so in your report and tell us the name or handle to use.
Questions, or prefer email? [email protected]