diff --git a/x/skyway/keeper/attestation.go b/x/skyway/keeper/attestation.go index 3cf5582f..786b04e5 100644 --- a/x/skyway/keeper/attestation.go +++ b/x/skyway/keeper/attestation.go @@ -579,7 +579,11 @@ func (k Keeper) UnobservedBlocksByAddr( ) ([]uint64, error) { lastCompassID := k.GetLatestCompassID(ctx, chainReferenceID) - var err error + lastObservedNonce, err := k.GetLastObservedSkywayNonce(ctx, chainReferenceID) + if err != nil { + return nil, err + } + var blocks []uint64 iterErr := k.IterateAttestations(ctx, chainReferenceID, false, func(_ []byte, att types.Attestation) bool { @@ -602,6 +606,13 @@ func (k Keeper) UnobservedBlocksByAddr( return false } + // If we ever reset the latest skyway nonce ahead of any observed claim, + // we don't need nor want pigeons trying to attest to them. So, we can + // filter claims that are behind the latest attested claim. + if claim.GetSkywayNonce() <= lastObservedNonce { + return false + } + blocks = append(blocks, claim.GetEthBlockHeight()) return false diff --git a/x/skyway/keeper/grpc_query_test.go b/x/skyway/keeper/grpc_query_test.go index 0244da73..81d5e031 100644 --- a/x/skyway/keeper/grpc_query_test.go +++ b/x/skyway/keeper/grpc_query_test.go @@ -609,7 +609,7 @@ func TestGetUnobservedBlocksByAddr(t *testing.T) { expected: nil, }, { - name: "unobserved message already signed by validator", + name: "unobserved messages already signed by validator", setup: func(ctx context.Context, k Keeper) { sdkCtx := sdktypes.UnwrapSDKContext(ctx) @@ -625,7 +625,7 @@ func TestGetUnobservedBlocksByAddr(t *testing.T) { require.NoError(t, err) att := &types.Attestation{ - Observed: true, + Observed: false, Votes: []string{address}, Height: uint64(sdkCtx.BlockHeight()), Claim: claim, @@ -636,6 +636,37 @@ func TestGetUnobservedBlocksByAddr(t *testing.T) { }, expected: nil, }, + { + name: "unobserved messages behind last observed nonce", + setup: func(ctx context.Context, k Keeper) { + sdkCtx := sdktypes.UnwrapSDKContext(ctx) + + err := k.setLastObservedSkywayNonce(ctx, chainReferenceID, 2) + require.NoError(t, err) + + for i := 0; i < 3; i++ { + msg := types.MsgLightNodeSaleClaim{ + SkywayNonce: uint64(i + 1), + EthBlockHeight: uint64(i + 1), + } + claim, err := codectypes.NewAnyWithValue(&msg) + require.NoError(t, err) + + hash, err := msg.ClaimHash() + require.NoError(t, err) + + att := &types.Attestation{ + Observed: false, + Votes: []string{}, + Height: uint64(sdkCtx.BlockHeight()), + Claim: claim, + } + + k.SetAttestation(ctx, chainReferenceID, uint64(i+1), hash, att) + } + }, + expected: []uint64{3}, + }, { name: "unobserved messages for current and porevious compass", setup: func(ctx context.Context, k Keeper) {