Skip to content
Draft
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
23 changes: 23 additions & 0 deletions e2e/cmd/custom-ibc/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: Apache-2.0

package main

import (
"os"

"github.com/cosmos/ibc/link/cli"
"github.com/cosmos/ibc/link/lightclient"
"github.com/cosmos/ibc/link/lightclient/remotepoc"
)

func main() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an example of how a consumer would construct the binary to compile their custom proving logic into the CLI.

registry := lightclient.NewRegistry()
if err := registry.Register(remotepoc.Factory{}); err != nil {
panic(err)
}

root := cli.NewRootCmd(cli.Options{
Relayer: cli.RelayerOptions{ProverFactories: registry},
})
os.Exit(cli.Execute(root))
}
132 changes: 132 additions & 0 deletions e2e/custom_light_client_cli_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// SPDX-License-Identifier: Apache-2.0

package e2e_test

import (
"context"
"math/big"
"net"
"net/http"
"os"
"os/exec"
"path/filepath"
"strconv"
"testing"
"time"

"github.com/stretchr/testify/require"

"github.com/cosmos/ibc/e2e/internal/e2etest"
"github.com/cosmos/ibc/e2e/internal/harness/environment"
"github.com/cosmos/ibc/e2e/internal/harness/ibclink"
relayerv2 "github.com/cosmos/ibc/link/api/v2/relayer"
"github.com/cosmos/ibc/link/lightclient/remotepoc"
)

// TestRemoteAttestationLightClientRelaysPacket relays through a remote prover.
func TestRemoteAttestationLightClientRelaysPacket(t *testing.T) {

@dhfang dhfang Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E2E POC

// Build the downstream CLI that registers the remote prover factory.
t.Setenv("IBC_BIN", buildCustomIBC(t))
ctx := t.Context()

listener, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err)

spec, runtime := attestedMesh(e2etest.EVMChains(
t, e2etest.EVMRequirements{}, e2etest.ChainA, e2etest.ChainB,
))
env := e2etest.Start(t, spec, runtime)
sender := e2etest.NewSigner(t)
route := e2etest.ManualAtoB(e2etest.ChainA, e2etest.ChainB)
var serviceConfig ibclink.RelayerConfig
// Keep the attestation config for the proof service, but configure the
// relayer to obtain those proofs from that service over HTTP.
driver, deployment := e2etest.DeployWithRelayerConfig(
t,
env,
sender,
e2etest.NewSigner(t),
func(cfg *ibclink.RelayerConfig) {
require.NotEmpty(t, cfg.Connections)
serviceConfig = cloneRelayerConfig(*cfg)
cfg.Connections[0].ClientAType = remotepoc.Type
cfg.Connections[0].ClientAParams = map[string]any{"url": "http://" + listener.Addr().String()}
},
route,
)
// Serve the built-in attestation prover behind the remote prover protocol.
serveAttestationProver(t, listener, env, serviceConfig)

// Relay a real packet through the custom-compiled CLI and remote prover.
relayer := e2etest.StartRelayer(t, driver, env)
transfer, err := e2etest.NewTransfer(t, env, deployment, sender, route).Send(
ctx, e2etest.TransferRequest{Amount: big.NewInt(1_234_000)},
)
require.NoError(t, err)
require.NoError(t, e2etest.RelayAll(ctx, relayer, transfer.PacketTx()))
_, err = e2etest.AwaitState(
ctx, relayer, transfer.PacketTx(), relayerv2.PacketState_PACKET_STATE_SUCCEEDED,
)
require.NoError(t, err)
require.NoError(t, transfer.VerifyDelivered(ctx))
}

func serveAttestationProver(
t *testing.T,
listener net.Listener,
env *environment.Environment,
cfg ibclink.RelayerConfig,
) {
t.Helper()
useEnvironmentRPCs(t, env, &cfg)
configPath := filepath.Join(t.TempDir(), "attestation-proof-service.yaml")
require.NoError(t, ibclink.WriteRelayerConfig(configPath, cfg))

client := cfg.Connections[0]
server, err := remotepoc.NewAttestationHandler(t.Context(), configPath, client.ChainA, client.ClientA)
require.NoError(t, err)
errs := make(chan error, 1)
go func() { errs <- server.Serve(listener) }()
t.Cleanup(func() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
require.NoError(t, server.Shutdown(ctx))
require.ErrorIs(t, <-errs, http.ErrServerClosed)
})
}

