-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix: Iteration through PacketMaturityTimes assumes maturity time order #622
Changes from 57 commits
5e1a187
9c7bf44
c19cb8d
c1e693e
789997c
43489eb
ce77f0a
f00ac6d
a82e5ee
b29f08e
b6cb90a
378f67d
2663554
7ca833e
74aaebc
f8613c7
40ffea5
643ae1c
b9706cf
02eb634
c67eb74
58d5c28
f876368
63707e1
8d4c4da
28ad814
d9f4358
b14ff29
87ed959
4259d30
e1fa7c7
6a5136e
a5fee38
9a04275
a2c93d2
3b80893
3e3f10b
b4112f7
4177544
60732d5
fe16a62
5229c7e
649d105
56f957e
9a7b31b
69b050b
2aca355
4fc4736
ec5645c
a2ec7bc
352a426
609dc86
d116efc
1e6e477
cc98971
3a44c2a
0b38380
ed5d15b
f36e4b2
1c027b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,7 +23,7 @@ message GenesisState { | |
// ProviderConsensusState filled in on new chain, nil on restart. | ||
ibc.lightclients.tendermint.v1.ConsensusState provider_consensus_state = 6; | ||
// MaturingPackets nil on new chain, filled in on restart. | ||
repeated MaturingVSCPacket maturing_packets = 7 | ||
repeated interchain_security.ccv.consumer.v1.MaturingVSCPacket maturing_packets = 7 | ||
[ (gogoproto.nullable) = false ]; | ||
// InitialValset filled in on new chain and on restart. | ||
repeated .tendermint.abci.ValidatorUpdate initial_val_set = 8 | ||
|
@@ -42,13 +42,6 @@ message GenesisState { | |
[ (gogoproto.nullable) = false ]; | ||
} | ||
|
||
// MaturingVSCPacket defines the genesis information for the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved to |
||
// unbonding VSC packet | ||
message MaturingVSCPacket { | ||
uint64 vscId = 1; | ||
uint64 maturity_time = 2; | ||
} | ||
|
||
// HeightValsetUpdateID defines the genesis information for the mapping | ||
// of each block height to a valset update id | ||
message HeightToValsetUpdateID { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ package keeper | |
import ( | ||
"encoding/binary" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/cosmos/cosmos-sdk/codec" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
|
@@ -206,76 +207,81 @@ func (k Keeper) DeletePendingChanges(ctx sdk.Context) { | |
store.Delete(types.PendingChangesKey()) | ||
} | ||
|
||
// GetElapsedPacketMaturityTimes returns a slice of already elapsed PacketMaturityTimes, sorted by vscIDs, | ||
// i.e., the slice contains the IDs of the matured VSCPackets | ||
func (k Keeper) GetElapsedPacketMaturityTimes(ctx sdk.Context) (maturingVSCPacket []consumertypes.MaturingVSCPacket) { | ||
currentTime := uint64(ctx.BlockTime().UnixNano()) | ||
// GetElapsedPacketMaturityTimes returns a slice of already elapsed PacketMaturityTimes, sorted by maturity times, | ||
// i.e., the slice contains the IDs of the matured VSCPackets. | ||
func (k Keeper) GetElapsedPacketMaturityTimes(ctx sdk.Context) (maturingVSCPackets []consumertypes.MaturingVSCPacket) { | ||
store := ctx.KVStore(k.storeKey) | ||
iterator := sdk.KVStorePrefixIterator(store, []byte{types.PacketMaturityTimeBytePrefix}) | ||
|
||
defer iterator.Close() | ||
|
||
for ; iterator.Valid(); iterator.Next() { | ||
vscId := binary.BigEndian.Uint64(iterator.Key()[1:]) | ||
maturityTime := binary.BigEndian.Uint64(iterator.Value()) | ||
var maturingVSCPacket consumertypes.MaturingVSCPacket | ||
if err := maturingVSCPacket.Unmarshal(iterator.Value()); err != nil { | ||
panic(fmt.Errorf("failed to unmarshal MaturingVSCPacket: %w", err)) | ||
} | ||
|
||
// If the maturity time is after the current time, then stop the iteration; | ||
mpoke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// TODO: the iteration over PacketMaturityTimes should be over maturity times, | ||
// see https://github.com/cosmos/interchain-security/issues/598 | ||
if currentTime < maturityTime { | ||
// this is possible since the iteration over PacketMaturityTimes is in order | ||
// of maturity times | ||
if ctx.BlockTime().Before(maturingVSCPacket.MaturityTime) { | ||
break | ||
} | ||
|
||
maturingVSCPacket = append(maturingVSCPacket, consumertypes.MaturingVSCPacket{ | ||
VscId: vscId, | ||
MaturityTime: maturityTime, | ||
}) | ||
maturingVSCPackets = append(maturingVSCPackets, maturingVSCPacket) | ||
} | ||
return maturingVSCPacket | ||
return maturingVSCPackets | ||
} | ||
|
||
// GetAllPacketMaturityTimes returns a slice of all PacketMaturityTimes, sorted by vscIDs. | ||
func (k Keeper) GetAllPacketMaturityTimes(ctx sdk.Context) (maturingVSCPacket []consumertypes.MaturingVSCPacket) { | ||
// GetAllPacketMaturityTimes returns a slice of all PacketMaturityTimes, sorted by maturity times. | ||
// | ||
// Note that PacketMaturityTimes are stored under keys with the following format: | ||
// PacketMaturityTimeBytePrefix | maturityTime.UnixNano() | vscID | ||
// Thus, the returned array is in ascending order of maturityTimes. | ||
// If two entries have the same maturityTime, then they are ordered by vscID. | ||
func (k Keeper) GetAllPacketMaturityTimes(ctx sdk.Context) (maturingVSCPackets []consumertypes.MaturingVSCPacket) { | ||
store := ctx.KVStore(k.storeKey) | ||
iterator := sdk.KVStorePrefixIterator(store, []byte{types.PacketMaturityTimeBytePrefix}) | ||
|
||
defer iterator.Close() | ||
for ; iterator.Valid(); iterator.Next() { | ||
vscId := binary.BigEndian.Uint64(iterator.Key()[1:]) | ||
maturityTime := binary.BigEndian.Uint64(iterator.Value()) | ||
var maturingVSCPacket consumertypes.MaturingVSCPacket | ||
if err := maturingVSCPacket.Unmarshal(iterator.Value()); err != nil { | ||
panic(fmt.Errorf("failed to unmarshal MaturingVSCPacket: %w", err)) | ||
} | ||
|
||
maturingVSCPacket = append(maturingVSCPacket, consumertypes.MaturingVSCPacket{ | ||
VscId: vscId, | ||
MaturityTime: maturityTime, | ||
}) | ||
maturingVSCPackets = append(maturingVSCPackets, maturingVSCPacket) | ||
} | ||
return maturingVSCPacket | ||
return maturingVSCPackets | ||
} | ||
|
||
// SetPacketMaturityTime sets the maturity time for a given received VSC packet id | ||
func (k Keeper) SetPacketMaturityTime(ctx sdk.Context, vscId, maturityTime uint64) { | ||
func (k Keeper) SetPacketMaturityTime(ctx sdk.Context, vscId uint64, maturityTime time.Time) { | ||
store := ctx.KVStore(k.storeKey) | ||
timeBytes := make([]byte, 8) | ||
binary.BigEndian.PutUint64(timeBytes, maturityTime) | ||
store.Set(types.PacketMaturityTimeKey(vscId), timeBytes) | ||
maturingVSCPacket := consumertypes.MaturingVSCPacket{ | ||
VscId: vscId, | ||
MaturityTime: maturityTime, | ||
} | ||
bz, err := maturingVSCPacket.Marshal() | ||
if err != nil { | ||
panic(fmt.Errorf("failed to marshal MaturingVSCPacket: %w", err)) | ||
} | ||
store.Set(types.PacketMaturityTimeKey(vscId, maturityTime), bz) | ||
} | ||
|
||
// GetPacketMaturityTime gets the maturity time for a given received VSC packet id | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@MSalopek @jtremback this means it would be hard to query the maturity of a VSCPacket (as we don't know the maturity time). |
||
func (k Keeper) GetPacketMaturityTime(ctx sdk.Context, vscId uint64) uint64 { | ||
// PacketMaturityExists checks whether the packet maturity time for a given vscId and maturityTime exists. | ||
// | ||
// Note: this method is only used in testing. | ||
func (k Keeper) PacketMaturityTimeExists(ctx sdk.Context, vscId uint64, maturityTime time.Time) bool { | ||
store := ctx.KVStore(k.storeKey) | ||
bz := store.Get(types.PacketMaturityTimeKey(vscId)) | ||
if bz == nil { | ||
return 0 | ||
} | ||
return binary.BigEndian.Uint64(bz) | ||
bz := store.Get(types.PacketMaturityTimeKey(vscId, maturityTime)) | ||
return bz != nil | ||
shaspitz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// DeletePacketMaturityTimes deletes the packet maturity time for given received VSC packet ids | ||
func (k Keeper) DeletePacketMaturityTimes(ctx sdk.Context, vscIds ...uint64) { | ||
// DeletePacketMaturityTimes deletes the packet maturity time for a given vscId and maturityTime | ||
func (k Keeper) DeletePacketMaturityTimes(ctx sdk.Context, vscId uint64, maturityTime time.Time) { | ||
store := ctx.KVStore(k.storeKey) | ||
for _, vscId := range vscIds { | ||
store.Delete(types.PacketMaturityTimeKey(vscId)) | ||
} | ||
store.Delete(types.PacketMaturityTimeKey(vscId, maturityTime)) | ||
} | ||
|
||
// VerifyProviderChain verifies that the chain trying to connect on the channel handshake | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prob worth noting that if this time is being stored on the consumer at all, the maturity time is in the future. Otherwise a VSCMatured packet is sent from consumer -> provider.
Is my understanding correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost. This is set either in
InitGenesis
on a consumer restart in which case the maturity time could be in the past, which would result inVSCMaturedPackets
sent in the firstEndBlock
.Most likely though, the maturity time is set in
OnRecvVSCPacket
, i.e.,