Skip to content

Commit

Permalink
try generic
Browse files Browse the repository at this point in the history
  • Loading branch information
danwt committed Nov 5, 2024
1 parent 76aa1e1 commit 3eb2090
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 0 deletions.
5 changes: 5 additions & 0 deletions x/lightclient/keeper/hook_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ func (hook rollappHook) AfterUpdateState(
client, ok = hook.k.GetProspectiveCanonicalClient(ctx, rollappId, stateInfo.GetLatestHeight()-1)
if ok {
hook.k.SetCanonicalClient(ctx, rollappId, client)
// we now verified everything up to and including stateInfo.GetLatestHeight()-1
// so we should prune everything up to stateInfo.GetLatestHeight()-1
if err := hook.k.PruneSignersBelow(ctx, rollappId, stateInfo.GetLatestHeight()); err != nil {
return errorsmod.Wrap(err, "prune signers")
}
}
return nil
}
Expand Down
70 changes: 70 additions & 0 deletions x/lightclient/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,76 @@ shouldnt be allowed
return nil
}

// func (p *PairRange[K1, K2])
type Foo[K1, K2 any] func(p *collections.PairRange[K1, K2], k2 K2) *collections.PairRange[K1, K2]

// PruneSignersBelow PruneSigners removes bookkeeping for all heights BELOW h for given rollapp
// This should only be called after canonical client set
func (k Keeper) PruneSignersBelow(ctx sdk.Context, rollapp string, h uint64) error {
client, ok := k.GetCanonicalClient(ctx, rollapp)
if !ok {
return gerrc.ErrInternal.Wrap(`
prune light client signers for rollapp before canonical client is set
this suggests fork happened prior to genesis bridge completion, which
shouldnt be allowed
`)
}
rng := collections.NewPrefixedPairRange[string, uint64](client).EndExclusive(h)

seqs := make([]string, 0)
heights := make([]uint64, 0)

// collect first to avoid del while iterating
if err := k.clientHeightToSigner.Walk(ctx, rng, func(key collections.Pair[string, uint64], value string) (stop bool, err error) {
seqs = append(seqs, value)
heights = append(heights, key.K2())
return false, nil
}); err != nil {
return errorsmod.Wrap(err, "walk signers")
}

for i := 0; i < len(seqs); i++ {
if err := k.RemoveSigner(ctx, seqs[i], client, heights[i]); err != nil {
return errorsmod.Wrap(err, "remove signer")
}
}
return nil
}

// PruneSignersBelow PruneSigners removes bookkeeping for all heights BELOW h for given rollapp
// This should only be called after canonical client set
func (k Keeper) PruneGeneric(ctx sdk.Context, rollapp string, h uint64, f Foo[string, uint64]) error {
client, ok := k.GetCanonicalClient(ctx, rollapp)
if !ok {
return gerrc.ErrInternal.Wrap(`
prune light client signers for rollapp before canonical client is set
this suggests fork happened prior to genesis bridge completion, which
shouldnt be allowed
`)
}
//rng := collections.NewPrefixedPairRange[string, uint64](client)
rng := f(collections.NewPrefixedPairRange[string, uint64](client), h)

seqs := make([]string, 0)
heights := make([]uint64, 0)

// collect first to avoid del while iterating
if err := k.clientHeightToSigner.Walk(ctx, rng, func(key collections.Pair[string, uint64], value string) (stop bool, err error) {
seqs = append(seqs, value)
heights = append(heights, key.K2())
return false, nil
}); err != nil {
return errorsmod.Wrap(err, "walk signers")
}

for i := 0; i < len(seqs); i++ {
if err := k.RemoveSigner(ctx, seqs[i], client, heights[i]); err != nil {
return errorsmod.Wrap(err, "remove signer")
}
}
return nil
}

// GetSigner returns the sequencer address who signed the header in the update
func (k Keeper) GetSigner(ctx sdk.Context, client string, h uint64) (string, error) {
return k.clientHeightToSigner.Get(ctx, collections.Join(client, h))
Expand Down
41 changes: 41 additions & 0 deletions x/lightclient/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,44 @@ func (s *TestSuite) TestUnbondConditionFlow() {
err = s.k().CanUnbond(s.Ctx, seq)
s.Require().NoError(err)
}

// Basic flow should prevent unbonding at appropriate times, and
// handle pruning.
func (s *TestSuite) TestPruneBelow() {
seq := keepertest.Alice

client := keepertest.CanonClientID

s.k().SetCanonicalClient(s.Ctx, seq.RollappId, client)

// allowed!
err := s.k().CanUnbond(s.Ctx, seq)
s.Require().NoError(err)

// add some unverified headers
for h := range 10 {
err := s.k().SaveSigner(s.Ctx, seq.Address, client, uint64(h))
s.Require().NoError(err)
}

// not allowed!
err = s.k().CanUnbond(s.Ctx, seq)
utest.IsErr(s.Require(), err, sequencertypes.ErrUnbondNotAllowed)

// we prune some, but still not allowed
err = s.k().PruneSignersBelow(s.Ctx, seq.RollappId, 6)
s.Require().NoError(err)

err = s.k().CanUnbond(s.Ctx, seq)
utest.IsErr(s.Require(), err, sequencertypes.ErrUnbondNotAllowed)

// the rest are verified
for h := 6; h < 10; h++ {
err := s.k().RemoveSigner(s.Ctx, seq.Address, client, uint64(h))
s.Require().NoError(err)
}

// allowed!
err = s.k().CanUnbond(s.Ctx, seq)
s.Require().NoError(err)
}

0 comments on commit 3eb2090

Please sign in to comment.