From a2afe2aff148560654fdf6b4ac1f1fcdce93d369 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 10:41:42 +0200 Subject: [PATCH 01/13] feat(rpc): implement block results endpoint --- .github/workflows/integration_test.yml | 7 ++- pkg/adapter/adapter.go | 75 ++++++++++++------------- pkg/rpc/core/blocks.go | 76 ++++++++++++++------------ pkg/rpc/core/consensus.go | 14 ++++- pkg/rpc/core/utils.go | 32 ++++------- 5 files changed, 106 insertions(+), 98 deletions(-) diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index a18bd930..9910dc32 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -348,8 +348,11 @@ jobs: sleep 20 BALANCE=$(celestia-appd query bank balances $CELESTIA_ADDR --output json --node http://localhost:26654 | jq '.balances') echo "Celestia balance after IBC transfer: $BALANCE" - # TODO: check that the balance is correct - # ref: https://github.com/rollkit/go-execution-abci/pull/138#discussion_r2156332760 + # fail if no denom starts with ibc/ + if ! echo "$BALANCE" | jq -e '.[] | select(.denom | startswith("ibc/"))' > /dev/null; then + echo "Error: No IBC denom found in balance after transfer!" + exit 1 + fi - name: ICS20 Transfer Celestia -> Rollkit run: | diff --git a/pkg/adapter/adapter.go b/pkg/adapter/adapter.go index 80902c5a..a61608cb 100644 --- a/pkg/adapter/adapter.go +++ b/pkg/adapter/adapter.go @@ -302,40 +302,9 @@ func (a *Adapter) ExecuteTxs( return nil, 0, fmt.Errorf("rollkit header not found in context") } - var proposedLastCommit abci.CommitInfo - var lastCommit *cmttypes.Commit - - if blockHeight > 1 { - header, data, err := a.RollkitStore.GetBlockData(ctx, blockHeight-1) - if err != nil { - return nil, 0, fmt.Errorf("failed to get previous block data: %w", err) - } - - commitForPrevBlock := &cmttypes.Commit{ - Height: int64(header.Height()), - Round: 0, - BlockID: cmttypes.BlockID{Hash: bytes.HexBytes(header.Hash()), PartSetHeader: cmttypes.PartSetHeader{Total: 1, Hash: bytes.HexBytes(data.Hash())}}, - Signatures: []cmttypes.CommitSig{ - { - BlockIDFlag: cmttypes.BlockIDFlagCommit, - ValidatorAddress: cmttypes.Address(header.ProposerAddress), - Timestamp: header.Time(), - Signature: header.Signature, - }, - }, - } - - lastCommit = commitForPrevBlock - proposedLastCommit = cometCommitToABCICommitInfo(commitForPrevBlock) - } else { - // For the first block, ProposedLastCommit is empty - proposedLastCommit = abci.CommitInfo{Round: 0, Votes: []abci.VoteInfo{}} - lastCommit = &cmttypes.Commit{ - Height: int64(blockHeight), - Round: 0, - BlockID: cmttypes.BlockID{}, - Signatures: []cmttypes.CommitSig{}, - } + lastCommit, err := a.getLastCommit(ctx, blockHeight) + if err != nil { + return nil, 0, fmt.Errorf("failed to get last commit: %w", err) } emptyBlock, err := cometcompat.ToABCIBlock(header, &types.Data{}, lastCommit) @@ -348,7 +317,7 @@ func (a *Adapter) ExecuteTxs( Height: int64(blockHeight), Time: timestamp, Txs: txs, - ProposedLastCommit: proposedLastCommit, + ProposedLastCommit: cometCommitToABCICommitInfo(lastCommit), Misbehavior: []abci.Misbehavior{}, ProposerAddress: s.Validators.Proposer.Address, NextValidatorsHash: s.NextValidators.Hash(), @@ -619,14 +588,39 @@ func (a *Adapter) SetFinal(ctx context.Context, blockHeight uint64) error { return nil } -func cometCommitToABCICommitInfo(commit *cmttypes.Commit) abci.CommitInfo { - if commit == nil { - return abci.CommitInfo{ - Round: 0, - Votes: []abci.VoteInfo{}, +func (a *Adapter) getLastCommit(ctx context.Context, blockHeight uint64) (*cmttypes.Commit, error) { + if blockHeight > 1 { + header, data, err := a.RollkitStore.GetBlockData(ctx, blockHeight-1) + if err != nil { + return nil, fmt.Errorf("failed to get previous block data: %w", err) } + + commitForPrevBlock := &cmttypes.Commit{ + Height: int64(header.Height()), + Round: 0, + BlockID: cmttypes.BlockID{Hash: bytes.HexBytes(header.Hash()), PartSetHeader: cmttypes.PartSetHeader{Total: 1, Hash: bytes.HexBytes(data.Hash())}}, + Signatures: []cmttypes.CommitSig{ + { + BlockIDFlag: cmttypes.BlockIDFlagCommit, + ValidatorAddress: cmttypes.Address(header.ProposerAddress), + Timestamp: header.Time(), + Signature: header.Signature, + }, + }, + } + + return commitForPrevBlock, nil } + return &cmttypes.Commit{ + Height: int64(blockHeight), + Round: 0, + BlockID: cmttypes.BlockID{}, + Signatures: []cmttypes.CommitSig{}, + }, nil +} + +func cometCommitToABCICommitInfo(commit *cmttypes.Commit) abci.CommitInfo { if len(commit.Signatures) == 0 { return abci.CommitInfo{ Round: commit.Round, @@ -644,6 +638,7 @@ func cometCommitToABCICommitInfo(commit *cmttypes.Commit) abci.CommitInfo { BlockIdFlag: cmtprototypes.BlockIDFlag(sig.BlockIDFlag), } } + return abci.CommitInfo{ Round: commit.Round, Votes: votes, diff --git a/pkg/rpc/core/blocks.go b/pkg/rpc/core/blocks.go index 688f5569..09df2c18 100644 --- a/pkg/rpc/core/blocks.go +++ b/pkg/rpc/core/blocks.go @@ -98,7 +98,10 @@ func BlockSearch( // If no height is provided, it will fetch the latest block. // More: https://docs.cometbft.com/v0.37/rpc/#/Info/block func Block(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlock, error) { - var heightValue uint64 + var ( + heightValue uint64 + err error + ) switch { case heightPtr != nil && *heightPtr == -1: @@ -116,7 +119,10 @@ func Block(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlock, error) heightValue = binary.LittleEndian.Uint64(rawVal) default: - heightValue = normalizeHeight(heightPtr) + heightValue, err = normalizeHeight(ctx.Context(), heightPtr) + if err != nil { + return nil, err + } } header, data, err := env.Adapter.RollkitStore.GetBlockData(ctx.Context(), heightValue) @@ -204,9 +210,12 @@ func BlockByHash(ctx *rpctypes.Context, hash []byte) (*ctypes.ResultBlock, error // If no height is provided, it will fetch the commit for the latest block. // More: https://docs.cometbft.com/main/rpc/#/Info/commit func Commit(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultCommit, error) { - wrappedCtx := ctx.Context() - heightValue := normalizeHeight(heightPtr) - header, rollkitData, err := env.Adapter.RollkitStore.GetBlockData(wrappedCtx, heightValue) + height, err := normalizeHeight(ctx.Context(), heightPtr) + if err != nil { + return nil, err + } + + header, rollkitData, err := env.Adapter.RollkitStore.GetBlockData(ctx.Context(), height) if err != nil { return nil, err } @@ -275,41 +284,40 @@ func Commit(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultCommit, erro // BlockResults is not fully implemented as in FullClient because // env.Adapter.RollkitStore (pkg/store.Store) does not provide GetBlockResponses method. func BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockResults, error) { - // var h uint64 - // var err error - // if heightPtr == nil { - // h, err = env.Adapter.RollkitStore.Height(ctx.Context()) - // if err != nil { - // return nil, err - // } - // } else { - // h = uint64(*heightPtr) - // } - // header, _, err := env.Adapter.RollkitStore.GetBlockData(ctx.Context(), h) - // if err != nil { - // return nil, err - // } - // resp, err := env.Adapter.Store.GetBlockResponses(ctx.Context(), h) - // if err != nil { - // return nil, err - // } - - // return &ctypes.ResultBlockResults{ - // Height: int64(h), //nolint:gosec - // TxsResults: resp.TxResults, - // FinalizeBlockEvents: resp.Events, - // ValidatorUpdates: resp.ValidatorUpdates, - // ConsensusParamUpdates: resp.ConsensusParamUpdates, - // AppHash: header.Header.AppHash, - // }, nil - return nil, errors.New("BlockResults not implemented") + height, err := normalizeHeight(ctx.Context(), heightPtr) + if err != nil { + return nil, err + } + + header, _, err := env.Adapter.RollkitStore.GetBlockData(ctx.Context(), height) + if err != nil { + return nil, err + } + + resp, err := env.Adapter.Store.GetBlockResponses(ctx.Context(), height) + if err != nil { + return nil, err + } + + return &ctypes.ResultBlockResults{ + Height: int64(height), + TxsResults: resp.TxResults, + FinalizeBlockEvents: resp.Events, + ValidatorUpdates: resp.ValidatorUpdates, + ConsensusParamUpdates: resp.ConsensusParamUpdates, + AppHash: header.Header.AppHash, + }, nil } // Header gets block header at a given height. // If no height is provided, it will fetch the latest header. // More: https://docs.cometbft.com/v0.37/rpc/#/Info/header func Header(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultHeader, error) { - height := normalizeHeight(heightPtr) + height, err := normalizeHeight(ctx.Context(), heightPtr) + if err != nil { + return nil, err + } + blockMeta := getBlockMeta(ctx.Context(), height) if blockMeta == nil { return nil, fmt.Errorf("block at height %d not found", height) diff --git a/pkg/rpc/core/consensus.go b/pkg/rpc/core/consensus.go index 131eab5d..a6750d6d 100644 --- a/pkg/rpc/core/consensus.go +++ b/pkg/rpc/core/consensus.go @@ -16,7 +16,11 @@ import ( // // More: https://docs.cometbft.com/v0.37/rpc/#/Info/validators func Validators(ctx *rpctypes.Context, heightPtr *int64, pagePtr, perPagePtr *int) (*coretypes.ResultValidators, error) { - height := normalizeHeight(heightPtr) + height, err := normalizeHeight(ctx.Context(), heightPtr) + if err != nil { + return nil, fmt.Errorf("failed to normalize height: %w", err) + } + genesisValidators := env.Adapter.AppGenesis.Consensus.Validators if len(genesisValidators) != 1 { @@ -62,13 +66,19 @@ func ConsensusState(ctx *rpctypes.Context) (*coretypes.ResultConsensusState, err // If no height is provided, it will fetch the latest consensus params. // More: https://docs.cometbft.com/v0.37/rpc/#/Info/consensus_params func ConsensusParams(ctx *rpctypes.Context, heightPtr *int64) (*coretypes.ResultConsensusParams, error) { + height, err := normalizeHeight(ctx.Context(), heightPtr) + if err != nil { + return nil, fmt.Errorf("failed to normalize height: %w", err) + } + state, err := env.Adapter.Store.LoadState(ctx.Context()) if err != nil { return nil, err } + params := state.ConsensusParams return &coretypes.ResultConsensusParams{ - BlockHeight: int64(normalizeHeight(heightPtr)), //nolint:gosec + BlockHeight: int64(height), //nolint:gosec ConsensusParams: cmttypes.ConsensusParams{ Block: cmttypes.BlockParams{ MaxBytes: params.Block.MaxBytes, diff --git a/pkg/rpc/core/utils.go b/pkg/rpc/core/utils.go index 210011d5..88821cca 100644 --- a/pkg/rpc/core/utils.go +++ b/pkg/rpc/core/utils.go @@ -19,32 +19,24 @@ import ( const NodeIDByteLength = 20 -func normalizeHeight(height *int64) uint64 { - var heightValue uint64 - if height == nil { - var err error - // TODO: Decide how to handle context here. Using background for now. - heightValue, err = env.Adapter.RollkitStore.Height(context.Background()) +func normalizeHeight(ctx context.Context, height *int64) (uint64, error) { + var ( + heightValue uint64 + err error + ) + + if height == nil || *height < 0 { + // Handle negative heights if they have special meaning + // (e.g., -1 for latest) + heightValue, err = env.Adapter.RollkitStore.Height(ctx) if err != nil { - // TODO: Consider logging or returning error - env.Logger.Error("Failed to get current height in normalizeHeight", "err", err) - return 0 - } - } else if *height < 0 { - // Handle negative heights if they have special meaning (e.g., -1 for latest) - // Currently, just treat them as 0 or latest, adjust as needed. - // For now, let's assume negative height means latest valid height. - var err error - heightValue, err = env.Adapter.RollkitStore.Height(context.Background()) - if err != nil { - env.Logger.Error("Failed to get current height for negative height in normalizeHeight", "err", err) - return 0 + return 0, fmt.Errorf("failed to get current height: %w", err) } } else { heightValue = uint64(*height) } - return heightValue + return heightValue, nil } func getLastCommit(ctx context.Context, blockHeight uint64) (*cmttypes.Commit, error) { From 65fccb36583b5c4b1f653023e78e679f87121331 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 10:56:51 +0200 Subject: [PATCH 02/13] updates --- pkg/adapter/adapter.go | 45 +++++++++++----------------------- pkg/adapter/store.go | 40 ++++++++++++++++++++++++++++-- pkg/adapter/store_test.go | 2 +- pkg/rpc/core/blocks.go | 6 ++--- pkg/rpc/core/consensus_test.go | 2 +- 5 files changed, 57 insertions(+), 38 deletions(-) diff --git a/pkg/adapter/adapter.go b/pkg/adapter/adapter.go index a61608cb..ccbfb9dd 100644 --- a/pkg/adapter/adapter.go +++ b/pkg/adapter/adapter.go @@ -8,7 +8,7 @@ import ( "cosmossdk.io/log" abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/config" + cmtcfg "github.com/cometbft/cometbft/config" "github.com/cometbft/cometbft/libs/bytes" "github.com/cometbft/cometbft/mempool" corep2p "github.com/cometbft/cometbft/p2p" @@ -44,7 +44,7 @@ type P2PClientInfo interface { } // LoadGenesisDoc returns the genesis document from the provided config file. -func LoadGenesisDoc(cfg *config.Config) (*cmttypes.GenesisDoc, error) { +func LoadGenesisDoc(cfg *cmtcfg.Config) (*cmttypes.GenesisDoc, error) { genesisFile := cfg.GenesisFile() doc, err := cmttypes.GenesisDocFromFile(genesisFile) if err != nil { @@ -80,7 +80,7 @@ func NewABCIExecutor( p2pClient *rollkitp2p.Client, p2pMetrics *rollkitp2p.Metrics, logger log.Logger, - cfg *config.Config, + cfg *cmtcfg.Config, appGenesis *genutiltypes.AppGenesis, metrics *Metrics, ) *Adapter { @@ -93,8 +93,8 @@ func NewABCIExecutor( Prefix: ds.NewKey(rollnode.RollkitPrefix), }) rollkitStore := rstore.New(rollkitPrefixStore) - // Create a new Store with ABCI prefix - abciStore := NewStore(store) + + abciStore := NewExecABCIStore(store) a := &Adapter{ App: app, @@ -433,46 +433,29 @@ func (a *Adapter) ExecuteTxs( cmtTxs[i] = txs[i] } - commit := &cmttypes.Commit{ - Height: int64(blockHeight), - Round: 0, - Signatures: []cmttypes.CommitSig{ + // if blockheight is 0, we create a signed last commit. + if blockHeight == 0 { + lastCommit.Signatures = []cmttypes.CommitSig{ { BlockIDFlag: cmttypes.BlockIDFlagCommit, ValidatorAddress: s.Validators.Proposer.Address, Timestamp: time.Now().UTC(), Signature: []byte{}, }, - }, - } - - if blockHeight > 1 { - header, data, err := a.RollkitStore.GetBlockData(ctx, blockHeight-1) - if err != nil { - return nil, 0, fmt.Errorf("failed to get previous block data: %w", err) - } - - commit = &cmttypes.Commit{ - Height: int64(header.Height()), - Round: 0, - BlockID: cmttypes.BlockID{Hash: bytes.HexBytes(header.Hash()), PartSetHeader: cmttypes.PartSetHeader{Total: 1, Hash: bytes.HexBytes(data.Hash())}}, - Signatures: []cmttypes.CommitSig{ - { - BlockIDFlag: cmttypes.BlockIDFlagCommit, - ValidatorAddress: cmttypes.Address(header.ProposerAddress), - Timestamp: header.Time(), - Signature: header.Signature, - }, - }, } } - block := s.MakeBlock(int64(blockHeight), cmtTxs, commit, nil, s.Validators.Proposer.Address) + block := s.MakeBlock(int64(blockHeight), cmtTxs, lastCommit, nil, s.Validators.Proposer.Address) currentBlockID := cmttypes.BlockID{Hash: block.Hash(), PartSetHeader: cmttypes.PartSetHeader{Total: 1, Hash: block.DataHash}} fireEvents(a.Logger, a.EventBus, block, currentBlockID, fbResp, validatorUpdates) + // save the finalized block response + if err := a.Store.SaveBlockResponse(ctx, blockHeight, fbResp); err != nil { + return nil, 0, fmt.Errorf("failed to save block response: %w", err) + } + a.Logger.Info("block executed successfully", "height", blockHeight, "appHash", fmt.Sprintf("%X", fbResp.AppHash)) return fbResp.AppHash, uint64(s.ConsensusParams.Block.MaxBytes), nil } diff --git a/pkg/adapter/store.go b/pkg/adapter/store.go index 5b8740f4..1b61355d 100644 --- a/pkg/adapter/store.go +++ b/pkg/adapter/store.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + abci "github.com/cometbft/cometbft/abci/types" cmtstateproto "github.com/cometbft/cometbft/proto/tendermint/state" cmtstate "github.com/cometbft/cometbft/state" proto "github.com/cosmos/gogoproto/proto" @@ -16,6 +17,8 @@ const ( keyPrefix = "abci" // stateKey is the key used for storing state stateKey = "s" + // blockResponseKey is the key used for storing block responses + blockResponseKey = "br" ) // Store wraps a datastore with ABCI-specific functionality @@ -23,8 +26,9 @@ type Store struct { prefixedStore ds.Batching } -// NewStore creates a new Store with the ABCI prefix -func NewStore(store ds.Batching) *Store { +// NewABCIStore creates a new Store with the ABCI prefix. +// The data is stored under rollkit database and not in the app's database. +func NewExecABCIStore(store ds.Batching) *Store { return &Store{ prefixedStore: kt.Wrap(store, &kt.PrefixTransform{ Prefix: ds.NewKey(keyPrefix), @@ -64,3 +68,35 @@ func (s *Store) SaveState(ctx context.Context, state *cmtstate.State) error { return s.prefixedStore.Put(ctx, ds.NewKey(stateKey), data) } + +// SaveBlockResponse saves the block response to disk per height +// This is used to store the results of the block execution +// so that they can be retrieved later, e.g., for querying transaction results. +func (s *Store) SaveBlockResponse(ctx context.Context, height uint64, resp *abci.ResponseFinalizeBlock) error { + data, err := proto.Marshal(resp) + if err != nil { + return fmt.Errorf("failed to marshal block response: %w", err) + } + + key := fmt.Sprintf("%s/%d", blockResponseKey, height) + return s.prefixedStore.Put(ctx, ds.NewKey(key), data) +} + +// LoadBlockResponse loads the block response from disk for a specific height +func (s *Store) LoadBlockResponse(ctx context.Context, height uint64) (*abci.ResponseFinalizeBlock, error) { + key := fmt.Sprintf("%s/%d", blockResponseKey, height) + data, err := s.prefixedStore.Get(ctx, ds.NewKey(key)) + if err != nil { + return nil, fmt.Errorf("failed to get block response: %w", err) + } + if data == nil { + return nil, nil + } + + resp := &abci.ResponseFinalizeBlock{} + if err := proto.Unmarshal(data, resp); err != nil { + return nil, fmt.Errorf("failed to unmarshal block response: %w", err) + } + + return resp, nil +} diff --git a/pkg/adapter/store_test.go b/pkg/adapter/store_test.go index 4261bf44..ef0020d9 100644 --- a/pkg/adapter/store_test.go +++ b/pkg/adapter/store_test.go @@ -14,7 +14,7 @@ import ( func TestStateIO(t *testing.T) { db := ds.NewMapDatastore() - abciStore := NewStore(db) + abciStore := NewExecABCIStore(db) myState := stateFixture() require.NoError(t, abciStore.SaveState(t.Context(), myState)) gotState, gotErr := abciStore.LoadState(t.Context()) diff --git a/pkg/rpc/core/blocks.go b/pkg/rpc/core/blocks.go index 09df2c18..811f4181 100644 --- a/pkg/rpc/core/blocks.go +++ b/pkg/rpc/core/blocks.go @@ -281,8 +281,8 @@ func Commit(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultCommit, erro }, nil } -// BlockResults is not fully implemented as in FullClient because -// env.Adapter.RollkitStore (pkg/store.Store) does not provide GetBlockResponses method. +// BlockResults gets block results at a given height. +// If no height is provided, it will fetch the results for the latest block. func BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockResults, error) { height, err := normalizeHeight(ctx.Context(), heightPtr) if err != nil { @@ -294,7 +294,7 @@ func BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockR return nil, err } - resp, err := env.Adapter.Store.GetBlockResponses(ctx.Context(), height) + resp, err := env.Adapter.Store.LoadBlockResponse(ctx.Context(), height) if err != nil { return nil, err } diff --git a/pkg/rpc/core/consensus_test.go b/pkg/rpc/core/consensus_test.go index 49971607..79ba160b 100644 --- a/pkg/rpc/core/consensus_test.go +++ b/pkg/rpc/core/consensus_test.go @@ -113,7 +113,7 @@ func setupTestConsensusParamsEnv(t *testing.T, useMockRollkitStore bool, stateTo } dsStore := ds.NewMapDatastore() - abciStore := adapter.NewStore(dsStore) + abciStore := adapter.NewExecABCIStore(dsStore) if stateToSave != nil { err := abciStore.SaveState(context.Background(), stateToSave) From abef6cae398f38e729025acb5bcdd13482a69957 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 11:02:05 +0200 Subject: [PATCH 03/13] linting --- pkg/adapter/adapter.go | 124 +++++++++++++++++++++-------------------- pkg/rpc/core/blocks.go | 2 +- 2 files changed, 66 insertions(+), 60 deletions(-) diff --git a/pkg/adapter/adapter.go b/pkg/adapter/adapter.go index ccbfb9dd..cd80f1cc 100644 --- a/pkg/adapter/adapter.go +++ b/pkg/adapter/adapter.go @@ -447,9 +447,14 @@ func (a *Adapter) ExecuteTxs( block := s.MakeBlock(int64(blockHeight), cmtTxs, lastCommit, nil, s.Validators.Proposer.Address) - currentBlockID := cmttypes.BlockID{Hash: block.Hash(), PartSetHeader: cmttypes.PartSetHeader{Total: 1, Hash: block.DataHash}} + currentBlockID := cmttypes.BlockID{ + Hash: block.Hash(), + PartSetHeader: cmttypes.PartSetHeader{Total: 1, Hash: block.DataHash}, + } - fireEvents(a.Logger, a.EventBus, block, currentBlockID, fbResp, validatorUpdates) + if err := fireEvents(a.EventBus, block, currentBlockID, fbResp, validatorUpdates); err != nil { + a.Logger.Error("failed to fire events", "err", err) + } // save the finalized block response if err := a.Store.SaveBlockResponse(ctx, blockHeight, fbResp); err != nil { @@ -461,25 +466,24 @@ func (a *Adapter) ExecuteTxs( } func fireEvents( - logger log.Logger, eventBus cmttypes.BlockEventPublisher, block *cmttypes.Block, blockID cmttypes.BlockID, abciResponse *abci.ResponseFinalizeBlock, validatorUpdates []*cmttypes.Validator, -) { +) error { if err := eventBus.PublishEventNewBlock(cmttypes.EventDataNewBlock{ Block: block, BlockID: blockID, ResultFinalizeBlock: *abciResponse, }); err != nil { - logger.Error("failed publishing new block", "err", err) + return fmt.Errorf("failed publishing new block: %w", err) } if err := eventBus.PublishEventNewBlockHeader(cmttypes.EventDataNewBlockHeader{ Header: block.Header, }); err != nil { - logger.Error("failed publishing new block header", "err", err) + return fmt.Errorf("failed publishing new block header: %w", err) } if err := eventBus.PublishEventNewBlockEvents(cmttypes.EventDataNewBlockEvents{ @@ -487,7 +491,7 @@ func fireEvents( Events: abciResponse.Events, NumTxs: int64(len(block.Txs)), }); err != nil { - logger.Error("failed publishing new block events", "err", err) + return fmt.Errorf("failed publishing new block events: %w", err) } if len(block.Evidence.Evidence) != 0 { @@ -496,7 +500,7 @@ func fireEvents( Evidence: ev, Height: block.Height, }); err != nil { - logger.Error("failed publishing new evidence", "err", err) + return fmt.Errorf("failed publishing new evidence: %w", err) } } } @@ -508,66 +512,17 @@ func fireEvents( Tx: tx, Result: *(abciResponse.TxResults[i]), }}); err != nil { - logger.Error("failed publishing event TX", "err", err) + return fmt.Errorf("failed publishing event TX: %w", err) } } if len(validatorUpdates) > 0 { if err := eventBus.PublishEventValidatorSetUpdates( cmttypes.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates}); err != nil { - logger.Error("failed publishing event", "err", err) + return fmt.Errorf("failed publishing event: %w", err) } } -} - -// GetTxs calls PrepareProposal with the next height from the store and returns the transactions from the ABCI app -func (a *Adapter) GetTxs(ctx context.Context) ([][]byte, error) { - getTxsStart := time.Now() - defer func() { - a.Metrics.GetTxsDurationSeconds.Observe(time.Since(getTxsStart).Seconds()) - }() - a.Logger.Debug("Getting transactions for proposal") - - s, err := a.Store.LoadState(ctx) - if err != nil { - return nil, fmt.Errorf("failed to load state for GetTxs: %w", err) - } - - if a.Mempool == nil { - err := fmt.Errorf("mempool not initialized") - return nil, err - } - - reapedTxs := a.Mempool.ReapMaxBytesMaxGas(int64(s.ConsensusParams.Block.MaxBytes), -1) - txsBytes := make([][]byte, len(reapedTxs)) - for i, tx := range reapedTxs { - txsBytes[i] = tx - } - - currentHeight, err := a.RollkitStore.Height(ctx) - if err != nil { - return nil, err - } - - resp, err := a.App.PrepareProposal(&abci.RequestPrepareProposal{ - Txs: txsBytes, - MaxTxBytes: int64(s.ConsensusParams.Block.MaxBytes), - Height: int64(currentHeight + 1), - Time: time.Now(), - NextValidatorsHash: s.NextValidators.Hash(), - ProposerAddress: s.Validators.Proposer.Address, - }) - if err != nil { - return nil, err - } - a.Metrics.TxsProposedTotal.Add(float64(len(resp.Txs))) - return resp.Txs, nil -} - -// SetFinal handles extra logic once the block has been finalized (posted to DA). -// For a Cosmos SDK app, this is a no-op we do not need to do anything to mark the block as finalized. -func (a *Adapter) SetFinal(ctx context.Context, blockHeight uint64) error { return nil } @@ -627,3 +582,54 @@ func cometCommitToABCICommitInfo(commit *cmttypes.Commit) abci.CommitInfo { Votes: votes, } } + +// GetTxs calls PrepareProposal with the next height from the store and returns the transactions from the ABCI app +func (a *Adapter) GetTxs(ctx context.Context) ([][]byte, error) { + getTxsStart := time.Now() + defer func() { + a.Metrics.GetTxsDurationSeconds.Observe(time.Since(getTxsStart).Seconds()) + }() + a.Logger.Debug("Getting transactions for proposal") + + s, err := a.Store.LoadState(ctx) + if err != nil { + return nil, fmt.Errorf("failed to load state for GetTxs: %w", err) + } + + if a.Mempool == nil { + err := fmt.Errorf("mempool not initialized") + return nil, err + } + + reapedTxs := a.Mempool.ReapMaxBytesMaxGas(int64(s.ConsensusParams.Block.MaxBytes), -1) + txsBytes := make([][]byte, len(reapedTxs)) + for i, tx := range reapedTxs { + txsBytes[i] = tx + } + + currentHeight, err := a.RollkitStore.Height(ctx) + if err != nil { + return nil, err + } + + resp, err := a.App.PrepareProposal(&abci.RequestPrepareProposal{ + Txs: txsBytes, + MaxTxBytes: int64(s.ConsensusParams.Block.MaxBytes), + Height: int64(currentHeight + 1), + Time: time.Now(), + NextValidatorsHash: s.NextValidators.Hash(), + ProposerAddress: s.Validators.Proposer.Address, + }) + if err != nil { + return nil, err + } + + a.Metrics.TxsProposedTotal.Add(float64(len(resp.Txs))) + return resp.Txs, nil +} + +// SetFinal handles extra logic once the block has been finalized (posted to DA). +// For a Cosmos SDK app, this is a no-op we do not need to do anything to mark the block as finalized. +func (a *Adapter) SetFinal(ctx context.Context, blockHeight uint64) error { + return nil +} diff --git a/pkg/rpc/core/blocks.go b/pkg/rpc/core/blocks.go index 811f4181..e75aad51 100644 --- a/pkg/rpc/core/blocks.go +++ b/pkg/rpc/core/blocks.go @@ -305,7 +305,7 @@ func BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockR FinalizeBlockEvents: resp.Events, ValidatorUpdates: resp.ValidatorUpdates, ConsensusParamUpdates: resp.ConsensusParamUpdates, - AppHash: header.Header.AppHash, + AppHash: header.AppHash, }, nil } From 4336086f38ab842889609b34134b534ddb87e69a Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 11:12:13 +0200 Subject: [PATCH 04/13] updates --- .github/workflows/ci_release.yml | 4 ++++ .github/workflows/integration_test.yml | 4 ++++ .github/workflows/test.yml | 4 ++++ pkg/adapter/store.go | 4 ++-- pkg/rpc/core/blocks.go | 2 +- pkg/rpc/core/consensus_test.go | 12 +++++++++--- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci_release.yml b/.github/workflows/ci_release.yml index 915b24e2..434d772b 100644 --- a/.github/workflows/ci_release.yml +++ b/.github/workflows/ci_release.yml @@ -23,6 +23,10 @@ on: - minor - major +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: lint: uses: ./.github/workflows/lint.yml diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index 9910dc32..bbe1db55 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -7,6 +7,10 @@ on: branches: ["main"] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: liveness: name: Test with Rollkit Chain diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b8613715..2b046956 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,6 +4,10 @@ name: Tests / Code Coverage on: workflow_call: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: go_mod_tidy_check: name: Go Mod Tidy Check diff --git a/pkg/adapter/store.go b/pkg/adapter/store.go index 1b61355d..b6fe450c 100644 --- a/pkg/adapter/store.go +++ b/pkg/adapter/store.go @@ -82,8 +82,8 @@ func (s *Store) SaveBlockResponse(ctx context.Context, height uint64, resp *abci return s.prefixedStore.Put(ctx, ds.NewKey(key), data) } -// LoadBlockResponse loads the block response from disk for a specific height -func (s *Store) LoadBlockResponse(ctx context.Context, height uint64) (*abci.ResponseFinalizeBlock, error) { +// GetBlockResponse loads the block response from disk for a specific height +func (s *Store) GetBlockResponse(ctx context.Context, height uint64) (*abci.ResponseFinalizeBlock, error) { key := fmt.Sprintf("%s/%d", blockResponseKey, height) data, err := s.prefixedStore.Get(ctx, ds.NewKey(key)) if err != nil { diff --git a/pkg/rpc/core/blocks.go b/pkg/rpc/core/blocks.go index e75aad51..45523280 100644 --- a/pkg/rpc/core/blocks.go +++ b/pkg/rpc/core/blocks.go @@ -294,7 +294,7 @@ func BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockR return nil, err } - resp, err := env.Adapter.Store.LoadBlockResponse(ctx.Context(), height) + resp, err := env.Adapter.Store.GetBlockResponse(ctx.Context(), height) if err != nil { return nil, err } diff --git a/pkg/rpc/core/consensus_test.go b/pkg/rpc/core/consensus_test.go index 79ba160b..09e7c7c7 100644 --- a/pkg/rpc/core/consensus_test.go +++ b/pkg/rpc/core/consensus_test.go @@ -287,12 +287,18 @@ func TestConsensusParams(t *testing.T) { mockRollkitStore.AssertExpectations(t) }) - t.Run("Success_HeightNormalizationReturnsZeroOnError", func(t *testing.T) { + t.Run("Error_NilHeightAndStoreError", func(t *testing.T) { mockRollkitStore, _ := setupTestConsensusParamsEnv(t, true, &testMockStateWithConsensusParams) mockRollkitStore.On("Height", testifymock.Anything).Return(uint64(0), errors.New("failed to get height")).Once() - // err := abciStore.SaveState(context.Background(), &testMockStateWithConsensusParams) // Moved to helper - // require.NoError(err) // Moved to helper + _, err := ConsensusParams(ctx, nil) + require.Error(err) + mockRollkitStore.AssertExpectations(t) + }) + + t.Run("Success_NilHeight", func(t *testing.T) { + mockRollkitStore, _ := setupTestConsensusParamsEnv(t, true, &testMockStateWithConsensusParams) + mockRollkitStore.On("Height", testifymock.Anything).Return(uint64(0), nil).Once() result, err := ConsensusParams(ctx, nil) require.NoError(err) From b87c1a4101c6e4596fde81336402ddd7741b606f Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 11:14:01 +0200 Subject: [PATCH 05/13] updates --- pkg/rpc/core/blocks.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pkg/rpc/core/blocks.go b/pkg/rpc/core/blocks.go index 45523280..d2b9dd82 100644 --- a/pkg/rpc/core/blocks.go +++ b/pkg/rpc/core/blocks.go @@ -289,11 +289,6 @@ func BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockR return nil, err } - header, _, err := env.Adapter.RollkitStore.GetBlockData(ctx.Context(), height) - if err != nil { - return nil, err - } - resp, err := env.Adapter.Store.GetBlockResponse(ctx.Context(), height) if err != nil { return nil, err @@ -305,7 +300,7 @@ func BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockR FinalizeBlockEvents: resp.Events, ValidatorUpdates: resp.ValidatorUpdates, ConsensusParamUpdates: resp.ConsensusParamUpdates, - AppHash: header.AppHash, + AppHash: resp.AppHash, }, nil } From 1d987d13e27cfee6d7eef762620ca0be3c733e80 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 11:31:45 +0200 Subject: [PATCH 06/13] query ibc tx result --- .github/workflows/integration_test.yml | 36 +++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index bbe1db55..1070abbc 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -348,8 +348,22 @@ jobs: run: | ROLLKIT_ADDR=$(./gmd/go/bin/gmd keys show carol -a --home ./gmd/.gm) CELESTIA_ADDR=$(celestia-appd keys show validator -a --keyring-backend test) - ./gmd/go/bin/gmd tx ibc-transfer transfer transfer channel-0 $CELESTIA_ADDR 100stake --from carol -y --home ./gmd/.gm - sleep 20 + + echo "Sending 100stake via IBC..." + TX_HASH=$(./gmd/go/bin/gmd tx ibc-transfer transfer transfer channel-0 $CELESTIA_ADDR 100stake --from carol -y --home ./gmd/.gm --output json | jq -r .txhash) + + sleep 3 + + # query the transaction + TX_RESULT=$(./gmd/go/bin/gmd query tx $TX_HASH --output json --home ./gmd/.gm) + TX_CODE=$(echo $TX_RESULT | jq -r '.code') + if [ "$TX_CODE" != "0" ]; then + echo "Error: Transaction failed with code $TX_CODE" + echo $TX_RESULT | jq + exit 1 + fi + + sleep 15 BALANCE=$(celestia-appd query bank balances $CELESTIA_ADDR --output json --node http://localhost:26654 | jq '.balances') echo "Celestia balance after IBC transfer: $BALANCE" # fail if no denom starts with ibc/ @@ -362,8 +376,22 @@ jobs: run: | ROLLKIT_ADDR=$(./gmd/go/bin/gmd keys show carol -a --home ./gmd/.gm) CELESTIA_ADDR=$(celestia-appd keys show validator -a --keyring-backend test) - celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y - sleep 20 + + echo "Sending 100stake via IBC..." + TX_HASH=$(celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y--output json | jq -r .txhash) + + sleep 3 + + # query the transaction + TX_RESULT=$(celestia-appd query tx $TX_HASH --output json) + TX_CODE=$(echo $TX_RESULT | jq -r '.code') + if [ "$TX_CODE" != "0" ]; then + echo "Error: Transaction failed with code $TX_CODE" + echo $TX_RESULT | jq + exit 1 + fi + + sleep 15 BALANCE=$(./gmd/go/bin/gmd query bank balances $ROLLKIT_ADDR --output json --home ./gmd/.gm | jq '.balances') echo "Gm balance after IBC transfer: $BALANCE" # fail if no denom starts with ibc/ From 685852825eed0718d17562a99daceeadca4b46a0 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 11:51:01 +0200 Subject: [PATCH 07/13] updates --- pkg/adapter/store.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/adapter/store.go b/pkg/adapter/store.go index b6fe450c..700f3604 100644 --- a/pkg/adapter/store.go +++ b/pkg/adapter/store.go @@ -89,8 +89,9 @@ func (s *Store) GetBlockResponse(ctx context.Context, height uint64) (*abci.Resp if err != nil { return nil, fmt.Errorf("failed to get block response: %w", err) } + if data == nil { - return nil, nil + return nil, fmt.Errorf("block response not found for height %d", height) } resp := &abci.ResponseFinalizeBlock{} From a8381490a35d2b19f78f0c586d7039e568c1ece7 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 12:21:10 +0200 Subject: [PATCH 08/13] updates --- .github/workflows/integration_test.yml | 28 +++++++++++++------------- .github/workflows/test.yml | 4 ---- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index 1070abbc..d5d4621c 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -344,18 +344,18 @@ jobs: run: | hermes create channel --a-chain gm --a-port transfer --b-chain celestia-local --b-port transfer --order unordered --new-client-connection --yes - - name: ICS20 Transfer Rollkit -> Celestia + - name: ICS20 Transfer Celestia -> Rollkit run: | ROLLKIT_ADDR=$(./gmd/go/bin/gmd keys show carol -a --home ./gmd/.gm) CELESTIA_ADDR=$(celestia-appd keys show validator -a --keyring-backend test) echo "Sending 100stake via IBC..." - TX_HASH=$(./gmd/go/bin/gmd tx ibc-transfer transfer transfer channel-0 $CELESTIA_ADDR 100stake --from carol -y --home ./gmd/.gm --output json | jq -r .txhash) + TX_HASH=$(celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y--output json | jq -r .txhash) - sleep 3 + sleep 2 # query the transaction - TX_RESULT=$(./gmd/go/bin/gmd query tx $TX_HASH --output json --home ./gmd/.gm) + TX_RESULT=$(celestia-appd query tx $TX_HASH --output json) TX_CODE=$(echo $TX_RESULT | jq -r '.code') if [ "$TX_CODE" != "0" ]; then echo "Error: Transaction failed with code $TX_CODE" @@ -363,27 +363,27 @@ jobs: exit 1 fi - sleep 15 - BALANCE=$(celestia-appd query bank balances $CELESTIA_ADDR --output json --node http://localhost:26654 | jq '.balances') - echo "Celestia balance after IBC transfer: $BALANCE" + sleep 10 + BALANCE=$(./gmd/go/bin/gmd query bank balances $ROLLKIT_ADDR --output json --home ./gmd/.gm | jq '.balances') + echo "Gm balance after IBC transfer: $BALANCE" # fail if no denom starts with ibc/ if ! echo "$BALANCE" | jq -e '.[] | select(.denom | startswith("ibc/"))' > /dev/null; then echo "Error: No IBC denom found in balance after transfer!" exit 1 fi - - name: ICS20 Transfer Celestia -> Rollkit + - name: ICS20 Transfer Rollkit -> Celestia run: | ROLLKIT_ADDR=$(./gmd/go/bin/gmd keys show carol -a --home ./gmd/.gm) CELESTIA_ADDR=$(celestia-appd keys show validator -a --keyring-backend test) echo "Sending 100stake via IBC..." - TX_HASH=$(celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y--output json | jq -r .txhash) + TX_HASH=$(./gmd/go/bin/gmd tx ibc-transfer transfer transfer channel-0 $CELESTIA_ADDR 100stake --from carol -y --home ./gmd/.gm --output json | jq -r .txhash) - sleep 3 + sleep 5 # query the transaction - TX_RESULT=$(celestia-appd query tx $TX_HASH --output json) + TX_RESULT=$(./gmd/go/bin/gmd query tx $TX_HASH --output json --home ./gmd/.gm) TX_CODE=$(echo $TX_RESULT | jq -r '.code') if [ "$TX_CODE" != "0" ]; then echo "Error: Transaction failed with code $TX_CODE" @@ -391,9 +391,9 @@ jobs: exit 1 fi - sleep 15 - BALANCE=$(./gmd/go/bin/gmd query bank balances $ROLLKIT_ADDR --output json --home ./gmd/.gm | jq '.balances') - echo "Gm balance after IBC transfer: $BALANCE" + sleep 10 + BALANCE=$(celestia-appd query bank balances $CELESTIA_ADDR --output json --node http://localhost:26654 | jq '.balances') + echo "Celestia balance after IBC transfer: $BALANCE" # fail if no denom starts with ibc/ if ! echo "$BALANCE" | jq -e '.[] | select(.denom | startswith("ibc/"))' > /dev/null; then echo "Error: No IBC denom found in balance after transfer!" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2b046956..b8613715 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,10 +4,6 @@ name: Tests / Code Coverage on: workflow_call: -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - jobs: go_mod_tidy_check: name: Go Mod Tidy Check From 4868b57bdf645417ed95a8a91e726c7ac93b73be Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 12:39:12 +0200 Subject: [PATCH 09/13] fixes --- .github/workflows/integration_test.yml | 2 +- pkg/rpc/core/consensus_test.go | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index d5d4621c..a51332b0 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -350,7 +350,7 @@ jobs: CELESTIA_ADDR=$(celestia-appd keys show validator -a --keyring-backend test) echo "Sending 100stake via IBC..." - TX_HASH=$(celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y--output json | jq -r .txhash) + TX_HASH=$(celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y --output json | jq -r .txhash) sleep 2 diff --git a/pkg/rpc/core/consensus_test.go b/pkg/rpc/core/consensus_test.go index 09e7c7c7..93a89397 100644 --- a/pkg/rpc/core/consensus_test.go +++ b/pkg/rpc/core/consensus_test.go @@ -195,9 +195,9 @@ func TestValidators(t *testing.T) { mockStore.AssertExpectations(t) }) - t.Run("Success_HeightNormalizationReturnsZeroOnError", func(t *testing.T) { + t.Run("Success_NilHeight", func(t *testing.T) { mockStore := setupTestValidatorsEnv(t, []cmttypes.GenesisValidator{testGenesisValidator}, testSampleConsensusParams) - mockStore.On("Height", testifymock.Anything).Return(uint64(0), errors.New("failed to get height")).Once() + mockStore.On("Height", testifymock.Anything).Return(uint64(0), nil).Once() result, err := Validators(ctx, nil, nil, nil) require.NoError(err) @@ -206,6 +206,17 @@ func TestValidators(t *testing.T) { assert.Len(result.Validators, 1) // Still expect validator details mockStore.AssertExpectations(t) }) + + t.Run("Error_NilHeightAndStoreError", func(t *testing.T) { + mockStore := setupTestValidatorsEnv(t, []cmttypes.GenesisValidator{testGenesisValidator}, testSampleConsensusParams) + mockStore.On("Height", testifymock.Anything).Return(uint64(0), errors.New("failed to get height")).Once() + + result, err := Validators(ctx, nil, nil, nil) + require.Error(err) + assert.Nil(result) + assert.Contains(err.Error(), "failed to get height") + mockStore.AssertExpectations(t) + }) } func TestDumpConsensusState(t *testing.T) { From 241b3640a73a4fe810695a9cfffb538e4c453559 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 12:47:34 +0200 Subject: [PATCH 10/13] wait right amount --- .github/workflows/integration_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index a51332b0..57edc45a 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -352,7 +352,7 @@ jobs: echo "Sending 100stake via IBC..." TX_HASH=$(celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y --output json | jq -r .txhash) - sleep 2 + sleep 6 # query the transaction TX_RESULT=$(celestia-appd query tx $TX_HASH --output json) @@ -380,7 +380,7 @@ jobs: echo "Sending 100stake via IBC..." TX_HASH=$(./gmd/go/bin/gmd tx ibc-transfer transfer transfer channel-0 $CELESTIA_ADDR 100stake --from carol -y --home ./gmd/.gm --output json | jq -r .txhash) - sleep 5 + sleep 2 # query the transaction TX_RESULT=$(./gmd/go/bin/gmd query tx $TX_HASH --output json --home ./gmd/.gm) From 57999a28a03bed672b0d36db891ef9b39caa3c1f Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 12:58:26 +0200 Subject: [PATCH 11/13] up --- .github/workflows/integration_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index 57edc45a..0ca79233 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -352,7 +352,7 @@ jobs: echo "Sending 100stake via IBC..." TX_HASH=$(celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y --output json | jq -r .txhash) - sleep 6 + sleep 10 # query the transaction TX_RESULT=$(celestia-appd query tx $TX_HASH --output json) @@ -380,7 +380,7 @@ jobs: echo "Sending 100stake via IBC..." TX_HASH=$(./gmd/go/bin/gmd tx ibc-transfer transfer transfer channel-0 $CELESTIA_ADDR 100stake --from carol -y --home ./gmd/.gm --output json | jq -r .txhash) - sleep 2 + sleep 10 # query the transaction TX_RESULT=$(./gmd/go/bin/gmd query tx $TX_HASH --output json --home ./gmd/.gm) From 5a0437c4c2228cdfca45d90c97e8bd22fe4e041e Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 13:15:08 +0200 Subject: [PATCH 12/13] updates --- .github/workflows/integration_test.yml | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index 0ca79233..4887d9fe 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -350,20 +350,9 @@ jobs: CELESTIA_ADDR=$(celestia-appd keys show validator -a --keyring-backend test) echo "Sending 100stake via IBC..." - TX_HASH=$(celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y --output json | jq -r .txhash) + celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y --output json - sleep 10 - - # query the transaction - TX_RESULT=$(celestia-appd query tx $TX_HASH --output json) - TX_CODE=$(echo $TX_RESULT | jq -r '.code') - if [ "$TX_CODE" != "0" ]; then - echo "Error: Transaction failed with code $TX_CODE" - echo $TX_RESULT | jq - exit 1 - fi - - sleep 10 + sleep 15 BALANCE=$(./gmd/go/bin/gmd query bank balances $ROLLKIT_ADDR --output json --home ./gmd/.gm | jq '.balances') echo "Gm balance after IBC transfer: $BALANCE" # fail if no denom starts with ibc/ @@ -380,7 +369,7 @@ jobs: echo "Sending 100stake via IBC..." TX_HASH=$(./gmd/go/bin/gmd tx ibc-transfer transfer transfer channel-0 $CELESTIA_ADDR 100stake --from carol -y --home ./gmd/.gm --output json | jq -r .txhash) - sleep 10 + sleep 2 # query the transaction TX_RESULT=$(./gmd/go/bin/gmd query tx $TX_HASH --output json --home ./gmd/.gm) From d314edd92e4af66606fd22a1095f341f27799a79 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 20 Jun 2025 13:27:37 +0200 Subject: [PATCH 13/13] updates --- .github/workflows/integration_test.yml | 42 +++++++------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index 4887d9fe..82717f21 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -344,45 +344,25 @@ jobs: run: | hermes create channel --a-chain gm --a-port transfer --b-chain celestia-local --b-port transfer --order unordered --new-client-connection --yes - - name: ICS20 Transfer Celestia -> Rollkit + - name: ICS20 Transfer Rollkit -> Celestia run: | ROLLKIT_ADDR=$(./gmd/go/bin/gmd keys show carol -a --home ./gmd/.gm) CELESTIA_ADDR=$(celestia-appd keys show validator -a --keyring-backend test) - - echo "Sending 100stake via IBC..." - celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y --output json - + ./gmd/go/bin/gmd tx ibc-transfer transfer transfer channel-0 $CELESTIA_ADDR 100stake --from carol -y --home ./gmd/.gm sleep 15 - BALANCE=$(./gmd/go/bin/gmd query bank balances $ROLLKIT_ADDR --output json --home ./gmd/.gm | jq '.balances') - echo "Gm balance after IBC transfer: $BALANCE" - # fail if no denom starts with ibc/ - if ! echo "$BALANCE" | jq -e '.[] | select(.denom | startswith("ibc/"))' > /dev/null; then - echo "Error: No IBC denom found in balance after transfer!" - exit 1 - fi + BALANCE=$(celestia-appd query bank balances $CELESTIA_ADDR --output json --node http://localhost:26654 | jq '.balances') + echo "Celestia balance after IBC transfer: $BALANCE" + # TODO: check that the balance is correct + # ref: https://github.com/rollkit/go-execution-abci/pull/138#discussion_r2156332760 - - name: ICS20 Transfer Rollkit -> Celestia + - name: ICS20 Transfer Celestia -> Rollkit run: | ROLLKIT_ADDR=$(./gmd/go/bin/gmd keys show carol -a --home ./gmd/.gm) CELESTIA_ADDR=$(celestia-appd keys show validator -a --keyring-backend test) - - echo "Sending 100stake via IBC..." - TX_HASH=$(./gmd/go/bin/gmd tx ibc-transfer transfer transfer channel-0 $CELESTIA_ADDR 100stake --from carol -y --home ./gmd/.gm --output json | jq -r .txhash) - - sleep 2 - - # query the transaction - TX_RESULT=$(./gmd/go/bin/gmd query tx $TX_HASH --output json --home ./gmd/.gm) - TX_CODE=$(echo $TX_RESULT | jq -r '.code') - if [ "$TX_CODE" != "0" ]; then - echo "Error: Transaction failed with code $TX_CODE" - echo $TX_RESULT | jq - exit 1 - fi - - sleep 10 - BALANCE=$(celestia-appd query bank balances $CELESTIA_ADDR --output json --node http://localhost:26654 | jq '.balances') - echo "Celestia balance after IBC transfer: $BALANCE" + celestia-appd tx ibc-transfer transfer transfer channel-0 $ROLLKIT_ADDR 100utia --from validator --node http://localhost:26654 --fees 400utia --keyring-backend test -y + sleep 15 + BALANCE=$(./gmd/go/bin/gmd query bank balances $ROLLKIT_ADDR --output json --home ./gmd/.gm | jq '.balances') + echo "Gm balance after IBC transfer: $BALANCE" # fail if no denom starts with ibc/ if ! echo "$BALANCE" | jq -e '.[] | select(.denom | startswith("ibc/"))' > /dev/null; then echo "Error: No IBC denom found in balance after transfer!"