Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions tools/celestia-node-fiber/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/celestiaorg/celestia-node/api/client"
blobapi "github.com/celestiaorg/celestia-node/nodebuilder/blob"
fibreapi "github.com/celestiaorg/celestia-node/nodebuilder/fibre"
headerapi "github.com/celestiaorg/celestia-node/nodebuilder/header"

"github.com/evstack/ev-node/block"
)
Expand All @@ -39,6 +40,7 @@ const defaultListenChannelSize = 16
type Adapter struct {
fibre fibreapi.Module
blob blobapi.Module
header headerapi.Module
listenChannelSz int

// closer, if non-nil, is invoked by Close. Set only when the Adapter
Expand All @@ -60,6 +62,7 @@ func New(ctx context.Context, cfg Config, kr keyring.Keyring) (*Adapter, error)
return &Adapter{
fibre: c.Fibre,
blob: c.Blob,
header: c.Header,
listenChannelSz: resolveListenChannelSize(cfg.ListenChannelSize),
closer: c.Close,
}, nil
Expand All @@ -85,6 +88,20 @@ func (a *Adapter) Close() error {
return a.closer()
}

// Head returns the bridge node's current local-head height. Returns 0 if
// the underlying client was constructed via FromModules without a Header
// module.
func (a *Adapter) Head(ctx context.Context) (uint64, error) {
if a.header == nil {
return 0, fmt.Errorf("Adapter has no Header module; construct via New")
}
h, err := a.header.LocalHead(ctx)
if err != nil {
return 0, fmt.Errorf("header.LocalHead: %w", err)
}
return h.Height(), nil
}

// Upload implements fiber.DA.Upload. client.Fibre.Upload does off-chain row
// upload plus validator-sig aggregation and spawns a background
// MsgPayForFibre broadcast; this call returns as soon as the off-chain
Expand Down
34 changes: 34 additions & 0 deletions tools/celestia-node-fiber/testing/docker/Dockerfile.app
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Build a celestia-appd binary with the `fibre` build tag enabled and a
# matching `fibre` server binary. Both go on PATH so the validator
# entrypoint can run them as separate processes.
#
# Pin CELESTIA_APP_REF to a feature/fibre commit; the default tracks
# whatever celestia-app `main` looks like at build time, which is where
# fibre development lives.
ARG GO_VERSION=1.26.1
ARG CELESTIA_APP_REPO=https://github.com/celestiaorg/celestia-app.git
ARG CELESTIA_APP_REF=feat/fibre-payments

FROM golang:${GO_VERSION}-bookworm AS build
ARG CELESTIA_APP_REPO
ARG CELESTIA_APP_REF
RUN apt-get update \
&& apt-get install -y --no-install-recommends git ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
RUN git clone --depth 1 --branch "${CELESTIA_APP_REF}" "${CELESTIA_APP_REPO}" celestia-app \
|| git clone "${CELESTIA_APP_REPO}" celestia-app
WORKDIR /src/celestia-app
RUN git checkout "${CELESTIA_APP_REF}" || true
ENV CGO_ENABLED=0 GOFLAGS="-mod=readonly"
RUN go build -tags "ledger,fibre" -o /out/celestia-appd ./cmd/celestia-appd
RUN go build -tags "ledger,fibre" -o /out/fibre ./fibre/cmd

FROM debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates jq curl \
&& rm -rf /var/lib/apt/lists/*
COPY --from=build /out/celestia-appd /usr/local/bin/celestia-appd
COPY --from=build /out/fibre /usr/local/bin/fibre
RUN chmod +x /usr/local/bin/celestia-appd /usr/local/bin/fibre
WORKDIR /home/celestia
28 changes: 28 additions & 0 deletions tools/celestia-node-fiber/testing/docker/Dockerfile.bridge
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Build a celestia-node bridge binary with the `fibre` build tag enabled.
# The bridge is what serves blob.Subscribe over JSON-RPC for the adapter's
# Listen path, and (on the read-only side) the fibre namespace API.
ARG GO_VERSION=1.26.1
ARG CELESTIA_NODE_REPO=https://github.com/celestiaorg/celestia-node.git
ARG CELESTIA_NODE_REF=feature/fibre-experimental

FROM golang:${GO_VERSION}-bookworm AS build
ARG CELESTIA_NODE_REPO
ARG CELESTIA_NODE_REF
RUN apt-get update \
&& apt-get install -y --no-install-recommends git ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
RUN git clone --depth 1 --branch "${CELESTIA_NODE_REF}" "${CELESTIA_NODE_REPO}" celestia-node \
|| git clone "${CELESTIA_NODE_REPO}" celestia-node
WORKDIR /src/celestia-node
RUN git checkout "${CELESTIA_NODE_REF}" || true
ENV CGO_ENABLED=0 GOFLAGS="-mod=readonly"
RUN go build -tags "fibre" -o /out/celestia ./cmd/celestia

FROM debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates jq curl \
&& rm -rf /var/lib/apt/lists/*
COPY --from=build /out/celestia /usr/local/bin/celestia
RUN chmod +x /usr/local/bin/celestia
WORKDIR /home/celestia
118 changes: 118 additions & 0 deletions tools/celestia-node-fiber/testing/docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Fibre 4-validator + bridge docker showcase

A docker-compose stack that brings up four celestia-app validators
(each running a Fibre server), a celestia-node bridge, and a one-shot
init container that registers Fibre Storage Provider hosts and funds an
escrow account. A Go test driver (`docker_test.go`) connects from the
host and exercises the `celestia-node-fiber` adapter end-to-end against
the real 2/3-quorum network.

## Why

The in-process `testing/showcase_test.go` runs against a single
validator inside the test process. That proves the adapter wires
correctly, but it doesn't exercise:

- real consensus 2/3 quorum collection (single validator trivially
satisfies it),
- inter-validator P2P,
- multiple Fibre servers contributing partial signatures,
- the host:port registry resolution path,
- the bridge syncing real headers off a network it doesn't itself drive.

This stack does.

## Architecture

```
+---------- bootstrap (one-shot) ----------+
| init-genesis.sh: 4-val genesis + keys |
+-------+----------------------------------+
| shared volume
+------------+------------+------------+
v v v v
val0 val1 val2 val3
(appd + (appd + (appd + (appd +
fibre) fibre) fibre) fibre)
^
| gRPC :9090, RPC :26657
|
bridge (celestia-node)
^
| JSON-RPC/WebSocket :26658
|
+--------+--------+
| Go test |
| (docker_test.go) |
+-----------------+
```

## Run

```bash
cd tools/celestia-node-fiber/testing/docker

# First boot: builds two images (~5–10 min on a cold cache).
docker compose up -d --build

# Watch the bootstrap + registration progress:
docker compose logs -f bootstrap register

# Once `register` exits 0 and writes /shared/setup.done, the bridge
# connects and the stack is ready.

# From the parent dir, run the Go-side driver:
cd ../..
go test -tags 'fibre fibre_docker' -count=1 -timeout 5m ./testing/docker/...

# Tear down (preserves volumes — add -v to wipe shared genesis state):
docker compose -f testing/docker/compose.yaml down
```

Override endpoints from the host with env vars if your ports collide:

```
FIBRE_BRIDGE_ADDR=ws://127.0.0.1:36658 \
FIBRE_CONSENSUS_ADDR=127.0.0.1:19090 \
go test -tags 'fibre fibre_docker' ...
```

## Build args

Both Dockerfiles accept refs:

| arg | Dockerfile | default | what it does |
|---|---|---|---|
| `CELESTIA_APP_REPO` | `Dockerfile.app` | celestia-app upstream | clone source |
| `CELESTIA_APP_REF` | `Dockerfile.app` | `main` | git ref to build with `-tags fibre,ledger` |
| `CELESTIA_NODE_REPO` | `Dockerfile.bridge` | celestia-node upstream | clone source |
| `CELESTIA_NODE_REF` | `Dockerfile.bridge` | `feature/fibre` | git ref to build with `-tags fibre` |

Example pinning to a specific commit:

```
docker compose build --build-arg CELESTIA_NODE_REF=194cc74c ...
```

## Known TODOs

The scaffold has been validated end-to-end on Apple Silicon
(Docker Desktop 4.70 / linux/arm64). A few rough edges remain that
are worth tightening for CI:

1. **`config.toml` / `app.toml` overrides** in `start-validator.sh`
use `sed` against expected default lines. If the celestia-app
defaults change verb/spacing, the substitutions silently no-op.
Consider a `dasel`/`tomlq` rewrite if it bites.
2. **No healthchecks** on validators. `register` waits on
`service_started`, which is only "container booted", not "RPC
responding". The script polls `celestia-appd status` which
handles that, but a proper healthcheck would let `bridge` start
sooner without polling itself.
3. **No CI integration**. Adding `make docker-test` that wraps
`docker compose up -d --wait`, runs the test, then tears down,
is a sensible follow-up.
4. **Build cache** — every `docker compose up --build` re-clones
celestia-app + celestia-node. To iterate faster, set up a
docker volume cache for `/go/pkg/mod` and `/root/.cache/go-build`,
or build the images once and re-use.
Loading
Loading