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
8 changes: 4 additions & 4 deletions .github/workflows/migration_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
fetch-depth: 1

- name: Log in to GHCR
uses: docker/login-action@v4
Expand Down Expand Up @@ -107,7 +107,7 @@ jobs:
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
fetch-depth: 1

- name: Log in to GHCR
uses: docker/login-action@v4
Expand Down Expand Up @@ -152,7 +152,7 @@ jobs:
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
fetch-depth: 1

- name: Set up Go
uses: actions/setup-go@v6
Expand Down Expand Up @@ -194,7 +194,7 @@ jobs:
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
fetch-depth: 1

- name: Set up Go
uses: actions/setup-go@v6
Expand Down
1 change: 1 addition & 0 deletions tests/integration/docker/Dockerfile.gm
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ RUN chmod +x /workspace/patch-app-wiring.sh && \
# Align module versions like in CI
RUN go mod edit -replace github.com/evstack/ev-node=github.com/evstack/ev-node@${EVNODE_VERSION} \
&& go mod edit -replace github.com/evstack/ev-abci=../ev-abci \
&& go mod edit -replace github.com/bytedance/sonic=github.com/bytedance/sonic@v1.15.0 \
&& go mod tidy

# Build gmd binary
Expand Down
12 changes: 12 additions & 0 deletions tests/integration/docker/patches/app-wiring/patch-app-wiring.sh
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,18 @@ func (app *App) GetNetworkKeeper() networkkeeper.Keeper {
EOF
fi

# Add BlockID provider setter (required by ev-abci server wiring)
if ! grep -q "SetNetworkKeeperBlockIDProvider" "$APP_GO"; then
echo "[patch-app-wiring] Adding SetNetworkKeeperBlockIDProvider method"
add_import "$APP_GO" $'\tnetworktypes "github.com/evstack/ev-abci/modules/network/types"'
cat >>"$APP_GO" <<'EOF'

func (app *App) SetNetworkKeeperBlockIDProvider(p networktypes.BlockIDProvider) {
app.NetworkKeeper.SetBlockIDProvider(p)
}
EOF
fi

echo "[patch-app-wiring] Step 5: Final validation"

# Validate critical components
Expand Down
116 changes: 115 additions & 1 deletion tests/integration/gm_gaia_health_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package integration_test

import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"strings"
"testing"
"time"

Expand All @@ -16,6 +18,8 @@ import (
"github.com/celestiaorg/tastora/framework/testutil/sdkacc"
"github.com/celestiaorg/tastora/framework/testutil/wait"
"github.com/celestiaorg/tastora/framework/types"
cmted25519 "github.com/cometbft/cometbft/crypto/ed25519"
cmttypes "github.com/cometbft/cometbft/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module/testutil"
Expand Down Expand Up @@ -94,6 +98,53 @@ func (s *DockerIntegrationTestSuite) TestAttesterSystem() {
require.NoError(s.T(), err)
s.T().Log("Attester node started successfully")

// Wait for the attester to attest some blocks and LastAttestedHeight to advance.
s.T().Log("Waiting for attestations to reach quorum...")
var targetHeight int64 = 10
err = wait.ForCondition(ctx, 2*time.Minute, 2*time.Second, func() (bool, error) {
node := gmChain.GetNodes()[0]
rpcClient, _ := node.GetRPCClient()
if rpcClient == nil {
return false, nil
}
status, statusErr := rpcClient.Status(ctx)
if statusErr != nil {
return false, nil
}
return status.SyncInfo.LatestBlockHeight >= targetHeight, nil
})
s.Require().NoError(err, "chain did not reach target height %d", targetHeight)

// Fetch /commit for the target height and assert VerifyCommitLight passes.
{
node := gmChain.GetNodes()[0]
rpcClient, err := node.GetRPCClient()
s.Require().NoError(err)
commitResp, err := rpcClient.Commit(ctx, &targetHeight)
s.Require().NoError(err, "fetch commit at height %d", targetHeight)

privValJSONBz, err := node.ReadFile(ctx, "config/priv_validator_key.json")
s.Require().NoError(err)
var pv struct {
PubKey struct {
Type string `json:"type"`
Value string `json:"value"`
} `json:"pub_key"`
}
s.Require().NoError(json.Unmarshal(privValJSONBz, &pv))
pkBytes, err := base64.StdEncoding.DecodeString(pv.PubKey.Value)
s.Require().NoError(err)
cmtPub := cmted25519.PubKey(pkBytes)
valSet := cmttypes.NewValidatorSet([]*cmttypes.Validator{cmttypes.NewValidator(cmtPub, 1)})

commit := commitResp.SignedHeader.Commit
s.Require().NoError(
valSet.VerifyCommitLight("gm", commit.BlockID, targetHeight, commit),
"reconstructed commit must pass 07-tendermint light-client verification",
)
s.T().Logf("commit at height %d passes VerifyCommitLight with %d signatures", targetHeight, len(commit.Signatures))
}

hermes, err := relayer.NewHermes(ctx, s.dockerClient, s.T().Name(), s.networkID, 0, s.logger)
require.NoError(s.T(), err, "failed to create hermes relayer")

Expand Down Expand Up @@ -256,7 +307,7 @@ func (s *DockerIntegrationTestSuite) getGmChain(ctx context.Context) *cosmos.Cha
"--log_level", "*:info",
).
WithNode(cosmos.NewChainNodeConfigBuilder().
WithPostInit(AddSingleSequencer, writePasshraseFile("12345678")).
WithPostInit(AddSingleSequencer, AddGenesisAttester, writePasshraseFile("12345678")).
Build()).
Build(ctx)
require.NoError(s.T(), err)
Expand Down Expand Up @@ -305,6 +356,69 @@ func AddSingleSequencer(ctx context.Context, node *cosmos.ChainNode) error {
return node.WriteFile(ctx, "config/genesis.json", updatedGenesis)
}

// AddGenesisAttester populates app_state.network.attester_infos with a single
// attester entry derived from the node's priv_validator_key.json and the
// operator address of the "validator" keyring entry.
func AddGenesisAttester(ctx context.Context, node *cosmos.ChainNode) error {
genesisBz, err := node.ReadFile(ctx, "config/genesis.json")
if err != nil {
return fmt.Errorf("read genesis: %w", err)
}

pubKey, err := getPubKey(ctx, node)
if err != nil {
return fmt.Errorf("get consensus pubkey: %w", err)
}

// Consensus address (cosmosvalcons1... derived from ed25519 Address())
consensusAddress := sdk.ConsAddress(pubKey.Address()).String()

// Operator address: run `gmd keys show validator -a` inside the node container.
stdout, stderr, err := node.Exec(ctx, []string{
node.BinaryName,
"keys", "show", "validator", "-a",
"--keyring-backend", "test",
"--home", node.HomeDir(),
}, nil)
if err != nil {
return fmt.Errorf("query validator operator address (stderr=%q): %w", string(stderr), err)
}
authority := strings.TrimSpace(string(stdout))
if authority == "" {
return fmt.Errorf("empty operator address for validator keyring entry")
}

attesterInfo := map[string]interface{}{
"authority": authority,
"pubkey": map[string]interface{}{
"@type": "/cosmos.crypto.ed25519.PubKey",
"key": base64.StdEncoding.EncodeToString(pubKey.Bytes()),
},
"joined_height": 0,
"consensus_address": consensusAddress,
}

var genDoc map[string]interface{}
if err := json.Unmarshal(genesisBz, &genDoc); err != nil {
return fmt.Errorf("parse genesis: %w", err)
}
appState, ok := genDoc["app_state"].(map[string]interface{})
if !ok {
return fmt.Errorf("genesis has no app_state object")
}
network, ok := appState["network"].(map[string]interface{})
if !ok {
return fmt.Errorf("genesis has no app_state.network object")
}
network["attester_infos"] = []interface{}{attesterInfo}

updatedBz, err := json.MarshalIndent(genDoc, "", " ")
if err != nil {
return fmt.Errorf("marshal genesis: %w", err)
}
return node.WriteFile(ctx, "config/genesis.json", updatedBz)
}

// setupIBCConnection establishes a complete IBC connection and channel
func setupIBCConnection(t *testing.T, ctx context.Context, chainA, chainB types.Chain, hermes *relayer.Hermes) (ibc.Connection, ibc.Channel) {
err := hermes.CreateClients(ctx, chainA, chainB)
Expand Down
Loading