func cloneRelayerConfig(cfg ibclink.RelayerConfig) ibclink.RelayerConfig {
cfg.Chains = append([]ibclink.RelayerChain(nil), cfg.Chains...)
cfg.Connections = append([]ibclink.RelayerConnection(nil), cfg.Connections...)
cfg.Attestors = append([]ibclink.RelayerAttestor(nil), cfg.Attestors...)
return cfg
}

func useEnvironmentRPCs(
t *testing.T, env *environment.Environment, cfg *ibclink.RelayerConfig,
) {
t.Helper()
for i := range cfg.Chains {
for _, id := range env.Chains() {
chain, err := env.Chain(id)
require.NoError(t, err)
if strconv.FormatUint(chain.EVMChainID(), 10) == cfg.Chains[i].ChainID {
cfg.Chains[i].RPC = chain.RPCURL()
break
}
}
require.NotContains(t, cfg.Chains[i].RPC, "${")
}
}

func buildCustomIBC(t *testing.T) string {
t.Helper()

binary := filepath.Join(t.TempDir(), "ibc")
cmd := exec.CommandContext(t.Context(), "go", "build", "-o", binary, "./cmd/custom-ibc")
cmd.Env = append(os.Environ(), "GOCACHE="+filepath.Join(t.TempDir(), "go-cache"))
output, err := cmd.CombinedOutput()
require.NoError(t, err, "build custom ibc binary:\n%s", output)

return binary
}
19 changes: 19 additions & 0 deletions e2e/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require (
)

require (
connectrpc.com/grpcreflect v1.3.0 // indirect
cosmossdk.io/api v1.0.0 // indirect
cosmossdk.io/collections v1.4.0 // indirect
cosmossdk.io/core v1.1.0 // indirect
Expand All @@ -41,6 +42,7 @@ require (
github.com/bytedance/sonic v1.15.0 // indirect
github.com/bytedance/sonic/loader v0.5.1 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cloudflare/circl v1.6.3 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/cockroachdb/crlib v0.0.0-20241112164430-1264a2edc35b // indirect
github.com/cockroachdb/errors v1.13.0 // indirect
Expand Down Expand Up @@ -69,6 +71,7 @@ require (
github.com/danieljoos/wincred v1.2.3 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/dchest/siphash v1.2.3 // indirect
github.com/deliveryhero/pipeline/v2 v2.2.0 // indirect
github.com/desertbit/timer v1.0.1 // indirect
github.com/dgraph-io/badger/v4 v4.9.1 // indirect
github.com/dgraph-io/ristretto/v2 v2.4.0 // indirect
Expand All @@ -82,10 +85,12 @@ require (
github.com/fjl/jsonw v0.1.0 // indirect
github.com/flynn/noise v1.1.0 // indirect
github.com/getsentry/sentry-go v0.46.0 // indirect
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
github.com/go-kit/kit v0.13.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.1 // indirect
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.12.1 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
Expand Down Expand Up @@ -122,6 +127,10 @@ require (
github.com/improbable-eng/grpc-web v0.15.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/ipfs/go-cid v0.5.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.10.0 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
Expand Down Expand Up @@ -164,6 +173,7 @@ require (
github.com/multiformats/go-multistream v0.6.1 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20251114093237-2ab5a27a1729 // indirect
github.com/oklog/run v1.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
Expand Down Expand Up @@ -198,9 +208,11 @@ require (
github.com/quic-go/quic-go v0.60.0 // indirect
github.com/quic-go/webtransport-go v0.11.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/rs/cors v1.11.1 // indirect
github.com/rs/zerolog v1.35.0 // indirect
github.com/rubenv/sql-migrate v1.8.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sasha-s/go-deadlock v0.3.9 // indirect
Expand All @@ -211,6 +223,7 @@ require (
github.com/spf13/cobra v1.10.2 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/spf13/viper v1.21.0 // indirect
github.com/stretchr/objx v0.5.3 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
Expand Down Expand Up @@ -271,6 +284,10 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
gotest.tools/v3 v3.5.2 // indirect
lukechampine.com/blake3 v1.4.1 // indirect
modernc.org/libc v1.73.4 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.53.0 // indirect
nhooyr.io/websocket v1.8.17 // indirect
pgregory.net/rapid v1.3.0 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
Expand Down Expand Up @@ -347,3 +364,5 @@ require (
)

replace github.com/cosmos/ibc/link => ../link

replace github.com/cometbft/cometbft => github.com/cometbft/cometbft v0.39.0-rc1.0.20260615134937-9ea34470f336
Loading