Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c021416
test(network): commit bitmap unit tests baseline
randygrok Apr 22, 2026
3d8b00f
proto(network): add attester_infos to GenesisState
randygrok Apr 22, 2026
641b401
feat(network): load attester set from genesis with pubkey/address val…
randygrok Apr 22, 2026
ce7a716
test(network): add signTestVote helper for signed vote bytes
randygrok Apr 22, 2026
1fbed0b
feat(network): add verifyVote helper with signature and consistency c…
randygrok Apr 22, 2026
aa9b835
feat(network): enforce vote signature verification in MsgAttest
randygrok Apr 22, 2026
63b9293
feat(network): disable MsgJoinAttesterSet and MsgLeaveAttesterSet
randygrok Apr 22, 2026
a557a43
refactor(network): drop runtime valset rebuild; set is fixed at genesis
randygrok Apr 22, 2026
d521945
test(adapter): guard validator-hasher ordering against address sort
randygrok Apr 22, 2026
66b0f89
feat(rpc): deterministic commit reconstruction with absent entries an…
randygrok Apr 22, 2026
887b5d6
fix(attester): sign and broadcast the same vote struct
randygrok Apr 22, 2026
426e8d6
feat(attester): every-block loop; assert registered instead of joining
randygrok Apr 22, 2026
6b1dee5
test(integration): verify attested commit passes 07-tendermint light …
randygrok Apr 22, 2026
dec5aee
test(integration): populate attester_infos at genesis; assert VerifyC…
randygrok Apr 22, 2026
7a07b0c
fix(docker): pin sonic v1.15.0 for Go 1.26 compatibility
randygrok Apr 22, 2026
b4132fb
fix(test): targetHeight must be var to take address for rpcClient.Commit
randygrok Apr 22, 2026
85be381
fix(network): implement GenesisState.UnpackInterfaces for AttesterInf…
randygrok Apr 22, 2026
168cf18
fix(network): validate attester pubkey/consensus_address at byte leve…
randygrok Apr 22, 2026
888d290
fix(attester): use consensus-key address for assertRegistered and Msg…
randygrok Apr 22, 2026
775314e
fix(attester): fetch latest height via /block not /status (attester-m…
randygrok Apr 22, 2026
89b3567
test(integration): exercise IBC transfer with GM-native token in both…
randygrok Apr 22, 2026
5354895
fix(network): pin vote BlockID.Hash to sequencer's stored block hash
randygrok Apr 23, 2026
178f11c
style(network): fix lint issues in keeper tests
randygrok Apr 23, 2026
c43cf97
test(integration): drop GM-native Celestia transfer case
randygrok Apr 23, 2026
65a06da
ci: reduce checkout depth in migration workflow
randygrok Apr 23, 2026
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
110 changes: 71 additions & 39 deletions modules/network/genesis.go
Original file line number Diff line number Diff line change
@@ -1,48 +1,93 @@
package network

import (
"bytes"
"fmt"
"sort"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/bech32"

"github.com/evstack/ev-abci/modules/network/keeper"
"github.com/evstack/ev-abci/modules/network/types"
)

// InitGenesis initializes the network module's state from a provided genesis state.
func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) error {
// Set module params
if err := k.SetParams(ctx, genState.Params); err != nil {
return fmt.Errorf("set params: %s", err)
}

// Set validator indices
for _, vi := range genState.ValidatorIndices {
if err := k.SetValidatorIndex(ctx, vi.Address, uint16(vi.Index), vi.Power); err != nil {
return err
// Load attesters: validate pubkey/address match, then insert and assign indices.
attesters := make([]types.AttesterInfo, len(genState.AttesterInfos))
copy(attesters, genState.AttesterInfos)

for i := range attesters {
info := attesters[i]
pk, err := info.GetPubKey()
if err != nil {
return fmt.Errorf("attester %d: %w", i, err)
}
// Also add to attester set
if err := k.SetAttesterSetMember(ctx, vi.Address); err != nil {
return err
// Validate pubkey ↔ consensus_address match at the raw-bytes level so
// the check is independent of bech32 prefix (e.g. "cosmosvalcons" vs
// "celestiavalcons"). Whatever prefix was used in genesis, the 20-byte
// payload must equal the pubkey's Address().
_, rawAddr, decErr := bech32.DecodeAndConvert(info.ConsensusAddress)
if decErr != nil {
return fmt.Errorf("attester %d: decode consensus_address %q: %w", i, info.ConsensusAddress, decErr)
}
if !bytes.Equal(rawAddr, pk.Address()) {
return fmt.Errorf("attester %d: pubkey address mismatch (derived bytes %x, stated bytes %x)",
i, pk.Address(), rawAddr)
}
// Re-encode consensus_address with the runtime SDK config so the
// stored value matches what ConsAddress().String() produces elsewhere
// in the module at runtime.
derived := sdk.ConsAddress(pk.Address()).String()
info.ConsensusAddress = derived
attesters[i] = info
}

// Order by pubkey.Address() bytes ascending to match cmttypes.NewValidatorSet.
sort.Slice(attesters, func(i, j int) bool {
pki, _ := attesters[i].GetPubKey()
pkj, _ := attesters[j].GetPubKey()
return bytes.Compare(pki.Address(), pkj.Address()) < 0
})

for idx, info := range attesters {
if err := k.SetAttesterInfo(ctx, info.ConsensusAddress, &info); err != nil {
return fmt.Errorf("set attester info: %w", err)
}
if err := k.SetAttesterSetMember(ctx, info.ConsensusAddress); err != nil {
return fmt.Errorf("set attester set member: %w", err)
}
if err := k.SetValidatorIndex(ctx, info.ConsensusAddress, uint16(idx), 1); err != nil {
return fmt.Errorf("set validator index: %w", err)
}
}

// Set attestation bitmaps
// Still load historical bitmaps if provided (upgrade/dump scenarios).
for _, ab := range genState.AttestationBitmaps {
if err := k.SetAttestationBitmap(ctx, ab.Height, ab.Bitmap); err != nil {
return err
}
// Store full attestation info using collections API
if err := k.StoredAttestationInfo.Set(ctx, ab.Height, ab); err != nil {
return err
}

if ab.SoftConfirmed {
if err := setSoftConfirmed(ctx, k, ab.Height); err != nil {
return err
}
}
}

// Legacy: genState.ValidatorIndices is now derived from AttesterInfos and
// ignored. Warn if non-empty so operators notice.
if len(genState.ValidatorIndices) > 0 {
k.Logger(ctx).Error("genesis.validator_indices is deprecated and ignored; use attester_infos")
}

return nil
}

Expand All @@ -51,54 +96,41 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
genesis := types.DefaultGenesisState()
genesis.Params = k.GetParams(ctx)

// Export validator indices using collections API
var validatorIndices []types.ValidatorIndex
// Iterate through all validator indices
if err := k.ValidatorIndex.Walk(ctx, nil, func(addr string, index uint16) (bool, error) {
power, err := k.GetValidatorPower(ctx, index)
if err != nil {
return false, fmt.Errorf("get validator power: %w", err)
}
validatorIndices = append(validatorIndices, types.ValidatorIndex{
Address: addr,
Index: uint32(index),
Power: power,
})
var attesters []types.AttesterInfo
if err := k.AttesterInfo.Walk(ctx, nil, func(_ string, info types.AttesterInfo) (bool, error) {
attesters = append(attesters, info)
return false, nil
}); err != nil {
panic(err)
}
genesis.ValidatorIndices = validatorIndices
sort.Slice(attesters, func(i, j int) bool {
pki, _ := attesters[i].GetPubKey()
pkj, _ := attesters[j].GetPubKey()
return bytes.Compare(pki.Address(), pkj.Address()) < 0
})
genesis.AttesterInfos = attesters

// Export attestation bitmaps using collections API
var attestationBitmaps []types.AttestationBitmap
// Iterate through all stored attestation info
if err := k.StoredAttestationInfo.Walk(ctx, nil, func(height int64, ab types.AttestationBitmap) (bool, error) {
if err := k.StoredAttestationInfo.Walk(ctx, nil, func(_ int64, ab types.AttestationBitmap) (bool, error) {
attestationBitmaps = append(attestationBitmaps, ab)
return false, nil
}); err != nil {
panic(err)
}
genesis.AttestationBitmaps = attestationBitmaps

// ValidatorIndices no longer exported: they are derived deterministically
// from AttesterInfos order.
genesis.ValidatorIndices = nil

return genesis
}

// Helper function to set soft confirmed status
func setSoftConfirmed(ctx sdk.Context, k keeper.Keeper, height int64) error {
// Get the existing attestation bitmap
ab, err := k.StoredAttestationInfo.Get(ctx, height)
if err != nil {
// If there's no existing attestation bitmap, we can't set it as soft confirmed
return err
}

// Set the SoftConfirmed field to true
ab.SoftConfirmed = true

// Update the attestation bitmap in the collection
if err := k.StoredAttestationInfo.Set(ctx, height, ab); err != nil {
return err
}
return nil
return k.StoredAttestationInfo.Set(ctx, height, ab)
}
9 changes: 4 additions & 5 deletions modules/network/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,13 @@ func (k Keeper) processEpochEnd(ctx sdk.Context, epoch uint64) error {
}
}

// todo (Alex): find a way to prune only bitmaps that are not used anymore
// Validator indices are established at genesis and never mutate at runtime
// (MsgJoin/MsgLeave are disabled). Nothing to rebuild here.

// todo: find a way to prune only bitmaps that are not used anymore
// if err := k.PruneOldBitmaps(ctx, epoch); err != nil {
// return fmt.Errorf("pruning old data at epoch %d: %w", epoch, err)
// }

if err := k.BuildValidatorIndexMap(ctx); err != nil {
return fmt.Errorf("rebuilding validator index map at epoch %d: %w", epoch, err)
}
return nil
}

Expand Down
Loading
Loading