Skip to content
Merged
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
14 changes: 10 additions & 4 deletions tools/celestia-node-fiber/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ replace (
replace github.com/evstack/ev-node => ../../.

require (
cosmossdk.io/math v1.5.3
github.com/celestiaorg/celestia-app/v8 v8.0.0-20260408095837-ab08b6d5e54e
github.com/celestiaorg/celestia-node v0.0.0-20260423103931-b07242fbfec8
github.com/celestiaorg/go-square/v4 v4.0.0-rc4.0.20260318002530-1ca8ff7b42ea
github.com/cometbft/cometbft v1.0.1
github.com/cosmos/cosmos-sdk v0.50.13
github.com/cristalhq/jwt/v5 v5.4.0
github.com/evstack/ev-node v1.1.0
github.com/stretchr/testify v1.11.1
go.uber.org/fx v1.24.0
)

require (
Expand All @@ -58,7 +62,6 @@ require (
cosmossdk.io/depinject v1.2.1 // indirect
cosmossdk.io/errors v1.0.2 // indirect
cosmossdk.io/log v1.6.1 // indirect
cosmossdk.io/math v1.5.3 // indirect
cosmossdk.io/store v1.1.2 // indirect
cosmossdk.io/x/circuit v0.1.1 // indirect
cosmossdk.io/x/evidence v0.1.1 // indirect
Expand All @@ -70,6 +73,7 @@ require (
filippo.io/keygen v0.0.0-20260114151900-8e2790ea4c5b // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.2 // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
github.com/DataDog/datadog-go v4.8.3+incompatible // indirect
github.com/DataDog/zstd v1.5.7 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 // indirect
Expand Down Expand Up @@ -131,7 +135,6 @@ require (
github.com/cockroachdb/redact v1.1.6 // indirect
github.com/cockroachdb/swiss v0.0.0-20251224182025-b0f6560f979b // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb // indirect
github.com/cometbft/cometbft v1.0.1 // indirect
github.com/cometbft/cometbft-db v1.0.4 // indirect
github.com/consensys/gnark v0.14.0 // indirect
github.com/consensys/gnark-crypto v0.19.2 // indirect
Expand All @@ -147,7 +150,6 @@ require (
github.com/cosmos/ibc-go/v8 v8.7.0 // indirect
github.com/cosmos/ics23/go v0.11.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.15.0 // indirect
github.com/cristalhq/jwt/v5 v5.4.0 // indirect
github.com/cskr/pubsub v1.0.2 // indirect
github.com/danieljoos/wincred v1.2.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
Expand Down Expand Up @@ -184,6 +186,7 @@ require (
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gofrs/flock v0.13.0 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.3 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
Expand Down Expand Up @@ -232,6 +235,7 @@ require (
github.com/huin/goupnp v1.3.0 // indirect
github.com/iancoleman/orderedmap v0.3.0 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/improbable-eng/grpc-web v0.15.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/ingonyama-zk/icicle-gnark/v3 v3.2.2 // indirect
Expand Down Expand Up @@ -335,6 +339,7 @@ require (
github.com/quic-go/webtransport-go v0.10.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/rollkit/go-da v0.9.0 // indirect
github.com/ronanh/intcomp v1.1.1 // indirect
github.com/rs/cors v1.11.1 // indirect
github.com/rs/zerolog v1.35.0 // indirect
Expand Down Expand Up @@ -363,9 +368,11 @@ require (
go.etcd.io/bbolt v1.4.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect
go.opentelemetry.io/contrib/instrumentation/runtime v0.67.0 // indirect
go.opentelemetry.io/otel v1.43.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect
Expand All @@ -377,7 +384,6 @@ require (
go.opentelemetry.io/otel/trace v1.43.0 // indirect
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
go.uber.org/dig v1.19.0 // indirect
go.uber.org/fx v1.24.0 // indirect
go.uber.org/mock v0.5.2 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.1 // indirect
Expand Down
8 changes: 8 additions & 0 deletions tools/celestia-node-fiber/listen.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ func resolveHeight(resp *blob.SubscriptionResponse) uint64 {
// fibreBlobToEvent reconstructs the Fibre BlobID (version byte + 32-byte
// commitment) from a share-version-2 libshare.Blob and wraps it as a
// BlobEvent.
//
// DataSize caveat: a v2 share carries only (fibre_blob_version + commitment),
// not the original blob payload, so b.DataLen() is the on-chain share size
// (a fixed constant), not the user-facing "how big is this blob" number
// that ev-node's fibermock and its consumers typically expect. Reporting
// the true payload size requires an on-chain query against x/fibre's
// PaymentPromise keyed by commitment. Tracked as a follow-up; for now we
// report the share size so the field is non-zero.
func fibreBlobToEvent(b *libshare.Blob, height uint64) (block.FiberBlobEvent, error) {
version, err := b.FibreBlobVersion()
if err != nil {
Expand Down
135 changes: 135 additions & 0 deletions tools/celestia-node-fiber/testing/bridge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//go:build fibre

package cnfibertest

import (
"context"
"crypto/rand"
"net"
"testing"
"time"

"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cristalhq/jwt/v5"
"github.com/stretchr/testify/require"
"go.uber.org/fx"

appfibre "github.com/celestiaorg/celestia-app/v8/fibre"

"github.com/celestiaorg/celestia-node/api/client"
"github.com/celestiaorg/celestia-node/api/rpc/perms"
"github.com/celestiaorg/celestia-node/nodebuilder"
"github.com/celestiaorg/celestia-node/nodebuilder/node"
"github.com/celestiaorg/celestia-node/nodebuilder/p2p"
stateapi "github.com/celestiaorg/celestia-node/nodebuilder/state"
)

// Bridge bundles an in-process celestia-node bridge node and the admin
// JWT that grants it authenticated RPC access. The adapter's ReadConfig
// needs both the address and the token for Blob.Subscribe to work.
type Bridge struct {
Node *nodebuilder.Node
AdminToken string
}

// RPCAddr returns a WebSocket URL the adapter uses in
// Config.ReadConfig.BridgeDAAddr. WebSocket (not HTTP) is required
// because Blob.Subscribe returns a channel; go-jsonrpc only supports
// channel-returning methods over a streaming transport.
func (b *Bridge) RPCAddr() string {
return "ws://" + b.Node.RPCServer.ListenAddr()
}

// StartBridge brings up an in-process celestia-node bridge connected to
// the Network's consensus gRPC endpoint. Mirrors celestia-node's
// api/client test helpers so TestShowcase has a real JSON-RPC server for
// Blob.Subscribe.
func StartBridge(t *testing.T, ctx context.Context, network *Network) *Bridge {
t.Helper()

cfg := nodebuilder.DefaultConfig(node.Bridge)

ip, port, err := net.SplitHostPort(network.ConsensusGRPCAddr())
require.NoError(t, err, "splitting consensus gRPC addr")
cfg.Core.IP = ip
cfg.Core.Port = port
// Pin the bridge RPC to an ephemeral port; the test discovers it via
// Node.RPCServer.ListenAddr() after Start.
cfg.RPC.Port = "0"

tempDir := t.TempDir()
store := nodebuilder.MockStore(t, cfg)

auth, adminToken := bridgeAuth(t)
kr := bridgeKeyring(t, tempDir)

bn, err := nodebuilder.New(node.Bridge, p2p.Private, store,
auth,
stateapi.WithKeyring(kr),
stateapi.WithKeyName(stateapi.AccountName(bridgeSigningKey)),
fx.Replace(node.StorePath(tempDir)),
)
require.NoError(t, err, "constructing bridge node")

require.NoError(t, bn.Start(ctx), "starting bridge node")
t.Cleanup(func() {
stopCtx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
_ = bn.Stop(stopCtx)
})

return &Bridge{
Node: bn,
AdminToken: adminToken,
}
}

// bridgeSigningKey is the keyring account the bridge uses for its own
// tx submissions. Distinct from the client's account so the two keyrings
// don't collide.
const bridgeSigningKey = "bridge-signer"

func bridgeKeyring(t *testing.T, tempDir string) keyring.Keyring {
t.Helper()

kr, err := client.KeyringWithNewKey(client.KeyringConfig{
KeyName: bridgeSigningKey,
BackendName: keyring.BackendTest,
}, tempDir)
require.NoError(t, err, "creating bridge keyring")

// The Fibre module on the bridge expects a key under
// appfibre.DefaultKeyName to exist, even though our client never uses
// the bridge's Fibre module for Upload/Download. Without it,
// fx.Start fails during fibre module wiring.
_, _, err = kr.NewMnemonic(
appfibre.DefaultKeyName,
keyring.English, "", "", hd.Secp256k1,
)
require.NoError(t, err, "provisioning bridge fibre key")
return kr
}

// bridgeAuth creates an HS256 JWT signer pair and an admin token. The
// returned fx option injects the signer/verifier into the node; the
// token is what the adapter puts in ReadConfig.DAAuthToken.
func bridgeAuth(t *testing.T) (fx.Option, string) {
t.Helper()

key := make([]byte, 32)
_, err := rand.Read(key)
require.NoError(t, err, "rand.Read jwt key")

signer, err := jwt.NewSignerHS(jwt.HS256, key)
require.NoError(t, err)
verifier, err := jwt.NewVerifierHS(jwt.HS256, key)
require.NoError(t, err)

token, err := perms.NewTokenWithPerms(signer, perms.AllPerms)
require.NoError(t, err)

return fx.Decorate(func() (jwt.Signer, jwt.Verifier, error) {
return signer, verifier, nil
}), string(token)
}
16 changes: 16 additions & 0 deletions tools/celestia-node-fiber/testing/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//go:build fibre

// Package cnfibertest wires a single-validator Celestia chain, an in-process
// Fibre server, a celestia-node bridge and the celestia-node-fiber adapter
// together so Upload → Listen → Download can be exercised end-to-end in a
// Go test.
//
// The chain is a celestia-app testnode built with -tags fibre. The Fibre
// server runs in the same process and its FSP endpoint is registered with
// the valaddr module so the client's host registry can find it. The
// underlying adapter talks directly to consensus gRPC and the Fibre server;
// only Listen goes through the bridge node's blob subscription.
//
// This is the "fast sanity" variant. A multi-validator showcase is planned
// as a Docker Compose follow-up that exercises real quorum collection.
package cnfibertest
Loading
Loading