From f55ea69f105797f0f630f6240f91f5462ece766f Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 27 Nov 2024 12:21:52 -0300 Subject: [PATCH 001/132] chore: add todos --- x/incentive/keeper/btc_staking_gauge.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/incentive/keeper/btc_staking_gauge.go b/x/incentive/keeper/btc_staking_gauge.go index a8ad38f33..35ec2081c 100644 --- a/x/incentive/keeper/btc_staking_gauge.go +++ b/x/incentive/keeper/btc_staking_gauge.go @@ -36,12 +36,16 @@ func (k Keeper) RewardBTCStaking(ctx context.Context, height uint64, dc *ftypes. k.accumulateRewardGauge(ctx, types.FinalityProviderType, fp.GetAddress(), coinsForCommission) // reward the rest of coins to each BTC delegation proportional to its voting power portion coinsForBTCDels := coinsForFpsAndDels.Sub(coinsForCommission...) + // TODO: remove this iteration. It could be avoided by using accumulated rewards per period + // for each finality provider, and for each delegation (fp, delegator) keep track of last period + // TODO(rafilx): Add acumulative rewards for each validator for _, btcDel := range fp.BtcDels { btcDelPortion := fp.GetBTCDelPortion(btcDel) coinsForDel := types.GetCoinsPortion(coinsForBTCDels, btcDelPortion) k.accumulateRewardGauge(ctx, types.BTCDelegationType, btcDel.GetAddress(), coinsForDel) } } + // TODO: prune unnecessary state (delete BTCStakingGauge after the amount is used) } func (k Keeper) accumulateBTCStakingReward(ctx context.Context, btcStakingReward sdk.Coins) { From e338dbf50d37f6533f2066b4eae52186abb10567 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 27 Nov 2024 23:17:06 -0300 Subject: [PATCH 002/132] chore: add FinalityProviderRewards structure to help track BTC delegation rewards --- proto/babylon/incentive/rewards.proto | 25 ++ x/finality/keeper/power_dist_change.go | 7 + x/incentive/keeper/btc_staking_gauge.go | 2 + x/incentive/types/rewards.pb.go | 344 ++++++++++++++++++++++++ 4 files changed, 378 insertions(+) create mode 100644 proto/babylon/incentive/rewards.proto create mode 100644 x/incentive/types/rewards.pb.go diff --git a/proto/babylon/incentive/rewards.proto b/proto/babylon/incentive/rewards.proto new file mode 100644 index 000000000..4ba11b10e --- /dev/null +++ b/proto/babylon/incentive/rewards.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; +package babylon.incentive; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +option go_package = "github.com/babylonlabs-io/babylon/x/incentive/types"; + +// FinalityProviderRewards represents the cumulative rewards ratio of the +// finality provider per sat in that period. +// The period is ommited here and should be part of the key used to store this structure. +message FinalityProviderRewards { + // The cumulative rewards of that finality provider at some specific period + // This coins will aways increase the value, never be reduced due to keep acumulation + // and when the cumulative rewards will be used to distribute rewards, 2 periods will + // be interpolated and calculate the difference and multiplied by the total sat amount delegated + // https://github.com/cosmos/cosmos-sdk/blob/e76102f885b71fd6e1c1efb692052173c4b3c3a3/x/distribution/keeper/delegation.go#L47 + // This is also not considering slash of the rewards. + repeated cosmos.base.v1beta1.Coin CumulativeRewardsPerSat = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + // TODO(rafilx): add reference count for state prunning + // https://github.com/cosmos/cosmos-sdk/blob/d9c53bfefc1e75a3c6b09065ea8b3a836cda0d18/x/distribution/types/distribution.pb.go#L98 +} diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 8873851d6..1ffc34756 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -203,6 +203,10 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( fpBTCPKHex := fpBTCPK.MarshalHex() activeBTCDels[fpBTCPKHex] = append(activeBTCDels[fpBTCPKHex], btcDel) } + // Becomes active, it should withdraw the rewards available + // and create a new BTCDelegationRewardsInfo. + // TODO: research how can we charge the gas for this process during + // the withdraw of rewards. } else if delEvent.NewState == types.BTCDelegationStatus_UNBONDED { // emit expired event if it is not early unbonding if !btcDel.IsUnbondedEarly() { @@ -210,6 +214,9 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( } // add the unbonded BTC delegation to the map unbondedBTCDels[delEvent.StakingTxHash] = struct{}{} + // Becomes unbonded, it should withdraw the rewards available + // and create a new BTCDelegationRewardsInfo or delete it if does not have more sats + // for this finality provider. } case *types.EventPowerDistUpdate_SlashedFp: // record slashed fps diff --git a/x/incentive/keeper/btc_staking_gauge.go b/x/incentive/keeper/btc_staking_gauge.go index 35ec2081c..3cbd5e792 100644 --- a/x/incentive/keeper/btc_staking_gauge.go +++ b/x/incentive/keeper/btc_staking_gauge.go @@ -19,6 +19,7 @@ func (k Keeper) RewardBTCStaking(ctx context.Context, height uint64, dc *ftypes. // failing to get a reward gauge at previous height is a programming error panic("failed to get a reward gauge at previous height") } + // TODO(rafilx): Finality providers also use the available rewards instead of reward gauge. // reward each of the finality provider and its BTC delegations in proportion for i, fp := range dc.FinalityProviders { // only reward the first NumActiveFps finality providers @@ -36,6 +37,7 @@ func (k Keeper) RewardBTCStaking(ctx context.Context, height uint64, dc *ftypes. k.accumulateRewardGauge(ctx, types.FinalityProviderType, fp.GetAddress(), coinsForCommission) // reward the rest of coins to each BTC delegation proportional to its voting power portion coinsForBTCDels := coinsForFpsAndDels.Sub(coinsForCommission...) + // TODO: remove this iteration. It could be avoided by using accumulated rewards per period // for each finality provider, and for each delegation (fp, delegator) keep track of last period // TODO(rafilx): Add acumulative rewards for each validator diff --git a/x/incentive/types/rewards.pb.go b/x/incentive/types/rewards.pb.go new file mode 100644 index 000000000..8bd4d3a12 --- /dev/null +++ b/x/incentive/types/rewards.pb.go @@ -0,0 +1,344 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: babylon/incentive/rewards.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// FinalityProviderRewards represents the cumulative rewards ratio of the +// finality provider per sat in that period. +// The period is ommited here and should be part of the key used to store this structure. +type FinalityProviderRewards struct { + // The cumulative rewards of that finality provider at some specific period + // This coins will aways increase the value, never be reduced due to keep acumulation + // and when the cumulative rewards will be used to distribute rewards, 2 periods will + // be interpolated and calculate the difference and multiplied by the total sat amount delegated + // https://github.com/cosmos/cosmos-sdk/blob/e76102f885b71fd6e1c1efb692052173c4b3c3a3/x/distribution/keeper/delegation.go#L47 + // This is also not considering slash of the rewards. + CumulativeRewardsPerSat github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=CumulativeRewardsPerSat,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"CumulativeRewardsPerSat"` +} + +func (m *FinalityProviderRewards) Reset() { *m = FinalityProviderRewards{} } +func (m *FinalityProviderRewards) String() string { return proto.CompactTextString(m) } +func (*FinalityProviderRewards) ProtoMessage() {} +func (*FinalityProviderRewards) Descriptor() ([]byte, []int) { + return fileDescriptor_fa5a587351117eb0, []int{0} +} +func (m *FinalityProviderRewards) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FinalityProviderRewards) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FinalityProviderRewards.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *FinalityProviderRewards) XXX_Merge(src proto.Message) { + xxx_messageInfo_FinalityProviderRewards.Merge(m, src) +} +func (m *FinalityProviderRewards) XXX_Size() int { + return m.Size() +} +func (m *FinalityProviderRewards) XXX_DiscardUnknown() { + xxx_messageInfo_FinalityProviderRewards.DiscardUnknown(m) +} + +var xxx_messageInfo_FinalityProviderRewards proto.InternalMessageInfo + +func (m *FinalityProviderRewards) GetCumulativeRewardsPerSat() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.CumulativeRewardsPerSat + } + return nil +} + +func init() { + proto.RegisterType((*FinalityProviderRewards)(nil), "babylon.incentive.FinalityProviderRewards") +} + +func init() { proto.RegisterFile("babylon/incentive/rewards.proto", fileDescriptor_fa5a587351117eb0) } + +var fileDescriptor_fa5a587351117eb0 = []byte{ + // 269 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0x4a, 0x4c, 0xaa, + 0xcc, 0xc9, 0xcf, 0xd3, 0xcf, 0xcc, 0x4b, 0x4e, 0xcd, 0x2b, 0xc9, 0x2c, 0x4b, 0xd5, 0x2f, 0x4a, + 0x2d, 0x4f, 0x2c, 0x4a, 0x29, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x84, 0x2a, 0xd0, + 0x83, 0x2b, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xcb, 0xea, 0x83, 0x58, 0x10, 0x85, 0x52, + 0x72, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0x49, 0x89, 0xc5, 0xa9, 0xfa, 0x65, 0x86, 0x49, + 0xa9, 0x25, 0x89, 0x86, 0xfa, 0xc9, 0xf9, 0x99, 0x79, 0x10, 0x79, 0xa5, 0x85, 0x8c, 0x5c, 0xe2, + 0x6e, 0x99, 0x79, 0x89, 0x39, 0x99, 0x25, 0x95, 0x01, 0x45, 0xf9, 0x65, 0x99, 0x29, 0xa9, 0x45, + 0x41, 0x10, 0xab, 0x84, 0x5a, 0x19, 0xb9, 0xc4, 0x9d, 0x4b, 0x73, 0x4b, 0x73, 0x12, 0x41, 0x16, + 0x40, 0x45, 0x03, 0x52, 0x8b, 0x82, 0x13, 0x4b, 0x24, 0x18, 0x15, 0x98, 0x35, 0xb8, 0x8d, 0x24, + 0xf5, 0x20, 0xc6, 0xeb, 0x81, 0x8c, 0xd7, 0x83, 0x1a, 0xaf, 0xe7, 0x9c, 0x9f, 0x99, 0xe7, 0x64, + 0x70, 0xe2, 0x9e, 0x3c, 0xc3, 0xaa, 0xfb, 0xf2, 0x1a, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, + 0xc9, 0xf9, 0xb9, 0xfa, 0x50, 0xb7, 0x40, 0x28, 0xdd, 0xe2, 0x94, 0x6c, 0xfd, 0x92, 0xca, 0x82, + 0xd4, 0x62, 0xb0, 0x86, 0xe2, 0x20, 0x5c, 0x76, 0x39, 0xf9, 0x9e, 0x78, 0x24, 0xc7, 0x78, 0xe1, + 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, + 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x31, 0x92, 0xe1, 0xd0, 0x10, 0xc9, 0x49, 0x4c, 0x2a, 0xd6, 0xcd, + 0xcc, 0x87, 0x71, 0xf5, 0x2b, 0x90, 0xc2, 0x10, 0x6c, 0x5b, 0x12, 0x1b, 0xd8, 0xe7, 0xc6, 0x80, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x12, 0xa7, 0x76, 0x9c, 0x65, 0x01, 0x00, 0x00, +} + +func (m *FinalityProviderRewards) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *FinalityProviderRewards) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FinalityProviderRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CumulativeRewardsPerSat) > 0 { + for iNdEx := len(m.CumulativeRewardsPerSat) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.CumulativeRewardsPerSat[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRewards(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintRewards(dAtA []byte, offset int, v uint64) int { + offset -= sovRewards(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *FinalityProviderRewards) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.CumulativeRewardsPerSat) > 0 { + for _, e := range m.CumulativeRewardsPerSat { + l = e.Size() + n += 1 + l + sovRewards(uint64(l)) + } + } + return n +} + +func sovRewards(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozRewards(x uint64) (n int) { + return sovRewards(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *FinalityProviderRewards) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FinalityProviderRewards: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FinalityProviderRewards: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CumulativeRewardsPerSat", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CumulativeRewardsPerSat = append(m.CumulativeRewardsPerSat, types.Coin{}) + if err := m.CumulativeRewardsPerSat[len(m.CumulativeRewardsPerSat)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRewards(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRewards + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipRewards(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRewards + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRewards + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRewards + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthRewards + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupRewards + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthRewards + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthRewards = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowRewards = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupRewards = fmt.Errorf("proto: unexpected end of group") +) From 58d9451e06545ac0d9011daa3d190767036051c3 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 27 Nov 2024 23:45:13 -0300 Subject: [PATCH 003/132] chore: add BTC delegation rewards structure tracker --- proto/babylon/incentive/rewards.proto | 9 + x/incentive/types/rewards.pb.go | 234 ++++++++++++++++++++++++-- 2 files changed, 225 insertions(+), 18 deletions(-) diff --git a/proto/babylon/incentive/rewards.proto b/proto/babylon/incentive/rewards.proto index 4ba11b10e..bfcff7735 100644 --- a/proto/babylon/incentive/rewards.proto +++ b/proto/babylon/incentive/rewards.proto @@ -23,3 +23,12 @@ message FinalityProviderRewards { // TODO(rafilx): add reference count for state prunning // https://github.com/cosmos/cosmos-sdk/blob/d9c53bfefc1e75a3c6b09065ea8b3a836cda0d18/x/distribution/types/distribution.pb.go#L98 } + +// BTCDelegationRewardsTracker represents the structure that holds information +// from the last time this BTC delegator withdraw the rewards from the finality provider +// The finality provider address is ommitted here but should be part of the key used +// to store this structure together with the BTC delegator address. +message BTCDelegationRewardsTracker { + uint64 StartPeriodCumulativeRewardFP = 1; + uint64 DelegationTotalActiveSat = 2; +} \ No newline at end of file diff --git a/x/incentive/types/rewards.pb.go b/x/incentive/types/rewards.pb.go index 8bd4d3a12..46f3b1d7c 100644 --- a/x/incentive/types/rewards.pb.go +++ b/x/incentive/types/rewards.pb.go @@ -78,31 +78,93 @@ func (m *FinalityProviderRewards) GetCumulativeRewardsPerSat() github_com_cosmos return nil } +// BTCDelegationRewardsTracker represents the structure that holds information +// from the last time this BTC delegator withdraw the rewards from the finality provider +// The finality provider address is ommitted here but should be part of the key used +// to store this structure together with the BTC delegator address. +type BTCDelegationRewardsTracker struct { + StartPeriodCumulativeRewardFP uint64 `protobuf:"varint,1,opt,name=StartPeriodCumulativeRewardFP,proto3" json:"StartPeriodCumulativeRewardFP,omitempty"` + DelegationTotalActiveSat uint64 `protobuf:"varint,2,opt,name=DelegationTotalActiveSat,proto3" json:"DelegationTotalActiveSat,omitempty"` +} + +func (m *BTCDelegationRewardsTracker) Reset() { *m = BTCDelegationRewardsTracker{} } +func (m *BTCDelegationRewardsTracker) String() string { return proto.CompactTextString(m) } +func (*BTCDelegationRewardsTracker) ProtoMessage() {} +func (*BTCDelegationRewardsTracker) Descriptor() ([]byte, []int) { + return fileDescriptor_fa5a587351117eb0, []int{1} +} +func (m *BTCDelegationRewardsTracker) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BTCDelegationRewardsTracker) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BTCDelegationRewardsTracker.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BTCDelegationRewardsTracker) XXX_Merge(src proto.Message) { + xxx_messageInfo_BTCDelegationRewardsTracker.Merge(m, src) +} +func (m *BTCDelegationRewardsTracker) XXX_Size() int { + return m.Size() +} +func (m *BTCDelegationRewardsTracker) XXX_DiscardUnknown() { + xxx_messageInfo_BTCDelegationRewardsTracker.DiscardUnknown(m) +} + +var xxx_messageInfo_BTCDelegationRewardsTracker proto.InternalMessageInfo + +func (m *BTCDelegationRewardsTracker) GetStartPeriodCumulativeRewardFP() uint64 { + if m != nil { + return m.StartPeriodCumulativeRewardFP + } + return 0 +} + +func (m *BTCDelegationRewardsTracker) GetDelegationTotalActiveSat() uint64 { + if m != nil { + return m.DelegationTotalActiveSat + } + return 0 +} + func init() { proto.RegisterType((*FinalityProviderRewards)(nil), "babylon.incentive.FinalityProviderRewards") + proto.RegisterType((*BTCDelegationRewardsTracker)(nil), "babylon.incentive.BTCDelegationRewardsTracker") } func init() { proto.RegisterFile("babylon/incentive/rewards.proto", fileDescriptor_fa5a587351117eb0) } var fileDescriptor_fa5a587351117eb0 = []byte{ - // 269 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0x4a, 0x4c, 0xaa, - 0xcc, 0xc9, 0xcf, 0xd3, 0xcf, 0xcc, 0x4b, 0x4e, 0xcd, 0x2b, 0xc9, 0x2c, 0x4b, 0xd5, 0x2f, 0x4a, - 0x2d, 0x4f, 0x2c, 0x4a, 0x29, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x84, 0x2a, 0xd0, - 0x83, 0x2b, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xcb, 0xea, 0x83, 0x58, 0x10, 0x85, 0x52, - 0x72, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0x49, 0x89, 0xc5, 0xa9, 0xfa, 0x65, 0x86, 0x49, - 0xa9, 0x25, 0x89, 0x86, 0xfa, 0xc9, 0xf9, 0x99, 0x79, 0x10, 0x79, 0xa5, 0x85, 0x8c, 0x5c, 0xe2, - 0x6e, 0x99, 0x79, 0x89, 0x39, 0x99, 0x25, 0x95, 0x01, 0x45, 0xf9, 0x65, 0x99, 0x29, 0xa9, 0x45, - 0x41, 0x10, 0xab, 0x84, 0x5a, 0x19, 0xb9, 0xc4, 0x9d, 0x4b, 0x73, 0x4b, 0x73, 0x12, 0x41, 0x16, - 0x40, 0x45, 0x03, 0x52, 0x8b, 0x82, 0x13, 0x4b, 0x24, 0x18, 0x15, 0x98, 0x35, 0xb8, 0x8d, 0x24, - 0xf5, 0x20, 0xc6, 0xeb, 0x81, 0x8c, 0xd7, 0x83, 0x1a, 0xaf, 0xe7, 0x9c, 0x9f, 0x99, 0xe7, 0x64, - 0x70, 0xe2, 0x9e, 0x3c, 0xc3, 0xaa, 0xfb, 0xf2, 0x1a, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, - 0xc9, 0xf9, 0xb9, 0xfa, 0x50, 0xb7, 0x40, 0x28, 0xdd, 0xe2, 0x94, 0x6c, 0xfd, 0x92, 0xca, 0x82, - 0xd4, 0x62, 0xb0, 0x86, 0xe2, 0x20, 0x5c, 0x76, 0x39, 0xf9, 0x9e, 0x78, 0x24, 0xc7, 0x78, 0xe1, - 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, - 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x31, 0x92, 0xe1, 0xd0, 0x10, 0xc9, 0x49, 0x4c, 0x2a, 0xd6, 0xcd, - 0xcc, 0x87, 0x71, 0xf5, 0x2b, 0x90, 0xc2, 0x10, 0x6c, 0x5b, 0x12, 0x1b, 0xd8, 0xe7, 0xc6, 0x80, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x12, 0xa7, 0x76, 0x9c, 0x65, 0x01, 0x00, 0x00, + // 337 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xb1, 0x4e, 0x02, 0x31, + 0x1c, 0xc6, 0xaf, 0x6a, 0x1c, 0xce, 0xc9, 0x8b, 0x09, 0x88, 0xb1, 0x10, 0x26, 0x16, 0x5a, 0x91, + 0xcd, 0x4d, 0x20, 0x6c, 0x26, 0x17, 0x60, 0x72, 0x6b, 0xef, 0x9a, 0xb3, 0xe1, 0xe8, 0x9f, 0xb4, + 0x05, 0xe5, 0x01, 0xdc, 0x7d, 0x03, 0xe3, 0xea, 0x93, 0x30, 0x32, 0x3a, 0xa9, 0x81, 0x17, 0x31, + 0x77, 0x57, 0x95, 0x98, 0xe0, 0x74, 0xd7, 0x7e, 0x5f, 0x7f, 0x5f, 0xff, 0xfd, 0xfc, 0x2a, 0x67, + 0x7c, 0x91, 0x82, 0xa2, 0x52, 0x45, 0x42, 0x59, 0x39, 0x17, 0x54, 0x8b, 0x7b, 0xa6, 0x63, 0x43, + 0xa6, 0x1a, 0x2c, 0x04, 0xc7, 0xce, 0x40, 0x7e, 0x0c, 0x95, 0x93, 0x04, 0x12, 0xc8, 0x55, 0x9a, + 0xfd, 0x15, 0xc6, 0x0a, 0x8e, 0xc0, 0x4c, 0xc0, 0x50, 0xce, 0x8c, 0xa0, 0xf3, 0x16, 0x17, 0x96, + 0xb5, 0x68, 0x04, 0x52, 0x15, 0x7a, 0xfd, 0x05, 0xf9, 0xa5, 0xbe, 0x54, 0x2c, 0x95, 0x76, 0x11, + 0x6a, 0x98, 0xcb, 0x58, 0xe8, 0x41, 0x11, 0x15, 0x3c, 0x22, 0xbf, 0xd4, 0x9d, 0x4d, 0x66, 0x29, + 0xcb, 0x02, 0xdc, 0x6e, 0x28, 0xf4, 0x90, 0xd9, 0x32, 0xaa, 0xed, 0x37, 0x8e, 0x2e, 0x4f, 0x49, + 0x81, 0x27, 0x19, 0x9e, 0x38, 0x3c, 0xe9, 0x82, 0x54, 0x9d, 0x8b, 0xe5, 0x7b, 0xd5, 0x7b, 0xfd, + 0xa8, 0x36, 0x12, 0x69, 0xef, 0x66, 0x9c, 0x44, 0x30, 0xa1, 0xee, 0x2e, 0xc5, 0xa7, 0x69, 0xe2, + 0x31, 0xb5, 0x8b, 0xa9, 0x30, 0xf9, 0x01, 0x33, 0xd8, 0x95, 0x55, 0x7f, 0x46, 0xfe, 0x59, 0x67, + 0xd4, 0xed, 0x89, 0x54, 0x24, 0xcc, 0x4a, 0x50, 0x4e, 0x1e, 0x69, 0x16, 0x8d, 0x85, 0x0e, 0x7a, + 0xfe, 0xf9, 0xd0, 0x32, 0x6d, 0x43, 0xa1, 0x25, 0xc4, 0x7f, 0x29, 0xfd, 0xb0, 0x8c, 0x6a, 0xa8, + 0x71, 0x30, 0xf8, 0xdf, 0x14, 0x5c, 0xf9, 0xe5, 0xdf, 0x84, 0x11, 0x58, 0x96, 0x5e, 0x47, 0x99, + 0x21, 0x9b, 0x76, 0x2f, 0x07, 0xec, 0xd4, 0x3b, 0x37, 0xcb, 0x35, 0x46, 0xab, 0x35, 0x46, 0x9f, + 0x6b, 0x8c, 0x9e, 0x36, 0xd8, 0x5b, 0x6d, 0xb0, 0xf7, 0xb6, 0xc1, 0xde, 0x6d, 0x7b, 0x6b, 0x7c, + 0xd7, 0x59, 0xca, 0xb8, 0x69, 0x4a, 0xf8, 0x5e, 0xd2, 0x87, 0xad, 0x96, 0xf3, 0xf7, 0xe0, 0x87, + 0x79, 0x37, 0xed, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x82, 0xc4, 0x0e, 0x11, 0x07, 0x02, 0x00, + 0x00, } func (m *FinalityProviderRewards) Marshal() (dAtA []byte, err error) { @@ -142,6 +204,39 @@ func (m *FinalityProviderRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *BTCDelegationRewardsTracker) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BTCDelegationRewardsTracker) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BTCDelegationRewardsTracker) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.DelegationTotalActiveSat != 0 { + i = encodeVarintRewards(dAtA, i, uint64(m.DelegationTotalActiveSat)) + i-- + dAtA[i] = 0x10 + } + if m.StartPeriodCumulativeRewardFP != 0 { + i = encodeVarintRewards(dAtA, i, uint64(m.StartPeriodCumulativeRewardFP)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintRewards(dAtA []byte, offset int, v uint64) int { offset -= sovRewards(v) base := offset @@ -168,6 +263,21 @@ func (m *FinalityProviderRewards) Size() (n int) { return n } +func (m *BTCDelegationRewardsTracker) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.StartPeriodCumulativeRewardFP != 0 { + n += 1 + sovRewards(uint64(m.StartPeriodCumulativeRewardFP)) + } + if m.DelegationTotalActiveSat != 0 { + n += 1 + sovRewards(uint64(m.DelegationTotalActiveSat)) + } + return n +} + func sovRewards(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -258,6 +368,94 @@ func (m *FinalityProviderRewards) Unmarshal(dAtA []byte) error { } return nil } +func (m *BTCDelegationRewardsTracker) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BTCDelegationRewardsTracker: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BTCDelegationRewardsTracker: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StartPeriodCumulativeRewardFP", wireType) + } + m.StartPeriodCumulativeRewardFP = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StartPeriodCumulativeRewardFP |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegationTotalActiveSat", wireType) + } + m.DelegationTotalActiveSat = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DelegationTotalActiveSat |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipRewards(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRewards + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipRewards(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From 598608c38a326b8890e5083d90f2505b2d05c829 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Fri, 29 Nov 2024 20:32:48 -0300 Subject: [PATCH 004/132] chore: add todos and descriptions for rewards tracker --- proto/babylon/incentive/rewards.proto | 23 +- x/btcstaking/keeper/btc_delegators.go | 176 +++++++++++++ x/btcstaking/types/keys.go | 2 + x/finality/types/expected_keepers.go | 3 + x/finality/types/mocked_keepers.go | 28 ++ x/incentive/keeper/btc_staking_gauge.go | 2 + x/incentive/keeper/reward_tracker.go | 88 +++++++ x/incentive/types/errors.go | 7 +- x/incentive/types/keys.go | 11 +- x/incentive/types/rewards.go | 8 + x/incentive/types/rewards.pb.go | 330 ++++++++++++++++++++---- 11 files changed, 618 insertions(+), 60 deletions(-) create mode 100644 x/incentive/keeper/reward_tracker.go create mode 100644 x/incentive/types/rewards.go diff --git a/proto/babylon/incentive/rewards.proto b/proto/babylon/incentive/rewards.proto index bfcff7735..e44180dab 100644 --- a/proto/babylon/incentive/rewards.proto +++ b/proto/babylon/incentive/rewards.proto @@ -6,10 +6,10 @@ import "cosmos/base/v1beta1/coin.proto"; option go_package = "github.com/babylonlabs-io/babylon/x/incentive/types"; -// FinalityProviderRewards represents the cumulative rewards ratio of the +// FinalityProviderHistoricalRewards represents the cumulative rewards ratio of the // finality provider per sat in that period. // The period is ommited here and should be part of the key used to store this structure. -message FinalityProviderRewards { +message FinalityProviderHistoricalRewards { // The cumulative rewards of that finality provider at some specific period // This coins will aways increase the value, never be reduced due to keep acumulation // and when the cumulative rewards will be used to distribute rewards, 2 periods will @@ -24,6 +24,25 @@ message FinalityProviderRewards { // https://github.com/cosmos/cosmos-sdk/blob/d9c53bfefc1e75a3c6b09065ea8b3a836cda0d18/x/distribution/types/distribution.pb.go#L98 } +// FinalityProviderCurrentRewards represents the current rewards of the pool of +// BTC delegations that this finality provider is entitled to. +// Note: This rewards are for the BTC delegators that delegated to this FP +// the FP itself is not the owner or can withdraw this rewards. +message FinalityProviderCurrentRewards { + // CurrentRewards is the current rewards that the finality provider have and it was not + // yet stored inside the FinalityProviderHistoricalRewards. Once something happens that + // modifies the amount of satoshis delegated to this finality provider (activation, unbonding, slash) + // a new period must be created, accumulate this rewards to FinalityProviderHistoricalRewards + // with a new period and zero out the Current Rewards. + repeated cosmos.base.v1beta1.Coin CurrentRewards = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + // Period stores the current period that serves as a reference for + // creating new historical rewards. + uint64 period = 2; +} + // BTCDelegationRewardsTracker represents the structure that holds information // from the last time this BTC delegator withdraw the rewards from the finality provider // The finality provider address is ommitted here but should be part of the key used diff --git a/x/btcstaking/keeper/btc_delegators.go b/x/btcstaking/keeper/btc_delegators.go index 550a899fa..509831435 100644 --- a/x/btcstaking/keeper/btc_delegators.go +++ b/x/btcstaking/keeper/btc_delegators.go @@ -5,7 +5,11 @@ import ( "github.com/cosmos/cosmos-sdk/runtime" + corestoretypes "cosmossdk.io/core/store" + sdkmath "cosmossdk.io/math" "cosmossdk.io/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/btcsuite/btcd/chaincfg/chainhash" bbn "github.com/babylonlabs-io/babylon/types" @@ -77,3 +81,175 @@ func (k Keeper) btcDelegatorStore(ctx context.Context) prefix.Store { storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) return prefix.NewStore(storeAdapter, types.BTCDelegatorKey) } + +// storeDelStaked returns the KVStore of the delegator amount staked +// prefix: (DelegatorStakedBTCKey) +// key: Del addr +// value: sdk math Int +func (k Keeper) storeDelStaked(ctx context.Context) prefix.Store { + storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + return prefix.NewStore(storeAdapter, types.DelegatorStakedBTCKey) +} + +// Total active satoshi staked that is entitled to earn rewards. +func (k Keeper) TotalSatoshiStaked(ctx context.Context) (sdkmath.Int, error) { + kv := k.storeService.OpenKVStore(ctx) + key := types.TotalStakedBTCKey + return StoreGetInt(kv, key) +} + +func (k Keeper) addTotalSatoshiStaked(ctx context.Context, amtToAdd sdkmath.Int) (sdkmath.Int, error) { + kv := k.storeService.OpenKVStore(ctx) + key := types.TotalStakedBTCKey + + current, err := StoreGetInt(kv, key) + if err != nil { + return sdkmath.Int{}, err + } + + total := current.Add(amtToAdd) + if err := StoreSetInt(kv, key, total); err != nil { + return sdkmath.Int{}, err + } + + return total, nil +} + +func (k Keeper) subTotalSatoshiStaked(ctx context.Context, amtToAdd sdkmath.Int) (sdkmath.Int, error) { + kv := k.storeService.OpenKVStore(ctx) + key := types.TotalStakedBTCKey + + current, err := StoreGetInt(kv, key) + if err != nil { + return sdkmath.Int{}, err + } + + total := current.Sub(amtToAdd) + if err := StoreSetInt(kv, key, total); err != nil { + return sdkmath.Int{}, err + } + + return total, nil +} + +func (k Keeper) AddDelStaking(ctx context.Context, del sdk.AccAddress, amt sdkmath.Int) error { + st := k.storeDelStaked(ctx) + + currentStk, err := PrefixStoreGetInt(st, del) + if err != nil { + return err + } + + totalDelStaked := currentStk.Add(amt) + bz, err := totalDelStaked.Marshal() + if err != nil { + return err + } + + st.Set(del, bz) + _, err = k.addTotalSatoshiStaked(ctx, amt) + return err +} + +func (k Keeper) SubDelStaking(ctx context.Context, del sdk.AccAddress, amt sdkmath.Int) error { + st := k.storeDelStaked(ctx) + + currentStk, err := PrefixStoreGetInt(st, del) + if err != nil { + return err + } + + totalDelStaked := currentStk.Sub(amt) + bz, err := totalDelStaked.Marshal() + if err != nil { + return err + } + + st.Set(del, bz) + _, err = k.subTotalSatoshiStaked(ctx, amt) + return err +} + +func PrefixStoreGetInt(st prefix.Store, key []byte) (vInt sdkmath.Int, err error) { + if !st.Has(key) { + return sdkmath.NewInt(0), nil + } + + bz := st.Get(key) + vInt, err = ParseInt(bz) + if err != nil { + return sdkmath.Int{}, err + } + + return vInt, nil +} + +// StoreSetInt stores an sdkmath.Int from the KVStore. +func StoreSetInt(kv corestoretypes.KVStore, key []byte, vInt sdkmath.Int) (err error) { + bz, err := vInt.Marshal() + if err != nil { + return err + } + return kv.Set(key, bz) +} + +// StoreGetInt retrieves an sdkmath.Int from the KVStore. It returns zero int if not found. +func StoreGetInt(kv corestoretypes.KVStore, key []byte) (vInt sdkmath.Int, err error) { + exists, err := kv.Has(key) + if err != nil { + return sdkmath.Int{}, err + } + + if !exists { + return sdkmath.NewInt(0), nil + } + + bz, err := kv.Get(key) + if err != nil { + return sdkmath.Int{}, err + } + + vInt, err = ParseInt(bz) + if err != nil { + return sdkmath.Int{}, err + } + return vInt, nil +} + +// ParseInt parses an sdkmath.Int from bytes. +func ParseInt(bz []byte) (sdkmath.Int, error) { + var val sdkmath.Int + if err := val.Unmarshal(bz); err != nil { + return val, err + } + return val, nil +} + +// IterateBTCDelegators iterates over all the delegators that have some active BTC delegator +// staked and the total satoshi staked for that delegator address until an error is returned +// or the iterator finishes. Stops if error is returned. +// Should keep track of the total satoshi staked per delegator to avoid iterating over the +// delegator delegations +// func (k Keeper) IterateBTCDelegators(ctx context.Context, i func(delegator sdk.AccAddress, totalSatoshiStaked sdkmath.Int) error) error { +// st := k.storeDelStaked(ctx) + +// iter := st.Iterator(nil, nil) +// defer iter.Close() + +// for ; iter.Valid(); iter.Next() { +// sdkAddrBz := iter.Key() +// delAddr := sdk.AccAddress(sdkAddrBz) + +// delBtcStaked, err := ParseInt(iter.Value()) +// if err != nil { +// return err +// } + +// err = i(delAddr, delBtcStaked) +// if err != nil { +// return err +// } +// } + +// return nil +// } diff --git a/x/btcstaking/types/keys.go b/x/btcstaking/types/keys.go index a3313b97b..eeb4ee795 100644 --- a/x/btcstaking/types/keys.go +++ b/x/btcstaking/types/keys.go @@ -26,4 +26,6 @@ var ( // 0x07 was used for something else in the past PowerDistUpdateKey = []byte{0x08} // key prefix for power distribution update events AllowedStakingTxHashesKey = collections.NewPrefix(9) // key prefix for allowed staking tx hashes + DelegatorStakedBTCKey = []byte{0xA} // key prefix for delegator active staked amount int math.Int + TotalStakedBTCKey = []byte{0xB} // key prefix for protocol active staked amount int math.Int ) diff --git a/x/finality/types/expected_keepers.go b/x/finality/types/expected_keepers.go index b42441742..b82568bdf 100644 --- a/x/finality/types/expected_keepers.go +++ b/x/finality/types/expected_keepers.go @@ -34,4 +34,7 @@ type CheckpointingKeeper interface { type IncentiveKeeper interface { RewardBTCStaking(ctx context.Context, height uint64, filteredDc *VotingPowerDistCache) IndexRefundableMsg(ctx context.Context, msg sdk.Msg) + BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error + BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error + // TODO: handle slash } diff --git a/x/finality/types/mocked_keepers.go b/x/finality/types/mocked_keepers.go index 30bd8b13f..c789d904e 100644 --- a/x/finality/types/mocked_keepers.go +++ b/x/finality/types/mocked_keepers.go @@ -279,6 +279,34 @@ func (m *MockIncentiveKeeper) EXPECT() *MockIncentiveKeeperMockRecorder { return m.recorder } +// BtcDelegationActivated mocks base method. +func (m *MockIncentiveKeeper) BtcDelegationActivated(ctx context.Context, fp, del types1.AccAddress, sat uint64) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BtcDelegationActivated", ctx, fp, del, sat) + ret0, _ := ret[0].(error) + return ret0 +} + +// BtcDelegationActivated indicates an expected call of BtcDelegationActivated. +func (mr *MockIncentiveKeeperMockRecorder) BtcDelegationActivated(ctx, fp, del, sat interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BtcDelegationActivated", reflect.TypeOf((*MockIncentiveKeeper)(nil).BtcDelegationActivated), ctx, fp, del, sat) +} + +// BtcDelegationUnbonded mocks base method. +func (m *MockIncentiveKeeper) BtcDelegationUnbonded(ctx context.Context, fp, del types1.AccAddress, sat uint64) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BtcDelegationUnbonded", ctx, fp, del, sat) + ret0, _ := ret[0].(error) + return ret0 +} + +// BtcDelegationUnbonded indicates an expected call of BtcDelegationUnbonded. +func (mr *MockIncentiveKeeperMockRecorder) BtcDelegationUnbonded(ctx, fp, del, sat interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BtcDelegationUnbonded", reflect.TypeOf((*MockIncentiveKeeper)(nil).BtcDelegationUnbonded), ctx, fp, del, sat) +} + // IndexRefundableMsg mocks base method. func (m *MockIncentiveKeeper) IndexRefundableMsg(ctx context.Context, msg types1.Msg) { m.ctrl.T.Helper() diff --git a/x/incentive/keeper/btc_staking_gauge.go b/x/incentive/keeper/btc_staking_gauge.go index 3cbd5e792..9a9d0501c 100644 --- a/x/incentive/keeper/btc_staking_gauge.go +++ b/x/incentive/keeper/btc_staking_gauge.go @@ -35,8 +35,10 @@ func (k Keeper) RewardBTCStaking(ctx context.Context, height uint64, dc *ftypes. // reward the finality provider with commission coinsForCommission := types.GetCoinsPortion(coinsForFpsAndDels, *fp.Commission) k.accumulateRewardGauge(ctx, types.FinalityProviderType, fp.GetAddress(), coinsForCommission) + // reward the rest of coins to each BTC delegation proportional to its voting power portion coinsForBTCDels := coinsForFpsAndDels.Sub(coinsForCommission...) + // TODO(rafilx): add the coins entitled to the BTC delegations to the FinalityProviderCurrentRewards // TODO: remove this iteration. It could be avoided by using accumulated rewards per period // for each finality provider, and for each delegation (fp, delegator) keep track of last period diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go new file mode 100644 index 000000000..be08ae3f2 --- /dev/null +++ b/x/incentive/keeper/reward_tracker.go @@ -0,0 +1,88 @@ +package keeper + +import ( + "context" + + "cosmossdk.io/store/prefix" + "github.com/babylonlabs-io/babylon/x/incentive/types" + "github.com/cosmos/cosmos-sdk/runtime" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { + // if btc delegations does exists + // BeforeDelegationCreated + // IncrementValidatorPeriod + + // if btc delegations exists + // BeforeDelegationSharesModified + // withdrawDelegationRewards + // IncrementValidatorPeriod + + // IncrementValidatorPeriod + // gets the current rewards and send to historical the current period (the rewards are stored as "shares" which means the amount of rewards per satoshi) + // sets new empty current rewards with new period + + // adds new satoshi activated to + // val total + // val, del total + + return nil +} + +func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { + return nil +} + +// initializeBTCDelegation creates a new BTCDelegationRewardsTracker from the previous acumulative rewards +// period of the finality provider and it should be called right after a BTC delegator withdraw his rewards +// (in our case send the rewards to the reward gauge). Reminder that at every new modification to the amount +// of satoshi staked from this btc delegator to this finality provider (activivation or unbonding) of BTC +// delegations, it should withdraw all rewards (send to gauge) and initialize a new BTCDelegationRewardsTracker. +// TODO: add reference count to keep track of possible prunning state of val rewards +func (k Keeper) initializeBTCDelegation(ctx context.Context, fp, del sdk.AccAddress) error { + // period has already been incremented - we want to store the period ended by this delegation action + valCurrentRewards, err := k.GetFinalityProviderCurrentRewards(ctx, fp) + if err != nil { + return err + } + previousPeriod := valCurrentRewards.Period - 1 + + // validator, err := k.stakingKeeper.Validator(ctx, fp) + // if err != nil { + // return err + // } + + // delegation, err := k.stakingKeeper.Delegation(ctx, del, fp) + // if err != nil { + // return err + // } + + // sdkCtx := sdk.UnwrapSDKContext(ctx) + types.NewBTCDelegationRewardsTracker(previousPeriod, 0) + return nil + // return k.SetDelegatorStartingInfo(ctx, fp, del, dstrtypes.NewDelegatorStartingInfo(previousPeriod, stake, uint64(sdkCtx.BlockHeight()))) +} + +func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { + key := fp.Bytes() + bz := k.storeFpCurrentRewards(ctx).Get(key) + if bz == nil { + return types.FinalityProviderCurrentRewards{}, types.ErrFPCurrentRewardsNotFound + } + + var value types.FinalityProviderCurrentRewards + if err := k.cdc.Unmarshal(bz, &value); err != nil { + return types.FinalityProviderCurrentRewards{}, err + } + return value, nil +} + +// storeFpCurrentRewards returns the KVStore of the FP current rewards +// prefix: FinalityProviderCurrentRewardsKey +// key: (finality provider cosmos address) +// value: FinalityProviderCurrentRewards +func (k Keeper) storeFpCurrentRewards(ctx context.Context) prefix.Store { + storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + return prefix.NewStore(storeAdaptor, types.FinalityProviderCurrentRewardsKey) +} diff --git a/x/incentive/types/errors.go b/x/incentive/types/errors.go index ccf8a9dab..d70e67bb5 100644 --- a/x/incentive/types/errors.go +++ b/x/incentive/types/errors.go @@ -6,7 +6,8 @@ import ( // x/incentive module sentinel errors var ( - ErrBTCStakingGaugeNotFound = errorsmod.Register(ModuleName, 1100, "BTC staking gauge not found") - ErrRewardGaugeNotFound = errorsmod.Register(ModuleName, 1101, "reward gauge not found") - ErrNoWithdrawableCoins = errorsmod.Register(ModuleName, 1102, "no coin is withdrawable") + ErrBTCStakingGaugeNotFound = errorsmod.Register(ModuleName, 1100, "BTC staking gauge not found") + ErrRewardGaugeNotFound = errorsmod.Register(ModuleName, 1101, "reward gauge not found") + ErrNoWithdrawableCoins = errorsmod.Register(ModuleName, 1102, "no coin is withdrawable") + ErrFPCurrentRewardsNotFound = errorsmod.Register(ModuleName, 1103, "finality provider current rewards not found") ) diff --git a/x/incentive/types/keys.go b/x/incentive/types/keys.go index a7aeced74..b312b5cb8 100644 --- a/x/incentive/types/keys.go +++ b/x/incentive/types/keys.go @@ -17,9 +17,10 @@ const ( ) var ( - ParamsKey = []byte{0x01} // key prefix for the parameters - BTCStakingGaugeKey = []byte{0x02} // key prefix for BTC staking gauge at each height - ReservedKey = []byte{0x03} // reserved //nolint:unused - RewardGaugeKey = []byte{0x04} // key prefix for reward gauge for a given stakeholder in a given type - RefundableMsgKeySetPrefix = collections.NewPrefix(5) // key prefix for refundable msg key set + ParamsKey = []byte{0x01} // key prefix for the parameters + BTCStakingGaugeKey = []byte{0x02} // key prefix for BTC staking gauge at each height + ReservedKey = []byte{0x03} // reserved //nolint:unused + RewardGaugeKey = []byte{0x04} // key prefix for reward gauge for a given stakeholder in a given type + RefundableMsgKeySetPrefix = collections.NewPrefix(5) // key prefix for refundable msg key set + FinalityProviderCurrentRewardsKey = []byte{0x06} // key prefix for storing the Current rewards of finality provider by addr ) diff --git a/x/incentive/types/rewards.go b/x/incentive/types/rewards.go new file mode 100644 index 000000000..963573e16 --- /dev/null +++ b/x/incentive/types/rewards.go @@ -0,0 +1,8 @@ +package types + +func NewBTCDelegationRewardsTracker(startPeriod, totalSat uint64) BTCDelegationRewardsTracker { + return BTCDelegationRewardsTracker{ + StartPeriodCumulativeRewardFP: startPeriod, + DelegationTotalActiveSat: totalSat, + } +} diff --git a/x/incentive/types/rewards.pb.go b/x/incentive/types/rewards.pb.go index 46f3b1d7c..82a9adf71 100644 --- a/x/incentive/types/rewards.pb.go +++ b/x/incentive/types/rewards.pb.go @@ -25,10 +25,10 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// FinalityProviderRewards represents the cumulative rewards ratio of the +// FinalityProviderHistoricalRewards represents the cumulative rewards ratio of the // finality provider per sat in that period. // The period is ommited here and should be part of the key used to store this structure. -type FinalityProviderRewards struct { +type FinalityProviderHistoricalRewards struct { // The cumulative rewards of that finality provider at some specific period // This coins will aways increase the value, never be reduced due to keep acumulation // and when the cumulative rewards will be used to distribute rewards, 2 periods will @@ -38,18 +38,18 @@ type FinalityProviderRewards struct { CumulativeRewardsPerSat github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=CumulativeRewardsPerSat,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"CumulativeRewardsPerSat"` } -func (m *FinalityProviderRewards) Reset() { *m = FinalityProviderRewards{} } -func (m *FinalityProviderRewards) String() string { return proto.CompactTextString(m) } -func (*FinalityProviderRewards) ProtoMessage() {} -func (*FinalityProviderRewards) Descriptor() ([]byte, []int) { +func (m *FinalityProviderHistoricalRewards) Reset() { *m = FinalityProviderHistoricalRewards{} } +func (m *FinalityProviderHistoricalRewards) String() string { return proto.CompactTextString(m) } +func (*FinalityProviderHistoricalRewards) ProtoMessage() {} +func (*FinalityProviderHistoricalRewards) Descriptor() ([]byte, []int) { return fileDescriptor_fa5a587351117eb0, []int{0} } -func (m *FinalityProviderRewards) XXX_Unmarshal(b []byte) error { +func (m *FinalityProviderHistoricalRewards) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *FinalityProviderRewards) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *FinalityProviderHistoricalRewards) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_FinalityProviderRewards.Marshal(b, m, deterministic) + return xxx_messageInfo_FinalityProviderHistoricalRewards.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -59,25 +59,88 @@ func (m *FinalityProviderRewards) XXX_Marshal(b []byte, deterministic bool) ([]b return b[:n], nil } } -func (m *FinalityProviderRewards) XXX_Merge(src proto.Message) { - xxx_messageInfo_FinalityProviderRewards.Merge(m, src) +func (m *FinalityProviderHistoricalRewards) XXX_Merge(src proto.Message) { + xxx_messageInfo_FinalityProviderHistoricalRewards.Merge(m, src) } -func (m *FinalityProviderRewards) XXX_Size() int { +func (m *FinalityProviderHistoricalRewards) XXX_Size() int { return m.Size() } -func (m *FinalityProviderRewards) XXX_DiscardUnknown() { - xxx_messageInfo_FinalityProviderRewards.DiscardUnknown(m) +func (m *FinalityProviderHistoricalRewards) XXX_DiscardUnknown() { + xxx_messageInfo_FinalityProviderHistoricalRewards.DiscardUnknown(m) } -var xxx_messageInfo_FinalityProviderRewards proto.InternalMessageInfo +var xxx_messageInfo_FinalityProviderHistoricalRewards proto.InternalMessageInfo -func (m *FinalityProviderRewards) GetCumulativeRewardsPerSat() github_com_cosmos_cosmos_sdk_types.Coins { +func (m *FinalityProviderHistoricalRewards) GetCumulativeRewardsPerSat() github_com_cosmos_cosmos_sdk_types.Coins { if m != nil { return m.CumulativeRewardsPerSat } return nil } +// FinalityProviderCurrentRewards represents the current rewards of the pool of +// BTC delegations that this finality provider is entitled to. +// Note: This rewards are for the BTC delegators that delegated to this FP +// the FP itself is not the owner or can withdraw this rewards. +type FinalityProviderCurrentRewards struct { + // CurrentRewards is the current rewards that the finality provider have and it was not + // yet stored inside the FinalityProviderHistoricalRewards. Once something happens that + // modifies the amount of satoshis delegated to this finality provider (activation, unbonding, slash) + // a new period must be created, accumulate this rewards to FinalityProviderHistoricalRewards + // with a new period and zero out the Current Rewards. + CurrentRewards github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=CurrentRewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"CurrentRewards"` + // Period stores the current period that serves as a reference for + // creating new historical rewards. + Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` +} + +func (m *FinalityProviderCurrentRewards) Reset() { *m = FinalityProviderCurrentRewards{} } +func (m *FinalityProviderCurrentRewards) String() string { return proto.CompactTextString(m) } +func (*FinalityProviderCurrentRewards) ProtoMessage() {} +func (*FinalityProviderCurrentRewards) Descriptor() ([]byte, []int) { + return fileDescriptor_fa5a587351117eb0, []int{1} +} +func (m *FinalityProviderCurrentRewards) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FinalityProviderCurrentRewards) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FinalityProviderCurrentRewards.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *FinalityProviderCurrentRewards) XXX_Merge(src proto.Message) { + xxx_messageInfo_FinalityProviderCurrentRewards.Merge(m, src) +} +func (m *FinalityProviderCurrentRewards) XXX_Size() int { + return m.Size() +} +func (m *FinalityProviderCurrentRewards) XXX_DiscardUnknown() { + xxx_messageInfo_FinalityProviderCurrentRewards.DiscardUnknown(m) +} + +var xxx_messageInfo_FinalityProviderCurrentRewards proto.InternalMessageInfo + +func (m *FinalityProviderCurrentRewards) GetCurrentRewards() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.CurrentRewards + } + return nil +} + +func (m *FinalityProviderCurrentRewards) GetPeriod() uint64 { + if m != nil { + return m.Period + } + return 0 +} + // BTCDelegationRewardsTracker represents the structure that holds information // from the last time this BTC delegator withdraw the rewards from the finality provider // The finality provider address is ommitted here but should be part of the key used @@ -91,7 +154,7 @@ func (m *BTCDelegationRewardsTracker) Reset() { *m = BTCDelegationReward func (m *BTCDelegationRewardsTracker) String() string { return proto.CompactTextString(m) } func (*BTCDelegationRewardsTracker) ProtoMessage() {} func (*BTCDelegationRewardsTracker) Descriptor() ([]byte, []int) { - return fileDescriptor_fa5a587351117eb0, []int{1} + return fileDescriptor_fa5a587351117eb0, []int{2} } func (m *BTCDelegationRewardsTracker) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -135,39 +198,43 @@ func (m *BTCDelegationRewardsTracker) GetDelegationTotalActiveSat() uint64 { } func init() { - proto.RegisterType((*FinalityProviderRewards)(nil), "babylon.incentive.FinalityProviderRewards") + proto.RegisterType((*FinalityProviderHistoricalRewards)(nil), "babylon.incentive.FinalityProviderHistoricalRewards") + proto.RegisterType((*FinalityProviderCurrentRewards)(nil), "babylon.incentive.FinalityProviderCurrentRewards") proto.RegisterType((*BTCDelegationRewardsTracker)(nil), "babylon.incentive.BTCDelegationRewardsTracker") } func init() { proto.RegisterFile("babylon/incentive/rewards.proto", fileDescriptor_fa5a587351117eb0) } var fileDescriptor_fa5a587351117eb0 = []byte{ - // 337 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xb1, 0x4e, 0x02, 0x31, - 0x1c, 0xc6, 0xaf, 0x6a, 0x1c, 0xce, 0xc9, 0x8b, 0x09, 0x88, 0xb1, 0x10, 0x26, 0x16, 0x5a, 0x91, - 0xcd, 0x4d, 0x20, 0x6c, 0x26, 0x17, 0x60, 0x72, 0x6b, 0xef, 0x9a, 0xb3, 0xe1, 0xe8, 0x9f, 0xb4, - 0x05, 0xe5, 0x01, 0xdc, 0x7d, 0x03, 0xe3, 0xea, 0x93, 0x30, 0x32, 0x3a, 0xa9, 0x81, 0x17, 0x31, - 0x77, 0x57, 0x95, 0x98, 0xe0, 0x74, 0xd7, 0x7e, 0x5f, 0x7f, 0x5f, 0xff, 0xfd, 0xfc, 0x2a, 0x67, - 0x7c, 0x91, 0x82, 0xa2, 0x52, 0x45, 0x42, 0x59, 0x39, 0x17, 0x54, 0x8b, 0x7b, 0xa6, 0x63, 0x43, - 0xa6, 0x1a, 0x2c, 0x04, 0xc7, 0xce, 0x40, 0x7e, 0x0c, 0x95, 0x93, 0x04, 0x12, 0xc8, 0x55, 0x9a, - 0xfd, 0x15, 0xc6, 0x0a, 0x8e, 0xc0, 0x4c, 0xc0, 0x50, 0xce, 0x8c, 0xa0, 0xf3, 0x16, 0x17, 0x96, - 0xb5, 0x68, 0x04, 0x52, 0x15, 0x7a, 0xfd, 0x05, 0xf9, 0xa5, 0xbe, 0x54, 0x2c, 0x95, 0x76, 0x11, - 0x6a, 0x98, 0xcb, 0x58, 0xe8, 0x41, 0x11, 0x15, 0x3c, 0x22, 0xbf, 0xd4, 0x9d, 0x4d, 0x66, 0x29, - 0xcb, 0x02, 0xdc, 0x6e, 0x28, 0xf4, 0x90, 0xd9, 0x32, 0xaa, 0xed, 0x37, 0x8e, 0x2e, 0x4f, 0x49, - 0x81, 0x27, 0x19, 0x9e, 0x38, 0x3c, 0xe9, 0x82, 0x54, 0x9d, 0x8b, 0xe5, 0x7b, 0xd5, 0x7b, 0xfd, - 0xa8, 0x36, 0x12, 0x69, 0xef, 0x66, 0x9c, 0x44, 0x30, 0xa1, 0xee, 0x2e, 0xc5, 0xa7, 0x69, 0xe2, - 0x31, 0xb5, 0x8b, 0xa9, 0x30, 0xf9, 0x01, 0x33, 0xd8, 0x95, 0x55, 0x7f, 0x46, 0xfe, 0x59, 0x67, - 0xd4, 0xed, 0x89, 0x54, 0x24, 0xcc, 0x4a, 0x50, 0x4e, 0x1e, 0x69, 0x16, 0x8d, 0x85, 0x0e, 0x7a, - 0xfe, 0xf9, 0xd0, 0x32, 0x6d, 0x43, 0xa1, 0x25, 0xc4, 0x7f, 0x29, 0xfd, 0xb0, 0x8c, 0x6a, 0xa8, - 0x71, 0x30, 0xf8, 0xdf, 0x14, 0x5c, 0xf9, 0xe5, 0xdf, 0x84, 0x11, 0x58, 0x96, 0x5e, 0x47, 0x99, - 0x21, 0x9b, 0x76, 0x2f, 0x07, 0xec, 0xd4, 0x3b, 0x37, 0xcb, 0x35, 0x46, 0xab, 0x35, 0x46, 0x9f, - 0x6b, 0x8c, 0x9e, 0x36, 0xd8, 0x5b, 0x6d, 0xb0, 0xf7, 0xb6, 0xc1, 0xde, 0x6d, 0x7b, 0x6b, 0x7c, - 0xd7, 0x59, 0xca, 0xb8, 0x69, 0x4a, 0xf8, 0x5e, 0xd2, 0x87, 0xad, 0x96, 0xf3, 0xf7, 0xe0, 0x87, - 0x79, 0x37, 0xed, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x82, 0xc4, 0x0e, 0x11, 0x07, 0x02, 0x00, - 0x00, -} - -func (m *FinalityProviderRewards) Marshal() (dAtA []byte, err error) { + // 387 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x92, 0xbf, 0x6e, 0xe2, 0x40, + 0x10, 0xc6, 0xbd, 0x77, 0x27, 0x8a, 0x3d, 0xe9, 0xa4, 0xb3, 0x4e, 0x77, 0x3e, 0x4e, 0xb7, 0x70, + 0x54, 0x34, 0x78, 0x8f, 0xd0, 0xa5, 0x0b, 0x46, 0x28, 0x4d, 0x24, 0x0b, 0xa8, 0xd2, 0xad, 0xed, + 0x95, 0xb3, 0xc2, 0xec, 0xa0, 0xdd, 0x35, 0x09, 0x0f, 0x90, 0x3e, 0x6f, 0x90, 0x3e, 0x51, 0xde, + 0x83, 0x92, 0x32, 0x55, 0x12, 0xc1, 0x8b, 0x44, 0xfe, 0x43, 0x42, 0x90, 0x48, 0x97, 0xca, 0x9e, + 0x99, 0x6f, 0xf6, 0xf7, 0xed, 0xec, 0xe0, 0x5a, 0xc0, 0x82, 0x79, 0x02, 0x92, 0x0a, 0x19, 0x72, + 0x69, 0xc4, 0x8c, 0x53, 0xc5, 0xcf, 0x99, 0x8a, 0xb4, 0x3b, 0x55, 0x60, 0xc0, 0xfe, 0x5e, 0x0a, + 0xdc, 0x17, 0x41, 0xf5, 0x47, 0x0c, 0x31, 0xe4, 0x55, 0x9a, 0xfd, 0x15, 0xc2, 0x2a, 0x09, 0x41, + 0x4f, 0x40, 0xd3, 0x80, 0x69, 0x4e, 0x67, 0xed, 0x80, 0x1b, 0xd6, 0xa6, 0x21, 0x08, 0x59, 0xd4, + 0x1b, 0xb7, 0x08, 0xff, 0xeb, 0x0b, 0xc9, 0x12, 0x61, 0xe6, 0xbe, 0x82, 0x99, 0x88, 0xb8, 0x3a, + 0x16, 0xda, 0x80, 0x12, 0x21, 0x4b, 0x06, 0x05, 0xd4, 0xbe, 0x44, 0xf8, 0x97, 0x97, 0x4e, 0xd2, + 0x84, 0x65, 0xa8, 0x32, 0xeb, 0x73, 0x35, 0x64, 0xc6, 0x41, 0xf5, 0xcf, 0xcd, 0xaf, 0x07, 0xbf, + 0xdd, 0x02, 0xe4, 0x66, 0x20, 0xb7, 0x04, 0xb9, 0x1e, 0x08, 0xd9, 0xfd, 0xbf, 0x78, 0xa8, 0x59, + 0x37, 0x8f, 0xb5, 0x66, 0x2c, 0xcc, 0x59, 0x1a, 0xb8, 0x21, 0x4c, 0x68, 0xe9, 0xaa, 0xf8, 0xb4, + 0x74, 0x34, 0xa6, 0x66, 0x3e, 0xe5, 0x3a, 0x6f, 0xd0, 0x83, 0x7d, 0xac, 0xc6, 0x1d, 0xc2, 0x64, + 0xd7, 0xad, 0x97, 0x2a, 0xc5, 0xa5, 0xd9, 0x58, 0xd5, 0xf8, 0xdb, 0xdb, 0xcc, 0x47, 0x18, 0xdc, + 0x41, 0xd8, 0x3f, 0x71, 0x65, 0xca, 0x95, 0x80, 0xc8, 0xf9, 0x54, 0x47, 0xcd, 0x2f, 0x83, 0x32, + 0x6a, 0x5c, 0x23, 0xfc, 0xa7, 0x3b, 0xf2, 0x7a, 0x3c, 0xe1, 0x31, 0x33, 0x02, 0x64, 0xd9, 0x30, + 0x52, 0x2c, 0x1c, 0x73, 0x65, 0xf7, 0xf0, 0xdf, 0xa1, 0x61, 0xca, 0xf8, 0xb9, 0x7c, 0xf7, 0xd6, + 0x7d, 0xdf, 0x41, 0xf9, 0x71, 0xef, 0x8b, 0xec, 0x43, 0xec, 0xbc, 0x12, 0x46, 0x60, 0x58, 0x72, + 0x14, 0x66, 0x82, 0xec, 0x75, 0x0a, 0x3f, 0x7b, 0xeb, 0xdd, 0x93, 0xc5, 0x8a, 0xa0, 0xe5, 0x8a, + 0xa0, 0xa7, 0x15, 0x41, 0x57, 0x6b, 0x62, 0x2d, 0xd7, 0xc4, 0xba, 0x5f, 0x13, 0xeb, 0xb4, 0xb3, + 0x35, 0x8d, 0x72, 0xdb, 0x12, 0x16, 0xe8, 0x96, 0x80, 0x4d, 0x48, 0x2f, 0xb6, 0xf6, 0x33, 0x1f, + 0x4f, 0x50, 0xc9, 0xb7, 0xaa, 0xf3, 0x1c, 0x00, 0x00, 0xff, 0xff, 0x96, 0x0b, 0x56, 0x59, 0xc1, + 0x02, 0x00, 0x00, +} + +func (m *FinalityProviderHistoricalRewards) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -177,12 +244,12 @@ func (m *FinalityProviderRewards) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *FinalityProviderRewards) MarshalTo(dAtA []byte) (int, error) { +func (m *FinalityProviderHistoricalRewards) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *FinalityProviderRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *FinalityProviderHistoricalRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -204,6 +271,48 @@ func (m *FinalityProviderRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *FinalityProviderCurrentRewards) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *FinalityProviderCurrentRewards) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FinalityProviderCurrentRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Period != 0 { + i = encodeVarintRewards(dAtA, i, uint64(m.Period)) + i-- + dAtA[i] = 0x10 + } + if len(m.CurrentRewards) > 0 { + for iNdEx := len(m.CurrentRewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.CurrentRewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRewards(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *BTCDelegationRewardsTracker) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -248,7 +357,7 @@ func encodeVarintRewards(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *FinalityProviderRewards) Size() (n int) { +func (m *FinalityProviderHistoricalRewards) Size() (n int) { if m == nil { return 0 } @@ -263,6 +372,24 @@ func (m *FinalityProviderRewards) Size() (n int) { return n } +func (m *FinalityProviderCurrentRewards) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.CurrentRewards) > 0 { + for _, e := range m.CurrentRewards { + l = e.Size() + n += 1 + l + sovRewards(uint64(l)) + } + } + if m.Period != 0 { + n += 1 + sovRewards(uint64(m.Period)) + } + return n +} + func (m *BTCDelegationRewardsTracker) Size() (n int) { if m == nil { return 0 @@ -284,7 +411,7 @@ func sovRewards(x uint64) (n int) { func sozRewards(x uint64) (n int) { return sovRewards(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *FinalityProviderRewards) Unmarshal(dAtA []byte) error { +func (m *FinalityProviderHistoricalRewards) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -307,10 +434,10 @@ func (m *FinalityProviderRewards) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: FinalityProviderRewards: wiretype end group for non-group") + return fmt.Errorf("proto: FinalityProviderHistoricalRewards: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: FinalityProviderRewards: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: FinalityProviderHistoricalRewards: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -368,6 +495,109 @@ func (m *FinalityProviderRewards) Unmarshal(dAtA []byte) error { } return nil } +func (m *FinalityProviderCurrentRewards) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FinalityProviderCurrentRewards: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FinalityProviderCurrentRewards: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentRewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CurrentRewards = append(m.CurrentRewards, types.Coin{}) + if err := m.CurrentRewards[len(m.CurrentRewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Period", wireType) + } + m.Period = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Period |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipRewards(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRewards + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *BTCDelegationRewardsTracker) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 From 530cd88ad902e4588355be1a3e122aa5524758c4 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 1 Dec 2024 18:06:09 -0300 Subject: [PATCH 005/132] chore: adding shape to FP reward tracker periods --- x/btcstaking/keeper/btc_delegators.go | 175 ------------ x/btcstaking/types/keys.go | 2 - x/finality/keeper/power_dist_change.go | 10 + x/incentive/keeper/reward_tracker.go | 377 ++++++++++++++++++++++++- x/incentive/types/errors.go | 9 +- x/incentive/types/keys.go | 16 +- x/incentive/types/rewards.go | 15 + 7 files changed, 413 insertions(+), 191 deletions(-) diff --git a/x/btcstaking/keeper/btc_delegators.go b/x/btcstaking/keeper/btc_delegators.go index 509831435..1c42113fa 100644 --- a/x/btcstaking/keeper/btc_delegators.go +++ b/x/btcstaking/keeper/btc_delegators.go @@ -5,10 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/runtime" - corestoretypes "cosmossdk.io/core/store" - sdkmath "cosmossdk.io/math" "cosmossdk.io/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -81,175 +78,3 @@ func (k Keeper) btcDelegatorStore(ctx context.Context) prefix.Store { storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) return prefix.NewStore(storeAdapter, types.BTCDelegatorKey) } - -// storeDelStaked returns the KVStore of the delegator amount staked -// prefix: (DelegatorStakedBTCKey) -// key: Del addr -// value: sdk math Int -func (k Keeper) storeDelStaked(ctx context.Context) prefix.Store { - storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return prefix.NewStore(storeAdapter, types.DelegatorStakedBTCKey) -} - -// Total active satoshi staked that is entitled to earn rewards. -func (k Keeper) TotalSatoshiStaked(ctx context.Context) (sdkmath.Int, error) { - kv := k.storeService.OpenKVStore(ctx) - key := types.TotalStakedBTCKey - return StoreGetInt(kv, key) -} - -func (k Keeper) addTotalSatoshiStaked(ctx context.Context, amtToAdd sdkmath.Int) (sdkmath.Int, error) { - kv := k.storeService.OpenKVStore(ctx) - key := types.TotalStakedBTCKey - - current, err := StoreGetInt(kv, key) - if err != nil { - return sdkmath.Int{}, err - } - - total := current.Add(amtToAdd) - if err := StoreSetInt(kv, key, total); err != nil { - return sdkmath.Int{}, err - } - - return total, nil -} - -func (k Keeper) subTotalSatoshiStaked(ctx context.Context, amtToAdd sdkmath.Int) (sdkmath.Int, error) { - kv := k.storeService.OpenKVStore(ctx) - key := types.TotalStakedBTCKey - - current, err := StoreGetInt(kv, key) - if err != nil { - return sdkmath.Int{}, err - } - - total := current.Sub(amtToAdd) - if err := StoreSetInt(kv, key, total); err != nil { - return sdkmath.Int{}, err - } - - return total, nil -} - -func (k Keeper) AddDelStaking(ctx context.Context, del sdk.AccAddress, amt sdkmath.Int) error { - st := k.storeDelStaked(ctx) - - currentStk, err := PrefixStoreGetInt(st, del) - if err != nil { - return err - } - - totalDelStaked := currentStk.Add(amt) - bz, err := totalDelStaked.Marshal() - if err != nil { - return err - } - - st.Set(del, bz) - _, err = k.addTotalSatoshiStaked(ctx, amt) - return err -} - -func (k Keeper) SubDelStaking(ctx context.Context, del sdk.AccAddress, amt sdkmath.Int) error { - st := k.storeDelStaked(ctx) - - currentStk, err := PrefixStoreGetInt(st, del) - if err != nil { - return err - } - - totalDelStaked := currentStk.Sub(amt) - bz, err := totalDelStaked.Marshal() - if err != nil { - return err - } - - st.Set(del, bz) - _, err = k.subTotalSatoshiStaked(ctx, amt) - return err -} - -func PrefixStoreGetInt(st prefix.Store, key []byte) (vInt sdkmath.Int, err error) { - if !st.Has(key) { - return sdkmath.NewInt(0), nil - } - - bz := st.Get(key) - vInt, err = ParseInt(bz) - if err != nil { - return sdkmath.Int{}, err - } - - return vInt, nil -} - -// StoreSetInt stores an sdkmath.Int from the KVStore. -func StoreSetInt(kv corestoretypes.KVStore, key []byte, vInt sdkmath.Int) (err error) { - bz, err := vInt.Marshal() - if err != nil { - return err - } - return kv.Set(key, bz) -} - -// StoreGetInt retrieves an sdkmath.Int from the KVStore. It returns zero int if not found. -func StoreGetInt(kv corestoretypes.KVStore, key []byte) (vInt sdkmath.Int, err error) { - exists, err := kv.Has(key) - if err != nil { - return sdkmath.Int{}, err - } - - if !exists { - return sdkmath.NewInt(0), nil - } - - bz, err := kv.Get(key) - if err != nil { - return sdkmath.Int{}, err - } - - vInt, err = ParseInt(bz) - if err != nil { - return sdkmath.Int{}, err - } - return vInt, nil -} - -// ParseInt parses an sdkmath.Int from bytes. -func ParseInt(bz []byte) (sdkmath.Int, error) { - var val sdkmath.Int - if err := val.Unmarshal(bz); err != nil { - return val, err - } - return val, nil -} - -// IterateBTCDelegators iterates over all the delegators that have some active BTC delegator -// staked and the total satoshi staked for that delegator address until an error is returned -// or the iterator finishes. Stops if error is returned. -// Should keep track of the total satoshi staked per delegator to avoid iterating over the -// delegator delegations -// func (k Keeper) IterateBTCDelegators(ctx context.Context, i func(delegator sdk.AccAddress, totalSatoshiStaked sdkmath.Int) error) error { -// st := k.storeDelStaked(ctx) - -// iter := st.Iterator(nil, nil) -// defer iter.Close() - -// for ; iter.Valid(); iter.Next() { -// sdkAddrBz := iter.Key() -// delAddr := sdk.AccAddress(sdkAddrBz) - -// delBtcStaked, err := ParseInt(iter.Value()) -// if err != nil { -// return err -// } - -// err = i(delAddr, delBtcStaked) -// if err != nil { -// return err -// } -// } - -// return nil -// } diff --git a/x/btcstaking/types/keys.go b/x/btcstaking/types/keys.go index eeb4ee795..a3313b97b 100644 --- a/x/btcstaking/types/keys.go +++ b/x/btcstaking/types/keys.go @@ -26,6 +26,4 @@ var ( // 0x07 was used for something else in the past PowerDistUpdateKey = []byte{0x08} // key prefix for power distribution update events AllowedStakingTxHashesKey = collections.NewPrefix(9) // key prefix for allowed staking tx hashes - DelegatorStakedBTCKey = []byte{0xA} // key prefix for delegator active staked amount int math.Int - TotalStakedBTCKey = []byte{0xB} // key prefix for protocol active staked amount int math.Int ) diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 1ffc34756..b237ee3a2 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -276,6 +276,11 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( btcDel := *dc.FinalityProviders[i].BtcDels[j] if _, ok := unbondedBTCDels[btcDel.StakingTxHash]; !ok { fp.AddBTCDelDistInfo(&btcDel) + + err := k.IncentiveKeeper.BtcDelegationUnbonded(ctx, fp.GetAddress(), sdk.MustAccAddressFromBech32(btcDel.StakerAddr), btcDel.TotalSat) + if err != nil { + panic(err) // check if it should panic + } } } @@ -325,6 +330,11 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( fpActiveBTCDels := activeBTCDels[fpBTCPKHex] for _, d := range fpActiveBTCDels { fpDistInfo.AddBTCDel(d) + + err := k.IncentiveKeeper.BtcDelegationActivated(ctx, sdk.MustAccAddressFromBech32(newFP.Addr), sdk.MustAccAddressFromBech32(d.StakerAddr), d.TotalSat) + if err != nil { + panic(err) // check if it should panic + } } // add this finality provider to the new cache if it has voting power diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index be08ae3f2..892a83db5 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -2,15 +2,28 @@ package keeper import ( "context" + "encoding/binary" + "errors" "cosmossdk.io/store/prefix" "github.com/babylonlabs-io/babylon/x/incentive/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" + + corestoretypes "cosmossdk.io/core/store" + sdkmath "cosmossdk.io/math" ) +func (k Keeper) FpSlashed(ctx context.Context, fp sdk.AccAddress) error { + // withdrawDelegationRewards + // Delete all the delegations reward tracker associated with this FP + // Delete the FP reward tracker + return nil +} + func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { - // if btc delegations does exists + amtSat := sdkmath.NewIntFromUint64(sat) + // if btc delegations does not exists // BeforeDelegationCreated // IncrementValidatorPeriod @@ -23,17 +36,144 @@ func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddre // gets the current rewards and send to historical the current period (the rewards are stored as "shares" which means the amount of rewards per satoshi) // sets new empty current rewards with new period - // adds new satoshi activated to - // val total - // val, del total + endedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp) + if err != nil { + return err + } + + // rewardsRaw, err := k.CalculateDelegationRewards(ctx, val, del, endingPeriod) + // if err != nil { + // return nil, err + // } + + if err := k.AddDelegationStaking(ctx, fp, del, amtSat); err != nil { + return err + } return nil } func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { + amtSat := sdkmath.NewIntFromUint64(sat) + + // withdraw rewards + // + + if err := k.SubDelegationStaking(ctx, fp, del, amtSat); err != nil { + return err + } return nil } +func (k Keeper) CalculateDelegationRewards(ctx context.Context, fp, del sdk.AccAddress, endPeriod uint64) (sdk.Coins, error) { + delActiveStakedSat, err := k.getDelegationStaking(ctx, fp, del) + if err != nil { + return sdk.Coins{}, err + } + + if delActiveStakedSat.IsZero() { + return sdk.NewCoins(), nil + } + +} + +// calculate the rewards accrued by a delegation between two periods +func (k Keeper) calculateDelegationRewardsBetween( + ctx context.Context, + fp, del sdk.AccAddress, + startingPeriod, endingPeriod uint64, + delActiveStakedSat sdkmath.Int, +) (sdk.Coins, error) { + // sanity check + if startingPeriod > endingPeriod { + panic("startingPeriod cannot be greater than endingPeriod") + } + + // sanity check + if delActiveStakedSat.IsNegative() { + panic("BTC delegation active stake should not be negative") + } + + // return staking * (ending - starting) + starting, err := k.getFinalityProviderHistoricalRewards(ctx, fp, startingPeriod) + if err != nil { + return sdk.Coins{}, err + } + + ending, err := k.getFinalityProviderHistoricalRewards(ctx, fp, endingPeriod) + if err != nil { + return sdk.Coins{}, err + } + + // creates the difference amount of rewards (ending - starting) periods + // this difference is the amount of rewards entitled per satoshi active stake + difference := ending.CumulativeRewardsPerSat.Sub(starting.CumulativeRewardsPerSat...) + if difference.IsAnyNegative() { + panic("negative rewards should not be possible") + } + + // note: necessary to truncate so we don't allow withdrawing more rewards than owed + rewards := difference.MulInt(delActiveStakedSat) + return rewards, nil +} + +// IncrementFinalityProviderPeriod +func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccAddress) (endedPeriod uint64, err error) { + // IncrementValidatorPeriod + // gets the current rewards and send to historical the current period (the rewards are stored as "shares" which means the amount of rewards per satoshi) + // sets new empty current rewards with new period + fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) + if err != nil { + if errors.Is(err, types.ErrFPCurrentRewardsNotFound) { + // initialize Validator + err := k.initializeFinalityProvider(ctx, fp) + if err != nil { + return 0, err + } + return 1, nil + } + return 0, err + } + + fpAmtStaked, err := k.getFinalityProviderStaked(ctx, fp) + if err != nil { + return 0, err + } + + currentRewardsPerSat := sdk.NewCoins() + if !fpAmtStaked.IsZero() { + currentRewardsPerSat = fpCurrentRwd.CurrentRewards.QuoInt(fpAmtStaked) + } + + fpHistoricalRwd, err := k.getFinalityProviderHistoricalRewards(ctx, fp, fpCurrentRwd.Period-1) + if err != nil { + return 0, err + } + + newFpHistoricalRwd := types.NewFinalityProviderHistoricalRewards(fpHistoricalRwd.CumulativeRewardsPerSat.Add(currentRewardsPerSat...)) + if err := k.setFinalityProviderHistoricalRewards(ctx, fp, fpCurrentRwd.Period, newFpHistoricalRwd); err != nil { + return 0, err + } + + // initiates a new period with empty rewards + newCurrentRwd := types.NewFinalityProviderCurrentRewards(sdk.NewCoins(), fpCurrentRwd.Period+1) + if err := k.setFinalityProviderCurrentRewards(ctx, fp, newCurrentRwd); err != nil { + return 0, err + } + + return fpCurrentRwd.Period, nil +} + +func (k Keeper) initializeFinalityProvider(ctx context.Context, fp sdk.AccAddress) error { + // historical rewards starts at the period 0 + err := k.setFinalityProviderHistoricalRewards(ctx, fp, 0, types.NewFinalityProviderHistoricalRewards(sdk.NewCoins())) + if err != nil { + return err + } + // set current rewards (starting at period 1) + return k.setFinalityProviderCurrentRewards(ctx, fp, types.NewFinalityProviderCurrentRewards(sdk.NewCoins(), 1)) +} + // initializeBTCDelegation creates a new BTCDelegationRewardsTracker from the previous acumulative rewards // period of the finality provider and it should be called right after a BTC delegator withdraw his rewards // (in our case send the rewards to the reward gauge). Reminder that at every new modification to the amount @@ -78,6 +218,46 @@ func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.Ac return value, nil } +func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress, rwd types.FinalityProviderCurrentRewards) error { + key := fp.Bytes() + bz, err := rwd.Marshal() + if err != nil { + return err + } + + k.storeFpCurrentRewards(ctx).Set(key, bz) + return nil +} + +func (k Keeper) getFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64) (types.FinalityProviderHistoricalRewards, error) { + key := make([]byte, 8) + binary.LittleEndian.PutUint64(key, period) + + bz := k.storeFpHistoricalRewards(ctx, fp).Get(key) + if bz == nil { + return types.FinalityProviderHistoricalRewards{}, types.ErrFPCurrentRewardsNotFound + } + + var value types.FinalityProviderHistoricalRewards + if err := k.cdc.Unmarshal(bz, &value); err != nil { + return types.FinalityProviderHistoricalRewards{}, err + } + return value, nil +} + +func (k Keeper) setFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64, rwd types.FinalityProviderHistoricalRewards) error { + key := make([]byte, 8) + binary.LittleEndian.PutUint64(key, period) + + bz, err := rwd.Marshal() + if err != nil { + return err + } + + k.storeFpHistoricalRewards(ctx, fp).Set(key, bz) + return nil +} + // storeFpCurrentRewards returns the KVStore of the FP current rewards // prefix: FinalityProviderCurrentRewardsKey // key: (finality provider cosmos address) @@ -86,3 +266,192 @@ func (k Keeper) storeFpCurrentRewards(ctx context.Context) prefix.Store { storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) return prefix.NewStore(storeAdaptor, types.FinalityProviderCurrentRewardsKey) } + +// storeFpHistoricalRewards returns the KVStore of the FP historical rewards +// prefix: FinalityProviderHistoricalRewardsKey +// key: (finality provider cosmos address, period) +// value: FinalityProviderCurrentRewards +func (k Keeper) storeFpHistoricalRewards(ctx context.Context, fp sdk.AccAddress) prefix.Store { + storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + st := prefix.NewStore(storeAdaptor, types.FinalityProviderHistoricalRewardsKey) + return prefix.NewStore(st, fp.Bytes()) +} + +// storeFinalityProviderStaked returns the KVStore of the finality provider amount active staked +// prefix: (DelegatorStakedBTCKey) +// key: (FinalityProviderStakedBTCKey) +// value: sdk math Int +func (k Keeper) storeFinalityProviderStaked(ctx context.Context) prefix.Store { + storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + return prefix.NewStore(storeAdapter, types.FinalityProviderStakedBTCKey) +} + +// storeDelegationFpStaked returns the KVStore of the delegator amount staked +// prefix: (DelegatorStakedBTCKey) +// key: (FpAddr, DelAddr) +// value: sdk math Int +func (k Keeper) storeDelegationFpStaked(ctx context.Context, fp sdk.AccAddress) prefix.Store { + storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + st := prefix.NewStore(storeAdapter, types.DelegationStakedBTCKey) + return prefix.NewStore(st, fp.Bytes()) +} + +func (k Keeper) addFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress, amt sdkmath.Int) error { + st := k.storeFinalityProviderStaked(ctx) + key := fp.Bytes() + + return OperationWithInt(st, key, func(currentFpStaked sdkmath.Int) sdkmath.Int { + return currentFpStaked.Add(amt) + }) +} + +func (k Keeper) getFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress) (amt sdkmath.Int, err error) { + st := k.storeFinalityProviderStaked(ctx) + key := fp.Bytes() + + return PrefixStoreGetInt(st, key) +} + +func (k Keeper) subFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress, amt sdkmath.Int) error { + st := k.storeFinalityProviderStaked(ctx) + key := fp.Bytes() + + return OperationWithInt(st, key, func(currentFpStaked sdkmath.Int) sdkmath.Int { + return currentFpStaked.Sub(amt) + }) +} + +func (k Keeper) getDelegationStaking(ctx context.Context, fp, del sdk.AccAddress) (sdkmath.Int, error) { + st := k.storeDelegationFpStaked(ctx, fp) + key := del.Bytes() + + return PrefixStoreGetInt(st, key) +} + +func (k Keeper) AddDelegationStaking(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { + st := k.storeDelegationFpStaked(ctx, fp) + key := del.Bytes() + + err := OperationWithInt(st, key, func(currenDelegationStaked sdkmath.Int) sdkmath.Int { + return currenDelegationStaked.Add(amt) + }) + if err != nil { + return err + } + + return k.addFinalityProviderStaked(ctx, fp, amt) +} + +func (k Keeper) SubDelegationStaking(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { + st := k.storeDelegationFpStaked(ctx, fp) + key := fp.Bytes() + + err := OperationWithInt(st, key, func(currenDelegationStaked sdkmath.Int) sdkmath.Int { + return currenDelegationStaked.Sub(amt) + }) + if err != nil { + return err + } + + return k.subFinalityProviderStaked(ctx, fp, amt) +} + +func OperationWithInt(st prefix.Store, key []byte, update func(vIntFromStore sdkmath.Int) (updatedValue sdkmath.Int)) (err error) { + currentValue, err := PrefixStoreGetInt(st, key) + if err != nil { + return err + } + + currentValue = update(currentValue) + bz, err := currentValue.Marshal() + if err != nil { + return err + } + + st.Set(key, bz) + return nil +} + +func PrefixStoreGetInt(st prefix.Store, key []byte) (vInt sdkmath.Int, err error) { + if !st.Has(key) { + return sdkmath.NewInt(0), nil + } + + bz := st.Get(key) + vInt, err = ParseInt(bz) + if err != nil { + return sdkmath.Int{}, err + } + + return vInt, nil +} + +// StoreSetInt stores an sdkmath.Int from the KVStore. +func StoreSetInt(kv corestoretypes.KVStore, key []byte, vInt sdkmath.Int) (err error) { + bz, err := vInt.Marshal() + if err != nil { + return err + } + return kv.Set(key, bz) +} + +// StoreGetInt retrieves an sdkmath.Int from the KVStore. It returns zero int if not found. +func StoreGetInt(kv corestoretypes.KVStore, key []byte) (vInt sdkmath.Int, err error) { + exists, err := kv.Has(key) + if err != nil { + return sdkmath.Int{}, err + } + + if !exists { + return sdkmath.NewInt(0), nil + } + + bz, err := kv.Get(key) + if err != nil { + return sdkmath.Int{}, err + } + + vInt, err = ParseInt(bz) + if err != nil { + return sdkmath.Int{}, err + } + return vInt, nil +} + +// ParseInt parses an sdkmath.Int from bytes. +func ParseInt(bz []byte) (sdkmath.Int, error) { + var val sdkmath.Int + if err := val.Unmarshal(bz); err != nil { + return val, err + } + return val, nil +} + +// IterateBTCDelegators iterates over all the delegators that have some active BTC delegator +// staked and the total satoshi staked for that delegator address until an error is returned +// or the iterator finishes. Stops if error is returned. +// Should keep track of the total satoshi staked per delegator to avoid iterating over the +// delegator delegations +// func (k Keeper) IterateBTCDelegators(ctx context.Context, i func(delegator sdk.AccAddress, totalSatoshiStaked sdkmath.Int) error) error { +// st := k.storeDelStaked(ctx) + +// iter := st.Iterator(nil, nil) +// defer iter.Close() + +// for ; iter.Valid(); iter.Next() { +// sdkAddrBz := iter.Key() +// delAddr := sdk.AccAddress(sdkAddrBz) + +// delBtcStaked, err := ParseInt(iter.Value()) +// if err != nil { +// return err +// } + +// err = i(delAddr, delBtcStaked) +// if err != nil { +// return err +// } +// } + +// return nil +// } diff --git a/x/incentive/types/errors.go b/x/incentive/types/errors.go index d70e67bb5..1b56a9cbf 100644 --- a/x/incentive/types/errors.go +++ b/x/incentive/types/errors.go @@ -6,8 +6,9 @@ import ( // x/incentive module sentinel errors var ( - ErrBTCStakingGaugeNotFound = errorsmod.Register(ModuleName, 1100, "BTC staking gauge not found") - ErrRewardGaugeNotFound = errorsmod.Register(ModuleName, 1101, "reward gauge not found") - ErrNoWithdrawableCoins = errorsmod.Register(ModuleName, 1102, "no coin is withdrawable") - ErrFPCurrentRewardsNotFound = errorsmod.Register(ModuleName, 1103, "finality provider current rewards not found") + ErrBTCStakingGaugeNotFound = errorsmod.Register(ModuleName, 1100, "BTC staking gauge not found") + ErrRewardGaugeNotFound = errorsmod.Register(ModuleName, 1101, "reward gauge not found") + ErrNoWithdrawableCoins = errorsmod.Register(ModuleName, 1102, "no coin is withdrawable") + ErrFPCurrentRewardsNotFound = errorsmod.Register(ModuleName, 1103, "finality provider current rewards not found") + ErrFPHistoricalRewardsNotFound = errorsmod.Register(ModuleName, 1104, "finality provider historical rewards not found") ) diff --git a/x/incentive/types/keys.go b/x/incentive/types/keys.go index b312b5cb8..1859b61c2 100644 --- a/x/incentive/types/keys.go +++ b/x/incentive/types/keys.go @@ -17,10 +17,14 @@ const ( ) var ( - ParamsKey = []byte{0x01} // key prefix for the parameters - BTCStakingGaugeKey = []byte{0x02} // key prefix for BTC staking gauge at each height - ReservedKey = []byte{0x03} // reserved //nolint:unused - RewardGaugeKey = []byte{0x04} // key prefix for reward gauge for a given stakeholder in a given type - RefundableMsgKeySetPrefix = collections.NewPrefix(5) // key prefix for refundable msg key set - FinalityProviderCurrentRewardsKey = []byte{0x06} // key prefix for storing the Current rewards of finality provider by addr + ParamsKey = []byte{0x01} // key prefix for the parameters + BTCStakingGaugeKey = []byte{0x02} // key prefix for BTC staking gauge at each height + ReservedKey = []byte{0x03} // reserved //nolint:unused + RewardGaugeKey = []byte{0x04} // key prefix for reward gauge for a given stakeholder in a given type + RefundableMsgKeySetPrefix = collections.NewPrefix(5) // key prefix for refundable msg key set + FinalityProviderCurrentRewardsKey = []byte{0x06} // key prefix for storing the Current rewards of finality provider by addr + FinalityProviderHistoricalRewardsKey = []byte{0x07} // key prefix for storing the Historical rewards of finality provider by addr and period + DelegationStakedBTCKey = []byte{0x8} // key prefix for BTC delegation (del,fp) active staked math.Int + FinalityProviderStakedBTCKey = []byte{0x9} // key prefix for BTC finality provider active staked math.Int + TotalStakedBTCKey = []byte{0xA} // key prefix for protocol active staked amount int math.Int ) diff --git a/x/incentive/types/rewards.go b/x/incentive/types/rewards.go index 963573e16..189587ca7 100644 --- a/x/incentive/types/rewards.go +++ b/x/incentive/types/rewards.go @@ -1,8 +1,23 @@ package types +import sdk "github.com/cosmos/cosmos-sdk/types" + func NewBTCDelegationRewardsTracker(startPeriod, totalSat uint64) BTCDelegationRewardsTracker { return BTCDelegationRewardsTracker{ StartPeriodCumulativeRewardFP: startPeriod, DelegationTotalActiveSat: totalSat, } } + +func NewFinalityProviderCurrentRewards(currentRewards sdk.Coins, period uint64) FinalityProviderCurrentRewards { + return FinalityProviderCurrentRewards{ + CurrentRewards: currentRewards, + Period: period, + } +} + +func NewFinalityProviderHistoricalRewards(cumulativeRewardsPerSat sdk.Coins) FinalityProviderHistoricalRewards { + return FinalityProviderHistoricalRewards{ + CumulativeRewardsPerSat: cumulativeRewardsPerSat, + } +} From e79d0e1bb3adb6a2cd2da47bbee8b7842d36e5ba Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 1 Dec 2024 22:34:39 -0300 Subject: [PATCH 006/132] chore: modified to use same structure to store the amt staked --- proto/babylon/incentive/rewards.proto | 18 ++- proto/babylon/incentive/tx.proto | 4 +- x/incentive/keeper/reward_tracker.go | 91 ++++++++----- x/incentive/types/errors.go | 11 +- x/incentive/types/keys.go | 6 +- x/incentive/types/rewards.go | 14 +- x/incentive/types/rewards.pb.go | 179 +++++++++++++++++--------- 7 files changed, 215 insertions(+), 108 deletions(-) diff --git a/proto/babylon/incentive/rewards.proto b/proto/babylon/incentive/rewards.proto index e44180dab..0bea0e2ee 100644 --- a/proto/babylon/incentive/rewards.proto +++ b/proto/babylon/incentive/rewards.proto @@ -3,6 +3,7 @@ package babylon.incentive; import "gogoproto/gogo.proto"; import "cosmos/base/v1beta1/coin.proto"; +import "cosmos_proto/cosmos.proto"; option go_package = "github.com/babylonlabs-io/babylon/x/incentive/types"; @@ -16,7 +17,7 @@ message FinalityProviderHistoricalRewards { // be interpolated and calculate the difference and multiplied by the total sat amount delegated // https://github.com/cosmos/cosmos-sdk/blob/e76102f885b71fd6e1c1efb692052173c4b3c3a3/x/distribution/keeper/delegation.go#L47 // This is also not considering slash of the rewards. - repeated cosmos.base.v1beta1.Coin CumulativeRewardsPerSat = 1 [ + repeated cosmos.base.v1beta1.Coin cumulative_rewards_per_sat = 1 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; @@ -34,13 +35,18 @@ message FinalityProviderCurrentRewards { // modifies the amount of satoshis delegated to this finality provider (activation, unbonding, slash) // a new period must be created, accumulate this rewards to FinalityProviderHistoricalRewards // with a new period and zero out the Current Rewards. - repeated cosmos.base.v1beta1.Coin CurrentRewards = 1 [ + repeated cosmos.base.v1beta1.Coin current_rewards = 1 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; // Period stores the current period that serves as a reference for // creating new historical rewards. uint64 period = 2; + bytes total_active_sat = 3 [ + (cosmos_proto.scalar) = "cosmos.Int", + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false + ]; } // BTCDelegationRewardsTracker represents the structure that holds information @@ -48,6 +54,10 @@ message FinalityProviderCurrentRewards { // The finality provider address is ommitted here but should be part of the key used // to store this structure together with the BTC delegator address. message BTCDelegationRewardsTracker { - uint64 StartPeriodCumulativeRewardFP = 1; - uint64 DelegationTotalActiveSat = 2; + uint64 start_period_cumulative_reward = 1; + bytes total_active_sat = 2 [ + (cosmos_proto.scalar) = "cosmos.Int", + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false + ]; } \ No newline at end of file diff --git a/proto/babylon/incentive/tx.proto b/proto/babylon/incentive/tx.proto index 321996e71..4cdc96329 100644 --- a/proto/babylon/incentive/tx.proto +++ b/proto/babylon/incentive/tx.proto @@ -42,13 +42,13 @@ message MsgWithdrawRewardResponse { // MsgUpdateParams defines a message for updating incentive module parameters. message MsgUpdateParams { option (cosmos.msg.v1.signer) = "authority"; - + // authority is the address of the governance account. // just FYI: cosmos.AddressString marks that this field should use type alias // for AddressString instead of string, but the functionality is not yet implemented // in cosmos-proto string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - + // params defines the incentive parameters to update. // // NOTE: All parameters must be supplied. diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 892a83db5..4e9239ce1 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -26,6 +26,8 @@ func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddre // if btc delegations does not exists // BeforeDelegationCreated // IncrementValidatorPeriod + // initializeDelegation + // AddDelegationStaking // if btc delegations exists // BeforeDelegationSharesModified @@ -41,16 +43,16 @@ func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddre return err } - // rewardsRaw, err := k.CalculateDelegationRewards(ctx, val, del, endingPeriod) - // if err != nil { - // return nil, err - // } - - if err := k.AddDelegationStaking(ctx, fp, del, amtSat); err != nil { + rewards, err := k.CalculateDelegationRewards(ctx, fp, del, endedPeriod) + if err != nil { return err } - return nil + if !rewards.IsZero() { // there is some rewards + k.accumulateRewardGauge(ctx, types.BTCDelegationType, del, rewards) + } + + return k.AddDelegationStaking(ctx, fp, del, amtSat) } func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { @@ -75,27 +77,36 @@ func (k Keeper) CalculateDelegationRewards(ctx context.Context, fp, del sdk.AccA return sdk.NewCoins(), nil } + btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) + if err != nil { + if errors.Is(err, types.ErrBTCDelegationRewardsTrackerNotFound) { + + } + return sdk.Coins{}, err + } + + return k.calculateDelegationRewardsBetween(ctx, fp, del, btcDelRwdTracker, endPeriod) } // calculate the rewards accrued by a delegation between two periods func (k Keeper) calculateDelegationRewardsBetween( ctx context.Context, fp, del sdk.AccAddress, - startingPeriod, endingPeriod uint64, - delActiveStakedSat sdkmath.Int, + btcDelRwdTracker types.BTCDelegationRewardsTracker, + endingPeriod uint64, ) (sdk.Coins, error) { // sanity check - if startingPeriod > endingPeriod { + if btcDelRwdTracker.StartPeriodCumulativeReward > endingPeriod { panic("startingPeriod cannot be greater than endingPeriod") } // sanity check - if delActiveStakedSat.IsNegative() { - panic("BTC delegation active stake should not be negative") - } + // if btcDelRwdTracker..IsNegative() { + // panic("BTC delegation active stake should not be negative") + // } // return staking * (ending - starting) - starting, err := k.getFinalityProviderHistoricalRewards(ctx, fp, startingPeriod) + starting, err := k.getFinalityProviderHistoricalRewards(ctx, fp, btcDelRwdTracker.StartPeriodCumulativeReward) if err != nil { return sdk.Coins{}, err } @@ -113,7 +124,7 @@ func (k Keeper) calculateDelegationRewardsBetween( } // note: necessary to truncate so we don't allow withdrawing more rewards than owed - rewards := difference.MulInt(delActiveStakedSat) + rewards := difference.MulInt(btcDelRwdTracker.TotalActiveSat) return rewards, nil } @@ -124,25 +135,20 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA // sets new empty current rewards with new period fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) if err != nil { - if errors.Is(err, types.ErrFPCurrentRewardsNotFound) { - // initialize Validator - err := k.initializeFinalityProvider(ctx, fp) - if err != nil { - return 0, err - } - return 1, nil + if !errors.Is(err, types.ErrFPCurrentRewardsNotFound) { + return 0, err } - return 0, err - } - fpAmtStaked, err := k.getFinalityProviderStaked(ctx, fp) - if err != nil { - return 0, err + // initialize Validator and return 1 as ended period + if err := k.initializeFinalityProvider(ctx, fp); err != nil { + return 0, err + } + return 1, nil } currentRewardsPerSat := sdk.NewCoins() - if !fpAmtStaked.IsZero() { - currentRewardsPerSat = fpCurrentRwd.CurrentRewards.QuoInt(fpAmtStaked) + if !fpCurrentRwd.TotalActiveSat.IsZero() { + currentRewardsPerSat = fpCurrentRwd.CurrentRewards.QuoInt(fpCurrentRwd.TotalActiveSat) } fpHistoricalRwd, err := k.getFinalityProviderHistoricalRewards(ctx, fp, fpCurrentRwd.Period-1) @@ -155,8 +161,8 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA return 0, err } - // initiates a new period with empty rewards - newCurrentRwd := types.NewFinalityProviderCurrentRewards(sdk.NewCoins(), fpCurrentRwd.Period+1) + // initiates a new period with empty rewards and the same amount of active sat (this value should be updated latter if needed) + newCurrentRwd := types.NewFinalityProviderCurrentRewards(sdk.NewCoins(), fpCurrentRwd.Period+1, fpCurrentRwd.TotalActiveSat) if err := k.setFinalityProviderCurrentRewards(ctx, fp, newCurrentRwd); err != nil { return 0, err } @@ -218,6 +224,20 @@ func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.Ac return value, nil } +func (k Keeper) GetBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk.AccAddress) (types.BTCDelegationRewardsTracker, error) { + key := del.Bytes() + bz := k.storeBTCDelegationRewardsTracker(ctx, fp).Get(key) + if bz == nil { + return types.BTCDelegationRewardsTracker{}, types.ErrBTCDelegationRewardsTrackerNotFound + } + + var value types.BTCDelegationRewardsTracker + if err := k.cdc.Unmarshal(bz, &value); err != nil { + return types.BTCDelegationRewardsTracker{}, err + } + return value, nil +} + func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress, rwd types.FinalityProviderCurrentRewards) error { key := fp.Bytes() bz, err := rwd.Marshal() @@ -258,6 +278,15 @@ func (k Keeper) setFinalityProviderHistoricalRewards(ctx context.Context, fp sdk return nil } +// storeBTCDelegationRewardsTracker returns the KVStore of the FP current rewards +// prefix: BTCDelegationRewardsTrackerKey +// key: (FpAddr, DelAddr) +// value: BTCDelegationRewardsTracker +func (k Keeper) storeBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress) prefix.Store { + storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + return prefix.NewStore(storeAdaptor, types.BTCDelegationRewardsTrackerKey) +} + // storeFpCurrentRewards returns the KVStore of the FP current rewards // prefix: FinalityProviderCurrentRewardsKey // key: (finality provider cosmos address) diff --git a/x/incentive/types/errors.go b/x/incentive/types/errors.go index 1b56a9cbf..ba0df2360 100644 --- a/x/incentive/types/errors.go +++ b/x/incentive/types/errors.go @@ -6,9 +6,10 @@ import ( // x/incentive module sentinel errors var ( - ErrBTCStakingGaugeNotFound = errorsmod.Register(ModuleName, 1100, "BTC staking gauge not found") - ErrRewardGaugeNotFound = errorsmod.Register(ModuleName, 1101, "reward gauge not found") - ErrNoWithdrawableCoins = errorsmod.Register(ModuleName, 1102, "no coin is withdrawable") - ErrFPCurrentRewardsNotFound = errorsmod.Register(ModuleName, 1103, "finality provider current rewards not found") - ErrFPHistoricalRewardsNotFound = errorsmod.Register(ModuleName, 1104, "finality provider historical rewards not found") + ErrBTCStakingGaugeNotFound = errorsmod.Register(ModuleName, 1100, "BTC staking gauge not found") + ErrRewardGaugeNotFound = errorsmod.Register(ModuleName, 1101, "reward gauge not found") + ErrNoWithdrawableCoins = errorsmod.Register(ModuleName, 1102, "no coin is withdrawable") + ErrFPCurrentRewardsNotFound = errorsmod.Register(ModuleName, 1103, "finality provider current rewards not found") + ErrFPHistoricalRewardsNotFound = errorsmod.Register(ModuleName, 1104, "finality provider historical rewards not found") + ErrBTCDelegationRewardsTrackerNotFound = errorsmod.Register(ModuleName, 1105, "BTC delegation rewards tracker not found") ) diff --git a/x/incentive/types/keys.go b/x/incentive/types/keys.go index 1859b61c2..490540bed 100644 --- a/x/incentive/types/keys.go +++ b/x/incentive/types/keys.go @@ -24,7 +24,7 @@ var ( RefundableMsgKeySetPrefix = collections.NewPrefix(5) // key prefix for refundable msg key set FinalityProviderCurrentRewardsKey = []byte{0x06} // key prefix for storing the Current rewards of finality provider by addr FinalityProviderHistoricalRewardsKey = []byte{0x07} // key prefix for storing the Historical rewards of finality provider by addr and period - DelegationStakedBTCKey = []byte{0x8} // key prefix for BTC delegation (del,fp) active staked math.Int - FinalityProviderStakedBTCKey = []byte{0x9} // key prefix for BTC finality provider active staked math.Int - TotalStakedBTCKey = []byte{0xA} // key prefix for protocol active staked amount int math.Int + BTCDelegationRewardsTrackerKey = []byte{0x8} // key prefix for BTC delegation rewards tracker info (del,fp) => BTCDelegationRewardsTracker + DelegationStakedBTCKey = []byte{0x9} // key prefix for BTC delegation (del,fp) active staked math.Int + FinalityProviderStakedBTCKey = []byte{0xA} // key prefix for BTC finality provider active staked math.Int ) diff --git a/x/incentive/types/rewards.go b/x/incentive/types/rewards.go index 189587ca7..4b163a4bc 100644 --- a/x/incentive/types/rewards.go +++ b/x/incentive/types/rewards.go @@ -1,18 +1,22 @@ package types -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" +) -func NewBTCDelegationRewardsTracker(startPeriod, totalSat uint64) BTCDelegationRewardsTracker { +func NewBTCDelegationRewardsTracker(startPeriod uint64, totalSat sdkmath.Int) BTCDelegationRewardsTracker { return BTCDelegationRewardsTracker{ - StartPeriodCumulativeRewardFP: startPeriod, - DelegationTotalActiveSat: totalSat, + StartPeriodCumulativeReward: startPeriod, + TotalActiveSat: totalSat, } } -func NewFinalityProviderCurrentRewards(currentRewards sdk.Coins, period uint64) FinalityProviderCurrentRewards { +func NewFinalityProviderCurrentRewards(currentRewards sdk.Coins, period uint64, totalActiveSatFP sdkmath.Int) FinalityProviderCurrentRewards { return FinalityProviderCurrentRewards{ CurrentRewards: currentRewards, Period: period, + TotalActiveSat: totalActiveSatFP, } } diff --git a/x/incentive/types/rewards.pb.go b/x/incentive/types/rewards.pb.go index 82a9adf71..2cfc8b74f 100644 --- a/x/incentive/types/rewards.pb.go +++ b/x/incentive/types/rewards.pb.go @@ -4,7 +4,9 @@ package types import ( + cosmossdk_io_math "cosmossdk.io/math" fmt "fmt" + _ "github.com/cosmos/cosmos-proto" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" @@ -35,7 +37,7 @@ type FinalityProviderHistoricalRewards struct { // be interpolated and calculate the difference and multiplied by the total sat amount delegated // https://github.com/cosmos/cosmos-sdk/blob/e76102f885b71fd6e1c1efb692052173c4b3c3a3/x/distribution/keeper/delegation.go#L47 // This is also not considering slash of the rewards. - CumulativeRewardsPerSat github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=CumulativeRewardsPerSat,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"CumulativeRewardsPerSat"` + CumulativeRewardsPerSat github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=cumulative_rewards_per_sat,json=cumulativeRewardsPerSat,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"cumulative_rewards_per_sat"` } func (m *FinalityProviderHistoricalRewards) Reset() { *m = FinalityProviderHistoricalRewards{} } @@ -88,10 +90,11 @@ type FinalityProviderCurrentRewards struct { // modifies the amount of satoshis delegated to this finality provider (activation, unbonding, slash) // a new period must be created, accumulate this rewards to FinalityProviderHistoricalRewards // with a new period and zero out the Current Rewards. - CurrentRewards github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=CurrentRewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"CurrentRewards"` + CurrentRewards github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=current_rewards,json=currentRewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"current_rewards"` // Period stores the current period that serves as a reference for // creating new historical rewards. - Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` + Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` + TotalActiveSat cosmossdk_io_math.Int `protobuf:"bytes,3,opt,name=total_active_sat,json=totalActiveSat,proto3,customtype=cosmossdk.io/math.Int" json:"total_active_sat"` } func (m *FinalityProviderCurrentRewards) Reset() { *m = FinalityProviderCurrentRewards{} } @@ -146,8 +149,8 @@ func (m *FinalityProviderCurrentRewards) GetPeriod() uint64 { // The finality provider address is ommitted here but should be part of the key used // to store this structure together with the BTC delegator address. type BTCDelegationRewardsTracker struct { - StartPeriodCumulativeRewardFP uint64 `protobuf:"varint,1,opt,name=StartPeriodCumulativeRewardFP,proto3" json:"StartPeriodCumulativeRewardFP,omitempty"` - DelegationTotalActiveSat uint64 `protobuf:"varint,2,opt,name=DelegationTotalActiveSat,proto3" json:"DelegationTotalActiveSat,omitempty"` + StartPeriodCumulativeReward uint64 `protobuf:"varint,1,opt,name=start_period_cumulative_reward,json=startPeriodCumulativeReward,proto3" json:"start_period_cumulative_reward,omitempty"` + TotalActiveSat cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=total_active_sat,json=totalActiveSat,proto3,customtype=cosmossdk.io/math.Int" json:"total_active_sat"` } func (m *BTCDelegationRewardsTracker) Reset() { *m = BTCDelegationRewardsTracker{} } @@ -183,16 +186,9 @@ func (m *BTCDelegationRewardsTracker) XXX_DiscardUnknown() { var xxx_messageInfo_BTCDelegationRewardsTracker proto.InternalMessageInfo -func (m *BTCDelegationRewardsTracker) GetStartPeriodCumulativeRewardFP() uint64 { +func (m *BTCDelegationRewardsTracker) GetStartPeriodCumulativeReward() uint64 { if m != nil { - return m.StartPeriodCumulativeRewardFP - } - return 0 -} - -func (m *BTCDelegationRewardsTracker) GetDelegationTotalActiveSat() uint64 { - if m != nil { - return m.DelegationTotalActiveSat + return m.StartPeriodCumulativeReward } return 0 } @@ -206,32 +202,36 @@ func init() { func init() { proto.RegisterFile("babylon/incentive/rewards.proto", fileDescriptor_fa5a587351117eb0) } var fileDescriptor_fa5a587351117eb0 = []byte{ - // 387 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x92, 0xbf, 0x6e, 0xe2, 0x40, - 0x10, 0xc6, 0xbd, 0x77, 0x27, 0x8a, 0x3d, 0xe9, 0xa4, 0xb3, 0x4e, 0x77, 0x3e, 0x4e, 0xb7, 0x70, - 0x54, 0x34, 0x78, 0x8f, 0xd0, 0xa5, 0x0b, 0x46, 0x28, 0x4d, 0x24, 0x0b, 0xa8, 0xd2, 0xad, 0xed, - 0x95, 0xb3, 0xc2, 0xec, 0xa0, 0xdd, 0x35, 0x09, 0x0f, 0x90, 0x3e, 0x6f, 0x90, 0x3e, 0x51, 0xde, - 0x83, 0x92, 0x32, 0x55, 0x12, 0xc1, 0x8b, 0x44, 0xfe, 0x43, 0x42, 0x90, 0x48, 0x97, 0xca, 0x9e, - 0x99, 0x6f, 0xf6, 0xf7, 0xed, 0xec, 0xe0, 0x5a, 0xc0, 0x82, 0x79, 0x02, 0x92, 0x0a, 0x19, 0x72, - 0x69, 0xc4, 0x8c, 0x53, 0xc5, 0xcf, 0x99, 0x8a, 0xb4, 0x3b, 0x55, 0x60, 0xc0, 0xfe, 0x5e, 0x0a, - 0xdc, 0x17, 0x41, 0xf5, 0x47, 0x0c, 0x31, 0xe4, 0x55, 0x9a, 0xfd, 0x15, 0xc2, 0x2a, 0x09, 0x41, - 0x4f, 0x40, 0xd3, 0x80, 0x69, 0x4e, 0x67, 0xed, 0x80, 0x1b, 0xd6, 0xa6, 0x21, 0x08, 0x59, 0xd4, - 0x1b, 0xb7, 0x08, 0xff, 0xeb, 0x0b, 0xc9, 0x12, 0x61, 0xe6, 0xbe, 0x82, 0x99, 0x88, 0xb8, 0x3a, - 0x16, 0xda, 0x80, 0x12, 0x21, 0x4b, 0x06, 0x05, 0xd4, 0xbe, 0x44, 0xf8, 0x97, 0x97, 0x4e, 0xd2, - 0x84, 0x65, 0xa8, 0x32, 0xeb, 0x73, 0x35, 0x64, 0xc6, 0x41, 0xf5, 0xcf, 0xcd, 0xaf, 0x07, 0xbf, - 0xdd, 0x02, 0xe4, 0x66, 0x20, 0xb7, 0x04, 0xb9, 0x1e, 0x08, 0xd9, 0xfd, 0xbf, 0x78, 0xa8, 0x59, - 0x37, 0x8f, 0xb5, 0x66, 0x2c, 0xcc, 0x59, 0x1a, 0xb8, 0x21, 0x4c, 0x68, 0xe9, 0xaa, 0xf8, 0xb4, - 0x74, 0x34, 0xa6, 0x66, 0x3e, 0xe5, 0x3a, 0x6f, 0xd0, 0x83, 0x7d, 0xac, 0xc6, 0x1d, 0xc2, 0x64, - 0xd7, 0xad, 0x97, 0x2a, 0xc5, 0xa5, 0xd9, 0x58, 0xd5, 0xf8, 0xdb, 0xdb, 0xcc, 0x47, 0x18, 0xdc, - 0x41, 0xd8, 0x3f, 0x71, 0x65, 0xca, 0x95, 0x80, 0xc8, 0xf9, 0x54, 0x47, 0xcd, 0x2f, 0x83, 0x32, - 0x6a, 0x5c, 0x23, 0xfc, 0xa7, 0x3b, 0xf2, 0x7a, 0x3c, 0xe1, 0x31, 0x33, 0x02, 0x64, 0xd9, 0x30, - 0x52, 0x2c, 0x1c, 0x73, 0x65, 0xf7, 0xf0, 0xdf, 0xa1, 0x61, 0xca, 0xf8, 0xb9, 0x7c, 0xf7, 0xd6, - 0x7d, 0xdf, 0x41, 0xf9, 0x71, 0xef, 0x8b, 0xec, 0x43, 0xec, 0xbc, 0x12, 0x46, 0x60, 0x58, 0x72, - 0x14, 0x66, 0x82, 0xec, 0x75, 0x0a, 0x3f, 0x7b, 0xeb, 0xdd, 0x93, 0xc5, 0x8a, 0xa0, 0xe5, 0x8a, - 0xa0, 0xa7, 0x15, 0x41, 0x57, 0x6b, 0x62, 0x2d, 0xd7, 0xc4, 0xba, 0x5f, 0x13, 0xeb, 0xb4, 0xb3, - 0x35, 0x8d, 0x72, 0xdb, 0x12, 0x16, 0xe8, 0x96, 0x80, 0x4d, 0x48, 0x2f, 0xb6, 0xf6, 0x33, 0x1f, - 0x4f, 0x50, 0xc9, 0xb7, 0xaa, 0xf3, 0x1c, 0x00, 0x00, 0xff, 0xff, 0x96, 0x0b, 0x56, 0x59, 0xc1, - 0x02, 0x00, 0x00, + // 458 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0xcf, 0x6e, 0x13, 0x31, + 0x10, 0xc6, 0xe3, 0x14, 0xf5, 0x60, 0x50, 0x81, 0x88, 0x3f, 0x69, 0x2a, 0x39, 0xa1, 0xa7, 0x48, + 0x28, 0x6b, 0x4a, 0x9f, 0x80, 0x2c, 0x42, 0xf4, 0x80, 0x14, 0x85, 0x72, 0xe1, 0xb2, 0xf2, 0x7a, + 0xad, 0xd4, 0xca, 0xc6, 0x13, 0xd9, 0xb3, 0x81, 0x3c, 0x00, 0x12, 0x47, 0x9e, 0x83, 0x03, 0x27, + 0x2e, 0xbc, 0x41, 0x8f, 0x15, 0x27, 0xc4, 0xa1, 0xa0, 0xe4, 0x45, 0xd0, 0xda, 0x0e, 0x94, 0xc2, + 0x0d, 0x71, 0xda, 0x9d, 0x9d, 0xcf, 0xf3, 0xfd, 0xf4, 0x79, 0x96, 0x76, 0x73, 0x91, 0x2f, 0x4b, + 0x30, 0x5c, 0x1b, 0xa9, 0x0c, 0xea, 0x85, 0xe2, 0x56, 0xbd, 0x12, 0xb6, 0x70, 0xc9, 0xdc, 0x02, + 0x42, 0xeb, 0x66, 0x14, 0x24, 0x3f, 0x05, 0x9d, 0x5b, 0x13, 0x98, 0x80, 0xef, 0xf2, 0xfa, 0x2d, + 0x08, 0x3b, 0x4c, 0x82, 0x9b, 0x81, 0xe3, 0xb9, 0x70, 0x8a, 0x2f, 0x0e, 0x72, 0x85, 0xe2, 0x80, + 0x4b, 0xd0, 0x26, 0xf6, 0x77, 0x43, 0x3f, 0x0b, 0x07, 0x43, 0x11, 0x5a, 0xfb, 0x1f, 0x08, 0xbd, + 0xf7, 0x44, 0x1b, 0x51, 0x6a, 0x5c, 0x8e, 0x2c, 0x2c, 0x74, 0xa1, 0xec, 0x53, 0xed, 0x10, 0xac, + 0x96, 0xa2, 0x1c, 0x07, 0x9e, 0xd6, 0x5b, 0x42, 0x3b, 0xb2, 0x9a, 0x55, 0xa5, 0xa8, 0x29, 0xb2, + 0x88, 0x99, 0xcd, 0x95, 0xcd, 0x9c, 0xc0, 0x36, 0xe9, 0x6d, 0xf5, 0xaf, 0x3e, 0xdc, 0x4d, 0xe2, + 0xe4, 0x1a, 0x23, 0x89, 0x18, 0x49, 0x0a, 0xda, 0x0c, 0x1f, 0x9c, 0x9e, 0x77, 0x1b, 0xef, 0xbf, + 0x75, 0xfb, 0x13, 0x8d, 0x27, 0x55, 0x9e, 0x48, 0x98, 0x45, 0x8c, 0xf8, 0x18, 0xb8, 0x62, 0xca, + 0x71, 0x39, 0x57, 0xce, 0x1f, 0x70, 0xe3, 0xbb, 0xbf, 0xec, 0x22, 0xc4, 0x48, 0xd9, 0xe7, 0x02, + 0xf7, 0xdf, 0x34, 0x29, 0xbb, 0x0c, 0x9c, 0x56, 0xd6, 0x2a, 0x83, 0x1b, 0x5a, 0xa4, 0xd7, 0x65, + 0xf8, 0xb2, 0x21, 0xfd, 0x1f, 0x84, 0x3b, 0xf2, 0x77, 0xd7, 0x3b, 0x74, 0x7b, 0xae, 0xac, 0x86, + 0xa2, 0xdd, 0xec, 0x91, 0xfe, 0x95, 0x71, 0xac, 0x5a, 0x2f, 0xe8, 0x0d, 0x04, 0x14, 0x65, 0x26, + 0xa4, 0x0f, 0xaf, 0x0e, 0x6c, 0xab, 0x47, 0xfa, 0xd7, 0x86, 0xf7, 0x6b, 0xcf, 0xaf, 0xe7, 0xdd, + 0xdb, 0xc1, 0xc1, 0x15, 0xd3, 0x44, 0x03, 0x9f, 0x09, 0x3c, 0x49, 0x8e, 0x0c, 0x7e, 0xfe, 0x38, + 0xa0, 0x11, 0xf7, 0xc8, 0xe0, 0x78, 0xc7, 0x0f, 0x79, 0xe4, 0x67, 0xd4, 0x39, 0x7c, 0x22, 0x74, + 0x6f, 0x78, 0x9c, 0x3e, 0x56, 0xa5, 0x9a, 0x08, 0xd4, 0x60, 0x22, 0xc7, 0xb1, 0x15, 0x72, 0xaa, + 0x6c, 0x2b, 0xa5, 0xcc, 0xa1, 0xb0, 0x98, 0x05, 0x8c, 0xec, 0x8f, 0xeb, 0x6b, 0x13, 0x8f, 0xb9, + 0xe7, 0x55, 0x23, 0x2f, 0x4a, 0x2f, 0x65, 0xfe, 0x57, 0xf6, 0xe6, 0x3f, 0xb3, 0x0f, 0x9f, 0x9d, + 0xae, 0x18, 0x39, 0x5b, 0x31, 0xf2, 0x7d, 0xc5, 0xc8, 0xbb, 0x35, 0x6b, 0x9c, 0xad, 0x59, 0xe3, + 0xcb, 0x9a, 0x35, 0x5e, 0x1e, 0x5e, 0x88, 0x3f, 0x6e, 0x7f, 0x29, 0x72, 0x37, 0xd0, 0xb0, 0x29, + 0xf9, 0xeb, 0x0b, 0xff, 0x8b, 0xbf, 0x8f, 0x7c, 0xdb, 0xaf, 0xf2, 0xe1, 0x8f, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x9d, 0x04, 0xda, 0xdd, 0x51, 0x03, 0x00, 0x00, } func (m *FinalityProviderHistoricalRewards) Marshal() (dAtA []byte, err error) { @@ -291,6 +291,16 @@ func (m *FinalityProviderCurrentRewards) MarshalToSizedBuffer(dAtA []byte) (int, _ = i var l int _ = l + { + size := m.TotalActiveSat.Size() + i -= size + if _, err := m.TotalActiveSat.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintRewards(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a if m.Period != 0 { i = encodeVarintRewards(dAtA, i, uint64(m.Period)) i-- @@ -333,13 +343,18 @@ func (m *BTCDelegationRewardsTracker) MarshalToSizedBuffer(dAtA []byte) (int, er _ = i var l int _ = l - if m.DelegationTotalActiveSat != 0 { - i = encodeVarintRewards(dAtA, i, uint64(m.DelegationTotalActiveSat)) - i-- - dAtA[i] = 0x10 + { + size := m.TotalActiveSat.Size() + i -= size + if _, err := m.TotalActiveSat.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintRewards(dAtA, i, uint64(size)) } - if m.StartPeriodCumulativeRewardFP != 0 { - i = encodeVarintRewards(dAtA, i, uint64(m.StartPeriodCumulativeRewardFP)) + i-- + dAtA[i] = 0x12 + if m.StartPeriodCumulativeReward != 0 { + i = encodeVarintRewards(dAtA, i, uint64(m.StartPeriodCumulativeReward)) i-- dAtA[i] = 0x8 } @@ -387,6 +402,8 @@ func (m *FinalityProviderCurrentRewards) Size() (n int) { if m.Period != 0 { n += 1 + sovRewards(uint64(m.Period)) } + l = m.TotalActiveSat.Size() + n += 1 + l + sovRewards(uint64(l)) return n } @@ -396,12 +413,11 @@ func (m *BTCDelegationRewardsTracker) Size() (n int) { } var l int _ = l - if m.StartPeriodCumulativeRewardFP != 0 { - n += 1 + sovRewards(uint64(m.StartPeriodCumulativeRewardFP)) - } - if m.DelegationTotalActiveSat != 0 { - n += 1 + sovRewards(uint64(m.DelegationTotalActiveSat)) + if m.StartPeriodCumulativeReward != 0 { + n += 1 + sovRewards(uint64(m.StartPeriodCumulativeReward)) } + l = m.TotalActiveSat.Size() + n += 1 + l + sovRewards(uint64(l)) return n } @@ -577,6 +593,39 @@ func (m *FinalityProviderCurrentRewards) Unmarshal(dAtA []byte) error { break } } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalActiveSat", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TotalActiveSat.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRewards(dAtA[iNdEx:]) @@ -629,9 +678,9 @@ func (m *BTCDelegationRewardsTracker) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field StartPeriodCumulativeRewardFP", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field StartPeriodCumulativeReward", wireType) } - m.StartPeriodCumulativeRewardFP = 0 + m.StartPeriodCumulativeReward = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowRewards @@ -641,16 +690,16 @@ func (m *BTCDelegationRewardsTracker) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.StartPeriodCumulativeRewardFP |= uint64(b&0x7F) << shift + m.StartPeriodCumulativeReward |= uint64(b&0x7F) << shift if b < 0x80 { break } } case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field DelegationTotalActiveSat", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalActiveSat", wireType) } - m.DelegationTotalActiveSat = 0 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowRewards @@ -660,11 +709,25 @@ func (m *BTCDelegationRewardsTracker) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.DelegationTotalActiveSat |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } + if byteLen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TotalActiveSat.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRewards(dAtA[iNdEx:]) From 0a08ccee1c0bbb2cd35a3bf63153e4b1c3cbdfbf Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 1 Dec 2024 23:17:55 -0300 Subject: [PATCH 007/132] chore: removed single value in store and used structure to keep the total amount of satoshi staked as sdkmath.int --- x/incentive/keeper/reward_tracker.go | 167 ++++++--------------------- x/incentive/types/keys.go | 2 - x/incentive/types/rewards.go | 24 ++++ 3 files changed, 59 insertions(+), 134 deletions(-) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 4e9239ce1..c3612aa17 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -10,7 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - corestoretypes "cosmossdk.io/core/store" sdkmath "cosmossdk.io/math" ) @@ -68,15 +67,6 @@ func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddres } func (k Keeper) CalculateDelegationRewards(ctx context.Context, fp, del sdk.AccAddress, endPeriod uint64) (sdk.Coins, error) { - delActiveStakedSat, err := k.getDelegationStaking(ctx, fp, del) - if err != nil { - return sdk.Coins{}, err - } - - if delActiveStakedSat.IsZero() { - return sdk.NewCoins(), nil - } - btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) if err != nil { if errors.Is(err, types.ErrBTCDelegationRewardsTrackerNotFound) { @@ -85,6 +75,10 @@ func (k Keeper) CalculateDelegationRewards(ctx context.Context, fp, del sdk.AccA return sdk.Coins{}, err } + if btcDelRwdTracker.TotalActiveSat.IsZero() { + return sdk.NewCoins(), nil + } + return k.calculateDelegationRewardsBetween(ctx, fp, del, btcDelRwdTracker, endPeriod) } @@ -177,7 +171,7 @@ func (k Keeper) initializeFinalityProvider(ctx context.Context, fp sdk.AccAddres return err } // set current rewards (starting at period 1) - return k.setFinalityProviderCurrentRewards(ctx, fp, types.NewFinalityProviderCurrentRewards(sdk.NewCoins(), 1)) + return k.setFinalityProviderCurrentRewards(ctx, fp, types.NewFinalityProviderCurrentRewards(sdk.NewCoins(), 1, sdkmath.ZeroInt())) } // initializeBTCDelegation creates a new BTCDelegationRewardsTracker from the previous acumulative rewards @@ -205,7 +199,7 @@ func (k Keeper) initializeBTCDelegation(ctx context.Context, fp, del sdk.AccAddr // } // sdkCtx := sdk.UnwrapSDKContext(ctx) - types.NewBTCDelegationRewardsTracker(previousPeriod, 0) + types.NewBTCDelegationRewardsTracker(previousPeriod, sdkmath.ZeroInt()) return nil // return k.SetDelegatorStartingInfo(ctx, fp, del, dstrtypes.NewDelegatorStartingInfo(previousPeriod, stake, uint64(sdkCtx.BlockHeight()))) } @@ -238,6 +232,17 @@ func (k Keeper) GetBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk. return value, nil } +func (k Keeper) setBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk.AccAddress, rwd types.BTCDelegationRewardsTracker) error { + key := del.Bytes() + bz, err := rwd.Marshal() + if err != nil { + return err + } + + k.storeBTCDelegationRewardsTracker(ctx, fp).Set(key, bz) + return nil +} + func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress, rwd types.FinalityProviderCurrentRewards) error { key := fp.Bytes() bz, err := rwd.Marshal() @@ -306,154 +311,52 @@ func (k Keeper) storeFpHistoricalRewards(ctx context.Context, fp sdk.AccAddress) return prefix.NewStore(st, fp.Bytes()) } -// storeFinalityProviderStaked returns the KVStore of the finality provider amount active staked -// prefix: (DelegatorStakedBTCKey) -// key: (FinalityProviderStakedBTCKey) -// value: sdk math Int -func (k Keeper) storeFinalityProviderStaked(ctx context.Context) prefix.Store { - storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return prefix.NewStore(storeAdapter, types.FinalityProviderStakedBTCKey) -} - -// storeDelegationFpStaked returns the KVStore of the delegator amount staked -// prefix: (DelegatorStakedBTCKey) -// key: (FpAddr, DelAddr) -// value: sdk math Int -func (k Keeper) storeDelegationFpStaked(ctx context.Context, fp sdk.AccAddress) prefix.Store { - storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - st := prefix.NewStore(storeAdapter, types.DelegationStakedBTCKey) - return prefix.NewStore(st, fp.Bytes()) -} - func (k Keeper) addFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress, amt sdkmath.Int) error { - st := k.storeFinalityProviderStaked(ctx) - key := fp.Bytes() - - return OperationWithInt(st, key, func(currentFpStaked sdkmath.Int) sdkmath.Int { - return currentFpStaked.Add(amt) - }) -} - -func (k Keeper) getFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress) (amt sdkmath.Int, err error) { - st := k.storeFinalityProviderStaked(ctx) - key := fp.Bytes() - - return PrefixStoreGetInt(st, key) -} - -func (k Keeper) subFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress, amt sdkmath.Int) error { - st := k.storeFinalityProviderStaked(ctx) - key := fp.Bytes() - - return OperationWithInt(st, key, func(currentFpStaked sdkmath.Int) sdkmath.Int { - return currentFpStaked.Sub(amt) - }) -} - -func (k Keeper) getDelegationStaking(ctx context.Context, fp, del sdk.AccAddress) (sdkmath.Int, error) { - st := k.storeDelegationFpStaked(ctx, fp) - key := del.Bytes() - - return PrefixStoreGetInt(st, key) -} - -func (k Keeper) AddDelegationStaking(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { - st := k.storeDelegationFpStaked(ctx, fp) - key := del.Bytes() - - err := OperationWithInt(st, key, func(currenDelegationStaked sdkmath.Int) sdkmath.Int { - return currenDelegationStaked.Add(amt) - }) + fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) if err != nil { return err } - return k.addFinalityProviderStaked(ctx, fp, amt) + fpCurrentRwd.AddTotalActiveSat(amt) + return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) } -func (k Keeper) SubDelegationStaking(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { - st := k.storeDelegationFpStaked(ctx, fp) - key := fp.Bytes() - - err := OperationWithInt(st, key, func(currenDelegationStaked sdkmath.Int) sdkmath.Int { - return currenDelegationStaked.Sub(amt) - }) +func (k Keeper) subFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress, amt sdkmath.Int) error { + fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) if err != nil { return err } - return k.subFinalityProviderStaked(ctx, fp, amt) + fpCurrentRwd.SubTotalActiveSat(amt) + return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) } -func OperationWithInt(st prefix.Store, key []byte, update func(vIntFromStore sdkmath.Int) (updatedValue sdkmath.Int)) (err error) { - currentValue, err := PrefixStoreGetInt(st, key) +func (k Keeper) AddDelegationStaking(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { + btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) if err != nil { return err } - currentValue = update(currentValue) - bz, err := currentValue.Marshal() - if err != nil { + btcDelRwdTracker.AddTotalActiveSat(amt) + if err := k.setBTCDelegationRewardsTracker(ctx, fp, del, btcDelRwdTracker); err != nil { return err } - st.Set(key, bz) - return nil -} - -func PrefixStoreGetInt(st prefix.Store, key []byte) (vInt sdkmath.Int, err error) { - if !st.Has(key) { - return sdkmath.NewInt(0), nil - } - - bz := st.Get(key) - vInt, err = ParseInt(bz) - if err != nil { - return sdkmath.Int{}, err - } - - return vInt, nil + return k.addFinalityProviderStaked(ctx, fp, amt) } -// StoreSetInt stores an sdkmath.Int from the KVStore. -func StoreSetInt(kv corestoretypes.KVStore, key []byte, vInt sdkmath.Int) (err error) { - bz, err := vInt.Marshal() +func (k Keeper) SubDelegationStaking(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { + btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) if err != nil { return err } - return kv.Set(key, bz) -} - -// StoreGetInt retrieves an sdkmath.Int from the KVStore. It returns zero int if not found. -func StoreGetInt(kv corestoretypes.KVStore, key []byte) (vInt sdkmath.Int, err error) { - exists, err := kv.Has(key) - if err != nil { - return sdkmath.Int{}, err - } - if !exists { - return sdkmath.NewInt(0), nil - } - - bz, err := kv.Get(key) - if err != nil { - return sdkmath.Int{}, err - } - - vInt, err = ParseInt(bz) - if err != nil { - return sdkmath.Int{}, err + btcDelRwdTracker.SubTotalActiveSat(amt) + if err := k.setBTCDelegationRewardsTracker(ctx, fp, del, btcDelRwdTracker); err != nil { + return err } - return vInt, nil -} -// ParseInt parses an sdkmath.Int from bytes. -func ParseInt(bz []byte) (sdkmath.Int, error) { - var val sdkmath.Int - if err := val.Unmarshal(bz); err != nil { - return val, err - } - return val, nil + return k.subFinalityProviderStaked(ctx, fp, amt) } // IterateBTCDelegators iterates over all the delegators that have some active BTC delegator diff --git a/x/incentive/types/keys.go b/x/incentive/types/keys.go index 490540bed..bcc3dd29e 100644 --- a/x/incentive/types/keys.go +++ b/x/incentive/types/keys.go @@ -25,6 +25,4 @@ var ( FinalityProviderCurrentRewardsKey = []byte{0x06} // key prefix for storing the Current rewards of finality provider by addr FinalityProviderHistoricalRewardsKey = []byte{0x07} // key prefix for storing the Historical rewards of finality provider by addr and period BTCDelegationRewardsTrackerKey = []byte{0x8} // key prefix for BTC delegation rewards tracker info (del,fp) => BTCDelegationRewardsTracker - DelegationStakedBTCKey = []byte{0x9} // key prefix for BTC delegation (del,fp) active staked math.Int - FinalityProviderStakedBTCKey = []byte{0xA} // key prefix for BTC finality provider active staked math.Int ) diff --git a/x/incentive/types/rewards.go b/x/incentive/types/rewards.go index 4b163a4bc..fca82ef84 100644 --- a/x/incentive/types/rewards.go +++ b/x/incentive/types/rewards.go @@ -25,3 +25,27 @@ func NewFinalityProviderHistoricalRewards(cumulativeRewardsPerSat sdk.Coins) Fin CumulativeRewardsPerSat: cumulativeRewardsPerSat, } } + +func (f *FinalityProviderCurrentRewards) AddRewards(coinsToAdd sdk.Coins) { + f.CurrentRewards = f.CurrentRewards.Add(coinsToAdd...) +} + +func (f *FinalityProviderCurrentRewards) SubRewards(coinsToSubtract sdk.Coins) { + f.CurrentRewards = f.CurrentRewards.Sub(coinsToSubtract...) +} + +func (f *FinalityProviderCurrentRewards) AddTotalActiveSat(amt sdkmath.Int) { + f.TotalActiveSat = f.TotalActiveSat.Add(amt) +} + +func (f *FinalityProviderCurrentRewards) SubTotalActiveSat(amt sdkmath.Int) { + f.TotalActiveSat = f.TotalActiveSat.Sub(amt) +} + +func (f *BTCDelegationRewardsTracker) AddTotalActiveSat(amt sdkmath.Int) { + f.TotalActiveSat = f.TotalActiveSat.Add(amt) +} + +func (f *BTCDelegationRewardsTracker) SubTotalActiveSat(amt sdkmath.Int) { + f.TotalActiveSat = f.TotalActiveSat.Sub(amt) +} From 3f33dbaec42ebe01c8ecdd8665bc243088615b65 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 2 Dec 2024 00:14:40 -0300 Subject: [PATCH 008/132] chore: same structure to store the amount creates weird case where we need the total to create new delegation --- x/incentive/keeper/reward_tracker.go | 45 +++++++++++++++------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index c3612aa17..ed194d114 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -44,14 +44,21 @@ func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddre rewards, err := k.CalculateDelegationRewards(ctx, fp, del, endedPeriod) if err != nil { - return err + if !errors.Is(err, types.ErrBTCDelegationRewardsTrackerNotFound) { + return err + } + rewards = sdk.NewCoins() } - if !rewards.IsZero() { // there is some rewards + if !rewards.IsZero() { k.accumulateRewardGauge(ctx, types.BTCDelegationType, del, rewards) } - return k.AddDelegationStaking(ctx, fp, del, amtSat) + if err := k.AddDelegationSat(ctx, fp, del, amtSat); err != nil { + return err + } + + return k.initializeBTCDelegation(ctx, fp, del) } func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { @@ -69,9 +76,6 @@ func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddres func (k Keeper) CalculateDelegationRewards(ctx context.Context, fp, del sdk.AccAddress, endPeriod uint64) (sdk.Coins, error) { btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) if err != nil { - if errors.Is(err, types.ErrBTCDelegationRewardsTrackerNotFound) { - - } return sdk.Coins{}, err } @@ -188,20 +192,13 @@ func (k Keeper) initializeBTCDelegation(ctx context.Context, fp, del sdk.AccAddr } previousPeriod := valCurrentRewards.Period - 1 - // validator, err := k.stakingKeeper.Validator(ctx, fp) - // if err != nil { - // return err - // } - - // delegation, err := k.stakingKeeper.Delegation(ctx, del, fp) - // if err != nil { - // return err - // } + btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) + if err != nil { + return err + } - // sdkCtx := sdk.UnwrapSDKContext(ctx) - types.NewBTCDelegationRewardsTracker(previousPeriod, sdkmath.ZeroInt()) - return nil - // return k.SetDelegatorStartingInfo(ctx, fp, del, dstrtypes.NewDelegatorStartingInfo(previousPeriod, stake, uint64(sdkCtx.BlockHeight()))) + rwd := types.NewBTCDelegationRewardsTracker(previousPeriod, btcDelRwdTracker.TotalActiveSat) + return k.setBTCDelegationRewardsTracker(ctx, fp, del, rwd) } func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { @@ -331,10 +328,16 @@ func (k Keeper) subFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) } -func (k Keeper) AddDelegationStaking(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { +func (k Keeper) AddDelegationSat(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) if err != nil { - return err + if !errors.Is(err, types.ErrBTCDelegationRewardsTrackerNotFound) { + return err + } + + // first delegation to this pair (fp, del), can start as 0 previous period as it + // will be updated soon as initilize btc delegation + btcDelRwdTracker = types.NewBTCDelegationRewardsTracker(0, sdkmath.ZeroInt()) } btcDelRwdTracker.AddTotalActiveSat(amt) From a4bc64464a90ffa038fb39d31a638b4ee892bc1f Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 3 Dec 2024 21:49:14 -0300 Subject: [PATCH 009/132] fix: add #306 to changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 131e11c98..9f34ba1a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### Improvements +- [#306](https://github.com/babylonlabs-io/babylon/pull/306) feat: improve BTC reward distribution with +virtual block periods for each finality provider that has delegations and reward tracker structures. - [#309](https://github.com/babylonlabs-io/babylon/pull/309) feat(adr-036): custom withdrawal address - [#305](https://github.com/babylonlabs-io/babylon/pull/305) chore: add more error logs to `VerifyInclusionProofAndGetHeight` - [#304](https://github.com/babylonlabs-io/babylon/pull/304) Add highest voted height to finality provider From 8cc040037a097afbd27803a952da95b35485ebea Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 3 Dec 2024 21:57:13 -0300 Subject: [PATCH 010/132] fix: failing test --- testutil/btcstaking-helper/keeper.go | 2 ++ x/incentive/keeper/reward_tracker_test.go | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 x/incentive/keeper/reward_tracker_test.go diff --git a/testutil/btcstaking-helper/keeper.go b/testutil/btcstaking-helper/keeper.go index 8c86a5616..a67d9e919 100644 --- a/testutil/btcstaking-helper/keeper.go +++ b/testutil/btcstaking-helper/keeper.go @@ -66,6 +66,8 @@ func NewHelper( // mock refundable messages iKeeper := ftypes.NewMockIncentiveKeeper(ctrl) iKeeper.EXPECT().IndexRefundableMsg(gomock.Any(), gomock.Any()).AnyTimes() + iKeeper.EXPECT().BtcDelegationActivated(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + iKeeper.EXPECT().BtcDelegationUnbonded(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() ckptKeeper := ftypes.NewMockCheckpointingKeeper(ctrl) ckptKeeper.EXPECT().GetLastFinalizedEpoch(gomock.Any()).Return(timestampedEpoch).AnyTimes() diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go new file mode 100644 index 000000000..ac8c75830 --- /dev/null +++ b/x/incentive/keeper/reward_tracker_test.go @@ -0,0 +1,20 @@ +package keeper_test + +import ( + "testing" + + "cosmossdk.io/math" + "github.com/babylonlabs-io/babylon/testutil/datagen" + keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" + "github.com/golang/mock/gomock" +) + +func TestXxx(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + fpAddr, delAddr := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + k, ctx := keepertest.IncentiveKeeper(t, nil, nil, nil) + k.AddDelegationSat(ctx, fpAddr, delAddr, math.NewInt(2000)) +} From 482b860521c61d57f8a3ee91404d85e8d8b2effb Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 3 Dec 2024 21:59:29 -0300 Subject: [PATCH 011/132] fix: lint errcheck --- x/incentive/keeper/reward_tracker_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index ac8c75830..30d6f9158 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -7,6 +7,7 @@ import ( "github.com/babylonlabs-io/babylon/testutil/datagen" keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" ) func TestXxx(t *testing.T) { @@ -16,5 +17,6 @@ func TestXxx(t *testing.T) { fpAddr, delAddr := datagen.GenRandomAddress(), datagen.GenRandomAddress() k, ctx := keepertest.IncentiveKeeper(t, nil, nil, nil) - k.AddDelegationSat(ctx, fpAddr, delAddr, math.NewInt(2000)) + err := k.AddDelegationSat(ctx, fpAddr, delAddr, math.NewInt(2000)) + require.NoError(t, err) } From 63f4b6df1da5498dba79919e42cf760e80f6203d Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 3 Dec 2024 23:18:35 -0300 Subject: [PATCH 012/132] fix: storage of fp current rewards and add test for AddDelegationSat --- x/incentive/keeper/reward_tracker.go | 23 +++- x/incentive/keeper/reward_tracker_test.go | 138 +++++++++++++++++++++- 2 files changed, 151 insertions(+), 10 deletions(-) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index ed194d114..9f2ecca8e 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -138,7 +138,7 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA } // initialize Validator and return 1 as ended period - if err := k.initializeFinalityProvider(ctx, fp); err != nil { + if _, err := k.initializeFinalityProvider(ctx, fp); err != nil { return 0, err } return 1, nil @@ -168,14 +168,16 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA return fpCurrentRwd.Period, nil } -func (k Keeper) initializeFinalityProvider(ctx context.Context, fp sdk.AccAddress) error { +func (k Keeper) initializeFinalityProvider(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { // historical rewards starts at the period 0 err := k.setFinalityProviderHistoricalRewards(ctx, fp, 0, types.NewFinalityProviderHistoricalRewards(sdk.NewCoins())) if err != nil { - return err + return types.FinalityProviderCurrentRewards{}, err } + // set current rewards (starting at period 1) - return k.setFinalityProviderCurrentRewards(ctx, fp, types.NewFinalityProviderCurrentRewards(sdk.NewCoins(), 1, sdkmath.ZeroInt())) + newFp := types.NewFinalityProviderCurrentRewards(sdk.NewCoins(), 1, sdkmath.ZeroInt()) + return newFp, k.setFinalityProviderCurrentRewards(ctx, fp, newFp) } // initializeBTCDelegation creates a new BTCDelegationRewardsTracker from the previous acumulative rewards @@ -286,7 +288,8 @@ func (k Keeper) setFinalityProviderHistoricalRewards(ctx context.Context, fp sdk // value: BTCDelegationRewardsTracker func (k Keeper) storeBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress) prefix.Store { storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return prefix.NewStore(storeAdaptor, types.BTCDelegationRewardsTrackerKey) + st := prefix.NewStore(storeAdaptor, types.BTCDelegationRewardsTrackerKey) + return prefix.NewStore(st, fp.Bytes()) } // storeFpCurrentRewards returns the KVStore of the FP current rewards @@ -311,7 +314,15 @@ func (k Keeper) storeFpHistoricalRewards(ctx context.Context, fp sdk.AccAddress) func (k Keeper) addFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress, amt sdkmath.Int) error { fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) if err != nil { - return err + if !errors.Is(err, types.ErrFPCurrentRewardsNotFound) { + return err + } + + // this is needed as the amount of sats for the FP is inside the FpCurrentRewards + fpCurrentRwd, err = k.initializeFinalityProvider(ctx, fp) + if err != nil { + return err + } } fpCurrentRwd.AddTotalActiveSat(amt) diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index 30d6f9158..b0497e74e 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -10,13 +10,143 @@ import ( "github.com/stretchr/testify/require" ) -func TestXxx(t *testing.T) { +func TestAddDelegationSat(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() + k, ctx := keepertest.IncentiveKeeper(t, nil, nil, nil) - fpAddr, delAddr := datagen.GenRandomAddress(), datagen.GenRandomAddress() + fp1Addr, del1Addr := datagen.GenRandomAddress(), datagen.GenRandomAddress() + fp2Addr, del2Addr := datagen.GenRandomAddress(), datagen.GenRandomAddress() + amtFp1Del1, amtFp1Del2, amtFp2Del2, amtFp2Del1 := math.NewInt(2000), math.NewInt(4000), math.NewInt(500), math.NewInt(700) - k, ctx := keepertest.IncentiveKeeper(t, nil, nil, nil) - err := k.AddDelegationSat(ctx, fpAddr, delAddr, math.NewInt(2000)) + // adds 2000 for fp1, del1 + // fp1 => 2000 + // fp1, del1 => 2000 + err := k.AddDelegationSat(ctx, fp1Addr, del1Addr, amtFp1Del1) + require.NoError(t, err) + + fp1Rwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp1Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del1.String(), fp1Rwd.TotalActiveSat.String()) + + fp1Del1Rwd, err := k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del1Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del1.String(), fp1Del1Rwd.TotalActiveSat.String()) + + // adds 4000 for fp1, del2 + // fp1 => 6000 + // fp1, del1 => 2000 + // fp1, del2 => 4000 + err = k.AddDelegationSat(ctx, fp1Addr, del2Addr, amtFp1Del2) + require.NoError(t, err) + + fp1Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp1Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del1.Add(amtFp1Del2).String(), fp1Rwd.TotalActiveSat.String()) + + fp1Del2Rwd, err := k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del2Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del2.String(), fp1Del2Rwd.TotalActiveSat.String()) + + fp1Del1Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del1Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del1.String(), fp1Del1Rwd.TotalActiveSat.String()) + + // adds 500 for fp2, del2 + // fp1 => 6000 + // fp2 => 500 + // fp1, del1 => 2000 + // fp1, del2 => 4000 + // fp2, del2 => 500 + err = k.AddDelegationSat(ctx, fp2Addr, del2Addr, amtFp2Del2) + require.NoError(t, err) + + fp1Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp1Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del1.Add(amtFp1Del2).String(), fp1Rwd.TotalActiveSat.String()) + + fp2Rwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp2Addr) + require.NoError(t, err) + require.Equal(t, amtFp2Del2.String(), fp2Rwd.TotalActiveSat.String()) + + fp1Del1Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del1Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del1.String(), fp1Del1Rwd.TotalActiveSat.String()) + + fp1Del2Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del2Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del2.String(), fp1Del2Rwd.TotalActiveSat.String()) + + fp2Del2Rwd, err := k.GetBTCDelegationRewardsTracker(ctx, fp2Addr, del2Addr) + require.NoError(t, err) + require.Equal(t, amtFp2Del2.String(), fp2Del2Rwd.TotalActiveSat.String()) + + // adds 700 for fp2, del1 + // fp1 => 6000 + // fp2 => 1200 + // fp1, del1 => 2000 + // fp1, del2 => 4000 + // fp2, del1 => 700 + // fp2, del2 => 500 + err = k.AddDelegationSat(ctx, fp2Addr, del1Addr, amtFp2Del1) + require.NoError(t, err) + + fp1Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp1Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del1.Add(amtFp1Del2).String(), fp1Rwd.TotalActiveSat.String()) + + fp2Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp2Addr) + require.NoError(t, err) + require.Equal(t, amtFp2Del2.Add(amtFp2Del1).String(), fp2Rwd.TotalActiveSat.String()) + + fp1Del1Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del1Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del1.String(), fp1Del1Rwd.TotalActiveSat.String()) + + fp1Del2Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del2Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del2.String(), fp1Del2Rwd.TotalActiveSat.String()) + + fp2Del1Rwd, err := k.GetBTCDelegationRewardsTracker(ctx, fp2Addr, del1Addr) + require.NoError(t, err) + require.Equal(t, amtFp2Del1.String(), fp2Del1Rwd.TotalActiveSat.String()) + + fp2Del2Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp2Addr, del2Addr) + require.NoError(t, err) + require.Equal(t, amtFp2Del2.String(), fp2Del2Rwd.TotalActiveSat.String()) + + lastAmtFp1Del2 := math.NewInt(2000) + // adds 2000 for fp1, del2 + // fp1 => 8000 + // fp2 => 1200 + // fp1, del1 => 2000 + // fp1, del2 => 6000 + // fp2, del1 => 700 + // fp2, del2 => 500 + err = k.AddDelegationSat(ctx, fp1Addr, del2Addr, lastAmtFp1Del2) + require.NoError(t, err) + + fp1Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp1Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del1.Add(amtFp1Del2).Add(lastAmtFp1Del2).String(), fp1Rwd.TotalActiveSat.String()) + + fp2Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp2Addr) + require.NoError(t, err) + require.Equal(t, amtFp2Del2.Add(amtFp2Del1).String(), fp2Rwd.TotalActiveSat.String()) + + fp1Del1Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del1Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del1.String(), fp1Del1Rwd.TotalActiveSat.String()) + + fp1Del2Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del2Addr) + require.NoError(t, err) + require.Equal(t, amtFp1Del2.Add(lastAmtFp1Del2).String(), fp1Del2Rwd.TotalActiveSat.String()) + + fp2Del1Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp2Addr, del1Addr) + require.NoError(t, err) + require.Equal(t, amtFp2Del1.String(), fp2Del1Rwd.TotalActiveSat.String()) + + fp2Del2Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp2Addr, del2Addr) require.NoError(t, err) + require.Equal(t, amtFp2Del2.String(), fp2Del2Rwd.TotalActiveSat.String()) } From 8fc5d9e6403f157d22cad9f3a40103fef5471c37 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 3 Dec 2024 23:33:04 -0300 Subject: [PATCH 013/132] chore: add test for subtract delegation sats --- x/incentive/keeper/reward_tracker.go | 7 +- x/incentive/keeper/reward_tracker_test.go | 146 +++++++++------------- 2 files changed, 61 insertions(+), 92 deletions(-) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 9f2ecca8e..ee2c7d7bd 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -67,7 +67,7 @@ func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddres // withdraw rewards // - if err := k.SubDelegationStaking(ctx, fp, del, amtSat); err != nil { + if err := k.SubDelegationSat(ctx, fp, del, amtSat); err != nil { return err } return nil @@ -359,7 +359,10 @@ func (k Keeper) AddDelegationSat(ctx context.Context, fp, del sdk.AccAddress, am return k.addFinalityProviderStaked(ctx, fp, amt) } -func (k Keeper) SubDelegationStaking(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { +// SubDelegationSat there is no need to check if the fp or delegation exists, because they should exist +// otherwise it is probably a programming error calling to subtract the amount of active sat without +// having any sat added in the first place. +func (k Keeper) SubDelegationSat(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) if err != nil { return err diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index b0497e74e..f21c96edd 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -6,51 +6,39 @@ import ( "cosmossdk.io/math" "github.com/babylonlabs-io/babylon/testutil/datagen" keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" + "github.com/babylonlabs-io/babylon/x/incentive/keeper" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) -func TestAddDelegationSat(t *testing.T) { +func TestAddSubDelegationSat(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() k, ctx := keepertest.IncentiveKeeper(t, nil, nil, nil) - fp1Addr, del1Addr := datagen.GenRandomAddress(), datagen.GenRandomAddress() - fp2Addr, del2Addr := datagen.GenRandomAddress(), datagen.GenRandomAddress() + fp1, del1 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + fp2, del2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() amtFp1Del1, amtFp1Del2, amtFp2Del2, amtFp2Del1 := math.NewInt(2000), math.NewInt(4000), math.NewInt(500), math.NewInt(700) // adds 2000 for fp1, del1 // fp1 => 2000 // fp1, del1 => 2000 - err := k.AddDelegationSat(ctx, fp1Addr, del1Addr, amtFp1Del1) + err := k.AddDelegationSat(ctx, fp1, del1, amtFp1Del1) require.NoError(t, err) - - fp1Rwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp1Addr) - require.NoError(t, err) - require.Equal(t, amtFp1Del1.String(), fp1Rwd.TotalActiveSat.String()) - - fp1Del1Rwd, err := k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del1Addr) - require.NoError(t, err) - require.Equal(t, amtFp1Del1.String(), fp1Del1Rwd.TotalActiveSat.String()) + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) // adds 4000 for fp1, del2 // fp1 => 6000 // fp1, del1 => 2000 // fp1, del2 => 4000 - err = k.AddDelegationSat(ctx, fp1Addr, del2Addr, amtFp1Del2) + err = k.AddDelegationSat(ctx, fp1, del2, amtFp1Del2) require.NoError(t, err) - fp1Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp1Addr) - require.NoError(t, err) - require.Equal(t, amtFp1Del1.Add(amtFp1Del2).String(), fp1Rwd.TotalActiveSat.String()) - - fp1Del2Rwd, err := k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del2Addr) - require.NoError(t, err) - require.Equal(t, amtFp1Del2.String(), fp1Del2Rwd.TotalActiveSat.String()) - - fp1Del1Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del1Addr) - require.NoError(t, err) - require.Equal(t, amtFp1Del1.String(), fp1Del1Rwd.TotalActiveSat.String()) + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) + checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) // adds 500 for fp2, del2 // fp1 => 6000 @@ -58,28 +46,13 @@ func TestAddDelegationSat(t *testing.T) { // fp1, del1 => 2000 // fp1, del2 => 4000 // fp2, del2 => 500 - err = k.AddDelegationSat(ctx, fp2Addr, del2Addr, amtFp2Del2) - require.NoError(t, err) - - fp1Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp1Addr) + err = k.AddDelegationSat(ctx, fp2, del2, amtFp2Del2) require.NoError(t, err) - require.Equal(t, amtFp1Del1.Add(amtFp1Del2).String(), fp1Rwd.TotalActiveSat.String()) - - fp2Rwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp2Addr) - require.NoError(t, err) - require.Equal(t, amtFp2Del2.String(), fp2Rwd.TotalActiveSat.String()) - - fp1Del1Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del1Addr) - require.NoError(t, err) - require.Equal(t, amtFp1Del1.String(), fp1Del1Rwd.TotalActiveSat.String()) - - fp1Del2Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del2Addr) - require.NoError(t, err) - require.Equal(t, amtFp1Del2.String(), fp1Del2Rwd.TotalActiveSat.String()) - - fp2Del2Rwd, err := k.GetBTCDelegationRewardsTracker(ctx, fp2Addr, del2Addr) - require.NoError(t, err) - require.Equal(t, amtFp2Del2.String(), fp2Del2Rwd.TotalActiveSat.String()) + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) + checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) + checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2) + checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2) // adds 700 for fp2, del1 // fp1 => 6000 @@ -88,32 +61,14 @@ func TestAddDelegationSat(t *testing.T) { // fp1, del2 => 4000 // fp2, del1 => 700 // fp2, del2 => 500 - err = k.AddDelegationSat(ctx, fp2Addr, del1Addr, amtFp2Del1) - require.NoError(t, err) - - fp1Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp1Addr) - require.NoError(t, err) - require.Equal(t, amtFp1Del1.Add(amtFp1Del2).String(), fp1Rwd.TotalActiveSat.String()) - - fp2Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp2Addr) - require.NoError(t, err) - require.Equal(t, amtFp2Del2.Add(amtFp2Del1).String(), fp2Rwd.TotalActiveSat.String()) - - fp1Del1Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del1Addr) + err = k.AddDelegationSat(ctx, fp2, del1, amtFp2Del1) require.NoError(t, err) - require.Equal(t, amtFp1Del1.String(), fp1Del1Rwd.TotalActiveSat.String()) - - fp1Del2Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del2Addr) - require.NoError(t, err) - require.Equal(t, amtFp1Del2.String(), fp1Del2Rwd.TotalActiveSat.String()) - - fp2Del1Rwd, err := k.GetBTCDelegationRewardsTracker(ctx, fp2Addr, del1Addr) - require.NoError(t, err) - require.Equal(t, amtFp2Del1.String(), fp2Del1Rwd.TotalActiveSat.String()) - - fp2Del2Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp2Addr, del2Addr) - require.NoError(t, err) - require.Equal(t, amtFp2Del2.String(), fp2Del2Rwd.TotalActiveSat.String()) + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) + checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2.Add(amtFp2Del1)) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) + checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2) + checkFpDelTotalSat(t, ctx, k, fp2, del1, amtFp2Del1) + checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2) lastAmtFp1Del2 := math.NewInt(2000) // adds 2000 for fp1, del2 @@ -123,30 +78,41 @@ func TestAddDelegationSat(t *testing.T) { // fp1, del2 => 6000 // fp2, del1 => 700 // fp2, del2 => 500 - err = k.AddDelegationSat(ctx, fp1Addr, del2Addr, lastAmtFp1Del2) - require.NoError(t, err) - - fp1Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp1Addr) + err = k.AddDelegationSat(ctx, fp1, del2, lastAmtFp1Del2) require.NoError(t, err) - require.Equal(t, amtFp1Del1.Add(amtFp1Del2).Add(lastAmtFp1Del2).String(), fp1Rwd.TotalActiveSat.String()) + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2).Add(lastAmtFp1Del2)) + checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2.Add(amtFp2Del1)) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) + checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2.Add(lastAmtFp1Del2)) + checkFpDelTotalSat(t, ctx, k, fp2, del1, amtFp2Del1) + checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2) - fp2Rwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp2Addr) - require.NoError(t, err) - require.Equal(t, amtFp2Del2.Add(amtFp2Del1).String(), fp2Rwd.TotalActiveSat.String()) - - fp1Del1Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del1Addr) - require.NoError(t, err) - require.Equal(t, amtFp1Del1.String(), fp1Del1Rwd.TotalActiveSat.String()) - - fp1Del2Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp1Addr, del2Addr) - require.NoError(t, err) - require.Equal(t, amtFp1Del2.Add(lastAmtFp1Del2).String(), fp1Del2Rwd.TotalActiveSat.String()) + subAmtFp2Del2 := math.NewInt(350) + // subtract 350 for fp2, del2 + // fp1 => 8000 + // fp2 => 850 + // fp1, del1 => 2000 + // fp1, del2 => 6000 + // fp2, del1 => 700 + // fp2, del2 => 150 + err = k.SubDelegationSat(ctx, fp2, del2, subAmtFp2Del2) + require.NoError(t, err) + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2).Add(lastAmtFp1Del2)) + checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2.Add(amtFp2Del1).Sub(subAmtFp2Del2)) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) + checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2.Add(lastAmtFp1Del2)) + checkFpDelTotalSat(t, ctx, k, fp2, del1, amtFp2Del1) + checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2.Sub(subAmtFp2Del2)) +} - fp2Del1Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp2Addr, del1Addr) +func checkFpTotalSat(t *testing.T, ctx sdk.Context, k *keeper.Keeper, fp sdk.AccAddress, expectedSat math.Int) { + rwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) require.NoError(t, err) - require.Equal(t, amtFp2Del1.String(), fp2Del1Rwd.TotalActiveSat.String()) + require.Equal(t, expectedSat.String(), rwd.TotalActiveSat.String()) +} - fp2Del2Rwd, err = k.GetBTCDelegationRewardsTracker(ctx, fp2Addr, del2Addr) +func checkFpDelTotalSat(t *testing.T, ctx sdk.Context, k *keeper.Keeper, fp, del sdk.AccAddress, expectedSat math.Int) { + rwd, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) require.NoError(t, err) - require.Equal(t, amtFp2Del2.String(), fp2Del2Rwd.TotalActiveSat.String()) + require.Equal(t, expectedSat.String(), rwd.TotalActiveSat.String()) } From b3120e78901a4d8aee0cdfec64b957d4963c309e Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 4 Dec 2024 17:28:01 -0300 Subject: [PATCH 014/132] chore: add test for initilize fp --- x/incentive/keeper/btc_staking_gauge.go | 14 +++--- x/incentive/keeper/reward_tracker.go | 19 ++++++-- x/incentive/keeper/reward_tracker_test.go | 59 +++++++++++++++++++++++ 3 files changed, 82 insertions(+), 10 deletions(-) diff --git a/x/incentive/keeper/btc_staking_gauge.go b/x/incentive/keeper/btc_staking_gauge.go index 9a9d0501c..b3242e2cb 100644 --- a/x/incentive/keeper/btc_staking_gauge.go +++ b/x/incentive/keeper/btc_staking_gauge.go @@ -39,15 +39,17 @@ func (k Keeper) RewardBTCStaking(ctx context.Context, height uint64, dc *ftypes. // reward the rest of coins to each BTC delegation proportional to its voting power portion coinsForBTCDels := coinsForFpsAndDels.Sub(coinsForCommission...) // TODO(rafilx): add the coins entitled to the BTC delegations to the FinalityProviderCurrentRewards - + if err := k.AddFinalityProviderRewardsForDelegationsBTC(ctx, fp.GetAddress(), coinsForBTCDels); err != nil { + panic(err) + } // TODO: remove this iteration. It could be avoided by using accumulated rewards per period // for each finality provider, and for each delegation (fp, delegator) keep track of last period // TODO(rafilx): Add acumulative rewards for each validator - for _, btcDel := range fp.BtcDels { - btcDelPortion := fp.GetBTCDelPortion(btcDel) - coinsForDel := types.GetCoinsPortion(coinsForBTCDels, btcDelPortion) - k.accumulateRewardGauge(ctx, types.BTCDelegationType, btcDel.GetAddress(), coinsForDel) - } + // for _, btcDel := range fp.BtcDels { + // btcDelPortion := fp.GetBTCDelPortion(btcDel) + // coinsForDel := types.GetCoinsPortion(coinsForBTCDels, btcDelPortion) + // k.accumulateRewardGauge(ctx, types.BTCDelegationType, btcDel.GetAddress(), coinsForDel) + // } } // TODO: prune unnecessary state (delete BTCStakingGauge after the amount is used) } diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index ee2c7d7bd..a69f8f190 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -104,12 +104,12 @@ func (k Keeper) calculateDelegationRewardsBetween( // } // return staking * (ending - starting) - starting, err := k.getFinalityProviderHistoricalRewards(ctx, fp, btcDelRwdTracker.StartPeriodCumulativeReward) + starting, err := k.GetFinalityProviderHistoricalRewards(ctx, fp, btcDelRwdTracker.StartPeriodCumulativeReward) if err != nil { return sdk.Coins{}, err } - ending, err := k.getFinalityProviderHistoricalRewards(ctx, fp, endingPeriod) + ending, err := k.GetFinalityProviderHistoricalRewards(ctx, fp, endingPeriod) if err != nil { return sdk.Coins{}, err } @@ -138,6 +138,7 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA } // initialize Validator and return 1 as ended period + // the ended period is 1 because the just created historical sits at 0 if _, err := k.initializeFinalityProvider(ctx, fp); err != nil { return 0, err } @@ -149,7 +150,7 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA currentRewardsPerSat = fpCurrentRwd.CurrentRewards.QuoInt(fpCurrentRwd.TotalActiveSat) } - fpHistoricalRwd, err := k.getFinalityProviderHistoricalRewards(ctx, fp, fpCurrentRwd.Period-1) + fpHistoricalRwd, err := k.GetFinalityProviderHistoricalRewards(ctx, fp, fpCurrentRwd.Period-1) if err != nil { return 0, err } @@ -253,7 +254,7 @@ func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.Ac return nil } -func (k Keeper) getFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64) (types.FinalityProviderHistoricalRewards, error) { +func (k Keeper) GetFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64) (types.FinalityProviderHistoricalRewards, error) { key := make([]byte, 8) binary.LittleEndian.PutUint64(key, period) @@ -339,6 +340,16 @@ func (k Keeper) subFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) } +func (k Keeper) AddFinalityProviderRewardsForDelegationsBTC(ctx context.Context, fp sdk.AccAddress, rwd sdk.Coins) error { + fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) + if err != nil { + return err + } + + fpCurrentRwd.AddRewards(rwd) + return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) +} + func (k Keeper) AddDelegationSat(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) if err != nil { diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index f21c96edd..af0979e32 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -4,6 +4,7 @@ import ( "testing" "cosmossdk.io/math" + appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/testutil/datagen" keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" "github.com/babylonlabs-io/babylon/x/incentive/keeper" @@ -116,3 +117,61 @@ func checkFpDelTotalSat(t *testing.T, ctx sdk.Context, k *keeper.Keeper, fp, del require.NoError(t, err) require.Equal(t, expectedSat.String(), rwd.TotalActiveSat.String()) } + +func TestIncrementFinalityProviderPeriod(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + k, ctx := keepertest.IncentiveKeeper(t, nil, nil, nil) + + fp1, fp2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + del1 := datagen.GenRandomAddress() + + fp1EndedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp1) + require.NoError(t, err) + require.Equal(t, fp1EndedPeriod, uint64(1)) + + checkFpCurrentRwd(t, ctx, k, fp1, fp1EndedPeriod, sdk.NewCoins(), math.NewInt(0)) + checkFpHistoricalRwd(t, ctx, k, fp1, 0, sdk.NewCoins()) + + rwdAddedToPeriod1 := newBaseCoins(2_000000) // 2bbn + err = k.AddFinalityProviderRewardsForDelegationsBTC(ctx, fp1, rwdAddedToPeriod1) + require.NoError(t, err) + + // historical should not modify the rewards for the period already created + checkFpHistoricalRwd(t, ctx, k, fp1, 0, sdk.NewCoins()) + checkFpCurrentRwd(t, ctx, k, fp1, fp1EndedPeriod, rwdAddedToPeriod1, math.NewInt(0)) + + // needs to add some voting power so it can calculate the amount of rewards per share + satsDelegated := math.NewInt(500) + k.AddDelegationSat(ctx, fp1, del1, satsDelegated) + + fp1EndedPeriod, err = k.IncrementFinalityProviderPeriod(ctx, fp1) + require.NoError(t, err) + require.Equal(t, fp1EndedPeriod, uint64(1)) + + // now the historical that just ended should have as cumulative rewards 4000ubbn 2_000000ubbn/500sats + checkFpHistoricalRwd(t, ctx, k, fp1, fp1EndedPeriod, newBaseCoins(4000)) + checkFpCurrentRwd(t, ctx, k, fp1, fp1EndedPeriod+1, sdk.NewCoins(), satsDelegated) + + fp2EndedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp2) + require.NoError(t, err) + require.Equal(t, fp2EndedPeriod, uint64(1)) +} + +func checkFpHistoricalRwd(t *testing.T, ctx sdk.Context, k *keeper.Keeper, fp sdk.AccAddress, period uint64, expectedRwd sdk.Coins) { + historical, err := k.GetFinalityProviderHistoricalRewards(ctx, fp, period) + require.NoError(t, err) + require.Equal(t, historical.CumulativeRewardsPerSat.String(), expectedRwd.String()) +} + +func checkFpCurrentRwd(t *testing.T, ctx sdk.Context, k *keeper.Keeper, fp sdk.AccAddress, expectedPeriod uint64, expectedRwd sdk.Coins, totalActiveSat math.Int) { + fp1CurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) + require.NoError(t, err) + require.Equal(t, fp1CurrentRwd.CurrentRewards.String(), expectedRwd.String()) + require.Equal(t, fp1CurrentRwd.Period, expectedPeriod) + require.Equal(t, fp1CurrentRwd.TotalActiveSat.String(), totalActiveSat.String()) +} + +func newBaseCoins(amt uint64) sdk.Coins { + return sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, math.NewIntFromUint64(amt))) +} From ea15191c828a827951a8c5c89390302a11cd463b Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 4 Dec 2024 22:06:16 -0300 Subject: [PATCH 015/132] fix: precision points error and allowed 0.1% margin error in rewards distribution testing --- testutil/datagen/incentive.go | 2 +- x/incentive/keeper/btc_staking_gauge.go | 1 + x/incentive/keeper/btc_staking_gauge_test.go | 52 +++++++++++++++++++- x/incentive/keeper/reward_tracker.go | 48 +++++++++++++++--- x/incentive/keeper/reward_tracker_test.go | 2 +- 5 files changed, 94 insertions(+), 11 deletions(-) diff --git a/testutil/datagen/incentive.go b/testutil/datagen/incentive.go index f22a5b82d..db8f193a4 100644 --- a/testutil/datagen/incentive.go +++ b/testutil/datagen/incentive.go @@ -42,7 +42,7 @@ func GenRandomCoins(r *rand.Rand) sdk.Coins { coins := sdk.NewCoins() for i := int32(0); i < numCoins; i++ { demon := GenRandomDenom(r) - amount := r.Int63n(10000) + 1 + amount := r.Int63n(10_000000) + 10_000000 coin := sdk.NewInt64Coin(demon, amount) coins = coins.Add(coin) } diff --git a/x/incentive/keeper/btc_staking_gauge.go b/x/incentive/keeper/btc_staking_gauge.go index b3242e2cb..fb61bb96f 100644 --- a/x/incentive/keeper/btc_staking_gauge.go +++ b/x/incentive/keeper/btc_staking_gauge.go @@ -45,6 +45,7 @@ func (k Keeper) RewardBTCStaking(ctx context.Context, height uint64, dc *ftypes. // TODO: remove this iteration. It could be avoided by using accumulated rewards per period // for each finality provider, and for each delegation (fp, delegator) keep track of last period // TODO(rafilx): Add acumulative rewards for each validator + // for _, btcDel := range fp.BtcDels { // btcDelPortion := fp.GetBTCDelPortion(btcDel) // coinsForDel := types.GetCoinsPortion(coinsForBTCDels, btcDelPortion) diff --git a/x/incentive/keeper/btc_staking_gauge_test.go b/x/incentive/keeper/btc_staking_gauge_test.go index 957886b93..815f0e62b 100644 --- a/x/incentive/keeper/btc_staking_gauge_test.go +++ b/x/incentive/keeper/btc_staking_gauge_test.go @@ -4,6 +4,7 @@ import ( "math/rand" "testing" + "cosmossdk.io/math" "github.com/babylonlabs-io/babylon/testutil/datagen" testkeeper "github.com/babylonlabs-io/babylon/testutil/keeper" "github.com/babylonlabs-io/babylon/x/incentive/types" @@ -15,8 +16,8 @@ import ( func FuzzRewardBTCStaking(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() r := rand.New(rand.NewSource(seed)) - ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -41,6 +42,7 @@ func FuzzRewardBTCStaking(f *testing.F) { fpRewardMap := map[string]sdk.Coins{} // key: address, value: reward btcDelRewardMap := map[string]sdk.Coins{} // key: address, value: reward + sumCoinsForDels := sdk.NewCoins() for _, fp := range dc.FinalityProviders { fpPortion := dc.GetFinalityProviderPortion(fp) coinsForFpsAndDels := gauge.GetCoinsPortion(fpPortion) @@ -49,8 +51,15 @@ func FuzzRewardBTCStaking(f *testing.F) { fpRewardMap[fp.GetAddress().String()] = coinsForCommission distributedCoins.Add(coinsForCommission...) } + coinsForBTCDels := coinsForFpsAndDels.Sub(coinsForCommission...) + sumCoinsForDels = sumCoinsForDels.Add(coinsForBTCDels...) + fpAddr := fp.GetAddress() + for _, btcDel := range fp.BtcDels { + err := keeper.BtcDelegationActivated(ctx, fpAddr, btcDel.GetAddress(), btcDel.TotalSat) + require.NoError(t, err) + btcDelPortion := fp.GetBTCDelPortion(btcDel) coinsForDel := types.GetCoinsPortion(coinsForBTCDels, btcDelPortion) if coinsForDel.IsAllPositive() { @@ -63,6 +72,22 @@ func FuzzRewardBTCStaking(f *testing.F) { // distribute rewards in the gauge to finality providers/delegations keeper.RewardBTCStaking(ctx, height, dc) + for _, fp := range dc.FinalityProviders { + fpAddr := fp.GetAddress() + for _, btcDel := range fp.BtcDels { + delAddr := btcDel.GetAddress() + delRwd, err := keeper.GetBTCDelegationRewardsTracker(ctx, fpAddr, delAddr) + require.NoError(t, err) + require.Equal(t, delRwd.TotalActiveSat.Uint64(), btcDel.TotalSat) + + err = keeper.WithdrawDelegationRewardsToGauge(ctx, fpAddr, delAddr) + require.NoError(t, err) + } + fpCurrentRwd, err := keeper.GetFinalityProviderCurrentRewards(ctx, fpAddr) + require.NoError(t, err) + require.Equal(t, fpCurrentRwd.TotalActiveSat.Uint64(), fp.TotalBondedSat) + } + // assert consistency between reward map and reward gauge for addrStr, reward := range fpRewardMap { addr, err := sdk.AccAddressFromBech32(addrStr) @@ -71,15 +96,38 @@ func FuzzRewardBTCStaking(f *testing.F) { require.NotNil(t, rg) require.Equal(t, reward, rg.Coins) } + sumRewards := sdk.NewCoins() for addrStr, reward := range btcDelRewardMap { addr, err := sdk.AccAddressFromBech32(addrStr) require.NoError(t, err) rg := keeper.GetRewardGauge(ctx, types.BTCDelegationType, addr) require.NotNil(t, rg) - require.Equal(t, reward, rg.Coins) + + // A little bit of rewards could be lost in the process due to precision points + // so 0.1% difference can be considered okay + allowedMarginError := CalculatePointOnePercent(reward) + require.Truef(t, reward.Sub(rg.Coins...).IsAllLT(allowedMarginError), + "BTC delegation failed within the margin of error: %s\nRewards: %s\nGauge: %s", + allowedMarginError.String(), reward.String(), rg.Coins.String(), + ) + + sumRewards = sumRewards.Add(reward...) } + allowedMarginError := CalculatePointOnePercent(sumCoinsForDels) + require.Truef(t, sumCoinsForDels.Sub(sumRewards...).IsAllLT(allowedMarginError), + "Sum of total rewards failed within the margin of error: %s\nRewards: %s\nGauge: %s", + allowedMarginError.String(), sumCoinsForDels.String(), sumRewards.String(), + ) + // assert distributedCoins is a subset of coins in gauge require.True(t, gauge.Coins.IsAllGTE(distributedCoins)) }) } + +func CalculatePointOnePercent(value sdk.Coins) sdk.Coins { + numerator := math.NewInt(1) // 0.1% as numerator + denominator := math.NewInt(1000) // 0.1% denominator + result := value.MulInt(numerator).QuoInt(denominator) + return result +} diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index a69f8f190..c3c1f1586 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -13,6 +13,14 @@ import ( sdkmath "cosmossdk.io/math" ) +var ( + // it is needed to add decimal points when reducing the rewards amount + // per sat to latter when giving out the rewards to the gauge, reduce + // the decimal points back, currently 20 decimal points are being added + // the sdkmath.Int holds a big int which support up to 2^256 integers + DecimalAccumulatedRewards, _ = sdkmath.NewIntFromString("100000000000000000000") +) + func (k Keeper) FpSlashed(ctx context.Context, fp sdk.AccAddress) error { // withdrawDelegationRewards // Delete all the delegations reward tracker associated with this FP @@ -73,6 +81,27 @@ func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddres return nil } +func (k Keeper) WithdrawDelegationRewardsToGauge(ctx context.Context, fp, del sdk.AccAddress) error { + endedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp) + if err != nil { + return err + } + + rewards, err := k.CalculateDelegationRewards(ctx, fp, del, endedPeriod) + if err != nil { + if !errors.Is(err, types.ErrBTCDelegationRewardsTrackerNotFound) { + return err + } + rewards = sdk.NewCoins() + } + + if !rewards.IsZero() { + k.accumulateRewardGauge(ctx, types.BTCDelegationType, del, rewards) + } + + return k.initializeBTCDelegation(ctx, fp, del) +} + func (k Keeper) CalculateDelegationRewards(ctx context.Context, fp, del sdk.AccAddress, endPeriod uint64) (sdk.Coins, error) { btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) if err != nil { @@ -114,15 +143,16 @@ func (k Keeper) calculateDelegationRewardsBetween( return sdk.Coins{}, err } - // creates the difference amount of rewards (ending - starting) periods - // this difference is the amount of rewards entitled per satoshi active stake - difference := ending.CumulativeRewardsPerSat.Sub(starting.CumulativeRewardsPerSat...) - if difference.IsAnyNegative() { + // creates the differenceWithDecimals amount of rewards (ending - starting) periods + // this differenceWithDecimals is the amount of rewards entitled per satoshi active stake + differenceWithDecimals := ending.CumulativeRewardsPerSat.Sub(starting.CumulativeRewardsPerSat...) + if differenceWithDecimals.IsAnyNegative() { panic("negative rewards should not be possible") } - // note: necessary to truncate so we don't allow withdrawing more rewards than owed - rewards := difference.MulInt(btcDelRwdTracker.TotalActiveSat) + // note: necessary to truncate so we don't allow withdrawing more rewardsWithDecimals than owed + rewardsWithDecimals := differenceWithDecimals.MulInt(btcDelRwdTracker.TotalActiveSat) + rewards := rewardsWithDecimals.QuoInt(DecimalAccumulatedRewards) return rewards, nil } @@ -147,7 +177,10 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA currentRewardsPerSat := sdk.NewCoins() if !fpCurrentRwd.TotalActiveSat.IsZero() { - currentRewardsPerSat = fpCurrentRwd.CurrentRewards.QuoInt(fpCurrentRwd.TotalActiveSat) + // 1000 ubbn / 200 + // 1 sat = 5 ubbn + currentRewardsPerSatWithDecimals := fpCurrentRwd.CurrentRewards.MulInt(DecimalAccumulatedRewards) + currentRewardsPerSat = currentRewardsPerSatWithDecimals.QuoInt(fpCurrentRwd.TotalActiveSat) } fpHistoricalRwd, err := k.GetFinalityProviderHistoricalRewards(ctx, fp, fpCurrentRwd.Period-1) @@ -155,6 +188,7 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA return 0, err } + // Due to lost in precision point if the rewards are too low, it could become zero newFpHistoricalRwd := types.NewFinalityProviderHistoricalRewards(fpHistoricalRwd.CumulativeRewardsPerSat.Add(currentRewardsPerSat...)) if err := k.setFinalityProviderHistoricalRewards(ctx, fp, fpCurrentRwd.Period, newFpHistoricalRwd); err != nil { return 0, err diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index af0979e32..eb69a3b45 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -150,7 +150,7 @@ func TestIncrementFinalityProviderPeriod(t *testing.T) { require.Equal(t, fp1EndedPeriod, uint64(1)) // now the historical that just ended should have as cumulative rewards 4000ubbn 2_000000ubbn/500sats - checkFpHistoricalRwd(t, ctx, k, fp1, fp1EndedPeriod, newBaseCoins(4000)) + checkFpHistoricalRwd(t, ctx, k, fp1, fp1EndedPeriod, newBaseCoins(4000).MulInt(keeper.DecimalAccumulatedRewards)) checkFpCurrentRwd(t, ctx, k, fp1, fp1EndedPeriod+1, sdk.NewCoins(), satsDelegated) fp2EndedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp2) From dcc06f33461b1d46e3cdfcdba1019c8e40d2a8ed Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Fri, 6 Dec 2024 08:40:04 -0300 Subject: [PATCH 016/132] chore: merge main --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54d8bf618..e91eaa19a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## Unreleased +### Improvements + +- [#306](https://github.com/babylonlabs-io/babylon/pull/306) feat: improve BTC reward distribution with +virtual block periods for each finality provider that has delegations and reward tracker structures. + ### Bug fixes - [#324](https://github.com/babylonlabs-io/babylon/pull/324) Fix decrementing @@ -46,8 +51,6 @@ jailed fp counter ### Improvements -- [#306](https://github.com/babylonlabs-io/babylon/pull/306) feat: improve BTC reward distribution with -virtual block periods for each finality provider that has delegations and reward tracker structures. - [#309](https://github.com/babylonlabs-io/babylon/pull/309) feat(adr-036): custom withdrawal address - [#305](https://github.com/babylonlabs-io/babylon/pull/305) chore: add more error logs to `VerifyInclusionProofAndGetHeight` - [#304](https://github.com/babylonlabs-io/babylon/pull/304) Add highest voted height to finality provider @@ -68,6 +71,7 @@ to relay on UnbondingTime in delegation ## v0.17.2 ### Improvements + - [#311](https://github.com/babylonlabs-io/babylon/pull/311) Enforce version 2 for unbonding transactions From 7ca2ceb648e080b632ca586a7f8bcea717477dd2 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Fri, 6 Dec 2024 08:40:50 -0300 Subject: [PATCH 017/132] fix: lint add errcheck --- x/incentive/keeper/reward_tracker_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index eb69a3b45..f5d281cf2 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -143,7 +143,8 @@ func TestIncrementFinalityProviderPeriod(t *testing.T) { // needs to add some voting power so it can calculate the amount of rewards per share satsDelegated := math.NewInt(500) - k.AddDelegationSat(ctx, fp1, del1, satsDelegated) + err = k.AddDelegationSat(ctx, fp1, del1, satsDelegated) + require.NoError(t, err) fp1EndedPeriod, err = k.IncrementFinalityProviderPeriod(ctx, fp1) require.NoError(t, err) From 48882e257ef21b29943b59bffc18296344480741 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Fri, 6 Dec 2024 22:31:05 -0300 Subject: [PATCH 018/132] chore: add details for structures --- proto/babylon/incentive/rewards.proto | 29 ++++++++++++++++------ x/incentive/types/rewards.pb.go | 35 ++++++++++++++++++--------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/proto/babylon/incentive/rewards.proto b/proto/babylon/incentive/rewards.proto index 0bea0e2ee..1243c8d15 100644 --- a/proto/babylon/incentive/rewards.proto +++ b/proto/babylon/incentive/rewards.proto @@ -10,13 +10,13 @@ option go_package = "github.com/babylonlabs-io/babylon/x/incentive/types"; // FinalityProviderHistoricalRewards represents the cumulative rewards ratio of the // finality provider per sat in that period. // The period is ommited here and should be part of the key used to store this structure. +// Key: Prefix + Finality provider bech32 address + Period. message FinalityProviderHistoricalRewards { // The cumulative rewards of that finality provider at some specific period // This coins will aways increase the value, never be reduced due to keep acumulation // and when the cumulative rewards will be used to distribute rewards, 2 periods will - // be interpolated and calculate the difference and multiplied by the total sat amount delegated + // be loaded, calculate the difference and multiplied by the total sat amount delegated // https://github.com/cosmos/cosmos-sdk/blob/e76102f885b71fd6e1c1efb692052173c4b3c3a3/x/distribution/keeper/delegation.go#L47 - // This is also not considering slash of the rewards. repeated cosmos.base.v1beta1.Coin cumulative_rewards_per_sat = 1 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" @@ -26,13 +26,17 @@ message FinalityProviderHistoricalRewards { } // FinalityProviderCurrentRewards represents the current rewards of the pool of -// BTC delegations that this finality provider is entitled to. +// BTC delegations that delegated for this finality provider is entitled to. // Note: This rewards are for the BTC delegators that delegated to this FP // the FP itself is not the owner or can withdraw this rewards. +// If a slash event happens with this finality provider, all the delegations need +// to withdraw to the RewardGauge and the related scrutures should be deleted. +// Key: Prefix + Finality provider bech32 address. message FinalityProviderCurrentRewards { // CurrentRewards is the current rewards that the finality provider have and it was not // yet stored inside the FinalityProviderHistoricalRewards. Once something happens that - // modifies the amount of satoshis delegated to this finality provider (activation, unbonding, slash) + // modifies the amount of satoshis delegated to this finality provider or the delegators + // starting period (activation, unbonding or btc rewards withdraw) // a new period must be created, accumulate this rewards to FinalityProviderHistoricalRewards // with a new period and zero out the Current Rewards. repeated cosmos.base.v1beta1.Coin current_rewards = 1 [ @@ -40,8 +44,11 @@ message FinalityProviderCurrentRewards { (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; // Period stores the current period that serves as a reference for - // creating new historical rewards. + // creating new historical rewards and correlate with BTCDelegationRewardsTracker + // StartPeriodCumulativeReward. uint64 period = 2; + // TotalActiveSat is the total amount of active satoshi delegated + // to this finality provider. bytes total_active_sat = 3 [ (cosmos_proto.scalar) = "cosmos.Int", (gogoproto.customtype) = "cosmossdk.io/math.Int", @@ -50,11 +57,17 @@ message FinalityProviderCurrentRewards { } // BTCDelegationRewardsTracker represents the structure that holds information -// from the last time this BTC delegator withdraw the rewards from the finality provider -// The finality provider address is ommitted here but should be part of the key used -// to store this structure together with the BTC delegator address. +// from the last time this BTC delegator withdraw the rewards or modified his +// active staked amount to one finality provider. +// The finality provider address is ommitted here but should be part of the +// key used to store this structure together with the BTC delegator address. message BTCDelegationRewardsTracker { + // StartPeriodCumulativeReward the starting period the the BTC delegator + // made his last withdraw of rewards or modified his active staking amount + // of satoshis. uint64 start_period_cumulative_reward = 1; + // TotalActiveSat is the total amount of active satoshi delegated + // to one specific finality provider. bytes total_active_sat = 2 [ (cosmos_proto.scalar) = "cosmos.Int", (gogoproto.customtype) = "cosmossdk.io/math.Int", diff --git a/x/incentive/types/rewards.pb.go b/x/incentive/types/rewards.pb.go index 2cfc8b74f..fd890a830 100644 --- a/x/incentive/types/rewards.pb.go +++ b/x/incentive/types/rewards.pb.go @@ -30,13 +30,13 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // FinalityProviderHistoricalRewards represents the cumulative rewards ratio of the // finality provider per sat in that period. // The period is ommited here and should be part of the key used to store this structure. +// Key: Prefix + Finality provider bech32 address + Period. type FinalityProviderHistoricalRewards struct { // The cumulative rewards of that finality provider at some specific period // This coins will aways increase the value, never be reduced due to keep acumulation // and when the cumulative rewards will be used to distribute rewards, 2 periods will - // be interpolated and calculate the difference and multiplied by the total sat amount delegated + // be loaded, calculate the difference and multiplied by the total sat amount delegated // https://github.com/cosmos/cosmos-sdk/blob/e76102f885b71fd6e1c1efb692052173c4b3c3a3/x/distribution/keeper/delegation.go#L47 - // This is also not considering slash of the rewards. CumulativeRewardsPerSat github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=cumulative_rewards_per_sat,json=cumulativeRewardsPerSat,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"cumulative_rewards_per_sat"` } @@ -81,19 +81,26 @@ func (m *FinalityProviderHistoricalRewards) GetCumulativeRewardsPerSat() github_ } // FinalityProviderCurrentRewards represents the current rewards of the pool of -// BTC delegations that this finality provider is entitled to. +// BTC delegations that delegated for this finality provider is entitled to. // Note: This rewards are for the BTC delegators that delegated to this FP // the FP itself is not the owner or can withdraw this rewards. +// If a slash event happens with this finality provider, all the delegations need +// to withdraw to the RewardGauge and the related scrutures should be deleted. +// Key: Prefix + Finality provider bech32 address. type FinalityProviderCurrentRewards struct { // CurrentRewards is the current rewards that the finality provider have and it was not // yet stored inside the FinalityProviderHistoricalRewards. Once something happens that - // modifies the amount of satoshis delegated to this finality provider (activation, unbonding, slash) + // modifies the amount of satoshis delegated to this finality provider or the delegators + // starting period (activation, unbonding or btc rewards withdraw) // a new period must be created, accumulate this rewards to FinalityProviderHistoricalRewards // with a new period and zero out the Current Rewards. CurrentRewards github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=current_rewards,json=currentRewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"current_rewards"` // Period stores the current period that serves as a reference for - // creating new historical rewards. - Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` + // creating new historical rewards and correlate with BTCDelegationRewardsTracker + // StartPeriodCumulativeReward. + Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` + // TotalActiveSat is the total amount of active satoshi delegated + // to this finality provider. TotalActiveSat cosmossdk_io_math.Int `protobuf:"bytes,3,opt,name=total_active_sat,json=totalActiveSat,proto3,customtype=cosmossdk.io/math.Int" json:"total_active_sat"` } @@ -145,12 +152,18 @@ func (m *FinalityProviderCurrentRewards) GetPeriod() uint64 { } // BTCDelegationRewardsTracker represents the structure that holds information -// from the last time this BTC delegator withdraw the rewards from the finality provider -// The finality provider address is ommitted here but should be part of the key used -// to store this structure together with the BTC delegator address. +// from the last time this BTC delegator withdraw the rewards or modified his +// active staked amount to one finality provider. +// The finality provider address is ommitted here but should be part of the +// key used to store this structure together with the BTC delegator address. type BTCDelegationRewardsTracker struct { - StartPeriodCumulativeReward uint64 `protobuf:"varint,1,opt,name=start_period_cumulative_reward,json=startPeriodCumulativeReward,proto3" json:"start_period_cumulative_reward,omitempty"` - TotalActiveSat cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=total_active_sat,json=totalActiveSat,proto3,customtype=cosmossdk.io/math.Int" json:"total_active_sat"` + // StartPeriodCumulativeReward the starting period the the BTC delegator + // made his last withdraw of rewards or modified his active staking amount + // of satoshis. + StartPeriodCumulativeReward uint64 `protobuf:"varint,1,opt,name=start_period_cumulative_reward,json=startPeriodCumulativeReward,proto3" json:"start_period_cumulative_reward,omitempty"` + // TotalActiveSat is the total amount of active satoshi delegated + // to one specific finality provider. + TotalActiveSat cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=total_active_sat,json=totalActiveSat,proto3,customtype=cosmossdk.io/math.Int" json:"total_active_sat"` } func (m *BTCDelegationRewardsTracker) Reset() { *m = BTCDelegationRewardsTracker{} } From 92fffdcab4482c6a52749229afa628f6ef2a0f5d Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 8 Dec 2024 22:13:01 -0300 Subject: [PATCH 019/132] chore: add implementation of unbond and slash fp --- x/incentive/keeper/reward_tracker.go | 141 ++++++++++++++++++--------- 1 file changed, 96 insertions(+), 45 deletions(-) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index c3c1f1586..459244ed8 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -25,11 +25,26 @@ func (k Keeper) FpSlashed(ctx context.Context, fp sdk.AccAddress) error { // withdrawDelegationRewards // Delete all the delegations reward tracker associated with this FP // Delete the FP reward tracker + + endedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp) + if err != nil { + return err + } + + keysBtcDelRwdTracker := make([][]byte, 0) + if err := k.IterateBTCDelegationRewardsTracker(ctx, fp, func(fp, del sdk.AccAddress) error { + keysBtcDelRwdTracker = append(keysBtcDelRwdTracker, del.Bytes()) + return k.CalculateBTCDelegationRewardsAndSend(ctx, fp, del, endedPeriod) + }); err != nil { + return err + } + + k.deleteKeysFromBTCDelegationRewardsTracker(ctx, fp, keysBtcDelRwdTracker) + k.deleteAllFromFinalityProviderRwd(ctx, fp) return nil } func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { - amtSat := sdkmath.NewIntFromUint64(sat) // if btc delegations does not exists // BeforeDelegationCreated // IncrementValidatorPeriod @@ -44,50 +59,46 @@ func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddre // IncrementValidatorPeriod // gets the current rewards and send to historical the current period (the rewards are stored as "shares" which means the amount of rewards per satoshi) // sets new empty current rewards with new period + amtSat := sdkmath.NewIntFromUint64(sat) + return k.btcDelegationModified(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { + return k.AddDelegationSat(ctx, fp, del, amtSat) + }) +} + +func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { + amtSat := sdkmath.NewIntFromUint64(sat) + return k.btcDelegationModified(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { + return k.SubDelegationSat(ctx, fp, del, amtSat) + }) +} + +func (k Keeper) WithdrawDelegationRewardsToGauge(ctx context.Context, fp, del sdk.AccAddress) error { + return k.btcDelegationModified(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { return nil }) +} +func (k Keeper) btcDelegationModified( + ctx context.Context, + fp, del sdk.AccAddress, + preInitializeDelegation func(ctx context.Context, fp, del sdk.AccAddress) error, +) error { endedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp) if err != nil { return err } - rewards, err := k.CalculateDelegationRewards(ctx, fp, del, endedPeriod) - if err != nil { - if !errors.Is(err, types.ErrBTCDelegationRewardsTrackerNotFound) { - return err - } - rewards = sdk.NewCoins() - } - - if !rewards.IsZero() { - k.accumulateRewardGauge(ctx, types.BTCDelegationType, del, rewards) + if err := k.CalculateBTCDelegationRewardsAndSend(ctx, fp, del, endedPeriod); err != nil { + return err } - if err := k.AddDelegationSat(ctx, fp, del, amtSat); err != nil { + if err := preInitializeDelegation(ctx, fp, del); err != nil { return err } return k.initializeBTCDelegation(ctx, fp, del) } -func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { - amtSat := sdkmath.NewIntFromUint64(sat) - - // withdraw rewards - // - - if err := k.SubDelegationSat(ctx, fp, del, amtSat); err != nil { - return err - } - return nil -} - -func (k Keeper) WithdrawDelegationRewardsToGauge(ctx context.Context, fp, del sdk.AccAddress) error { - endedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp) - if err != nil { - return err - } - - rewards, err := k.CalculateDelegationRewards(ctx, fp, del, endedPeriod) +func (k Keeper) CalculateBTCDelegationRewardsAndSend(ctx context.Context, fp, del sdk.AccAddress, endPeriod uint64) error { + rewards, err := k.CalculateBTCDelegationRewards(ctx, fp, del, endPeriod) if err != nil { if !errors.Is(err, types.ErrBTCDelegationRewardsTrackerNotFound) { return err @@ -95,14 +106,15 @@ func (k Keeper) WithdrawDelegationRewardsToGauge(ctx context.Context, fp, del sd rewards = sdk.NewCoins() } - if !rewards.IsZero() { - k.accumulateRewardGauge(ctx, types.BTCDelegationType, del, rewards) + if rewards.IsZero() { + return nil } - return k.initializeBTCDelegation(ctx, fp, del) + k.accumulateRewardGauge(ctx, types.BTCDelegationType, del, rewards) + return nil } -func (k Keeper) CalculateDelegationRewards(ctx context.Context, fp, del sdk.AccAddress, endPeriod uint64) (sdk.Coins, error) { +func (k Keeper) CalculateBTCDelegationRewards(ctx context.Context, fp, del sdk.AccAddress, endPeriod uint64) (sdk.Coins, error) { btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) if err != nil { return sdk.Coins{}, err @@ -122,16 +134,10 @@ func (k Keeper) calculateDelegationRewardsBetween( btcDelRwdTracker types.BTCDelegationRewardsTracker, endingPeriod uint64, ) (sdk.Coins, error) { - // sanity check if btcDelRwdTracker.StartPeriodCumulativeReward > endingPeriod { panic("startingPeriod cannot be greater than endingPeriod") } - // sanity check - // if btcDelRwdTracker..IsNegative() { - // panic("BTC delegation active stake should not be negative") - // } - // return staking * (ending - starting) starting, err := k.GetFinalityProviderHistoricalRewards(ctx, fp, btcDelRwdTracker.StartPeriodCumulativeReward) if err != nil { @@ -150,8 +156,9 @@ func (k Keeper) calculateDelegationRewardsBetween( panic("negative rewards should not be possible") } - // note: necessary to truncate so we don't allow withdrawing more rewardsWithDecimals than owed rewardsWithDecimals := differenceWithDecimals.MulInt(btcDelRwdTracker.TotalActiveSat) + // note: necessary to truncate so we don't allow withdrawing more rewardsWithDecimals than owed + // QuoInt already truncates rewards := rewardsWithDecimals.QuoInt(DecimalAccumulatedRewards) return rewards, nil } @@ -177,8 +184,6 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA currentRewardsPerSat := sdk.NewCoins() if !fpCurrentRwd.TotalActiveSat.IsZero() { - // 1000 ubbn / 200 - // 1 sat = 5 ubbn currentRewardsPerSatWithDecimals := fpCurrentRwd.CurrentRewards.MulInt(DecimalAccumulatedRewards) currentRewardsPerSat = currentRewardsPerSatWithDecimals.QuoInt(fpCurrentRwd.TotalActiveSat) } @@ -188,7 +193,6 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA return 0, err } - // Due to lost in precision point if the rewards are too low, it could become zero newFpHistoricalRwd := types.NewFinalityProviderHistoricalRewards(fpHistoricalRwd.CumulativeRewardsPerSat.Add(currentRewardsPerSat...)) if err := k.setFinalityProviderHistoricalRewards(ctx, fp, fpCurrentRwd.Period, newFpHistoricalRwd); err != nil { return 0, err @@ -252,6 +256,30 @@ func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.Ac return value, nil } +// IterateBTCDelegationRewardsTracker iterates over all the delegation rewards tracker by the finality provider. +func (k Keeper) IterateBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress, it func(fp, del sdk.AccAddress) error) error { + st := k.storeBTCDelegationRewardsTracker(ctx, fp) + + iter := st.Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + del := sdk.AccAddress(iter.Key()) + if err := it(fp, del); err != nil { + return err + } + } + + return nil +} + +// deleteKeysFromBTCDelegationRewardsTracker iterates over all the BTC delegation rewards tracker by the finality provider and deletes it. +func (k Keeper) deleteKeysFromBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress, delKeys [][]byte) { + st := k.storeBTCDelegationRewardsTracker(ctx, fp) + for _, key := range delKeys { + st.Delete(key) + } +} + func (k Keeper) GetBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk.AccAddress) (types.BTCDelegationRewardsTracker, error) { key := del.Bytes() bz := k.storeBTCDelegationRewardsTracker(ctx, fp).Get(key) @@ -288,6 +316,29 @@ func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.Ac return nil } +func (k Keeper) deleteAllFromFinalityProviderRwd(ctx context.Context, fp sdk.AccAddress) { + st := k.storeFpHistoricalRewards(ctx, fp) + + keys := make([][]byte, 0) + + iter := st.Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + keys = append(keys, iter.Key()) + } + + for _, key := range keys { + st.Delete(key) + } + + k.deleteFinalityProviderCurrentRewards(ctx, fp) +} + +func (k Keeper) deleteFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) { + key := fp.Bytes() + k.storeFpCurrentRewards(ctx).Delete(key) +} + func (k Keeper) GetFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64) (types.FinalityProviderHistoricalRewards, error) { key := make([]byte, 8) binary.LittleEndian.PutUint64(key, period) From b9d9e09fca80186870fc440469de3ebb47547f81 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 8 Dec 2024 22:32:47 -0300 Subject: [PATCH 020/132] chore: add slash handle and split store set/get/iterator into specific file --- testutil/btcstaking-helper/keeper.go | 1 + x/finality/keeper/power_dist_change.go | 8 +- x/finality/types/expected_keepers.go | 2 +- x/finality/types/mocked_keepers.go | 14 ++ x/incentive/keeper/btc_staking_gauge_test.go | 5 +- x/incentive/keeper/reward_tracker.go | 187 ------------------- x/incentive/keeper/reward_tracker_store.go | 166 ++++++++++++++++ 7 files changed, 193 insertions(+), 190 deletions(-) create mode 100644 x/incentive/keeper/reward_tracker_store.go diff --git a/testutil/btcstaking-helper/keeper.go b/testutil/btcstaking-helper/keeper.go index 5f909d89f..cb1305305 100644 --- a/testutil/btcstaking-helper/keeper.go +++ b/testutil/btcstaking-helper/keeper.go @@ -68,6 +68,7 @@ func NewHelper( iKeeper.EXPECT().IndexRefundableMsg(gomock.Any(), gomock.Any()).AnyTimes() iKeeper.EXPECT().BtcDelegationActivated(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() iKeeper.EXPECT().BtcDelegationUnbonded(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + iKeeper.EXPECT().FpSlashed(gomock.Any(), gomock.Any()).AnyTimes() ckptKeeper := ftypes.NewMockCheckpointingKeeper(ctrl) ckptKeeper.EXPECT().GetLastFinalizedEpoch(gomock.Any()).Return(timestampedEpoch).AnyTimes() diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index b237ee3a2..bb482f1e5 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -255,6 +255,9 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // if this finality provider is slashed, continue to avoid // assigning delegation to it if _, ok := slashedFPs[fpBTCPKHex]; ok { + if err := k.IncentiveKeeper.FpSlashed(ctx, fp.GetAddress()); err != nil { + panic(err) + } fp.IsSlashed = true continue } @@ -327,11 +330,14 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( fpDistInfo := ftypes.NewFinalityProviderDistInfo(newFP) // add each BTC delegation + fpAddr := sdk.MustAccAddressFromBech32(newFP.Addr) fpActiveBTCDels := activeBTCDels[fpBTCPKHex] for _, d := range fpActiveBTCDels { fpDistInfo.AddBTCDel(d) - err := k.IncentiveKeeper.BtcDelegationActivated(ctx, sdk.MustAccAddressFromBech32(newFP.Addr), sdk.MustAccAddressFromBech32(d.StakerAddr), d.TotalSat) + // TODO: maybe use a hook to the activated btc delegation to add new stake + delAddr := sdk.MustAccAddressFromBech32(d.StakerAddr) + err := k.IncentiveKeeper.BtcDelegationActivated(ctx, fpAddr, delAddr, d.TotalSat) if err != nil { panic(err) // check if it should panic } diff --git a/x/finality/types/expected_keepers.go b/x/finality/types/expected_keepers.go index b82568bdf..7eae51243 100644 --- a/x/finality/types/expected_keepers.go +++ b/x/finality/types/expected_keepers.go @@ -36,5 +36,5 @@ type IncentiveKeeper interface { IndexRefundableMsg(ctx context.Context, msg sdk.Msg) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error - // TODO: handle slash + FpSlashed(ctx context.Context, fp sdk.AccAddress) error } diff --git a/x/finality/types/mocked_keepers.go b/x/finality/types/mocked_keepers.go index c789d904e..9db21938c 100644 --- a/x/finality/types/mocked_keepers.go +++ b/x/finality/types/mocked_keepers.go @@ -307,6 +307,20 @@ func (mr *MockIncentiveKeeperMockRecorder) BtcDelegationUnbonded(ctx, fp, del, s return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BtcDelegationUnbonded", reflect.TypeOf((*MockIncentiveKeeper)(nil).BtcDelegationUnbonded), ctx, fp, del, sat) } +// FpSlashed mocks base method. +func (m *MockIncentiveKeeper) FpSlashed(ctx context.Context, fp types1.AccAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FpSlashed", ctx, fp) + ret0, _ := ret[0].(error) + return ret0 +} + +// FpSlashed indicates an expected call of FpSlashed. +func (mr *MockIncentiveKeeperMockRecorder) FpSlashed(ctx, fp interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FpSlashed", reflect.TypeOf((*MockIncentiveKeeper)(nil).FpSlashed), ctx, fp) +} + // IndexRefundableMsg mocks base method. func (m *MockIncentiveKeeper) IndexRefundableMsg(ctx context.Context, msg types1.Msg) { m.ctrl.T.Helper() diff --git a/x/incentive/keeper/btc_staking_gauge_test.go b/x/incentive/keeper/btc_staking_gauge_test.go index 815f0e62b..a7cf3bceb 100644 --- a/x/incentive/keeper/btc_staking_gauge_test.go +++ b/x/incentive/keeper/btc_staking_gauge_test.go @@ -80,6 +80,7 @@ func FuzzRewardBTCStaking(f *testing.F) { require.NoError(t, err) require.Equal(t, delRwd.TotalActiveSat.Uint64(), btcDel.TotalSat) + // makes sure the rewards added reach the delegation gauge err = keeper.WithdrawDelegationRewardsToGauge(ctx, fpAddr, delAddr) require.NoError(t, err) } @@ -96,6 +97,7 @@ func FuzzRewardBTCStaking(f *testing.F) { require.NotNil(t, rg) require.Equal(t, reward, rg.Coins) } + sumRewards := sdk.NewCoins() for addrStr, reward := range btcDelRewardMap { addr, err := sdk.AccAddressFromBech32(addrStr) @@ -115,7 +117,8 @@ func FuzzRewardBTCStaking(f *testing.F) { } allowedMarginError := CalculatePointOnePercent(sumCoinsForDels) - require.Truef(t, sumCoinsForDels.Sub(sumRewards...).IsAllLT(allowedMarginError), + diff, _ := sumCoinsForDels.SafeSub(sumRewards...) + require.Truef(t, diff.IsAllLT(allowedMarginError), "Sum of total rewards failed within the margin of error: %s\nRewards: %s\nGauge: %s", allowedMarginError.String(), sumCoinsForDels.String(), sumRewards.String(), ) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 459244ed8..b018c4182 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -2,12 +2,9 @@ package keeper import ( "context" - "encoding/binary" "errors" - "cosmossdk.io/store/prefix" "github.com/babylonlabs-io/babylon/x/incentive/types" - "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" sdkmath "cosmossdk.io/math" @@ -242,161 +239,6 @@ func (k Keeper) initializeBTCDelegation(ctx context.Context, fp, del sdk.AccAddr return k.setBTCDelegationRewardsTracker(ctx, fp, del, rwd) } -func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { - key := fp.Bytes() - bz := k.storeFpCurrentRewards(ctx).Get(key) - if bz == nil { - return types.FinalityProviderCurrentRewards{}, types.ErrFPCurrentRewardsNotFound - } - - var value types.FinalityProviderCurrentRewards - if err := k.cdc.Unmarshal(bz, &value); err != nil { - return types.FinalityProviderCurrentRewards{}, err - } - return value, nil -} - -// IterateBTCDelegationRewardsTracker iterates over all the delegation rewards tracker by the finality provider. -func (k Keeper) IterateBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress, it func(fp, del sdk.AccAddress) error) error { - st := k.storeBTCDelegationRewardsTracker(ctx, fp) - - iter := st.Iterator(nil, nil) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - del := sdk.AccAddress(iter.Key()) - if err := it(fp, del); err != nil { - return err - } - } - - return nil -} - -// deleteKeysFromBTCDelegationRewardsTracker iterates over all the BTC delegation rewards tracker by the finality provider and deletes it. -func (k Keeper) deleteKeysFromBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress, delKeys [][]byte) { - st := k.storeBTCDelegationRewardsTracker(ctx, fp) - for _, key := range delKeys { - st.Delete(key) - } -} - -func (k Keeper) GetBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk.AccAddress) (types.BTCDelegationRewardsTracker, error) { - key := del.Bytes() - bz := k.storeBTCDelegationRewardsTracker(ctx, fp).Get(key) - if bz == nil { - return types.BTCDelegationRewardsTracker{}, types.ErrBTCDelegationRewardsTrackerNotFound - } - - var value types.BTCDelegationRewardsTracker - if err := k.cdc.Unmarshal(bz, &value); err != nil { - return types.BTCDelegationRewardsTracker{}, err - } - return value, nil -} - -func (k Keeper) setBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk.AccAddress, rwd types.BTCDelegationRewardsTracker) error { - key := del.Bytes() - bz, err := rwd.Marshal() - if err != nil { - return err - } - - k.storeBTCDelegationRewardsTracker(ctx, fp).Set(key, bz) - return nil -} - -func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress, rwd types.FinalityProviderCurrentRewards) error { - key := fp.Bytes() - bz, err := rwd.Marshal() - if err != nil { - return err - } - - k.storeFpCurrentRewards(ctx).Set(key, bz) - return nil -} - -func (k Keeper) deleteAllFromFinalityProviderRwd(ctx context.Context, fp sdk.AccAddress) { - st := k.storeFpHistoricalRewards(ctx, fp) - - keys := make([][]byte, 0) - - iter := st.Iterator(nil, nil) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - keys = append(keys, iter.Key()) - } - - for _, key := range keys { - st.Delete(key) - } - - k.deleteFinalityProviderCurrentRewards(ctx, fp) -} - -func (k Keeper) deleteFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) { - key := fp.Bytes() - k.storeFpCurrentRewards(ctx).Delete(key) -} - -func (k Keeper) GetFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64) (types.FinalityProviderHistoricalRewards, error) { - key := make([]byte, 8) - binary.LittleEndian.PutUint64(key, period) - - bz := k.storeFpHistoricalRewards(ctx, fp).Get(key) - if bz == nil { - return types.FinalityProviderHistoricalRewards{}, types.ErrFPCurrentRewardsNotFound - } - - var value types.FinalityProviderHistoricalRewards - if err := k.cdc.Unmarshal(bz, &value); err != nil { - return types.FinalityProviderHistoricalRewards{}, err - } - return value, nil -} - -func (k Keeper) setFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64, rwd types.FinalityProviderHistoricalRewards) error { - key := make([]byte, 8) - binary.LittleEndian.PutUint64(key, period) - - bz, err := rwd.Marshal() - if err != nil { - return err - } - - k.storeFpHistoricalRewards(ctx, fp).Set(key, bz) - return nil -} - -// storeBTCDelegationRewardsTracker returns the KVStore of the FP current rewards -// prefix: BTCDelegationRewardsTrackerKey -// key: (FpAddr, DelAddr) -// value: BTCDelegationRewardsTracker -func (k Keeper) storeBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress) prefix.Store { - storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - st := prefix.NewStore(storeAdaptor, types.BTCDelegationRewardsTrackerKey) - return prefix.NewStore(st, fp.Bytes()) -} - -// storeFpCurrentRewards returns the KVStore of the FP current rewards -// prefix: FinalityProviderCurrentRewardsKey -// key: (finality provider cosmos address) -// value: FinalityProviderCurrentRewards -func (k Keeper) storeFpCurrentRewards(ctx context.Context) prefix.Store { - storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return prefix.NewStore(storeAdaptor, types.FinalityProviderCurrentRewardsKey) -} - -// storeFpHistoricalRewards returns the KVStore of the FP historical rewards -// prefix: FinalityProviderHistoricalRewardsKey -// key: (finality provider cosmos address, period) -// value: FinalityProviderCurrentRewards -func (k Keeper) storeFpHistoricalRewards(ctx context.Context, fp sdk.AccAddress) prefix.Store { - storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - st := prefix.NewStore(storeAdaptor, types.FinalityProviderHistoricalRewardsKey) - return prefix.NewStore(st, fp.Bytes()) -} - func (k Keeper) addFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress, amt sdkmath.Int) error { fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) if err != nil { @@ -471,32 +313,3 @@ func (k Keeper) SubDelegationSat(ctx context.Context, fp, del sdk.AccAddress, am return k.subFinalityProviderStaked(ctx, fp, amt) } - -// IterateBTCDelegators iterates over all the delegators that have some active BTC delegator -// staked and the total satoshi staked for that delegator address until an error is returned -// or the iterator finishes. Stops if error is returned. -// Should keep track of the total satoshi staked per delegator to avoid iterating over the -// delegator delegations -// func (k Keeper) IterateBTCDelegators(ctx context.Context, i func(delegator sdk.AccAddress, totalSatoshiStaked sdkmath.Int) error) error { -// st := k.storeDelStaked(ctx) - -// iter := st.Iterator(nil, nil) -// defer iter.Close() - -// for ; iter.Valid(); iter.Next() { -// sdkAddrBz := iter.Key() -// delAddr := sdk.AccAddress(sdkAddrBz) - -// delBtcStaked, err := ParseInt(iter.Value()) -// if err != nil { -// return err -// } - -// err = i(delAddr, delBtcStaked) -// if err != nil { -// return err -// } -// } - -// return nil -// } diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go new file mode 100644 index 000000000..e26346cb5 --- /dev/null +++ b/x/incentive/keeper/reward_tracker_store.go @@ -0,0 +1,166 @@ +package keeper + +import ( + "context" + "encoding/binary" + + "cosmossdk.io/store/prefix" + "github.com/babylonlabs-io/babylon/x/incentive/types" + "github.com/cosmos/cosmos-sdk/runtime" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// storeBTCDelegationRewardsTracker returns the KVStore of the FP current rewards +// prefix: BTCDelegationRewardsTrackerKey +// key: (FpAddr, DelAddr) +// value: BTCDelegationRewardsTracker +func (k Keeper) storeBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress) prefix.Store { + storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + st := prefix.NewStore(storeAdaptor, types.BTCDelegationRewardsTrackerKey) + return prefix.NewStore(st, fp.Bytes()) +} + +// storeFpCurrentRewards returns the KVStore of the FP current rewards +// prefix: FinalityProviderCurrentRewardsKey +// key: (finality provider cosmos address) +// value: FinalityProviderCurrentRewards +func (k Keeper) storeFpCurrentRewards(ctx context.Context) prefix.Store { + storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + return prefix.NewStore(storeAdaptor, types.FinalityProviderCurrentRewardsKey) +} + +// storeFpHistoricalRewards returns the KVStore of the FP historical rewards +// prefix: FinalityProviderHistoricalRewardsKey +// key: (finality provider cosmos address, period) +// value: FinalityProviderCurrentRewards +func (k Keeper) storeFpHistoricalRewards(ctx context.Context, fp sdk.AccAddress) prefix.Store { + storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + st := prefix.NewStore(storeAdaptor, types.FinalityProviderHistoricalRewardsKey) + return prefix.NewStore(st, fp.Bytes()) +} + +func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { + key := fp.Bytes() + bz := k.storeFpCurrentRewards(ctx).Get(key) + if bz == nil { + return types.FinalityProviderCurrentRewards{}, types.ErrFPCurrentRewardsNotFound + } + + var value types.FinalityProviderCurrentRewards + if err := k.cdc.Unmarshal(bz, &value); err != nil { + return types.FinalityProviderCurrentRewards{}, err + } + return value, nil +} + +// IterateBTCDelegationRewardsTracker iterates over all the delegation rewards tracker by the finality provider. +func (k Keeper) IterateBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress, it func(fp, del sdk.AccAddress) error) error { + st := k.storeBTCDelegationRewardsTracker(ctx, fp) + + iter := st.Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + del := sdk.AccAddress(iter.Key()) + if err := it(fp, del); err != nil { + return err + } + } + + return nil +} + +// deleteKeysFromBTCDelegationRewardsTracker iterates over all the BTC delegation rewards tracker by the finality provider and deletes it. +func (k Keeper) deleteKeysFromBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress, delKeys [][]byte) { + st := k.storeBTCDelegationRewardsTracker(ctx, fp) + for _, key := range delKeys { + st.Delete(key) + } +} + +func (k Keeper) GetBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk.AccAddress) (types.BTCDelegationRewardsTracker, error) { + key := del.Bytes() + bz := k.storeBTCDelegationRewardsTracker(ctx, fp).Get(key) + if bz == nil { + return types.BTCDelegationRewardsTracker{}, types.ErrBTCDelegationRewardsTrackerNotFound + } + + var value types.BTCDelegationRewardsTracker + if err := k.cdc.Unmarshal(bz, &value); err != nil { + return types.BTCDelegationRewardsTracker{}, err + } + return value, nil +} + +func (k Keeper) setBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk.AccAddress, rwd types.BTCDelegationRewardsTracker) error { + key := del.Bytes() + bz, err := rwd.Marshal() + if err != nil { + return err + } + + k.storeBTCDelegationRewardsTracker(ctx, fp).Set(key, bz) + return nil +} + +func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress, rwd types.FinalityProviderCurrentRewards) error { + key := fp.Bytes() + bz, err := rwd.Marshal() + if err != nil { + return err + } + + k.storeFpCurrentRewards(ctx).Set(key, bz) + return nil +} + +func (k Keeper) deleteAllFromFinalityProviderRwd(ctx context.Context, fp sdk.AccAddress) { + st := k.storeFpHistoricalRewards(ctx, fp) + + keys := make([][]byte, 0) + + iter := st.Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + keys = append(keys, iter.Key()) + } + + for _, key := range keys { + st.Delete(key) + } + + k.deleteFinalityProviderCurrentRewards(ctx, fp) +} + +func (k Keeper) deleteFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) { + key := fp.Bytes() + k.storeFpCurrentRewards(ctx).Delete(key) +} + +func (k Keeper) GetFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64) (types.FinalityProviderHistoricalRewards, error) { + key := make([]byte, 8) + binary.LittleEndian.PutUint64(key, period) + + bz := k.storeFpHistoricalRewards(ctx, fp).Get(key) + if bz == nil { + return types.FinalityProviderHistoricalRewards{}, types.ErrFPCurrentRewardsNotFound + } + + var value types.FinalityProviderHistoricalRewards + if err := k.cdc.Unmarshal(bz, &value); err != nil { + return types.FinalityProviderHistoricalRewards{}, err + } + return value, nil +} + +func (k Keeper) setFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64, rwd types.FinalityProviderHistoricalRewards) error { + key := make([]byte, 8) + binary.LittleEndian.PutUint64(key, period) + + bz, err := rwd.Marshal() + if err != nil { + return err + } + + k.storeFpHistoricalRewards(ctx, fp).Set(key, bz) + return nil +} From d009991a0c6ded2ec45dc85db8f67c4366d45ace Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 8 Dec 2024 23:02:11 -0300 Subject: [PATCH 021/132] chore: add rewards to gauge on reward withdraw and reward calculation (needed to create a new set of keys to store map of del => fp address) --- x/incentive/keeper/grpc_query.go | 4 +++ x/incentive/keeper/msg_server.go | 5 +++ x/incentive/keeper/reward_gauge.go | 7 ++++ x/incentive/keeper/reward_tracker.go | 19 ++++++++-- x/incentive/keeper/reward_tracker_store.go | 42 ++++++++++++++++++++-- x/incentive/types/keys.go | 1 + 6 files changed, 72 insertions(+), 6 deletions(-) diff --git a/x/incentive/keeper/grpc_query.go b/x/incentive/keeper/grpc_query.go index a526fdc47..2ec9b60cb 100644 --- a/x/incentive/keeper/grpc_query.go +++ b/x/incentive/keeper/grpc_query.go @@ -27,6 +27,10 @@ func (k Keeper) RewardGauges(goCtx context.Context, req *types.QueryRewardGauges // find reward gauge for _, sType := range types.GetAllStakeholderTypes() { + if err := k.sendAllBtcRewardsToGauge(ctx, sType, address); err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + rg := k.GetRewardGauge(ctx, sType, address) if rg == nil { continue diff --git a/x/incentive/keeper/msg_server.go b/x/incentive/keeper/msg_server.go index 150e580c7..d1a6ae92e 100644 --- a/x/incentive/keeper/msg_server.go +++ b/x/incentive/keeper/msg_server.go @@ -2,6 +2,7 @@ package keeper import ( "context" + errorsmod "cosmossdk.io/errors" "github.com/babylonlabs-io/babylon/x/incentive/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -53,6 +54,10 @@ func (ms msgServer) WithdrawReward(goCtx context.Context, req *types.MsgWithdraw return nil, status.Error(codes.InvalidArgument, err.Error()) } + if err := ms.sendAllBtcRewardsToGauge(ctx, sType, addr); err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + // withdraw reward, i.e., send withdrawable reward to the stakeholder address and clear the reward gauge withdrawnCoins, err := ms.withdrawReward(ctx, sType, addr) if err != nil { diff --git a/x/incentive/keeper/reward_gauge.go b/x/incentive/keeper/reward_gauge.go index d05a66e0b..b434c573a 100644 --- a/x/incentive/keeper/reward_gauge.go +++ b/x/incentive/keeper/reward_gauge.go @@ -9,6 +9,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +func (k Keeper) sendAllBtcRewardsToGauge(ctx context.Context, sType types.StakeholderType, del sdk.AccAddress) error { + if sType != types.BTCDelegationType { + return nil + } + return k.sendAllRewardsToGauge(ctx, del) +} + func (k Keeper) withdrawReward(ctx context.Context, sType types.StakeholderType, addr sdk.AccAddress) (sdk.Coins, error) { // retrieve reward gauge of the given stakeholder rg := k.GetRewardGauge(ctx, sType, addr) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index b018c4182..c0dc44793 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -57,25 +57,32 @@ func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddre // gets the current rewards and send to historical the current period (the rewards are stored as "shares" which means the amount of rewards per satoshi) // sets new empty current rewards with new period amtSat := sdkmath.NewIntFromUint64(sat) - return k.btcDelegationModified(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { + return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { return k.AddDelegationSat(ctx, fp, del, amtSat) }) } func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { amtSat := sdkmath.NewIntFromUint64(sat) - return k.btcDelegationModified(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { + return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { return k.SubDelegationSat(ctx, fp, del, amtSat) }) } func (k Keeper) WithdrawDelegationRewardsToGauge(ctx context.Context, fp, del sdk.AccAddress) error { - return k.btcDelegationModified(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { return nil }) + return k.btcDelegationModified(ctx, fp, del) } func (k Keeper) btcDelegationModified( ctx context.Context, fp, del sdk.AccAddress, +) error { + return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { return nil }) +} + +func (k Keeper) btcDelegationModifiedWithPreInitDel( + ctx context.Context, + fp, del sdk.AccAddress, preInitializeDelegation func(ctx context.Context, fp, del sdk.AccAddress) error, ) error { endedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp) @@ -204,6 +211,12 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA return fpCurrentRwd.Period, nil } +func (k Keeper) sendAllRewardsToGauge(ctx context.Context, del sdk.AccAddress) error { + return k.iterBtcDelegatorToFP(ctx, del, func(del, fp sdk.AccAddress) error { + return k.WithdrawDelegationRewardsToGauge(ctx, fp, del) + }) +} + func (k Keeper) initializeFinalityProvider(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { // historical rewards starts at the period 0 err := k.setFinalityProviderHistoricalRewards(ctx, fp, 0, types.NewFinalityProviderHistoricalRewards(sdk.NewCoins())) diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index e26346cb5..f21b2212e 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -10,6 +10,16 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// storeBTCDelegatorToFp returns the KVStore of the mapping del => fp +// prefix: BTCDelegatorToFPKey +// key: (DelAddr, FpAddr) +// value: 0x00 +func (k Keeper) storeBTCDelegatorToFp(ctx context.Context, del sdk.AccAddress) prefix.Store { + storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + st := prefix.NewStore(storeAdaptor, types.BTCDelegatorToFPKey) + return prefix.NewStore(st, del.Bytes()) +} + // storeBTCDelegationRewardsTracker returns the KVStore of the FP current rewards // prefix: BTCDelegationRewardsTrackerKey // key: (FpAddr, DelAddr) @@ -39,6 +49,30 @@ func (k Keeper) storeFpHistoricalRewards(ctx context.Context, fp sdk.AccAddress) return prefix.NewStore(st, fp.Bytes()) } +func (k Keeper) setBTCDelegatorToFP(ctx context.Context, del, fp sdk.AccAddress) { + st := k.storeBTCDelegatorToFp(ctx, del) + st.Set(fp.Bytes(), []byte{0x00}) +} + +func (k Keeper) iterBtcDelegatorToFP(ctx context.Context, del sdk.AccAddress, it func(del, fp sdk.AccAddress) error) error { + st := k.storeBTCDelegatorToFp(ctx, del) + + iter := st.Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + fp := sdk.AccAddress(iter.Key()) + if err := it(del, fp); err != nil { + return err + } + } + return nil +} + +func (k Keeper) deleteBTCDelegatorToFP(ctx context.Context, del, fp sdk.AccAddress) { + st := k.storeBTCDelegatorToFp(ctx, del) + st.Delete(fp.Bytes()) +} + func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { key := fp.Bytes() bz := k.storeFpCurrentRewards(ctx).Get(key) @@ -71,9 +105,10 @@ func (k Keeper) IterateBTCDelegationRewardsTracker(ctx context.Context, fp sdk.A // deleteKeysFromBTCDelegationRewardsTracker iterates over all the BTC delegation rewards tracker by the finality provider and deletes it. func (k Keeper) deleteKeysFromBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress, delKeys [][]byte) { - st := k.storeBTCDelegationRewardsTracker(ctx, fp) - for _, key := range delKeys { - st.Delete(key) + stDelRwdTracker := k.storeBTCDelegationRewardsTracker(ctx, fp) + for _, delKey := range delKeys { + stDelRwdTracker.Delete(delKey) + k.deleteBTCDelegatorToFP(ctx, sdk.AccAddress(delKey), fp) } } @@ -98,6 +133,7 @@ func (k Keeper) setBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk. return err } + k.setBTCDelegatorToFP(ctx, del, fp) k.storeBTCDelegationRewardsTracker(ctx, fp).Set(key, bz) return nil } diff --git a/x/incentive/types/keys.go b/x/incentive/types/keys.go index 2984b37c5..7e01e9099 100644 --- a/x/incentive/types/keys.go +++ b/x/incentive/types/keys.go @@ -29,6 +29,7 @@ var ( FinalityProviderCurrentRewardsKey = []byte{0x06} // key prefix for storing the Current rewards of finality provider by addr FinalityProviderHistoricalRewardsKey = []byte{0x07} // key prefix for storing the Historical rewards of finality provider by addr and period BTCDelegationRewardsTrackerKey = []byte{0x8} // key prefix for BTC delegation rewards tracker info (del,fp) => BTCDelegationRewardsTracker + BTCDelegatorToFPKey = []byte{0x9} // key prefix for storing the map reference from delegation to finality provider (del) => fp ) // GetWithdrawAddrKey creates the key for a delegator's withdraw addr. From f80d9f6211cf5ff946bc9eaa6d8b0086b294a322 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 8 Dec 2024 23:04:33 -0300 Subject: [PATCH 022/132] chore: add todo for init/export gen --- x/incentive/genesis.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x/incentive/genesis.go b/x/incentive/genesis.go index a078143ca..79e989bee 100644 --- a/x/incentive/genesis.go +++ b/x/incentive/genesis.go @@ -2,6 +2,7 @@ package incentive import ( "context" + "github.com/babylonlabs-io/babylon/x/incentive/keeper" "github.com/babylonlabs-io/babylon/x/incentive/types" ) @@ -11,6 +12,7 @@ func InitGenesis(ctx context.Context, k keeper.Keeper, genState types.GenesisSta if err := k.SetParams(ctx, genState.Params); err != nil { panic(err) } + // TODO(rafilx): add gauge, reward tracker } // ExportGenesis returns the module's exported genesis @@ -18,5 +20,6 @@ func ExportGenesis(ctx context.Context, k keeper.Keeper) *types.GenesisState { genesis := types.DefaultGenesis() genesis.Params = k.GetParams(ctx) + // TODO(rafilx): add gauge, reward tracker return genesis } From 813a88677ce0003a0fec4f5e3b044f53ab2297c4 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 15:15:10 -0300 Subject: [PATCH 023/132] fix: unecessary coupling of signer PrivateSigner inside helpers --- app/app.go | 3 +- app/app_test.go | 5 +- app/encoding.go | 3 +- app/keepers/keepers.go | 3 +- app/keepers/utils.go | 27 -------- app/signer/private.go | 33 +++++++++ app/test_helpers.go | 45 ++---------- cmd/babylond/cmd/genhelpers/bls_add_test.go | 5 +- .../cmd/genhelpers/bls_create_test.go | 3 +- cmd/babylond/cmd/testnet_test.go | 3 +- cmd/babylond/cmd/validate_genesis_test.go | 3 +- test/e2e/btc_staking_e2e_test.go | 1 + testutil/datagen/genesiskey.go | 10 +-- testutil/helper/helper.go | 6 +- testutil/signer/private.go | 43 ++++++++++++ x/incentive/keeper/btc_staking_gauge.go | 10 --- .../keeper/reward_tracker_store_test.go | 69 +++++++++++++++++++ 17 files changed, 179 insertions(+), 93 deletions(-) create mode 100644 app/signer/private.go create mode 100644 testutil/signer/private.go create mode 100644 x/incentive/keeper/reward_tracker_store_test.go diff --git a/app/app.go b/app/app.go index 924cde78e..07fee6d9e 100644 --- a/app/app.go +++ b/app/app.go @@ -95,6 +95,7 @@ import ( "github.com/babylonlabs-io/babylon/app/ante" appkeepers "github.com/babylonlabs-io/babylon/app/keepers" appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/app/upgrades" "github.com/babylonlabs-io/babylon/client/docs" bbn "github.com/babylonlabs-io/babylon/types" @@ -206,7 +207,7 @@ func NewBabylonApp( loadLatest bool, skipUpgradeHeights map[int64]bool, invCheckPeriod uint, - privSigner *appkeepers.PrivSigner, + privSigner *signer.PrivSigner, appOpts servertypes.AppOptions, wasmOpts []wasmkeeper.Option, baseAppOptions ...func(*baseapp.BaseApp), diff --git a/app/app_test.go b/app/app_test.go index 47599538d..09b305eab 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -5,6 +5,7 @@ import ( "testing" "cosmossdk.io/log" + "github.com/babylonlabs-io/babylon/testutil/signer" abci "github.com/cometbft/cometbft/abci/types" dbm "github.com/cosmos/cosmos-db" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,7 +15,7 @@ import ( func TestBabylonBlockedAddrs(t *testing.T) { db := dbm.NewMemDB() - signer, _ := SetupTestPrivSigner() + signer, _ := signer.SetupTestPrivSigner() logger := log.NewTestLogger(t) app := NewBabylonAppWithCustomOptions(t, false, signer, SetupOptions{ @@ -71,7 +72,7 @@ func TestGetMaccPerms(t *testing.T) { func TestUpgradeStateOnGenesis(t *testing.T) { db := dbm.NewMemDB() - privSigner, err := SetupTestPrivSigner() + privSigner, err := signer.SetupTestPrivSigner() require.NoError(t, err) logger := log.NewTestLogger(t) diff --git a/app/encoding.go b/app/encoding.go index 57a5b6cf5..d67c63bc2 100644 --- a/app/encoding.go +++ b/app/encoding.go @@ -10,6 +10,7 @@ import ( simsutils "github.com/cosmos/cosmos-sdk/testutil/sims" appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/testutil/signer" bbn "github.com/babylonlabs-io/babylon/types" ) @@ -27,7 +28,7 @@ func TmpAppOptions() simsutils.AppOptionsMap { } func NewTmpBabylonApp() *BabylonApp { - signer, _ := SetupTestPrivSigner() + signer, _ := signer.SetupTestPrivSigner() return NewBabylonApp( log.NewNopLogger(), dbm.NewMemDB(), diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index a702c15a4..8074c41d5 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -60,6 +60,7 @@ import ( ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/app/signer" bbn "github.com/babylonlabs-io/babylon/types" owasm "github.com/babylonlabs-io/babylon/wasmbinding" btccheckpointkeeper "github.com/babylonlabs-io/babylon/x/btccheckpoint/keeper" @@ -162,7 +163,7 @@ func (ak *AppKeepers) InitKeepers( homePath string, invCheckPeriod uint, skipUpgradeHeights map[int64]bool, - privSigner *PrivSigner, + privSigner *signer.PrivSigner, appOpts servertypes.AppOptions, wasmConfig wasmtypes.WasmConfig, wasmOpts []wasmkeeper.Option, diff --git a/app/keepers/utils.go b/app/keepers/utils.go index 7efe4b78a..33cdff694 100644 --- a/app/keepers/utils.go +++ b/app/keepers/utils.go @@ -7,11 +7,7 @@ import ( "path/filepath" "text/template" - cmtconfig "github.com/cometbft/cometbft/config" - cmtos "github.com/cometbft/cometbft/libs/os" "github.com/cosmos/cosmos-sdk/client/config" - - "github.com/babylonlabs-io/babylon/privval" ) const defaultConfigTemplate = `# This is a TOML config file. @@ -33,29 +29,6 @@ node = "{{ .Node }}" broadcast-mode = "{{ .BroadcastMode }}" ` -type PrivSigner struct { - WrappedPV *privval.WrappedFilePV -} - -func InitPrivSigner(nodeDir string) (*PrivSigner, error) { - nodeCfg := cmtconfig.DefaultConfig() - pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile()) - err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777) - if err != nil { - return nil, err - } - pvStateFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorStateFile()) - err = cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777) - if err != nil { - return nil, err - } - wrappedPV := privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile) - - return &PrivSigner{ - WrappedPV: wrappedPV, - }, nil -} - func CreateClientConfig(chainID string, backend string, homePath string) (*config.ClientConfig, error) { cliConf := &config.ClientConfig{ ChainID: chainID, diff --git a/app/signer/private.go b/app/signer/private.go new file mode 100644 index 000000000..8fcd1f217 --- /dev/null +++ b/app/signer/private.go @@ -0,0 +1,33 @@ +package signer + +import ( + "path/filepath" + + cmtconfig "github.com/cometbft/cometbft/config" + cmtos "github.com/cometbft/cometbft/libs/os" + + "github.com/babylonlabs-io/babylon/privval" +) + +type PrivSigner struct { + WrappedPV *privval.WrappedFilePV +} + +func InitPrivSigner(nodeDir string) (*PrivSigner, error) { + nodeCfg := cmtconfig.DefaultConfig() + pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile()) + err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777) + if err != nil { + return nil, err + } + pvStateFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorStateFile()) + err = cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777) + if err != nil { + return nil, err + } + wrappedPV := privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile) + + return &PrivSigner{ + WrappedPV: wrappedPV, + }, nil +} diff --git a/app/test_helpers.go b/app/test_helpers.go index 155223aab..ecb52a6a1 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -3,13 +3,13 @@ package app import ( "bytes" "encoding/json" - "os" "testing" "time" "cosmossdk.io/log" "cosmossdk.io/math" pruningtypes "cosmossdk.io/store/pruning/types" + testsigner "github.com/babylonlabs-io/babylon/testutil/signer" minttypes "github.com/babylonlabs-io/babylon/x/mint/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto/ed25519" @@ -31,8 +31,8 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/require" - appkeepers "github.com/babylonlabs-io/babylon/app/keepers" appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/crypto/bls12381" "github.com/babylonlabs-io/babylon/privval" bbn "github.com/babylonlabs-io/babylon/types" @@ -49,7 +49,7 @@ type SetupOptions struct { AppOpts types.AppOptions } -func setup(t *testing.T, ps *appkeepers.PrivSigner, withGenesis bool, invCheckPeriod uint, btcConf bbn.SupportedBtcNetwork) (*BabylonApp, GenesisState) { +func setup(t *testing.T, ps *signer.PrivSigner, withGenesis bool, invCheckPeriod uint, btcConf bbn.SupportedBtcNetwork) (*BabylonApp, GenesisState) { db := dbm.NewMemDB() nodeHome := t.TempDir() @@ -83,7 +83,7 @@ func setup(t *testing.T, ps *appkeepers.PrivSigner, withGenesis bool, invCheckPe // Created Babylon application will have one validator with hardcoed amount of tokens. // This is necessary as from cosmos-sdk 0.46 it is required that there is at least // one validator in validator set during InitGenesis abci call - https://github.com/cosmos/cosmos-sdk/pull/9697 -func NewBabylonAppWithCustomOptions(t *testing.T, isCheckTx bool, privSigner *appkeepers.PrivSigner, options SetupOptions) *BabylonApp { +func NewBabylonAppWithCustomOptions(t *testing.T, isCheckTx bool, privSigner *signer.PrivSigner, options SetupOptions) *BabylonApp { t.Helper() // create validator set with single validator valKeys, err := privval.NewValidatorKeys(ed25519.GenPrivKey(), bls12381.GenPrivKey()) @@ -237,7 +237,7 @@ func Setup(t *testing.T, isCheckTx bool) *BabylonApp { func SetupWithBitcoinConf(t *testing.T, isCheckTx bool, btcConf bbn.SupportedBtcNetwork) *BabylonApp { t.Helper() - ps, err := SetupTestPrivSigner() + ps, err := testsigner.SetupTestPrivSigner() require.NoError(t, err) valPubKey := ps.WrappedPV.Key.PubKey // generate genesis account @@ -248,7 +248,7 @@ func SetupWithBitcoinConf(t *testing.T, isCheckTx bool, btcConf bbn.SupportedBtc } ps.WrappedPV.Key.DelegatorAddress = acc.GetAddress().String() // create validator set with single validator - genesisKey, err := GenesisKeyFromPrivSigner(ps) + genesisKey, err := testsigner.GenesisKeyFromPrivSigner(ps) require.NoError(t, err) genesisValSet := []*checkpointingtypes.GenesisKey{genesisKey} @@ -257,26 +257,12 @@ func SetupWithBitcoinConf(t *testing.T, isCheckTx bool, btcConf bbn.SupportedBtc return app } -// SetupTestPrivSigner sets up a PrivSigner for testing -func SetupTestPrivSigner() (*appkeepers.PrivSigner, error) { - // Create a temporary node directory - nodeDir, err := os.MkdirTemp("", "tmp-signer") - if err != nil { - return nil, err - } - defer func() { - _ = os.RemoveAll(nodeDir) - }() - privSigner, _ := appkeepers.InitPrivSigner(nodeDir) - return privSigner, nil -} - // SetupWithGenesisValSet initializes a new BabylonApp with a validator set and genesis accounts // that also act as delegators. For simplicity, each validator is bonded with a delegation // of one consensus engine unit (10^6) in the default token of the babylon app from first genesis // account. A Nop logger is set in BabylonApp. // Note that the privSigner should be the 0th item of valSet -func SetupWithGenesisValSet(t *testing.T, btcConf bbn.SupportedBtcNetwork, valSet []*checkpointingtypes.GenesisKey, privSigner *appkeepers.PrivSigner, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *BabylonApp { +func SetupWithGenesisValSet(t *testing.T, btcConf bbn.SupportedBtcNetwork, valSet []*checkpointingtypes.GenesisKey, privSigner *signer.PrivSigner, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *BabylonApp { t.Helper() app, genesisState := setup(t, privSigner, true, 5, btcConf) genesisState = genesisStateWithValSet(t, app, genesisState, valSet, genAccs, balances...) @@ -309,23 +295,6 @@ func SetupWithGenesisValSet(t *testing.T, btcConf bbn.SupportedBtcNetwork, valSe return app } -func GenesisKeyFromPrivSigner(ps *appkeepers.PrivSigner) (*checkpointingtypes.GenesisKey, error) { - valKeys, err := privval.NewValidatorKeys(ps.WrappedPV.GetValPrivKey(), ps.WrappedPV.GetBlsPrivKey()) - if err != nil { - return nil, err - } - valPubkey, err := cryptocodec.FromCmtPubKeyInterface(valKeys.ValPubkey) - if err != nil { - return nil, err - } - return checkpointingtypes.NewGenesisKey( - ps.WrappedPV.GetAddress(), - &valKeys.BlsPubkey, - valKeys.PoP, - &cosmosed.PubKey{Key: valPubkey.Bytes()}, - ) -} - // createRandomAccounts is a strategy used by addTestAddrs() in order to generated addresses in random order. func createRandomAccounts(accNum int) []sdk.AccAddress { testAddrs := make([]sdk.AccAddress, accNum) diff --git a/cmd/babylond/cmd/genhelpers/bls_add_test.go b/cmd/babylond/cmd/genhelpers/bls_add_test.go index 949b5dd14..52e50dfcc 100644 --- a/cmd/babylond/cmd/genhelpers/bls_add_test.go +++ b/cmd/babylond/cmd/genhelpers/bls_add_test.go @@ -35,6 +35,7 @@ import ( "github.com/babylonlabs-io/babylon/privval" "github.com/babylonlabs-io/babylon/testutil/cli" "github.com/babylonlabs-io/babylon/testutil/datagen" + "github.com/babylonlabs-io/babylon/testutil/signer" "github.com/babylonlabs-io/babylon/x/checkpointing/types" ) @@ -75,7 +76,7 @@ func Test_CmdCreateAddWithoutGentx(t *testing.T) { require.NoError(t, err) db := dbm.NewMemDB() - signer, err := app.SetupTestPrivSigner() + signer, err := signer.SetupTestPrivSigner() require.NoError(t, err) bbn := app.NewBabylonAppWithCustomOptions(t, false, signer, app.SetupOptions{ Logger: logger, @@ -117,7 +118,7 @@ func Test_CmdCreateAddWithoutGentx(t *testing.T) { // error is expected if adding duplicate func Test_CmdAddBlsWithGentx(t *testing.T) { db := dbm.NewMemDB() - signer, err := app.SetupTestPrivSigner() + signer, err := signer.SetupTestPrivSigner() require.NoError(t, err) bbn := app.NewBabylonAppWithCustomOptions(t, false, signer, app.SetupOptions{ Logger: log.NewNopLogger(), diff --git a/cmd/babylond/cmd/genhelpers/bls_create_test.go b/cmd/babylond/cmd/genhelpers/bls_create_test.go index c036794ac..4b0d94402 100644 --- a/cmd/babylond/cmd/genhelpers/bls_create_test.go +++ b/cmd/babylond/cmd/genhelpers/bls_create_test.go @@ -25,6 +25,7 @@ import ( "github.com/babylonlabs-io/babylon/app" "github.com/babylonlabs-io/babylon/cmd/babylond/cmd/genhelpers" "github.com/babylonlabs-io/babylon/privval" + "github.com/babylonlabs-io/babylon/testutil/helper" "github.com/babylonlabs-io/babylon/x/checkpointing/types" ) @@ -34,7 +35,7 @@ func Test_CmdCreateBls(t *testing.T) { cfg, err := genutiltest.CreateDefaultCometConfig(home) require.NoError(t, err) - signer, err := app.SetupTestPrivSigner() + signer, err := helper.SetupTestPrivSigner() require.NoError(t, err) bbn := app.NewBabylonAppWithCustomOptions(t, false, signer, app.SetupOptions{ Logger: logger, diff --git a/cmd/babylond/cmd/testnet_test.go b/cmd/babylond/cmd/testnet_test.go index f379b1357..be1002310 100644 --- a/cmd/babylond/cmd/testnet_test.go +++ b/cmd/babylond/cmd/testnet_test.go @@ -18,6 +18,7 @@ import ( "github.com/stretchr/testify/require" "github.com/babylonlabs-io/babylon/app" + "github.com/babylonlabs-io/babylon/testutil/signer" ) func Test_TestnetCmd(t *testing.T) { @@ -26,7 +27,7 @@ func Test_TestnetCmd(t *testing.T) { cfg, err := genutiltest.CreateDefaultCometConfig(home) require.NoError(t, err) - signer, err := app.SetupTestPrivSigner() + signer, err := signer.SetupTestPrivSigner() require.NoError(t, err) bbn := app.NewBabylonAppWithCustomOptions(t, false, signer, app.SetupOptions{ Logger: logger, diff --git a/cmd/babylond/cmd/validate_genesis_test.go b/cmd/babylond/cmd/validate_genesis_test.go index 1248d596d..feb82fe99 100644 --- a/cmd/babylond/cmd/validate_genesis_test.go +++ b/cmd/babylond/cmd/validate_genesis_test.go @@ -8,6 +8,7 @@ import ( dbm "github.com/cosmos/cosmos-db" + "github.com/babylonlabs-io/babylon/testutil/signer" checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" "github.com/cosmos/cosmos-sdk/x/genutil" @@ -89,7 +90,7 @@ func generateTestGenesisState(t *testing.T, home string, n int) (*app.BabylonApp logger := log.NewNopLogger() cfg, _ := genutiltest.CreateDefaultCometConfig(home) - signer, err := app.SetupTestPrivSigner() + signer, err := signer.SetupTestPrivSigner() require.NoError(t, err) bbn := app.NewBabylonAppWithCustomOptions(t, false, signer, app.SetupOptions{ Logger: logger, diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index 29f47d602..448898987 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -352,6 +352,7 @@ func (s *BTCStakingTestSuite) Test3CommitPublicRandomnessAndSubmitFinalitySignat }, true) // ensure finality provider has received rewards after the block is finalised + // unexpected status code: 500, body: {"code":13,"message":"negative coin amount: -20910810810810","details":[]} fpRewardGauges, err := nonValidatorNode.QueryRewardGauge(fpBabylonAddr) s.NoError(err) fpRewardGauge, ok := fpRewardGauges[itypes.FinalityProviderType.String()] diff --git a/testutil/datagen/genesiskey.go b/testutil/datagen/genesiskey.go index 77bffb8af..14116d075 100644 --- a/testutil/datagen/genesiskey.go +++ b/testutil/datagen/genesiskey.go @@ -1,10 +1,10 @@ package datagen import ( - "github.com/babylonlabs-io/babylon/app" - appkeepers "github.com/babylonlabs-io/babylon/app/keepers" + "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/crypto/bls12381" "github.com/babylonlabs-io/babylon/privval" + testsigner "github.com/babylonlabs-io/babylon/testutil/signer" checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" cmtcrypto "github.com/cometbft/cometbft/crypto" cmted25519 "github.com/cometbft/cometbft/crypto/ed25519" @@ -88,12 +88,12 @@ func GenesisValidatorSet(numVals int) (*GenesisValidators, error) { // GenesisValidatorSetWithPrivSigner generates a set with `numVals` genesis validators // along with the privSigner, which will be in the 0th position of the return validator set -func GenesisValidatorSetWithPrivSigner(numVals int) (*GenesisValidators, *appkeepers.PrivSigner, error) { - ps, err := app.SetupTestPrivSigner() +func GenesisValidatorSetWithPrivSigner(numVals int) (*GenesisValidators, *signer.PrivSigner, error) { + ps, err := testsigner.SetupTestPrivSigner() if err != nil { return nil, nil, err } - signerGenesisKey, err := app.GenesisKeyFromPrivSigner(ps) + signerGenesisKey, err := testsigner.GenesisKeyFromPrivSigner(ps) if err != nil { return nil, nil, err } diff --git a/testutil/helper/helper.go b/testutil/helper/helper.go index 9d9219767..46ba8d9dd 100644 --- a/testutil/helper/helper.go +++ b/testutil/helper/helper.go @@ -7,7 +7,7 @@ import ( "testing" "cosmossdk.io/core/header" - appkeepers "github.com/babylonlabs-io/babylon/app/keepers" + "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/crypto/bls12381" "github.com/babylonlabs-io/babylon/testutil/datagen" checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" @@ -57,7 +57,7 @@ func NewHelper(t *testing.T) *Helper { // NewHelperWithValSet is same as NewHelper, except that it creates a set of validators // the privSigner is the 0th validator in valSet -func NewHelperWithValSet(t *testing.T, valSet *datagen.GenesisValidators, privSigner *appkeepers.PrivSigner) *Helper { +func NewHelperWithValSet(t *testing.T, valSet *datagen.GenesisValidators, privSigner *signer.PrivSigner) *Helper { // generate the genesis account signerPubKey := privSigner.WrappedPV.Key.PubKey acc := authtypes.NewBaseAccount(signerPubKey.Address().Bytes(), &cosmosed.PubKey{Key: signerPubKey.Bytes()}, 0, 0) @@ -95,7 +95,7 @@ func NewHelperWithValSet(t *testing.T, valSet *datagen.GenesisValidators, privSi // NewHelperWithValSetNoSigner is same as NewHelperWithValSet, except that the privSigner is not // included in the validator set -func NewHelperWithValSetNoSigner(t *testing.T, valSet *datagen.GenesisValidators, privSigner *appkeepers.PrivSigner) *Helper { +func NewHelperWithValSetNoSigner(t *testing.T, valSet *datagen.GenesisValidators, privSigner *signer.PrivSigner) *Helper { // generate the genesis account signerPubKey := privSigner.WrappedPV.Key.PubKey acc := authtypes.NewBaseAccount(signerPubKey.Address().Bytes(), &cosmosed.PubKey{Key: signerPubKey.Bytes()}, 0, 0) diff --git a/testutil/signer/private.go b/testutil/signer/private.go new file mode 100644 index 000000000..a4f39cb3a --- /dev/null +++ b/testutil/signer/private.go @@ -0,0 +1,43 @@ +package signer + +import ( + "os" + + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + cosmosed "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + + "github.com/babylonlabs-io/babylon/app/signer" + "github.com/babylonlabs-io/babylon/privval" + checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" +) + +// SetupTestPrivSigner sets up a PrivSigner for testing +func SetupTestPrivSigner() (*signer.PrivSigner, error) { + // Create a temporary node directory + nodeDir, err := os.MkdirTemp("", "tmp-signer") + if err != nil { + return nil, err + } + defer func() { + _ = os.RemoveAll(nodeDir) + }() + privSigner, _ := signer.InitPrivSigner(nodeDir) + return privSigner, nil +} + +func GenesisKeyFromPrivSigner(ps *signer.PrivSigner) (*checkpointingtypes.GenesisKey, error) { + valKeys, err := privval.NewValidatorKeys(ps.WrappedPV.GetValPrivKey(), ps.WrappedPV.GetBlsPrivKey()) + if err != nil { + return nil, err + } + valPubkey, err := cryptocodec.FromCmtPubKeyInterface(valKeys.ValPubkey) + if err != nil { + return nil, err + } + return checkpointingtypes.NewGenesisKey( + ps.WrappedPV.GetAddress(), + &valKeys.BlsPubkey, + valKeys.PoP, + &cosmosed.PubKey{Key: valPubkey.Bytes()}, + ) +} diff --git a/x/incentive/keeper/btc_staking_gauge.go b/x/incentive/keeper/btc_staking_gauge.go index fb61bb96f..b8b70c780 100644 --- a/x/incentive/keeper/btc_staking_gauge.go +++ b/x/incentive/keeper/btc_staking_gauge.go @@ -38,19 +38,9 @@ func (k Keeper) RewardBTCStaking(ctx context.Context, height uint64, dc *ftypes. // reward the rest of coins to each BTC delegation proportional to its voting power portion coinsForBTCDels := coinsForFpsAndDels.Sub(coinsForCommission...) - // TODO(rafilx): add the coins entitled to the BTC delegations to the FinalityProviderCurrentRewards if err := k.AddFinalityProviderRewardsForDelegationsBTC(ctx, fp.GetAddress(), coinsForBTCDels); err != nil { panic(err) } - // TODO: remove this iteration. It could be avoided by using accumulated rewards per period - // for each finality provider, and for each delegation (fp, delegator) keep track of last period - // TODO(rafilx): Add acumulative rewards for each validator - - // for _, btcDel := range fp.BtcDels { - // btcDelPortion := fp.GetBTCDelPortion(btcDel) - // coinsForDel := types.GetCoinsPortion(coinsForBTCDels, btcDelPortion) - // k.accumulateRewardGauge(ctx, types.BTCDelegationType, btcDel.GetAddress(), coinsForDel) - // } } // TODO: prune unnecessary state (delete BTCStakingGauge after the amount is used) } diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go new file mode 100644 index 000000000..b6be13ec8 --- /dev/null +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -0,0 +1,69 @@ +package keeper + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "cosmossdk.io/core/header" + "cosmossdk.io/log" + "cosmossdk.io/store" + storemetrics "cosmossdk.io/store/metrics" + storetypes "cosmossdk.io/store/types" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/runtime" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/testutil/datagen" + "github.com/babylonlabs-io/babylon/x/incentive/types" +) + +func FuzzCheckSetBTCDelegatorToFP(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + k, ctx := NewKeeperWithCtx(t) + fp1, fp2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + del1, del2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + k.setBTCDelegatorToFP(ctx, del1, fp1) + count := 0 + err := k.iterBtcDelegatorToFP(ctx, del1, func(del, fp sdk.AccAddress) error { + require.Equal(t, del.String(), del1.String()) + require.Equal(t, fp1.String(), fp.String()) + count++ + return nil + }) + require.Equal(t, 1, count) + require.NoError(t, err) + + k.setBTCDelegatorToFP(ctx, del1, fp2) + + k.setBTCDelegatorToFP(ctx, del2, fp2) + }) +} + +func NewKeeperWithCtx(t *testing.T) (Keeper, sdk.Context) { + encConf := appparams.DefaultEncodingConfig() + + db := dbm.NewMemDB() + stateStore := store.NewCommitMultiStore(db, log.NewTestLogger(t), storemetrics.NewNoOpMetrics()) + + storeKey := storetypes.NewKVStoreKey(types.StoreKey) + + stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) + require.NoError(t, stateStore.LoadLatestVersion()) + + govAcc := authtypes.NewModuleAddress(govtypes.ModuleName).String() + feeColl := authtypes.NewModuleAddress(authtypes.FeeCollectorName).String() + k := NewKeeper(encConf.Codec, runtime.NewKVStoreService(storeKey), nil, nil, nil, govAcc, feeColl) + + ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) + ctx = ctx.WithHeaderInfo(header.Info{}) + + return k, ctx +} From e1bac018de4d232dd9a09f58a7c3ae88f4f6b5d5 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 15:19:22 -0300 Subject: [PATCH 024/132] chore: add test for private func setBTCDelegatorToFP --- .../keeper/reward_tracker_store_test.go | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index b6be13ec8..e590161a3 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -30,6 +30,8 @@ func FuzzCheckSetBTCDelegatorToFP(f *testing.F) { fp1, fp2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() del1, del2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + // only one set + // del1 -> fp1 k.setBTCDelegatorToFP(ctx, del1, fp1) count := 0 err := k.iterBtcDelegatorToFP(ctx, del1, func(del, fp sdk.AccAddress) error { @@ -41,9 +43,36 @@ func FuzzCheckSetBTCDelegatorToFP(f *testing.F) { require.Equal(t, 1, count) require.NoError(t, err) + // restart count every time + // del1 -> fp1, fp2 k.setBTCDelegatorToFP(ctx, del1, fp2) + count = 0 + err = k.iterBtcDelegatorToFP(ctx, del1, func(del, fp sdk.AccAddress) error { + count++ + require.Equal(t, del.String(), del1.String()) + if fp.Equals(fp1) { + require.Equal(t, fp1.String(), fp.String()) + return nil + } + + require.Equal(t, fp2.String(), fp.String()) + return nil + }) + require.Equal(t, 2, count) + require.NoError(t, err) + // new delegator + // del2 -> fp2 k.setBTCDelegatorToFP(ctx, del2, fp2) + count = 0 + err = k.iterBtcDelegatorToFP(ctx, del2, func(del, fp sdk.AccAddress) error { + count++ + require.Equal(t, del.String(), del2.String()) + require.Equal(t, fp2.String(), fp.String()) + return nil + }) + require.Equal(t, 1, count) + require.NoError(t, err) }) } From bc55debd8b7e4c28dc1b524c75c87f532eb8e69c Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 17:09:25 -0300 Subject: [PATCH 025/132] chore: add test case for deleting the BTC delegator to FP --- .../cmd/genhelpers/bls_create_test.go | 4 +- cmd/babylond/cmd/root.go | 6 +-- testutil/addr/const.go | 11 ++++ testutil/store/state.go | 36 +++++++++++++ x/incentive/keeper/btc_staking_gauge_test.go | 2 +- x/incentive/keeper/grpc_query.go | 2 +- x/incentive/keeper/msg_server.go | 2 +- x/incentive/keeper/reward_gauge.go | 4 +- x/incentive/keeper/reward_tracker.go | 8 +-- x/incentive/keeper/reward_tracker_store.go | 17 ++++++- .../keeper/reward_tracker_store_test.go | 51 ++++++++----------- 11 files changed, 97 insertions(+), 46 deletions(-) create mode 100644 testutil/addr/const.go create mode 100644 testutil/store/state.go diff --git a/cmd/babylond/cmd/genhelpers/bls_create_test.go b/cmd/babylond/cmd/genhelpers/bls_create_test.go index 4b0d94402..5b171fa90 100644 --- a/cmd/babylond/cmd/genhelpers/bls_create_test.go +++ b/cmd/babylond/cmd/genhelpers/bls_create_test.go @@ -25,7 +25,7 @@ import ( "github.com/babylonlabs-io/babylon/app" "github.com/babylonlabs-io/babylon/cmd/babylond/cmd/genhelpers" "github.com/babylonlabs-io/babylon/privval" - "github.com/babylonlabs-io/babylon/testutil/helper" + "github.com/babylonlabs-io/babylon/testutil/signer" "github.com/babylonlabs-io/babylon/x/checkpointing/types" ) @@ -35,7 +35,7 @@ func Test_CmdCreateBls(t *testing.T) { cfg, err := genutiltest.CreateDefaultCometConfig(home) require.NoError(t, err) - signer, err := helper.SetupTestPrivSigner() + signer, err := signer.SetupTestPrivSigner() require.NoError(t, err) bbn := app.NewBabylonAppWithCustomOptions(t, false, signer, app.SetupOptions{ Logger: logger, diff --git a/cmd/babylond/cmd/root.go b/cmd/babylond/cmd/root.go index 2228d2223..80f865ca2 100644 --- a/cmd/babylond/cmd/root.go +++ b/cmd/babylond/cmd/root.go @@ -8,7 +8,7 @@ import ( confixcmd "cosmossdk.io/tools/confix/cmd" "github.com/CosmWasm/wasmd/x/wasm" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - appkeepers "github.com/babylonlabs-io/babylon/app/keepers" + "github.com/babylonlabs-io/babylon/app/signer" cmtcfg "github.com/cometbft/cometbft/config" cmtcli "github.com/cometbft/cometbft/libs/cli" dbm "github.com/cosmos/cosmos-db" @@ -261,7 +261,7 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts serverty } homeDir := cast.ToString(appOpts.Get(flags.FlagHome)) - privSigner, err := appkeepers.InitPrivSigner(homeDir) + privSigner, err := signer.InitPrivSigner(homeDir) if err != nil { panic(err) } @@ -299,7 +299,7 @@ func appExport( return servertypes.ExportedApp{}, errors.New("application home not set") } - privSigner, err := appkeepers.InitPrivSigner(homePath) + privSigner, err := signer.InitPrivSigner(homePath) if err != nil { panic(err) } diff --git a/testutil/addr/const.go b/testutil/addr/const.go new file mode 100644 index 000000000..f1b97329b --- /dev/null +++ b/testutil/addr/const.go @@ -0,0 +1,11 @@ +package addr + +import ( + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +var ( + AccGov = authtypes.NewModuleAddress(govtypes.ModuleName) + AccFeeCollector = authtypes.NewModuleAddress(authtypes.FeeCollectorName) +) diff --git a/testutil/store/state.go b/testutil/store/state.go new file mode 100644 index 000000000..da203a1b3 --- /dev/null +++ b/testutil/store/state.go @@ -0,0 +1,36 @@ +package store + +import ( + "testing" + + "cosmossdk.io/core/header" + corestore "cosmossdk.io/core/store" + "cosmossdk.io/log" + "cosmossdk.io/store" + storemetrics "cosmossdk.io/store/metrics" + storetypes "cosmossdk.io/store/types" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/runtime" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func NewStoreService(t *testing.T, moduleName string) (kvStore corestore.KVStoreService, stateStore storetypes.CommitMultiStore) { + db := dbm.NewMemDB() + stateStore = store.NewCommitMultiStore(db, log.NewTestLogger(t), storemetrics.NewNoOpMetrics()) + + storeKey := storetypes.NewKVStoreKey(moduleName) + + stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) + require.NoError(t, stateStore.LoadLatestVersion()) + + return runtime.NewKVStoreService(storeKey), stateStore +} + +func NewStoreWithCtx(t *testing.T, moduleName string) (ctx sdk.Context, kvStore corestore.KVStoreService) { + kvStore, stateStore := NewStoreService(t, moduleName) + ctx = sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) + ctx = ctx.WithHeaderInfo(header.Info{}) + return ctx, kvStore +} diff --git a/x/incentive/keeper/btc_staking_gauge_test.go b/x/incentive/keeper/btc_staking_gauge_test.go index a7cf3bceb..846ef7554 100644 --- a/x/incentive/keeper/btc_staking_gauge_test.go +++ b/x/incentive/keeper/btc_staking_gauge_test.go @@ -81,7 +81,7 @@ func FuzzRewardBTCStaking(f *testing.F) { require.Equal(t, delRwd.TotalActiveSat.Uint64(), btcDel.TotalSat) // makes sure the rewards added reach the delegation gauge - err = keeper.WithdrawDelegationRewardsToGauge(ctx, fpAddr, delAddr) + err = keeper.SendBtcDelegationRewardsToGauge(ctx, fpAddr, delAddr) require.NoError(t, err) } fpCurrentRwd, err := keeper.GetFinalityProviderCurrentRewards(ctx, fpAddr) diff --git a/x/incentive/keeper/grpc_query.go b/x/incentive/keeper/grpc_query.go index 2ec9b60cb..9cb775dba 100644 --- a/x/incentive/keeper/grpc_query.go +++ b/x/incentive/keeper/grpc_query.go @@ -27,7 +27,7 @@ func (k Keeper) RewardGauges(goCtx context.Context, req *types.QueryRewardGauges // find reward gauge for _, sType := range types.GetAllStakeholderTypes() { - if err := k.sendAllBtcRewardsToGauge(ctx, sType, address); err != nil { + if err := k.sendAllBtcDelegatorRewardsToGauge(ctx, sType, address); err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/incentive/keeper/msg_server.go b/x/incentive/keeper/msg_server.go index d1a6ae92e..c8c0a6f1d 100644 --- a/x/incentive/keeper/msg_server.go +++ b/x/incentive/keeper/msg_server.go @@ -54,7 +54,7 @@ func (ms msgServer) WithdrawReward(goCtx context.Context, req *types.MsgWithdraw return nil, status.Error(codes.InvalidArgument, err.Error()) } - if err := ms.sendAllBtcRewardsToGauge(ctx, sType, addr); err != nil { + if err := ms.sendAllBtcDelegatorRewardsToGauge(ctx, sType, addr); err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/incentive/keeper/reward_gauge.go b/x/incentive/keeper/reward_gauge.go index b434c573a..d6a11b167 100644 --- a/x/incentive/keeper/reward_gauge.go +++ b/x/incentive/keeper/reward_gauge.go @@ -9,11 +9,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -func (k Keeper) sendAllBtcRewardsToGauge(ctx context.Context, sType types.StakeholderType, del sdk.AccAddress) error { +func (k Keeper) sendAllBtcDelegatorRewardsToGauge(ctx context.Context, sType types.StakeholderType, del sdk.AccAddress) error { if sType != types.BTCDelegationType { return nil } - return k.sendAllRewardsToGauge(ctx, del) + return k.sendAllBtcRewardsToGauge(ctx, del) } func (k Keeper) withdrawReward(ctx context.Context, sType types.StakeholderType, addr sdk.AccAddress) (sdk.Coins, error) { diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index c0dc44793..370d48aed 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -69,7 +69,7 @@ func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddres }) } -func (k Keeper) WithdrawDelegationRewardsToGauge(ctx context.Context, fp, del sdk.AccAddress) error { +func (k Keeper) SendBtcDelegationRewardsToGauge(ctx context.Context, fp, del sdk.AccAddress) error { return k.btcDelegationModified(ctx, fp, del) } @@ -211,9 +211,9 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA return fpCurrentRwd.Period, nil } -func (k Keeper) sendAllRewardsToGauge(ctx context.Context, del sdk.AccAddress) error { - return k.iterBtcDelegatorToFP(ctx, del, func(del, fp sdk.AccAddress) error { - return k.WithdrawDelegationRewardsToGauge(ctx, fp, del) +func (k Keeper) sendAllBtcRewardsToGauge(ctx context.Context, del sdk.AccAddress) error { + return k.iterBtcDelegationsByDelegator(ctx, del, func(del, fp sdk.AccAddress) error { + return k.SendBtcDelegationRewardsToGauge(ctx, fp, del) }) } diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index f21b2212e..80d30babc 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -11,6 +11,10 @@ import ( ) // storeBTCDelegatorToFp returns the KVStore of the mapping del => fp +// note: it stores the finality provider as key and sets a one byte as value +// so each BTC delegator address can have multiple finality providers. +// Usefull to iterate over all the pairs (fp,del) by filtering the +// delegator address. // prefix: BTCDelegatorToFPKey // key: (DelAddr, FpAddr) // value: 0x00 @@ -42,7 +46,7 @@ func (k Keeper) storeFpCurrentRewards(ctx context.Context) prefix.Store { // storeFpHistoricalRewards returns the KVStore of the FP historical rewards // prefix: FinalityProviderHistoricalRewardsKey // key: (finality provider cosmos address, period) -// value: FinalityProviderCurrentRewards +// value: FinalityProviderHistoricalRewards func (k Keeper) storeFpHistoricalRewards(ctx context.Context, fp sdk.AccAddress) prefix.Store { storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) st := prefix.NewStore(storeAdaptor, types.FinalityProviderHistoricalRewardsKey) @@ -54,11 +58,15 @@ func (k Keeper) setBTCDelegatorToFP(ctx context.Context, del, fp sdk.AccAddress) st.Set(fp.Bytes(), []byte{0x00}) } -func (k Keeper) iterBtcDelegatorToFP(ctx context.Context, del sdk.AccAddress, it func(del, fp sdk.AccAddress) error) error { +// iterBtcDelegationsByDelegator iterates over all the possible BTC delegations +// filtering by the delegator address (uses the BTCDelegatorToFPKey keystore) +// It stops if the `it` function returns an error +func (k Keeper) iterBtcDelegationsByDelegator(ctx context.Context, del sdk.AccAddress, it func(del, fp sdk.AccAddress) error) error { st := k.storeBTCDelegatorToFp(ctx, del) iter := st.Iterator(nil, nil) defer iter.Close() + for ; iter.Valid(); iter.Next() { fp := sdk.AccAddress(iter.Key()) if err := it(del, fp); err != nil { @@ -68,11 +76,15 @@ func (k Keeper) iterBtcDelegatorToFP(ctx context.Context, del sdk.AccAddress, it return nil } +// deleteBTCDelegatorToFP deletes one key (del, fp) from the store +// without checking if it exists. func (k Keeper) deleteBTCDelegatorToFP(ctx context.Context, del, fp sdk.AccAddress) { st := k.storeBTCDelegatorToFp(ctx, del) st.Delete(fp.Bytes()) } +// GetFinalityProviderCurrentRewards returns the Finality Provider current rewards +// based on the FP address key func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { key := fp.Bytes() bz := k.storeFpCurrentRewards(ctx).Get(key) @@ -88,6 +100,7 @@ func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.Ac } // IterateBTCDelegationRewardsTracker iterates over all the delegation rewards tracker by the finality provider. +// It stops if the function `it` returns an error. func (k Keeper) IterateBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress, it func(fp, del sdk.AccAddress) error) error { st := k.storeBTCDelegationRewardsTracker(ctx, fp) diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index e590161a3..58a2813db 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -5,24 +5,16 @@ import ( "github.com/stretchr/testify/require" - "cosmossdk.io/core/header" - "cosmossdk.io/log" - "cosmossdk.io/store" - storemetrics "cosmossdk.io/store/metrics" - storetypes "cosmossdk.io/store/types" - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - dbm "github.com/cosmos/cosmos-db" - "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/testutil/addr" "github.com/babylonlabs-io/babylon/testutil/datagen" + "github.com/babylonlabs-io/babylon/testutil/store" "github.com/babylonlabs-io/babylon/x/incentive/types" ) -func FuzzCheckSetBTCDelegatorToFP(f *testing.F) { +func FuzzCheckBTCDelegatorToFP(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) f.Fuzz(func(t *testing.T, seed int64) { @@ -34,7 +26,7 @@ func FuzzCheckSetBTCDelegatorToFP(f *testing.F) { // del1 -> fp1 k.setBTCDelegatorToFP(ctx, del1, fp1) count := 0 - err := k.iterBtcDelegatorToFP(ctx, del1, func(del, fp sdk.AccAddress) error { + err := k.iterBtcDelegationsByDelegator(ctx, del1, func(del, fp sdk.AccAddress) error { require.Equal(t, del.String(), del1.String()) require.Equal(t, fp1.String(), fp.String()) count++ @@ -47,7 +39,7 @@ func FuzzCheckSetBTCDelegatorToFP(f *testing.F) { // del1 -> fp1, fp2 k.setBTCDelegatorToFP(ctx, del1, fp2) count = 0 - err = k.iterBtcDelegatorToFP(ctx, del1, func(del, fp sdk.AccAddress) error { + err = k.iterBtcDelegationsByDelegator(ctx, del1, func(del, fp sdk.AccAddress) error { count++ require.Equal(t, del.String(), del1.String()) if fp.Equals(fp1) { @@ -65,7 +57,7 @@ func FuzzCheckSetBTCDelegatorToFP(f *testing.F) { // del2 -> fp2 k.setBTCDelegatorToFP(ctx, del2, fp2) count = 0 - err = k.iterBtcDelegatorToFP(ctx, del2, func(del, fp sdk.AccAddress) error { + err = k.iterBtcDelegationsByDelegator(ctx, del2, func(del, fp sdk.AccAddress) error { count++ require.Equal(t, del.String(), del2.String()) require.Equal(t, fp2.String(), fp.String()) @@ -73,26 +65,25 @@ func FuzzCheckSetBTCDelegatorToFP(f *testing.F) { }) require.Equal(t, 1, count) require.NoError(t, err) + + // deletes del1 -> fp1 + // iterates again should only have the del1 -> fp2 + count = 0 + k.deleteBTCDelegatorToFP(ctx, del1, fp1) + err = k.iterBtcDelegationsByDelegator(ctx, del1, func(del, fp sdk.AccAddress) error { + require.Equal(t, del.String(), del1.String()) + require.Equal(t, fp2.String(), fp.String()) + count++ + return nil + }) + require.Equal(t, 1, count) + require.NoError(t, err) }) } func NewKeeperWithCtx(t *testing.T) (Keeper, sdk.Context) { encConf := appparams.DefaultEncodingConfig() - - db := dbm.NewMemDB() - stateStore := store.NewCommitMultiStore(db, log.NewTestLogger(t), storemetrics.NewNoOpMetrics()) - - storeKey := storetypes.NewKVStoreKey(types.StoreKey) - - stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) - require.NoError(t, stateStore.LoadLatestVersion()) - - govAcc := authtypes.NewModuleAddress(govtypes.ModuleName).String() - feeColl := authtypes.NewModuleAddress(authtypes.FeeCollectorName).String() - k := NewKeeper(encConf.Codec, runtime.NewKVStoreService(storeKey), nil, nil, nil, govAcc, feeColl) - - ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) - ctx = ctx.WithHeaderInfo(header.Info{}) - + ctx, kvStore := store.NewStoreWithCtx(t, types.ModuleName) + k := NewKeeper(encConf.Codec, kvStore, nil, nil, nil, addr.AccGov.String(), addr.AccFeeCollector.String()) return k, ctx } From f6b13c64f2d5de98c0bfbf8df5d55dc7eab3651c Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 17:42:44 -0300 Subject: [PATCH 026/132] chore: add test for Btc delegation reward tracker --- testutil/datagen/datagen.go | 6 ++ .../keeper/reward_tracker_store_test.go | 67 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/testutil/datagen/datagen.go b/testutil/datagen/datagen.go index fcc096212..417df1cb7 100644 --- a/testutil/datagen/datagen.go +++ b/testutil/datagen/datagen.go @@ -3,6 +3,8 @@ package datagen import ( "encoding/hex" "math/rand" + + "cosmossdk.io/math" ) func GenRandomByteArray(r *rand.Rand, length uint64) []byte { @@ -24,6 +26,10 @@ func RandomInt(r *rand.Rand, rng int) uint64 { return uint64(r.Intn(rng)) } +func RandomMathInt(r *rand.Rand, rng int) math.Int { + return math.NewIntFromUint64(RandomInt(r, rng)) +} + func RandomUInt32(r *rand.Rand, rng uint32) uint32 { return uint32(r.Intn(int(rng))) } diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index 58a2813db..da7e5310c 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -1,8 +1,10 @@ package keeper import ( + "math/rand" "testing" + "cosmossdk.io/math" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -81,6 +83,71 @@ func FuzzCheckBTCDelegatorToFP(f *testing.F) { }) } +func FuzzCheckBTCDelegationRewardsTracker(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp1, fp2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + del1, del2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + // fp1, del1 + err := k.setBTCDelegationRewardsTracker(ctx, fp1, del1, types.NewBTCDelegationRewardsTracker(0, math.NewInt(100))) + require.NoError(t, err) + + count := 0 + err = k.IterateBTCDelegationRewardsTracker(ctx, fp1, func(fp, del sdk.AccAddress) error { + count++ + require.Equal(t, fp1, fp) + require.Equal(t, del1, del) + return nil + }) + require.Equal(t, 1, count) + require.NoError(t, err) + + // fp1, del2 + err = k.setBTCDelegationRewardsTracker(ctx, fp1, del2, types.NewBTCDelegationRewardsTracker(0, math.NewInt(100))) + require.NoError(t, err) + + count = 0 + err = k.IterateBTCDelegationRewardsTracker(ctx, fp1, func(fp, del sdk.AccAddress) error { + count++ + require.Equal(t, fp1, fp) + if del1.Equals(del) { + require.Equal(t, del1, del) + return nil + } + require.Equal(t, del2, del) + return nil + }) + require.Equal(t, 2, count) + require.NoError(t, err) + + // fp2, del1 + amtFp2Del1 := datagen.RandomMathInt(r, 20000) + startPeriodFp2Del1 := datagen.RandomInt(r, 200) + err = k.setBTCDelegationRewardsTracker(ctx, fp2, del1, types.NewBTCDelegationRewardsTracker(startPeriodFp2Del1, amtFp2Del1)) + require.NoError(t, err) + + btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp2, del1) + require.NoError(t, err) + require.Equal(t, amtFp2Del1.String(), btcDelRwdTracker.TotalActiveSat.String()) + require.Equal(t, startPeriodFp2Del1, btcDelRwdTracker.StartPeriodCumulativeReward) + + count = 0 + err = k.IterateBTCDelegationRewardsTracker(ctx, fp2, func(fp, del sdk.AccAddress) error { + count++ + require.Equal(t, fp2, fp) + require.Equal(t, del1, del) + return nil + }) + require.Equal(t, 1, count) + require.NoError(t, err) + }) +} + func NewKeeperWithCtx(t *testing.T) (Keeper, sdk.Context) { encConf := appparams.DefaultEncodingConfig() ctx, kvStore := store.NewStoreWithCtx(t, types.ModuleName) From a2eeede0daf97fade0242de638f2e8c4c80fbded Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 17:46:29 -0300 Subject: [PATCH 027/132] chore: add test of delete btc delegation tracker --- .../keeper/reward_tracker_store_test.go | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index da7e5310c..762819827 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -20,6 +20,7 @@ func FuzzCheckBTCDelegatorToFP(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() k, ctx := NewKeeperWithCtx(t) fp1, fp2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() del1, del2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() @@ -87,6 +88,7 @@ func FuzzCheckBTCDelegationRewardsTracker(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() r := rand.New(rand.NewSource(seed)) k, ctx := NewKeeperWithCtx(t) @@ -145,6 +147,29 @@ func FuzzCheckBTCDelegationRewardsTracker(f *testing.F) { }) require.Equal(t, 1, count) require.NoError(t, err) + + // check delete fp2 + k.deleteKeysFromBTCDelegationRewardsTracker(ctx, fp2, [][]byte{del1.Bytes()}) + count = 0 + err = k.IterateBTCDelegationRewardsTracker(ctx, fp2, func(fp, del sdk.AccAddress) error { + count++ + return nil + }) + require.Equal(t, 0, count) + require.NoError(t, err) + + // check delete all from fp1 + k.deleteKeysFromBTCDelegationRewardsTracker(ctx, fp1, [][]byte{del1.Bytes(), del2.Bytes()}) + count = 0 + err = k.IterateBTCDelegationRewardsTracker(ctx, fp1, func(fp, del sdk.AccAddress) error { + count++ + return nil + }) + require.Equal(t, 0, count) + require.NoError(t, err) + + _, err = k.GetBTCDelegationRewardsTracker(ctx, fp2, del1) + require.EqualError(t, err, types.ErrBTCDelegationRewardsTrackerNotFound.Error()) }) } From 6fb3549609ca71665d01c2206851fb957abd3b06 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 18:02:38 -0300 Subject: [PATCH 028/132] chore: add test for FinalityProviderCurrentRewards --- testutil/datagen/incentive.go | 8 ++++ x/incentive/keeper/reward_tracker_store.go | 7 ++++ .../keeper/reward_tracker_store_test.go | 40 +++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/testutil/datagen/incentive.go b/testutil/datagen/incentive.go index db8f193a4..58d14c556 100644 --- a/testutil/datagen/incentive.go +++ b/testutil/datagen/incentive.go @@ -8,6 +8,7 @@ import ( btcctypes "github.com/babylonlabs-io/babylon/x/btccheckpoint/types" ftypes "github.com/babylonlabs-io/babylon/x/finality/types" + "github.com/babylonlabs-io/babylon/x/incentive/types" itypes "github.com/babylonlabs-io/babylon/x/incentive/types" ) @@ -142,3 +143,10 @@ func GenRandomBTCTimestampingRewardDistInfo(r *rand.Rand) *btcctypes.RewardDistI } return btcctypes.NewRewardDistInfo(best, others...) } + +func GenRandomFinalityProviderCurrentRewards(r *rand.Rand) types.FinalityProviderCurrentRewards { + rwd := GenRandomCoins(r) + period := RandomInt(r, 100) + activeSatoshi := RandomMathInt(r, 10000) + return types.NewFinalityProviderCurrentRewards(rwd, period, activeSatoshi) +} diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index 80d30babc..86883984c 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -125,6 +125,8 @@ func (k Keeper) deleteKeysFromBTCDelegationRewardsTracker(ctx context.Context, f } } +// GetBTCDelegationRewardsTracker returns the BTCDelegationRewardsTracker based on the delegation key (fp, del) +// It returns an error in case the key is not found. func (k Keeper) GetBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk.AccAddress) (types.BTCDelegationRewardsTracker, error) { key := del.Bytes() bz := k.storeBTCDelegationRewardsTracker(ctx, fp).Get(key) @@ -139,6 +141,7 @@ func (k Keeper) GetBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk. return value, nil } +// setBTCDelegationRewardsTracker sets a new structure in the store, it fails and returns an error if the rwd fails to marshal. func (k Keeper) setBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk.AccAddress, rwd types.BTCDelegationRewardsTracker) error { key := del.Bytes() bz, err := rwd.Marshal() @@ -151,6 +154,7 @@ func (k Keeper) setBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk. return nil } +// setFinalityProviderCurrentRewards sets a new structure in the store, it fails and returns an error if the rwd fails to marshal. func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress, rwd types.FinalityProviderCurrentRewards) error { key := fp.Bytes() bz, err := rwd.Marshal() @@ -162,6 +166,8 @@ func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.Ac return nil } +// deleteAllFromFinalityProviderRwd deletes all the data related to Finality Provider Rewards +// Historical and current from a fp address key. func (k Keeper) deleteAllFromFinalityProviderRwd(ctx context.Context, fp sdk.AccAddress) { st := k.storeFpHistoricalRewards(ctx, fp) @@ -180,6 +186,7 @@ func (k Keeper) deleteAllFromFinalityProviderRwd(ctx context.Context, fp sdk.Acc k.deleteFinalityProviderCurrentRewards(ctx, fp) } +// deleteFinalityProviderCurrentRewards deletes the current FP reward based on the key received func (k Keeper) deleteFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) { key := fp.Bytes() k.storeFpCurrentRewards(ctx).Delete(key) diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index 762819827..2a14d9917 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -173,6 +173,46 @@ func FuzzCheckBTCDelegationRewardsTracker(f *testing.F) { }) } +func FuzzCheckFinalityProviderCurrentRewards(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp1, fp2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + _, err := k.GetFinalityProviderCurrentRewards(ctx, fp1) + require.EqualError(t, err, types.ErrFPCurrentRewardsNotFound.Error()) + + expectedCurrentRwdFp1 := datagen.GenRandomFinalityProviderCurrentRewards(r) + err = k.setFinalityProviderCurrentRewards(ctx, fp1, expectedCurrentRwdFp1) + require.NoError(t, err) + + currentRwdFp1, err := k.GetFinalityProviderCurrentRewards(ctx, fp1) + require.NoError(t, err) + require.Equal(t, expectedCurrentRwdFp1.CurrentRewards.String(), currentRwdFp1.CurrentRewards.String()) + require.Equal(t, expectedCurrentRwdFp1.TotalActiveSat.String(), currentRwdFp1.TotalActiveSat.String()) + require.Equal(t, expectedCurrentRwdFp1.Period, currentRwdFp1.Period) + + k.deleteAllFromFinalityProviderRwd(ctx, fp1) + _, err = k.GetFinalityProviderCurrentRewards(ctx, fp1) + require.EqualError(t, err, types.ErrFPCurrentRewardsNotFound.Error()) + + // sets a new fp + err = k.setFinalityProviderCurrentRewards(ctx, fp2, datagen.GenRandomFinalityProviderCurrentRewards(r)) + require.NoError(t, err) + + _, err = k.GetFinalityProviderCurrentRewards(ctx, fp2) + require.NoError(t, err) + + k.deleteFinalityProviderCurrentRewards(ctx, fp2) + _, err = k.GetFinalityProviderCurrentRewards(ctx, fp2) + require.EqualError(t, err, types.ErrFPCurrentRewardsNotFound.Error()) + }) +} + func NewKeeperWithCtx(t *testing.T) (Keeper, sdk.Context) { encConf := appparams.DefaultEncodingConfig() ctx, kvStore := store.NewStoreWithCtx(t, types.ModuleName) From 64edb3084d8181b1fa35fb543a36af73fe007b19 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 18:27:19 -0300 Subject: [PATCH 029/132] chore: finalized tests for simple store functions --- testutil/datagen/incentive.go | 5 ++ x/incentive/keeper/reward_tracker.go | 6 +-- x/incentive/keeper/reward_tracker_store.go | 19 ++++--- .../keeper/reward_tracker_store_test.go | 51 +++++++++++++++++++ 4 files changed, 71 insertions(+), 10 deletions(-) diff --git a/testutil/datagen/incentive.go b/testutil/datagen/incentive.go index 58d14c556..c8fc12320 100644 --- a/testutil/datagen/incentive.go +++ b/testutil/datagen/incentive.go @@ -150,3 +150,8 @@ func GenRandomFinalityProviderCurrentRewards(r *rand.Rand) types.FinalityProvide activeSatoshi := RandomMathInt(r, 10000) return types.NewFinalityProviderCurrentRewards(rwd, period, activeSatoshi) } + +func GenRandomFinalityProviderHistoricalRewards(r *rand.Rand) types.FinalityProviderHistoricalRewards { + rwd := GenRandomCoins(r) + return types.NewFinalityProviderHistoricalRewards(rwd) +} diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 370d48aed..7eb5801cc 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -31,7 +31,7 @@ func (k Keeper) FpSlashed(ctx context.Context, fp sdk.AccAddress) error { keysBtcDelRwdTracker := make([][]byte, 0) if err := k.IterateBTCDelegationRewardsTracker(ctx, fp, func(fp, del sdk.AccAddress) error { keysBtcDelRwdTracker = append(keysBtcDelRwdTracker, del.Bytes()) - return k.CalculateBTCDelegationRewardsAndSend(ctx, fp, del, endedPeriod) + return k.CalculateBTCDelegationRewardsAndSendToGauge(ctx, fp, del, endedPeriod) }); err != nil { return err } @@ -90,7 +90,7 @@ func (k Keeper) btcDelegationModifiedWithPreInitDel( return err } - if err := k.CalculateBTCDelegationRewardsAndSend(ctx, fp, del, endedPeriod); err != nil { + if err := k.CalculateBTCDelegationRewardsAndSendToGauge(ctx, fp, del, endedPeriod); err != nil { return err } @@ -101,7 +101,7 @@ func (k Keeper) btcDelegationModifiedWithPreInitDel( return k.initializeBTCDelegation(ctx, fp, del) } -func (k Keeper) CalculateBTCDelegationRewardsAndSend(ctx context.Context, fp, del sdk.AccAddress, endPeriod uint64) error { +func (k Keeper) CalculateBTCDelegationRewardsAndSendToGauge(ctx context.Context, fp, del sdk.AccAddress, endPeriod uint64) error { rewards, err := k.CalculateBTCDelegationRewards(ctx, fp, del, endPeriod) if err != nil { if !errors.Is(err, types.ErrBTCDelegationRewardsTrackerNotFound) { diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index 86883984c..41c24fe8c 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -13,7 +13,7 @@ import ( // storeBTCDelegatorToFp returns the KVStore of the mapping del => fp // note: it stores the finality provider as key and sets a one byte as value // so each BTC delegator address can have multiple finality providers. -// Usefull to iterate over all the pairs (fp,del) by filtering the +// Useful to iterate over all the pairs (fp,del) by filtering the // delegator address. // prefix: BTCDelegatorToFPKey // key: (DelAddr, FpAddr) @@ -53,6 +53,7 @@ func (k Keeper) storeFpHistoricalRewards(ctx context.Context, fp sdk.AccAddress) return prefix.NewStore(st, fp.Bytes()) } +// setBTCDelegatorToFP sets a new delegator to finality provider record. func (k Keeper) setBTCDelegatorToFP(ctx context.Context, del, fp sdk.AccAddress) { st := k.storeBTCDelegatorToFp(ctx, del) st.Set(fp.Bytes(), []byte{0x00}) @@ -169,18 +170,18 @@ func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.Ac // deleteAllFromFinalityProviderRwd deletes all the data related to Finality Provider Rewards // Historical and current from a fp address key. func (k Keeper) deleteAllFromFinalityProviderRwd(ctx context.Context, fp sdk.AccAddress) { - st := k.storeFpHistoricalRewards(ctx, fp) + stHistoricalRwd := k.storeFpHistoricalRewards(ctx, fp) - keys := make([][]byte, 0) - - iter := st.Iterator(nil, nil) + iter := stHistoricalRwd.Iterator(nil, nil) defer iter.Close() + + keys := make([][]byte, 0) for ; iter.Valid(); iter.Next() { keys = append(keys, iter.Key()) } for _, key := range keys { - st.Delete(key) + stHistoricalRwd.Delete(key) } k.deleteFinalityProviderCurrentRewards(ctx, fp) @@ -192,13 +193,15 @@ func (k Keeper) deleteFinalityProviderCurrentRewards(ctx context.Context, fp sdk k.storeFpCurrentRewards(ctx).Delete(key) } +// GetFinalityProviderHistoricalRewards returns the FinalityProviderHistoricalRewards based on the key (fp, period) +// It returns an error if the key is not found inside the store. func (k Keeper) GetFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64) (types.FinalityProviderHistoricalRewards, error) { key := make([]byte, 8) binary.LittleEndian.PutUint64(key, period) bz := k.storeFpHistoricalRewards(ctx, fp).Get(key) if bz == nil { - return types.FinalityProviderHistoricalRewards{}, types.ErrFPCurrentRewardsNotFound + return types.FinalityProviderHistoricalRewards{}, types.ErrFPHistoricalRewardsNotFound } var value types.FinalityProviderHistoricalRewards @@ -208,6 +211,8 @@ func (k Keeper) GetFinalityProviderHistoricalRewards(ctx context.Context, fp sdk return value, nil } +// setFinalityProviderHistoricalRewards sets a new value inside the store, it returns an error +// if the marshal of the `rwd` fails. func (k Keeper) setFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64, rwd types.FinalityProviderHistoricalRewards) error { key := make([]byte, 8) binary.LittleEndian.PutUint64(key, period) diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index 2a14d9917..f207894c3 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -213,6 +213,57 @@ func FuzzCheckFinalityProviderCurrentRewards(f *testing.F) { }) } +func FuzzCheckFinalityProviderHistoricalRewards(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp1, fp2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + fp1Period1 := datagen.RandomInt(r, 10) + _, err := k.GetFinalityProviderHistoricalRewards(ctx, fp1, fp1Period1) + require.EqualError(t, err, types.ErrFPHistoricalRewardsNotFound.Error()) + + expectedHistRwdFp1 := datagen.GenRandomFinalityProviderHistoricalRewards(r) + err = k.setFinalityProviderHistoricalRewards(ctx, fp1, fp1Period1, expectedHistRwdFp1) + require.NoError(t, err) + + fp1Period1Historical, err := k.GetFinalityProviderHistoricalRewards(ctx, fp1, fp1Period1) + require.NoError(t, err) + require.Equal(t, expectedHistRwdFp1.CumulativeRewardsPerSat.String(), fp1Period1Historical.CumulativeRewardsPerSat.String()) + + // sets multiple historical for fp2 + fp2Period1Historical := datagen.RandomInt(r, 10) + err = k.setFinalityProviderHistoricalRewards(ctx, fp2, fp2Period1Historical, datagen.GenRandomFinalityProviderHistoricalRewards(r)) + require.NoError(t, err) + fp2Period2Historical := datagen.RandomInt(r, 10) + err = k.setFinalityProviderHistoricalRewards(ctx, fp2, fp2Period2Historical, datagen.GenRandomFinalityProviderHistoricalRewards(r)) + require.NoError(t, err) + + // sets a new current fp rwd to check the delete all + err = k.setFinalityProviderCurrentRewards(ctx, fp2, datagen.GenRandomFinalityProviderCurrentRewards(r)) + require.NoError(t, err) + + _, err = k.GetFinalityProviderCurrentRewards(ctx, fp2) + require.NoError(t, err) + + // deleted all from fp2 + k.deleteAllFromFinalityProviderRwd(ctx, fp2) + + _, err = k.GetFinalityProviderCurrentRewards(ctx, fp2) + require.EqualError(t, err, types.ErrFPCurrentRewardsNotFound.Error()) + + _, err = k.GetFinalityProviderHistoricalRewards(ctx, fp2, fp2Period1Historical) + require.EqualError(t, err, types.ErrFPHistoricalRewardsNotFound.Error()) + + _, err = k.GetFinalityProviderHistoricalRewards(ctx, fp2, fp2Period2Historical) + require.EqualError(t, err, types.ErrFPHistoricalRewardsNotFound.Error()) + }) +} + func NewKeeperWithCtx(t *testing.T) (Keeper, sdk.Context) { encConf := appparams.DefaultEncodingConfig() ctx, kvStore := store.NewStoreWithCtx(t, types.ModuleName) From 3350ea878551700ceecad10222e2215309aa63b0 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 19:00:25 -0300 Subject: [PATCH 030/132] chore: moved simple sum sub to store file --- x/incentive/keeper/btc_staking_gauge_test.go | 23 ++-- x/incentive/keeper/reward_tracker.go | 29 +---- x/incentive/keeper/reward_tracker_store.go | 32 +++++ .../keeper/reward_tracker_store_test.go | 116 ++++++++++++++++- x/incentive/keeper/reward_tracker_test.go | 120 +----------------- 5 files changed, 164 insertions(+), 156 deletions(-) diff --git a/x/incentive/keeper/btc_staking_gauge_test.go b/x/incentive/keeper/btc_staking_gauge_test.go index 846ef7554..e73a27b65 100644 --- a/x/incentive/keeper/btc_staking_gauge_test.go +++ b/x/incentive/keeper/btc_staking_gauge_test.go @@ -24,14 +24,14 @@ func FuzzRewardBTCStaking(f *testing.F) { // mock bank keeper bankKeeper := types.NewMockBankKeeper(ctrl) - // create incentive keeper - keeper, ctx := testkeeper.IncentiveKeeper(t, bankKeeper, nil, nil) + // create incentive k + k, ctx := testkeeper.IncentiveKeeper(t, bankKeeper, nil, nil) height := datagen.RandomInt(r, 1000) ctx = datagen.WithCtxHeight(ctx, height) // set a random gauge gauge := datagen.GenRandomGauge(r) - keeper.SetBTCStakingGauge(ctx, height, gauge) + k.SetBTCStakingGauge(ctx, height, gauge) // generate a random voting power distribution cache dc, err := datagen.GenRandomVotingPowerDistCache(r, 100) @@ -57,7 +57,7 @@ func FuzzRewardBTCStaking(f *testing.F) { fpAddr := fp.GetAddress() for _, btcDel := range fp.BtcDels { - err := keeper.BtcDelegationActivated(ctx, fpAddr, btcDel.GetAddress(), btcDel.TotalSat) + err := k.BtcDelegationActivated(ctx, fpAddr, btcDel.GetAddress(), btcDel.TotalSat) require.NoError(t, err) btcDelPortion := fp.GetBTCDelPortion(btcDel) @@ -70,21 +70,21 @@ func FuzzRewardBTCStaking(f *testing.F) { } // distribute rewards in the gauge to finality providers/delegations - keeper.RewardBTCStaking(ctx, height, dc) + k.RewardBTCStaking(ctx, height, dc) for _, fp := range dc.FinalityProviders { fpAddr := fp.GetAddress() for _, btcDel := range fp.BtcDels { delAddr := btcDel.GetAddress() - delRwd, err := keeper.GetBTCDelegationRewardsTracker(ctx, fpAddr, delAddr) + delRwd, err := k.GetBTCDelegationRewardsTracker(ctx, fpAddr, delAddr) require.NoError(t, err) require.Equal(t, delRwd.TotalActiveSat.Uint64(), btcDel.TotalSat) // makes sure the rewards added reach the delegation gauge - err = keeper.SendBtcDelegationRewardsToGauge(ctx, fpAddr, delAddr) + err = k.SendBtcDelegationRewardsToGauge(ctx, fpAddr, delAddr) require.NoError(t, err) } - fpCurrentRwd, err := keeper.GetFinalityProviderCurrentRewards(ctx, fpAddr) + fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fpAddr) require.NoError(t, err) require.Equal(t, fpCurrentRwd.TotalActiveSat.Uint64(), fp.TotalBondedSat) } @@ -93,7 +93,7 @@ func FuzzRewardBTCStaking(f *testing.F) { for addrStr, reward := range fpRewardMap { addr, err := sdk.AccAddressFromBech32(addrStr) require.NoError(t, err) - rg := keeper.GetRewardGauge(ctx, types.FinalityProviderType, addr) + rg := k.GetRewardGauge(ctx, types.FinalityProviderType, addr) require.NotNil(t, rg) require.Equal(t, reward, rg.Coins) } @@ -102,13 +102,14 @@ func FuzzRewardBTCStaking(f *testing.F) { for addrStr, reward := range btcDelRewardMap { addr, err := sdk.AccAddressFromBech32(addrStr) require.NoError(t, err) - rg := keeper.GetRewardGauge(ctx, types.BTCDelegationType, addr) + rg := k.GetRewardGauge(ctx, types.BTCDelegationType, addr) require.NotNil(t, rg) // A little bit of rewards could be lost in the process due to precision points // so 0.1% difference can be considered okay allowedMarginError := CalculatePointOnePercent(reward) - require.Truef(t, reward.Sub(rg.Coins...).IsAllLT(allowedMarginError), + diff, _ := reward.SafeSub(rg.Coins...) + require.Truef(t, diff.IsAllLT(allowedMarginError), "BTC delegation failed within the margin of error: %s\nRewards: %s\nGauge: %s", allowedMarginError.String(), reward.String(), rg.Coins.String(), ) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 7eb5801cc..5681c77ed 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -65,7 +65,7 @@ func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddre func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { amtSat := sdkmath.NewIntFromUint64(sat) return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { - return k.SubDelegationSat(ctx, fp, del, amtSat) + return k.subDelegationSat(ctx, fp, del, amtSat) }) } @@ -270,16 +270,6 @@ func (k Keeper) addFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) } -func (k Keeper) subFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress, amt sdkmath.Int) error { - fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) - if err != nil { - return err - } - - fpCurrentRwd.SubTotalActiveSat(amt) - return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) -} - func (k Keeper) AddFinalityProviderRewardsForDelegationsBTC(ctx context.Context, fp sdk.AccAddress, rwd sdk.Coins) error { fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) if err != nil { @@ -309,20 +299,3 @@ func (k Keeper) AddDelegationSat(ctx context.Context, fp, del sdk.AccAddress, am return k.addFinalityProviderStaked(ctx, fp, amt) } - -// SubDelegationSat there is no need to check if the fp or delegation exists, because they should exist -// otherwise it is probably a programming error calling to subtract the amount of active sat without -// having any sat added in the first place. -func (k Keeper) SubDelegationSat(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { - btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) - if err != nil { - return err - } - - btcDelRwdTracker.SubTotalActiveSat(amt) - if err := k.setBTCDelegationRewardsTracker(ctx, fp, del, btcDelRwdTracker); err != nil { - return err - } - - return k.subFinalityProviderStaked(ctx, fp, amt) -} diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index 41c24fe8c..39fe66c25 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -4,6 +4,7 @@ import ( "context" "encoding/binary" + sdkmath "cosmossdk.io/math" "cosmossdk.io/store/prefix" "github.com/babylonlabs-io/babylon/x/incentive/types" "github.com/cosmos/cosmos-sdk/runtime" @@ -225,3 +226,34 @@ func (k Keeper) setFinalityProviderHistoricalRewards(ctx context.Context, fp sdk k.storeFpHistoricalRewards(ctx, fp).Set(key, bz) return nil } + +// subDelegationSat subtracts an amount of active stake from the BTCDelegationRewardsTracker +// and the FinalityProviderCurrentRewards. +// There is no need to check if the fp or delegation exists, because they should exist +// otherwise it is probably a programming error calling to subtract the amount of active sat without +// having any sat added in the first place that created the structures. +func (k Keeper) subDelegationSat(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { + btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) + if err != nil { + return err + } + + btcDelRwdTracker.SubTotalActiveSat(amt) + if err := k.setBTCDelegationRewardsTracker(ctx, fp, del, btcDelRwdTracker); err != nil { + return err + } + + return k.subFinalityProviderStaked(ctx, fp, amt) +} + +// subFinalityProviderStaked subtracts an amount of active stake from the +// FinalityProviderCurrentRewards, it errors out if the finality provider does not exist. +func (k Keeper) subFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress, amt sdkmath.Int) error { + fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) + if err != nil { + return err + } + + fpCurrentRwd.SubTotalActiveSat(amt) + return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) +} diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index f207894c3..8fd3765ba 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -264,9 +264,121 @@ func FuzzCheckFinalityProviderHistoricalRewards(f *testing.F) { }) } -func NewKeeperWithCtx(t *testing.T) (Keeper, sdk.Context) { +func TestAddSubDelegationSat(t *testing.T) { + k, ctx := NewKeeperWithCtx(t) + + fp1, del1 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + fp2, del2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + amtFp1Del1, amtFp1Del2, amtFp2Del2, amtFp2Del1 := math.NewInt(2000), math.NewInt(4000), math.NewInt(500), math.NewInt(700) + + _, err := k.GetBTCDelegationRewardsTracker(ctx, fp1, del1) + require.EqualError(t, err, types.ErrBTCDelegationRewardsTrackerNotFound.Error()) + + // adds 2000 for fp1, del1 + // fp1 => 2000 + // fp1, del1 => 2000 + err = k.AddDelegationSat(ctx, fp1, del1, amtFp1Del1) + require.NoError(t, err) + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) + + btcDelRwdFp1Del1, err := k.GetBTCDelegationRewardsTracker(ctx, fp1, del1) + require.NoError(t, err) + // if the normal flow with initilize BTC delegation would have been called, + // it would start as 1. + require.Equal(t, btcDelRwdFp1Del1.StartPeriodCumulativeReward, uint64(0)) + + // adds 4000 for fp1, del2 + // fp1 => 6000 + // fp1, del1 => 2000 + // fp1, del2 => 4000 + err = k.AddDelegationSat(ctx, fp1, del2, amtFp1Del2) + require.NoError(t, err) + + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) + checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) + + // adds 500 for fp2, del2 + // fp1 => 6000 + // fp2 => 500 + // fp1, del1 => 2000 + // fp1, del2 => 4000 + // fp2, del2 => 500 + err = k.AddDelegationSat(ctx, fp2, del2, amtFp2Del2) + require.NoError(t, err) + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) + checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) + checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2) + checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2) + + // adds 700 for fp2, del1 + // fp1 => 6000 + // fp2 => 1200 + // fp1, del1 => 2000 + // fp1, del2 => 4000 + // fp2, del1 => 700 + // fp2, del2 => 500 + err = k.AddDelegationSat(ctx, fp2, del1, amtFp2Del1) + require.NoError(t, err) + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) + checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2.Add(amtFp2Del1)) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) + checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2) + checkFpDelTotalSat(t, ctx, k, fp2, del1, amtFp2Del1) + checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2) + + lastAmtFp1Del2 := math.NewInt(2000) + // adds 2000 for fp1, del2 + // fp1 => 8000 + // fp2 => 1200 + // fp1, del1 => 2000 + // fp1, del2 => 6000 + // fp2, del1 => 700 + // fp2, del2 => 500 + err = k.AddDelegationSat(ctx, fp1, del2, lastAmtFp1Del2) + require.NoError(t, err) + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2).Add(lastAmtFp1Del2)) + checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2.Add(amtFp2Del1)) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) + checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2.Add(lastAmtFp1Del2)) + checkFpDelTotalSat(t, ctx, k, fp2, del1, amtFp2Del1) + checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2) + + subAmtFp2Del2 := math.NewInt(350) + // subtract 350 for fp2, del2 + // fp1 => 8000 + // fp2 => 850 + // fp1, del1 => 2000 + // fp1, del2 => 6000 + // fp2, del1 => 700 + // fp2, del2 => 150 + err = k.subDelegationSat(ctx, fp2, del2, subAmtFp2Del2) + require.NoError(t, err) + checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2).Add(lastAmtFp1Del2)) + checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2.Add(amtFp2Del1).Sub(subAmtFp2Del2)) + checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) + checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2.Add(lastAmtFp1Del2)) + checkFpDelTotalSat(t, ctx, k, fp2, del1, amtFp2Del1) + checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2.Sub(subAmtFp2Del2)) +} + +func checkFpTotalSat(t *testing.T, ctx sdk.Context, k *Keeper, fp sdk.AccAddress, expectedSat math.Int) { + rwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) + require.NoError(t, err) + require.Equal(t, expectedSat.String(), rwd.TotalActiveSat.String()) +} + +func checkFpDelTotalSat(t *testing.T, ctx sdk.Context, k *Keeper, fp, del sdk.AccAddress, expectedSat math.Int) { + rwd, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) + require.NoError(t, err) + require.Equal(t, expectedSat.String(), rwd.TotalActiveSat.String()) +} + +func NewKeeperWithCtx(t *testing.T) (*Keeper, sdk.Context) { encConf := appparams.DefaultEncodingConfig() ctx, kvStore := store.NewStoreWithCtx(t, types.ModuleName) k := NewKeeper(encConf.Codec, kvStore, nil, nil, nil, addr.AccGov.String(), addr.AccFeeCollector.String()) - return k, ctx + return &k, ctx } diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index f5d281cf2..561bd9b42 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -1,4 +1,4 @@ -package keeper_test +package keeper import ( "testing" @@ -6,122 +6,12 @@ import ( "cosmossdk.io/math" appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/testutil/datagen" - keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" - "github.com/babylonlabs-io/babylon/x/incentive/keeper" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) -func TestAddSubDelegationSat(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() - k, ctx := keepertest.IncentiveKeeper(t, nil, nil, nil) - - fp1, del1 := datagen.GenRandomAddress(), datagen.GenRandomAddress() - fp2, del2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() - amtFp1Del1, amtFp1Del2, amtFp2Del2, amtFp2Del1 := math.NewInt(2000), math.NewInt(4000), math.NewInt(500), math.NewInt(700) - - // adds 2000 for fp1, del1 - // fp1 => 2000 - // fp1, del1 => 2000 - err := k.AddDelegationSat(ctx, fp1, del1, amtFp1Del1) - require.NoError(t, err) - checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1) - checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) - - // adds 4000 for fp1, del2 - // fp1 => 6000 - // fp1, del1 => 2000 - // fp1, del2 => 4000 - err = k.AddDelegationSat(ctx, fp1, del2, amtFp1Del2) - require.NoError(t, err) - - checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) - checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2) - checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) - - // adds 500 for fp2, del2 - // fp1 => 6000 - // fp2 => 500 - // fp1, del1 => 2000 - // fp1, del2 => 4000 - // fp2, del2 => 500 - err = k.AddDelegationSat(ctx, fp2, del2, amtFp2Del2) - require.NoError(t, err) - checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) - checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2) - checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) - checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2) - checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2) - - // adds 700 for fp2, del1 - // fp1 => 6000 - // fp2 => 1200 - // fp1, del1 => 2000 - // fp1, del2 => 4000 - // fp2, del1 => 700 - // fp2, del2 => 500 - err = k.AddDelegationSat(ctx, fp2, del1, amtFp2Del1) - require.NoError(t, err) - checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) - checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2.Add(amtFp2Del1)) - checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) - checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2) - checkFpDelTotalSat(t, ctx, k, fp2, del1, amtFp2Del1) - checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2) - - lastAmtFp1Del2 := math.NewInt(2000) - // adds 2000 for fp1, del2 - // fp1 => 8000 - // fp2 => 1200 - // fp1, del1 => 2000 - // fp1, del2 => 6000 - // fp2, del1 => 700 - // fp2, del2 => 500 - err = k.AddDelegationSat(ctx, fp1, del2, lastAmtFp1Del2) - require.NoError(t, err) - checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2).Add(lastAmtFp1Del2)) - checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2.Add(amtFp2Del1)) - checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) - checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2.Add(lastAmtFp1Del2)) - checkFpDelTotalSat(t, ctx, k, fp2, del1, amtFp2Del1) - checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2) - - subAmtFp2Del2 := math.NewInt(350) - // subtract 350 for fp2, del2 - // fp1 => 8000 - // fp2 => 850 - // fp1, del1 => 2000 - // fp1, del2 => 6000 - // fp2, del1 => 700 - // fp2, del2 => 150 - err = k.SubDelegationSat(ctx, fp2, del2, subAmtFp2Del2) - require.NoError(t, err) - checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2).Add(lastAmtFp1Del2)) - checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2.Add(amtFp2Del1).Sub(subAmtFp2Del2)) - checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) - checkFpDelTotalSat(t, ctx, k, fp1, del2, amtFp1Del2.Add(lastAmtFp1Del2)) - checkFpDelTotalSat(t, ctx, k, fp2, del1, amtFp2Del1) - checkFpDelTotalSat(t, ctx, k, fp2, del2, amtFp2Del2.Sub(subAmtFp2Del2)) -} - -func checkFpTotalSat(t *testing.T, ctx sdk.Context, k *keeper.Keeper, fp sdk.AccAddress, expectedSat math.Int) { - rwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) - require.NoError(t, err) - require.Equal(t, expectedSat.String(), rwd.TotalActiveSat.String()) -} - -func checkFpDelTotalSat(t *testing.T, ctx sdk.Context, k *keeper.Keeper, fp, del sdk.AccAddress, expectedSat math.Int) { - rwd, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) - require.NoError(t, err) - require.Equal(t, expectedSat.String(), rwd.TotalActiveSat.String()) -} - func TestIncrementFinalityProviderPeriod(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() - k, ctx := keepertest.IncentiveKeeper(t, nil, nil, nil) + k, ctx := NewKeeperWithCtx(t) fp1, fp2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() del1 := datagen.GenRandomAddress() @@ -151,7 +41,7 @@ func TestIncrementFinalityProviderPeriod(t *testing.T) { require.Equal(t, fp1EndedPeriod, uint64(1)) // now the historical that just ended should have as cumulative rewards 4000ubbn 2_000000ubbn/500sats - checkFpHistoricalRwd(t, ctx, k, fp1, fp1EndedPeriod, newBaseCoins(4000).MulInt(keeper.DecimalAccumulatedRewards)) + checkFpHistoricalRwd(t, ctx, k, fp1, fp1EndedPeriod, newBaseCoins(4000).MulInt(DecimalAccumulatedRewards)) checkFpCurrentRwd(t, ctx, k, fp1, fp1EndedPeriod+1, sdk.NewCoins(), satsDelegated) fp2EndedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp2) @@ -159,13 +49,13 @@ func TestIncrementFinalityProviderPeriod(t *testing.T) { require.Equal(t, fp2EndedPeriod, uint64(1)) } -func checkFpHistoricalRwd(t *testing.T, ctx sdk.Context, k *keeper.Keeper, fp sdk.AccAddress, period uint64, expectedRwd sdk.Coins) { +func checkFpHistoricalRwd(t *testing.T, ctx sdk.Context, k *Keeper, fp sdk.AccAddress, period uint64, expectedRwd sdk.Coins) { historical, err := k.GetFinalityProviderHistoricalRewards(ctx, fp, period) require.NoError(t, err) require.Equal(t, historical.CumulativeRewardsPerSat.String(), expectedRwd.String()) } -func checkFpCurrentRwd(t *testing.T, ctx sdk.Context, k *keeper.Keeper, fp sdk.AccAddress, expectedPeriod uint64, expectedRwd sdk.Coins, totalActiveSat math.Int) { +func checkFpCurrentRwd(t *testing.T, ctx sdk.Context, k *Keeper, fp sdk.AccAddress, expectedPeriod uint64, expectedRwd sdk.Coins, totalActiveSat math.Int) { fp1CurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) require.NoError(t, err) require.Equal(t, fp1CurrentRwd.CurrentRewards.String(), expectedRwd.String()) From ab11cd0a2be886f312529dd6f95c7dc297d50e5e Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 19:48:59 -0300 Subject: [PATCH 031/132] chore: add test for sub fp staked --- .../keeper/reward_tracker_store_test.go | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index 8fd3765ba..054a6dea2 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -264,6 +264,33 @@ func FuzzCheckFinalityProviderHistoricalRewards(f *testing.F) { }) } +func FuzzChecksubFinalityProviderStaked(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp1, fp2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + amtSub := datagen.RandomMathInt(r, 100) + err := k.subFinalityProviderStaked(ctx, fp1, amtSub) + require.EqualError(t, err, types.ErrFPCurrentRewardsNotFound.Error()) + + fp2Set := datagen.GenRandomFinalityProviderCurrentRewards(r) + err = k.setFinalityProviderCurrentRewards(ctx, fp2, fp2Set) + require.NoError(t, err) + + err = k.subFinalityProviderStaked(ctx, fp2, fp2Set.TotalActiveSat) + require.NoError(t, err) + + fp2CurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp2) + require.NoError(t, err) + require.True(t, fp2CurrentRwd.TotalActiveSat.IsZero()) + }) +} + func TestAddSubDelegationSat(t *testing.T) { k, ctx := NewKeeperWithCtx(t) From 6ff435835fafb03611afb0c7b44b79b231d653f8 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 19:55:34 -0300 Subject: [PATCH 032/132] chore: add test for sub delegations sat --- .../keeper/reward_tracker_store_test.go | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index 054a6dea2..6837596c9 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -264,7 +264,7 @@ func FuzzCheckFinalityProviderHistoricalRewards(f *testing.F) { }) } -func FuzzChecksubFinalityProviderStaked(f *testing.F) { +func FuzzCheckSubFinalityProviderStaked(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) f.Fuzz(func(t *testing.T, seed int64) { @@ -291,6 +291,44 @@ func FuzzChecksubFinalityProviderStaked(f *testing.F) { }) } +func FuzzCheckSubDelegationSat(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp, del := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + amtToSub := datagen.RandomMathInt(r, 10000).AddRaw(10) + err := k.subDelegationSat(ctx, fp, del, amtToSub) + require.EqualError(t, err, types.ErrBTCDelegationRewardsTrackerNotFound.Error()) + + amtInRwd := amtToSub.AddRaw(120) + err = k.setBTCDelegationRewardsTracker(ctx, fp, del, types.NewBTCDelegationRewardsTracker(1, amtInRwd)) + require.NoError(t, err) + + fpCurrentRwd := datagen.GenRandomFinalityProviderCurrentRewards(r) + fpCurrentRwd.TotalActiveSat = amtInRwd + err = k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) + require.NoError(t, err) + + err = k.subDelegationSat(ctx, fp, del, amtToSub) + require.NoError(t, err) + + expectedAmt := amtInRwd.Sub(amtToSub) + + delRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) + require.NoError(t, err) + require.Equal(t, expectedAmt.String(), delRwdTracker.TotalActiveSat.String()) + + fpCurrentRwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp) + require.NoError(t, err) + require.Equal(t, expectedAmt.String(), fpCurrentRwd.TotalActiveSat.String()) + }) +} + func TestAddSubDelegationSat(t *testing.T) { k, ctx := NewKeeperWithCtx(t) From 7e594ab1eaef252e3eae6dfb0bcedf2f97269036 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 21:08:15 -0300 Subject: [PATCH 033/132] chore: tryfix test --- test/e2e/btc_staking_pre_approval_e2e_test.go | 2 +- x/incentive/keeper/btc_staking_gauge_test.go | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/test/e2e/btc_staking_pre_approval_e2e_test.go b/test/e2e/btc_staking_pre_approval_e2e_test.go index 8fcdd6d1d..73e7fbdd2 100644 --- a/test/e2e/btc_staking_pre_approval_e2e_test.go +++ b/test/e2e/btc_staking_pre_approval_e2e_test.go @@ -382,7 +382,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test4CommitPublicRandomnessAndSubmitFin s.NoError(err) btcPK := bbn.NewBIP340PubKeyFromBTCPK(pk) nonValidatorNode.AddFinalitySig(btcPK, activatedHeight, &randListInfo.PRList[idx], *randListInfo.ProofList[idx].ToProto(), appHash, eotsSig) - nonValidatorNode.WaitForNextBlock() + nonValidatorNode.WaitForNextBlocks(2) }, false) // ensure finality provider has received rewards after the block is finalised diff --git a/x/incentive/keeper/btc_staking_gauge_test.go b/x/incentive/keeper/btc_staking_gauge_test.go index e73a27b65..13e0e37c5 100644 --- a/x/incentive/keeper/btc_staking_gauge_test.go +++ b/x/incentive/keeper/btc_staking_gauge_test.go @@ -133,5 +133,18 @@ func CalculatePointOnePercent(value sdk.Coins) sdk.Coins { numerator := math.NewInt(1) // 0.1% as numerator denominator := math.NewInt(1000) // 0.1% denominator result := value.MulInt(numerator).QuoInt(denominator) - return result + return coinsAtLeastMinAmount(result, math.OneInt()) +} + +func coinsAtLeastMinAmount(value sdk.Coins, minAmt math.Int) sdk.Coins { + ret := sdk.NewCoins() + for _, v := range value { + if v.Amount.GT(minAmt) { + ret = ret.Add(v) + continue + } + ret = ret.Add(sdk.NewCoin(v.Denom, minAmt)) + } + return ret + } From c861835386df4eb1750ece278a21a9d25d628db7 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 21:21:09 -0300 Subject: [PATCH 034/132] tryfix: e2e test --- test/e2e/btc_staking_e2e_test.go | 4 ++-- test/e2e/e2e_test.go | 1 + x/incentive/keeper/btc_staking_gauge.go | 2 +- x/incentive/keeper/reward_tracker.go | 20 +------------------- x/incentive/keeper/reward_tracker_store.go | 22 ++++++++++++++++++++++ x/incentive/keeper/reward_tracker_test.go | 2 +- 6 files changed, 28 insertions(+), 23 deletions(-) diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index 448898987..66c974287 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -318,7 +318,7 @@ func (s *BTCStakingTestSuite) Test3CommitPublicRandomnessAndSubmitFinalitySignat return false } return activatedHeight > 0 - }, time.Minute, time.Millisecond*50) + }, time.Minute*3, time.Millisecond*50) s.T().Logf("the activated height is %d", activatedHeight) /* @@ -652,7 +652,7 @@ func (s *BTCStakingTestSuite) Test7BTCDelegationFeeGrant() { func (s *BTCStakingTestSuite) Test8BTCDelegationFeeGrantTyped() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - node, err := chainA.GetNodeAtIndex(2) + node, err := chainA.GetNodeAtIndex(0) s.NoError(err) wGratee, wGranter := "staker", "feePayer" diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 8e0908f9b..e041082e3 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -23,6 +23,7 @@ func TestBTCTimestampingTestSuite(t *testing.T) { func TestBTCStakingTestSuite(t *testing.T) { suite.Run(t, new(BTCStakingTestSuite)) } + func TestBTCStakingPreApprovalTestSuite(t *testing.T) { suite.Run(t, new(BTCStakingPreApprovalTestSuite)) } diff --git a/x/incentive/keeper/btc_staking_gauge.go b/x/incentive/keeper/btc_staking_gauge.go index b8b70c780..8d6609aaa 100644 --- a/x/incentive/keeper/btc_staking_gauge.go +++ b/x/incentive/keeper/btc_staking_gauge.go @@ -38,7 +38,7 @@ func (k Keeper) RewardBTCStaking(ctx context.Context, height uint64, dc *ftypes. // reward the rest of coins to each BTC delegation proportional to its voting power portion coinsForBTCDels := coinsForFpsAndDels.Sub(coinsForCommission...) - if err := k.AddFinalityProviderRewardsForDelegationsBTC(ctx, fp.GetAddress(), coinsForBTCDels); err != nil { + if err := k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp.GetAddress(), coinsForBTCDels); err != nil { panic(err) } } diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 5681c77ed..844b4ddab 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -252,25 +252,7 @@ func (k Keeper) initializeBTCDelegation(ctx context.Context, fp, del sdk.AccAddr return k.setBTCDelegationRewardsTracker(ctx, fp, del, rwd) } -func (k Keeper) addFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress, amt sdkmath.Int) error { - fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) - if err != nil { - if !errors.Is(err, types.ErrFPCurrentRewardsNotFound) { - return err - } - - // this is needed as the amount of sats for the FP is inside the FpCurrentRewards - fpCurrentRwd, err = k.initializeFinalityProvider(ctx, fp) - if err != nil { - return err - } - } - - fpCurrentRwd.AddTotalActiveSat(amt) - return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) -} - -func (k Keeper) AddFinalityProviderRewardsForDelegationsBTC(ctx context.Context, fp sdk.AccAddress, rwd sdk.Coins) error { +func (k Keeper) AddFinalityProviderRewardsForBtcDelegations(ctx context.Context, fp sdk.AccAddress, rwd sdk.Coins) error { fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) if err != nil { return err diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index 39fe66c25..bdf4dbadb 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -3,6 +3,7 @@ package keeper import ( "context" "encoding/binary" + "errors" sdkmath "cosmossdk.io/math" "cosmossdk.io/store/prefix" @@ -257,3 +258,24 @@ func (k Keeper) subFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress fpCurrentRwd.SubTotalActiveSat(amt) return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) } + +// addFinalityProviderStaked increases the total amount of active satoshi to a finality provider +// if it does not exist one current reward in the store, it initializes a new one +// The initialization of a finality provider also stores one historical fp reward. +func (k Keeper) addFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress, amt sdkmath.Int) error { + fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) + if err != nil { + if !errors.Is(err, types.ErrFPCurrentRewardsNotFound) { + return err + } + + // this is needed as the amount of sats for the FP is inside the FpCurrentRewards + fpCurrentRwd, err = k.initializeFinalityProvider(ctx, fp) + if err != nil { + return err + } + } + + fpCurrentRwd.AddTotalActiveSat(amt) + return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) +} diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index 561bd9b42..a81929d83 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -24,7 +24,7 @@ func TestIncrementFinalityProviderPeriod(t *testing.T) { checkFpHistoricalRwd(t, ctx, k, fp1, 0, sdk.NewCoins()) rwdAddedToPeriod1 := newBaseCoins(2_000000) // 2bbn - err = k.AddFinalityProviderRewardsForDelegationsBTC(ctx, fp1, rwdAddedToPeriod1) + err = k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp1, rwdAddedToPeriod1) require.NoError(t, err) // historical should not modify the rewards for the period already created From 2791f70997823a78e50d1e1393bce584ae4819d0 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 21:32:16 -0300 Subject: [PATCH 035/132] chore: add test for addFinalityProviderStaked --- .../keeper/reward_tracker_store_test.go | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index 6837596c9..d437bf924 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -329,6 +329,57 @@ func FuzzCheckSubDelegationSat(f *testing.F) { }) } +func FuzzCheckAddFinalityProviderStaked(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp1, fp2 := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + amtAdded := datagen.RandomMathInt(r, 1000) + err := k.addFinalityProviderStaked(ctx, fp1, amtAdded) + require.NoError(t, err) + + currentRwdFp1, err := k.GetFinalityProviderCurrentRewards(ctx, fp1) + require.NoError(t, err) + require.Equal(t, currentRwdFp1.TotalActiveSat, amtAdded) + require.Equal(t, currentRwdFp1.Period, uint64(1)) + require.Equal(t, currentRwdFp1.CurrentRewards.String(), sdk.NewCoins().String()) + + err = k.addFinalityProviderStaked(ctx, fp1, amtAdded) + require.NoError(t, err) + currentRwdFp1, err = k.GetFinalityProviderCurrentRewards(ctx, fp1) + require.NoError(t, err) + require.Equal(t, currentRwdFp1.TotalActiveSat, amtAdded.MulRaw(2)) + require.Equal(t, currentRwdFp1.Period, uint64(1)) + require.Equal(t, currentRwdFp1.CurrentRewards.String(), sdk.NewCoins().String()) + + currentRwdFp2, err := k.initializeFinalityProvider(ctx, fp2) + require.NoError(t, err) + + rwdOnFp2 := datagen.GenRandomCoins(r) + err = k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp2, rwdOnFp2) + require.NoError(t, err) + + require.Equal(t, currentRwdFp2.TotalActiveSat, math.ZeroInt()) + require.Equal(t, currentRwdFp2.Period, uint64(1)) + require.Equal(t, currentRwdFp2.CurrentRewards.String(), sdk.NewCoins().String()) + + amtAddedToFp2 := datagen.RandomMathInt(r, 1000) + err = k.addFinalityProviderStaked(ctx, fp2, amtAddedToFp2) + require.NoError(t, err) + + currentRwdFp2, err = k.GetFinalityProviderCurrentRewards(ctx, fp2) + require.NoError(t, err) + require.Equal(t, currentRwdFp2.TotalActiveSat.String(), amtAddedToFp2.String()) + require.Equal(t, currentRwdFp2.Period, uint64(1)) + require.Equal(t, currentRwdFp2.CurrentRewards.String(), rwdOnFp2.String()) + }) +} + func TestAddSubDelegationSat(t *testing.T) { k, ctx := NewKeeperWithCtx(t) From fc01c10b9af3afba1246270961b9d557e006d5f2 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 21:54:20 -0300 Subject: [PATCH 036/132] chore: add test to AddDelegationSat --- x/incentive/keeper/reward_tracker.go | 58 +++++-------- .../keeper/reward_tracker_store_test.go | 85 +++++++++++++++++++ 2 files changed, 106 insertions(+), 37 deletions(-) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 844b4ddab..c59aff5f9 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -18,16 +18,27 @@ var ( DecimalAccumulatedRewards, _ = sdkmath.NewIntFromString("100000000000000000000") ) -func (k Keeper) FpSlashed(ctx context.Context, fp sdk.AccAddress) error { - // withdrawDelegationRewards - // Delete all the delegations reward tracker associated with this FP - // Delete the FP reward tracker +func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { + amtSat := sdkmath.NewIntFromUint64(sat) + return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { + return k.AddDelegationSat(ctx, fp, del, amtSat) + }) +} + +func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { + amtSat := sdkmath.NewIntFromUint64(sat) + return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { + return k.subDelegationSat(ctx, fp, del, amtSat) + }) +} +func (k Keeper) FpSlashed(ctx context.Context, fp sdk.AccAddress) error { endedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp) if err != nil { return err } + // remove all the rewards available from the ended periods keysBtcDelRwdTracker := make([][]byte, 0) if err := k.IterateBTCDelegationRewardsTracker(ctx, fp, func(fp, del sdk.AccAddress) error { keysBtcDelRwdTracker = append(keysBtcDelRwdTracker, del.Bytes()) @@ -36,43 +47,22 @@ func (k Keeper) FpSlashed(ctx context.Context, fp sdk.AccAddress) error { return err } + // delete all reward tracer that correlates with the slashed finality provider. k.deleteKeysFromBTCDelegationRewardsTracker(ctx, fp, keysBtcDelRwdTracker) k.deleteAllFromFinalityProviderRwd(ctx, fp) return nil } -func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { - // if btc delegations does not exists - // BeforeDelegationCreated - // IncrementValidatorPeriod - // initializeDelegation - // AddDelegationStaking - - // if btc delegations exists - // BeforeDelegationSharesModified - // withdrawDelegationRewards - // IncrementValidatorPeriod - - // IncrementValidatorPeriod - // gets the current rewards and send to historical the current period (the rewards are stored as "shares" which means the amount of rewards per satoshi) - // sets new empty current rewards with new period - amtSat := sdkmath.NewIntFromUint64(sat) - return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { - return k.AddDelegationSat(ctx, fp, del, amtSat) - }) +func (k Keeper) SendBtcDelegationRewardsToGauge(ctx context.Context, fp, del sdk.AccAddress) error { + return k.btcDelegationModified(ctx, fp, del) } -func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { - amtSat := sdkmath.NewIntFromUint64(sat) - return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { - return k.subDelegationSat(ctx, fp, del, amtSat) +func (k Keeper) sendAllBtcRewardsToGauge(ctx context.Context, del sdk.AccAddress) error { + return k.iterBtcDelegationsByDelegator(ctx, del, func(del, fp sdk.AccAddress) error { + return k.SendBtcDelegationRewardsToGauge(ctx, fp, del) }) } -func (k Keeper) SendBtcDelegationRewardsToGauge(ctx context.Context, fp, del sdk.AccAddress) error { - return k.btcDelegationModified(ctx, fp, del) -} - func (k Keeper) btcDelegationModified( ctx context.Context, fp, del sdk.AccAddress, @@ -211,12 +201,6 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA return fpCurrentRwd.Period, nil } -func (k Keeper) sendAllBtcRewardsToGauge(ctx context.Context, del sdk.AccAddress) error { - return k.iterBtcDelegationsByDelegator(ctx, del, func(del, fp sdk.AccAddress) error { - return k.SendBtcDelegationRewardsToGauge(ctx, fp, del) - }) -} - func (k Keeper) initializeFinalityProvider(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { // historical rewards starts at the period 0 err := k.setFinalityProviderHistoricalRewards(ctx, fp, 0, types.NewFinalityProviderHistoricalRewards(sdk.NewCoins())) diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index d437bf924..5138e4346 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -380,6 +380,91 @@ func FuzzCheckAddFinalityProviderStaked(f *testing.F) { }) } +func FuzzCheckAddDelegationSat(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp1, del := datagen.GenRandomAddress(), datagen.GenRandomAddress() + fp2 := datagen.GenRandomAddress() + + amtAdded := datagen.RandomMathInt(r, 1000) + err := k.AddDelegationSat(ctx, fp1, del, amtAdded) + require.NoError(t, err) + + rwdTrackerFp1Del1, err := k.GetBTCDelegationRewardsTracker(ctx, fp1, del) + require.NoError(t, err) + require.Equal(t, amtAdded.String(), rwdTrackerFp1Del1.TotalActiveSat.String()) + require.Equal(t, uint64(0), rwdTrackerFp1Del1.StartPeriodCumulativeReward) + + currentRwdFp1, err := k.GetFinalityProviderCurrentRewards(ctx, fp1) + require.NoError(t, err) + require.Equal(t, amtAdded.String(), currentRwdFp1.TotalActiveSat.String()) + require.Equal(t, uint64(1), currentRwdFp1.Period) + require.Equal(t, sdk.NewCoins().String(), currentRwdFp1.CurrentRewards.String()) + + currentHistRwdFp1Del1, err := k.GetFinalityProviderHistoricalRewards(ctx, fp1, 0) + require.NoError(t, err) + require.Equal(t, sdk.NewCoins().String(), currentHistRwdFp1Del1.CumulativeRewardsPerSat.String()) + + // add delegation again + err = k.AddDelegationSat(ctx, fp1, del, amtAdded) + require.NoError(t, err) + + // just verifies that the amount duplicated, without modifying the periods + rwdTrackerFp1Del1, err = k.GetBTCDelegationRewardsTracker(ctx, fp1, del) + require.NoError(t, err) + require.Equal(t, amtAdded.MulRaw(2).String(), rwdTrackerFp1Del1.TotalActiveSat.String()) + require.Equal(t, uint64(0), rwdTrackerFp1Del1.StartPeriodCumulativeReward) + + currentRwdFp1, err = k.GetFinalityProviderCurrentRewards(ctx, fp1) + require.NoError(t, err) + require.Equal(t, amtAdded.MulRaw(2).String(), currentRwdFp1.TotalActiveSat.String()) + require.Equal(t, uint64(1), currentRwdFp1.Period) + require.Equal(t, sdk.NewCoins().String(), currentRwdFp1.CurrentRewards.String()) + + currentHistRwdFp1Del1, err = k.GetFinalityProviderHistoricalRewards(ctx, fp1, 0) + require.NoError(t, err) + require.Equal(t, sdk.NewCoins().String(), currentHistRwdFp1Del1.CumulativeRewardsPerSat.String()) + + // adds delegation sat to already initilialized FP and delegation + // needs to initialize the FP first, then the delegation + fp2CurrentRwd, err := k.initializeFinalityProvider(ctx, fp2) + require.NoError(t, err) + + startingActiveAmt := datagen.RandomMathInt(r, 100) + err = k.setBTCDelegationRewardsTracker(ctx, fp2, del, types.NewBTCDelegationRewardsTracker(fp2CurrentRwd.Period, startingActiveAmt)) + require.NoError(t, err) + + err = k.initializeBTCDelegation(ctx, fp2, del) + require.NoError(t, err) + + err = k.AddDelegationSat(ctx, fp2, del, amtAdded) + require.NoError(t, err) + + // verifies the amount added + rwdTrackerFp2Del1, err := k.GetBTCDelegationRewardsTracker(ctx, fp2, del) + require.NoError(t, err) + require.Equal(t, amtAdded.Add(startingActiveAmt).String(), rwdTrackerFp2Del1.TotalActiveSat.String()) + require.Equal(t, uint64(0), rwdTrackerFp2Del1.StartPeriodCumulativeReward) + + currentRwdFp2, err := k.GetFinalityProviderCurrentRewards(ctx, fp2) + require.NoError(t, err) + // since it was artificially set the starting amount of the delegation + // the FP should only have the amount added. + require.Equal(t, amtAdded.String(), currentRwdFp2.TotalActiveSat.String()) + require.Equal(t, uint64(1), currentRwdFp2.Period) + require.Equal(t, sdk.NewCoins().String(), currentRwdFp2.CurrentRewards.String()) + + currentHistRwdFp2Del1, err := k.GetFinalityProviderHistoricalRewards(ctx, fp2, 0) + require.NoError(t, err) + require.Equal(t, sdk.NewCoins().String(), currentHistRwdFp2Del1.CumulativeRewardsPerSat.String()) + }) +} + func TestAddSubDelegationSat(t *testing.T) { k, ctx := NewKeeperWithCtx(t) From d5cc28087c4b31f50cdcb0c2dfced045a04ec94d Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 21:54:41 -0300 Subject: [PATCH 037/132] fix: lint trailing space --- x/incentive/keeper/btc_staking_gauge_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/incentive/keeper/btc_staking_gauge_test.go b/x/incentive/keeper/btc_staking_gauge_test.go index 13e0e37c5..1115ee520 100644 --- a/x/incentive/keeper/btc_staking_gauge_test.go +++ b/x/incentive/keeper/btc_staking_gauge_test.go @@ -146,5 +146,4 @@ func coinsAtLeastMinAmount(value sdk.Coins, minAmt math.Int) sdk.Coins { ret = ret.Add(sdk.NewCoin(v.Denom, minAmt)) } return ret - } From 9768030048316a84a2e7c1238e05d09a23f4de71 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 22:09:55 -0300 Subject: [PATCH 038/132] chore: moved addDelegationSat to store tracker file --- test/e2e/btc_staking_pre_approval_e2e_test.go | 4 ++-- x/incentive/keeper/reward_tracker.go | 22 +----------------- x/incentive/keeper/reward_tracker_store.go | 23 +++++++++++++++++++ .../keeper/reward_tracker_store_test.go | 16 ++++++------- x/incentive/keeper/reward_tracker_test.go | 2 +- 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/test/e2e/btc_staking_pre_approval_e2e_test.go b/test/e2e/btc_staking_pre_approval_e2e_test.go index 73e7fbdd2..e810ea7cc 100644 --- a/test/e2e/btc_staking_pre_approval_e2e_test.go +++ b/test/e2e/btc_staking_pre_approval_e2e_test.go @@ -285,7 +285,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test3SendStakingTransctionInclusionProo func (s *BTCStakingPreApprovalTestSuite) Test4CommitPublicRandomnessAndSubmitFinalitySignature() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - nonValidatorNode, err := chainA.GetNodeAtIndex(2) + nonValidatorNode, err := chainA.GetNodeAtIndex(1) s.NoError(err) /* @@ -382,7 +382,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test4CommitPublicRandomnessAndSubmitFin s.NoError(err) btcPK := bbn.NewBIP340PubKeyFromBTCPK(pk) nonValidatorNode.AddFinalitySig(btcPK, activatedHeight, &randListInfo.PRList[idx], *randListInfo.ProofList[idx].ToProto(), appHash, eotsSig) - nonValidatorNode.WaitForNextBlocks(2) + nonValidatorNode.WaitForNextBlock() }, false) // ensure finality provider has received rewards after the block is finalised diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index c59aff5f9..c7ac8b153 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -21,7 +21,7 @@ var ( func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { amtSat := sdkmath.NewIntFromUint64(sat) return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { - return k.AddDelegationSat(ctx, fp, del, amtSat) + return k.addDelegationSat(ctx, fp, del, amtSat) }) } @@ -245,23 +245,3 @@ func (k Keeper) AddFinalityProviderRewardsForBtcDelegations(ctx context.Context, fpCurrentRwd.AddRewards(rwd) return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) } - -func (k Keeper) AddDelegationSat(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { - btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) - if err != nil { - if !errors.Is(err, types.ErrBTCDelegationRewardsTrackerNotFound) { - return err - } - - // first delegation to this pair (fp, del), can start as 0 previous period as it - // will be updated soon as initilize btc delegation - btcDelRwdTracker = types.NewBTCDelegationRewardsTracker(0, sdkmath.ZeroInt()) - } - - btcDelRwdTracker.AddTotalActiveSat(amt) - if err := k.setBTCDelegationRewardsTracker(ctx, fp, del, btcDelRwdTracker); err != nil { - return err - } - - return k.addFinalityProviderStaked(ctx, fp, amt) -} diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index bdf4dbadb..6c16838a4 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -279,3 +279,26 @@ func (k Keeper) addFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress fpCurrentRwd.AddTotalActiveSat(amt) return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) } + +// addDelegationSat it increases the amount of satoshi staked for the delegation (fp, del) +// and for the finality provider as well, it initializes the finality provider and the +// BTC delegation rewards tracker if it does not exist. +func (k Keeper) addDelegationSat(ctx context.Context, fp, del sdk.AccAddress, amt sdkmath.Int) error { + btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) + if err != nil { + if !errors.Is(err, types.ErrBTCDelegationRewardsTrackerNotFound) { + return err + } + + // first delegation to this pair (fp, del), can start as 0 previous period as it + // it should be updated afterwards with initilize btc delegation + btcDelRwdTracker = types.NewBTCDelegationRewardsTracker(0, sdkmath.ZeroInt()) + } + + btcDelRwdTracker.AddTotalActiveSat(amt) + if err := k.setBTCDelegationRewardsTracker(ctx, fp, del, btcDelRwdTracker); err != nil { + return err + } + + return k.addFinalityProviderStaked(ctx, fp, amt) +} diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index 5138e4346..8f51fe267 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -392,7 +392,7 @@ func FuzzCheckAddDelegationSat(f *testing.F) { fp2 := datagen.GenRandomAddress() amtAdded := datagen.RandomMathInt(r, 1000) - err := k.AddDelegationSat(ctx, fp1, del, amtAdded) + err := k.addDelegationSat(ctx, fp1, del, amtAdded) require.NoError(t, err) rwdTrackerFp1Del1, err := k.GetBTCDelegationRewardsTracker(ctx, fp1, del) @@ -411,7 +411,7 @@ func FuzzCheckAddDelegationSat(f *testing.F) { require.Equal(t, sdk.NewCoins().String(), currentHistRwdFp1Del1.CumulativeRewardsPerSat.String()) // add delegation again - err = k.AddDelegationSat(ctx, fp1, del, amtAdded) + err = k.addDelegationSat(ctx, fp1, del, amtAdded) require.NoError(t, err) // just verifies that the amount duplicated, without modifying the periods @@ -442,7 +442,7 @@ func FuzzCheckAddDelegationSat(f *testing.F) { err = k.initializeBTCDelegation(ctx, fp2, del) require.NoError(t, err) - err = k.AddDelegationSat(ctx, fp2, del, amtAdded) + err = k.addDelegationSat(ctx, fp2, del, amtAdded) require.NoError(t, err) // verifies the amount added @@ -478,7 +478,7 @@ func TestAddSubDelegationSat(t *testing.T) { // adds 2000 for fp1, del1 // fp1 => 2000 // fp1, del1 => 2000 - err = k.AddDelegationSat(ctx, fp1, del1, amtFp1Del1) + err = k.addDelegationSat(ctx, fp1, del1, amtFp1Del1) require.NoError(t, err) checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1) checkFpDelTotalSat(t, ctx, k, fp1, del1, amtFp1Del1) @@ -493,7 +493,7 @@ func TestAddSubDelegationSat(t *testing.T) { // fp1 => 6000 // fp1, del1 => 2000 // fp1, del2 => 4000 - err = k.AddDelegationSat(ctx, fp1, del2, amtFp1Del2) + err = k.addDelegationSat(ctx, fp1, del2, amtFp1Del2) require.NoError(t, err) checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) @@ -506,7 +506,7 @@ func TestAddSubDelegationSat(t *testing.T) { // fp1, del1 => 2000 // fp1, del2 => 4000 // fp2, del2 => 500 - err = k.AddDelegationSat(ctx, fp2, del2, amtFp2Del2) + err = k.addDelegationSat(ctx, fp2, del2, amtFp2Del2) require.NoError(t, err) checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2) @@ -521,7 +521,7 @@ func TestAddSubDelegationSat(t *testing.T) { // fp1, del2 => 4000 // fp2, del1 => 700 // fp2, del2 => 500 - err = k.AddDelegationSat(ctx, fp2, del1, amtFp2Del1) + err = k.addDelegationSat(ctx, fp2, del1, amtFp2Del1) require.NoError(t, err) checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2)) checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2.Add(amtFp2Del1)) @@ -538,7 +538,7 @@ func TestAddSubDelegationSat(t *testing.T) { // fp1, del2 => 6000 // fp2, del1 => 700 // fp2, del2 => 500 - err = k.AddDelegationSat(ctx, fp1, del2, lastAmtFp1Del2) + err = k.addDelegationSat(ctx, fp1, del2, lastAmtFp1Del2) require.NoError(t, err) checkFpTotalSat(t, ctx, k, fp1, amtFp1Del1.Add(amtFp1Del2).Add(lastAmtFp1Del2)) checkFpTotalSat(t, ctx, k, fp2, amtFp2Del2.Add(amtFp2Del1)) diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index a81929d83..aca76593f 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -33,7 +33,7 @@ func TestIncrementFinalityProviderPeriod(t *testing.T) { // needs to add some voting power so it can calculate the amount of rewards per share satsDelegated := math.NewInt(500) - err = k.AddDelegationSat(ctx, fp1, del1, satsDelegated) + err = k.addDelegationSat(ctx, fp1, del1, satsDelegated) require.NoError(t, err) fp1EndedPeriod, err = k.IncrementFinalityProviderPeriod(ctx, fp1) From 2e8363fdab8ab116ed247d828a4287c3a5c7ed26 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 22:13:45 -0300 Subject: [PATCH 039/132] chore: modified to always use the node at idx 1 --- test/e2e/btc_staking_pre_approval_e2e_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/e2e/btc_staking_pre_approval_e2e_test.go b/test/e2e/btc_staking_pre_approval_e2e_test.go index e810ea7cc..7d2866641 100644 --- a/test/e2e/btc_staking_pre_approval_e2e_test.go +++ b/test/e2e/btc_staking_pre_approval_e2e_test.go @@ -75,7 +75,7 @@ func (s *BTCStakingPreApprovalTestSuite) TearDownSuite() { func (s *BTCStakingPreApprovalTestSuite) Test1CreateFinalityProviderAndDelegation() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - nonValidatorNode, err := chainA.GetNodeAtIndex(2) + nonValidatorNode, err := chainA.GetNodeAtIndex(1) s.NoError(err) s.cacheFP = CreateNodeFP( @@ -147,7 +147,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test1CreateFinalityProviderAndDelegatio func (s *BTCStakingPreApprovalTestSuite) Test2SubmitCovenantSignature() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - nonValidatorNode, err := chainA.GetNodeAtIndex(2) + nonValidatorNode, err := chainA.GetNodeAtIndex(1) s.NoError(err) // get last BTC delegation @@ -253,7 +253,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test2SubmitCovenantSignature() { func (s *BTCStakingPreApprovalTestSuite) Test3SendStakingTransctionInclusionProof() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - nonValidatorNode, err := chainA.GetNodeAtIndex(2) + nonValidatorNode, err := chainA.GetNodeAtIndex(1) s.NoError(err) verifiedDelegations := nonValidatorNode.QueryVerifiedDelegations() @@ -402,7 +402,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test4CommitPublicRandomnessAndSubmitFin func (s *BTCStakingPreApprovalTestSuite) Test4WithdrawReward() { chainA := s.configurer.GetChainConfig(0) - nonValidatorNode, err := chainA.GetNodeAtIndex(2) + nonValidatorNode, err := chainA.GetNodeAtIndex(1) s.NoError(err) // finality provider balance before withdraw @@ -466,7 +466,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test4WithdrawReward() { func (s *BTCStakingPreApprovalTestSuite) Test5SubmitStakerUnbonding() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - nonValidatorNode, err := chainA.GetNodeAtIndex(2) + nonValidatorNode, err := chainA.GetNodeAtIndex(1) s.NoError(err) // wait for a block so that above txs take effect nonValidatorNode.WaitForNextBlock() From e33a1765e6f22210a7b33d9097bb05682b4b879f Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 22:20:04 -0300 Subject: [PATCH 040/132] chore: add test for add fp rewards --- x/incentive/keeper/reward_tracker.go | 6 ++++ x/incentive/keeper/reward_tracker_test.go | 36 +++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index c7ac8b153..b20c0f2a4 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -236,6 +236,12 @@ func (k Keeper) initializeBTCDelegation(ctx context.Context, fp, del sdk.AccAddr return k.setBTCDelegationRewardsTracker(ctx, fp, del, rwd) } +// AddFinalityProviderRewardsForBtcDelegations gets the current finality provider rewards +// and adds rewards to it, without increasing the finality provider period +// it also does not initiliaze the FP, so it must have been initialized prior +// to adding rewards. In the sense that a FP would first receive active delegations sats +// be properly initialized (creates current and historical reward structures in the store) +// than will start to receive rewards for contributing. func (k Keeper) AddFinalityProviderRewardsForBtcDelegations(ctx context.Context, fp sdk.AccAddress, rwd sdk.Coins) error { fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) if err != nil { diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index aca76593f..096249aa6 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -1,15 +1,51 @@ package keeper import ( + "math/rand" "testing" "cosmossdk.io/math" appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/testutil/datagen" + "github.com/babylonlabs-io/babylon/x/incentive/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) +func FuzzCheckAddFinalityProviderRewardsForBtcDelegations(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp := datagen.GenRandomAddress() + + coinsAdded := datagen.GenRandomCoins(r) + // add rewards without initiliaze should error out + err := k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp, coinsAdded) + require.EqualError(t, err, types.ErrFPCurrentRewardsNotFound.Error()) + + _, err = k.initializeFinalityProvider(ctx, fp) + require.NoError(t, err) + err = k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp, coinsAdded) + require.NoError(t, err) + + currentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) + require.NoError(t, err) + require.Equal(t, coinsAdded.String(), currentRwd.CurrentRewards.String()) + + // adds again the same amounts + err = k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp, coinsAdded) + require.NoError(t, err) + + currentRwd, err = k.GetFinalityProviderCurrentRewards(ctx, fp) + require.NoError(t, err) + require.Equal(t, coinsAdded.MulInt(math.NewInt(2)).String(), currentRwd.CurrentRewards.String()) + }) +} + func TestIncrementFinalityProviderPeriod(t *testing.T) { k, ctx := NewKeeperWithCtx(t) From c3112c1493cc15ebddaca08e91496cf1423087b4 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 22:43:27 -0300 Subject: [PATCH 041/132] chore: reduce log lever --- test/e2e/initialization/node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/initialization/node.go b/test/e2e/initialization/node.go index e3ad31c99..99ac416f0 100644 --- a/test/e2e/initialization/node.go +++ b/test/e2e/initialization/node.go @@ -354,7 +354,7 @@ func (n *internalNode) initNodeConfigs(persistentPeers []string) error { valConfig.P2P.ExternalAddress = fmt.Sprintf("%s:%d", n.moniker, 26656) valConfig.RPC.ListenAddress = "tcp://0.0.0.0:26657" valConfig.StateSync.Enable = false - valConfig.LogLevel = "debug" + valConfig.LogLevel = "info" valConfig.P2P.PersistentPeers = strings.Join(persistentPeers, ",") valConfig.Storage.DiscardABCIResponses = false From 90cfc29f67d23f0f4024fcddc7d23638d49156e8 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 9 Dec 2024 23:10:12 -0300 Subject: [PATCH 042/132] chore: add test for initializeFinalityProvider --- x/incentive/keeper/reward_tracker.go | 3 +++ x/incentive/keeper/reward_tracker_test.go | 32 +++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index b20c0f2a4..d0e4e5cec 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -201,6 +201,9 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA return fpCurrentRwd.Period, nil } +// initializeFinalityProvider initializes a new finality provider current rewards at period 1, empty rewards and zero sats +// and also a historical rewards at period 0 and zero rewards as well. +// It does not verifies if it exists prior to overwrite, who calls it needs to verify. func (k Keeper) initializeFinalityProvider(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { // historical rewards starts at the period 0 err := k.setFinalityProviderHistoricalRewards(ctx, fp, 0, types.NewFinalityProviderHistoricalRewards(sdk.NewCoins())) diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index 096249aa6..8fc5334ac 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -46,6 +46,38 @@ func FuzzCheckAddFinalityProviderRewardsForBtcDelegations(f *testing.F) { }) } +func FuzzCheckInitializeFinalityProvider(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + + k, ctx := NewKeeperWithCtx(t) + fp := datagen.GenRandomAddress() + + currentRwdFp, err := k.initializeFinalityProvider(ctx, fp) + require.NoError(t, err) + require.Equal(t, currentRwdFp.CurrentRewards.String(), sdk.NewCoins().String()) + require.Equal(t, currentRwdFp.TotalActiveSat.String(), math.ZeroInt().String()) + require.Equal(t, currentRwdFp.Period, uint64(1)) + + histRwdFp, err := k.GetFinalityProviderHistoricalRewards(ctx, fp, 0) + require.NoError(t, err) + require.Equal(t, histRwdFp.CumulativeRewardsPerSat.String(), sdk.NewCoins().String()) + + // if initializes it again, the values should be the same + currentRwdFp, err = k.initializeFinalityProvider(ctx, fp) + require.NoError(t, err) + require.Equal(t, currentRwdFp.CurrentRewards.String(), sdk.NewCoins().String()) + require.Equal(t, currentRwdFp.TotalActiveSat.String(), math.ZeroInt().String()) + require.Equal(t, currentRwdFp.Period, uint64(1)) + + histRwdFp, err = k.GetFinalityProviderHistoricalRewards(ctx, fp, 0) + require.NoError(t, err) + require.Equal(t, histRwdFp.CumulativeRewardsPerSat.String(), sdk.NewCoins().String()) + }) +} + func TestIncrementFinalityProviderPeriod(t *testing.T) { k, ctx := NewKeeperWithCtx(t) From 56114053726479460a5971c33b5dc18619f3a9b3 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 10 Dec 2024 10:09:43 -0300 Subject: [PATCH 043/132] chore: remove unnecessary command --- x/incentive/keeper/btc_staking_gauge.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x/incentive/keeper/btc_staking_gauge.go b/x/incentive/keeper/btc_staking_gauge.go index 8d6609aaa..10f316026 100644 --- a/x/incentive/keeper/btc_staking_gauge.go +++ b/x/incentive/keeper/btc_staking_gauge.go @@ -19,8 +19,7 @@ func (k Keeper) RewardBTCStaking(ctx context.Context, height uint64, dc *ftypes. // failing to get a reward gauge at previous height is a programming error panic("failed to get a reward gauge at previous height") } - // TODO(rafilx): Finality providers also use the available rewards instead of reward gauge. - // reward each of the finality provider and its BTC delegations in proportion + for i, fp := range dc.FinalityProviders { // only reward the first NumActiveFps finality providers // note that ApplyActiveFinalityProviders is called before saving `dc` From bcfa5a9306674b746238d8d6c2b12a01ea186fc9 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 10 Dec 2024 12:53:47 -0300 Subject: [PATCH 044/132] chore: move add fp rwd --- x/incentive/keeper/reward_tracker.go | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index d0e4e5cec..ef851481a 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -18,6 +18,22 @@ var ( DecimalAccumulatedRewards, _ = sdkmath.NewIntFromString("100000000000000000000") ) +// AddFinalityProviderRewardsForBtcDelegations gets the current finality provider rewards +// and adds rewards to it, without increasing the finality provider period +// it also does not initiliaze the FP, so it must have been initialized prior +// to adding rewards. In the sense that a FP would first receive active delegations sats +// be properly initialized (creates current and historical reward structures in the store) +// than will start to receive rewards for contributing. +func (k Keeper) AddFinalityProviderRewardsForBtcDelegations(ctx context.Context, fp sdk.AccAddress, rwd sdk.Coins) error { + fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) + if err != nil { + return err + } + + fpCurrentRwd.AddRewards(rwd) + return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) +} + func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { amtSat := sdkmath.NewIntFromUint64(sat) return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { @@ -238,19 +254,3 @@ func (k Keeper) initializeBTCDelegation(ctx context.Context, fp, del sdk.AccAddr rwd := types.NewBTCDelegationRewardsTracker(previousPeriod, btcDelRwdTracker.TotalActiveSat) return k.setBTCDelegationRewardsTracker(ctx, fp, del, rwd) } - -// AddFinalityProviderRewardsForBtcDelegations gets the current finality provider rewards -// and adds rewards to it, without increasing the finality provider period -// it also does not initiliaze the FP, so it must have been initialized prior -// to adding rewards. In the sense that a FP would first receive active delegations sats -// be properly initialized (creates current and historical reward structures in the store) -// than will start to receive rewards for contributing. -func (k Keeper) AddFinalityProviderRewardsForBtcDelegations(ctx context.Context, fp sdk.AccAddress, rwd sdk.Coins) error { - fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) - if err != nil { - return err - } - - fpCurrentRwd.AddRewards(rwd) - return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) -} From a8b453eba85d28f58aa393e87abafb6d69822951 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 10 Dec 2024 20:45:27 -0300 Subject: [PATCH 045/132] fix: lint signer --- test/replay/app_replay_e2e_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/replay/app_replay_e2e_test.go b/test/replay/app_replay_e2e_test.go index fb3ee6927..b31289d9e 100644 --- a/test/replay/app_replay_e2e_test.go +++ b/test/replay/app_replay_e2e_test.go @@ -16,7 +16,7 @@ import ( "cosmossdk.io/log" "github.com/babylonlabs-io/babylon/app" babylonApp "github.com/babylonlabs-io/babylon/app" - appkeepers "github.com/babylonlabs-io/babylon/app/keepers" + "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/test/e2e/initialization" btclighttypes "github.com/babylonlabs-io/babylon/x/btclightclient/types" dbmc "github.com/cometbft/cometbft-db" @@ -96,7 +96,7 @@ type FinalizedBlock struct { type BabylonAppDriver struct { App *app.BabylonApp - PrivSigner *appkeepers.PrivSigner + PrivSigner *signer.PrivSigner BlockExec *sm.BlockExecutor BlockStore *store.BlockStore StateStore *sm.Store @@ -152,7 +152,7 @@ func NewBabylonAppDriver( panic(err) } - signer, err := appkeepers.InitPrivSigner(chain.Nodes[0].ConfigDir) + signer, err := signer.InitPrivSigner(chain.Nodes[0].ConfigDir) require.NoError(t, err) require.NotNil(t, signer) signerValAddress := signer.WrappedPV.GetAddress() @@ -383,7 +383,7 @@ func NewBlockReplayer(t *testing.T, nodeDir string) *BlockReplayer { panic(err) } - signer, err := appkeepers.InitPrivSigner(nodeDir) + signer, err := signer.InitPrivSigner(nodeDir) require.NoError(t, err) require.NotNil(t, signer) signerValAddress := signer.WrappedPV.GetAddress() From a660f7612b5baad633cf80dd15599136bf948303 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 10 Dec 2024 20:46:49 -0300 Subject: [PATCH 046/132] chore: add test for initializeBTCDelegation --- testutil/datagen/incentive.go | 8 +++++- x/incentive/keeper/reward_tracker_test.go | 34 ++++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/testutil/datagen/incentive.go b/testutil/datagen/incentive.go index c8fc12320..284e0f379 100644 --- a/testutil/datagen/incentive.go +++ b/testutil/datagen/incentive.go @@ -146,9 +146,15 @@ func GenRandomBTCTimestampingRewardDistInfo(r *rand.Rand) *btcctypes.RewardDistI func GenRandomFinalityProviderCurrentRewards(r *rand.Rand) types.FinalityProviderCurrentRewards { rwd := GenRandomCoins(r) + period := RandomInt(r, 100) + 3 + activeSatoshi := RandomMathInt(r, 10000).AddRaw(10) + return types.NewFinalityProviderCurrentRewards(rwd, period, activeSatoshi) +} + +func GenRandomBTCDelegationRewardsTracker(r *rand.Rand) types.BTCDelegationRewardsTracker { period := RandomInt(r, 100) activeSatoshi := RandomMathInt(r, 10000) - return types.NewFinalityProviderCurrentRewards(rwd, period, activeSatoshi) + return types.NewBTCDelegationRewardsTracker(period, activeSatoshi) } func GenRandomFinalityProviderHistoricalRewards(r *rand.Rand) types.FinalityProviderHistoricalRewards { diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index 8fc5334ac..697644cf9 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -46,9 +46,41 @@ func FuzzCheckAddFinalityProviderRewardsForBtcDelegations(f *testing.F) { }) } -func FuzzCheckInitializeFinalityProvider(f *testing.F) { +func FuzzCheckInitializeBTCDelegation(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp, del := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + err := k.initializeBTCDelegation(ctx, fp, del) + require.EqualError(t, err, types.ErrFPCurrentRewardsNotFound.Error()) + + fpCurrentRwd := datagen.GenRandomFinalityProviderCurrentRewards(r) + err = k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) + require.NoError(t, err) + + err = k.initializeBTCDelegation(ctx, fp, del) + require.EqualError(t, err, types.ErrBTCDelegationRewardsTrackerNotFound.Error()) + delBtcRwdTrackerBeforeInitialize := datagen.GenRandomBTCDelegationRewardsTracker(r) + err = k.setBTCDelegationRewardsTracker(ctx, fp, del, delBtcRwdTrackerBeforeInitialize) + require.NoError(t, err) + + err = k.initializeBTCDelegation(ctx, fp, del) + require.NoError(t, err) + + actBtcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) + require.NoError(t, err) + require.Equal(t, fpCurrentRwd.Period-1, actBtcDelRwdTracker.StartPeriodCumulativeReward) + require.Equal(t, delBtcRwdTrackerBeforeInitialize.TotalActiveSat, actBtcDelRwdTracker.TotalActiveSat) + }) +} + +func FuzzCheckInitializeFinalityProvider(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) f.Fuzz(func(t *testing.T, seed int64) { t.Parallel() From f3bf5c92c88526ad45a68f6f7d28e7d591cffa91 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 10 Dec 2024 21:36:04 -0300 Subject: [PATCH 047/132] chore: add test for IncrementFinalityProviderPeriod --- x/incentive/keeper/reward_tracker.go | 14 ++++++-- x/incentive/keeper/reward_tracker_test.go | 41 +++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index ef851481a..a40aca562 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -173,7 +173,15 @@ func (k Keeper) calculateDelegationRewardsBetween( return rewards, nil } -// IncrementFinalityProviderPeriod +// IncrementFinalityProviderPeriod gets or initializes the finality provider, +// increases the period from the current FP rewards and empty the rewards. +// It also creates a new historical with the ended period and sets the rewards +// of the newly historical period as the amount from the previous historical +// plus the amount of rewards that each satoshi staked is entitled to receive. +// The rewards in the historical are stored with multiplied decimals +// (DecimalAccumulatedRewards) to increase precision, and need to be +// reduced when the rewards are calculated in calculateDelegationRewardsBetween +// prior to send out to the delegator gauge. func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccAddress) (endedPeriod uint64, err error) { // IncrementValidatorPeriod // gets the current rewards and send to historical the current period (the rewards are stored as "shares" which means the amount of rewards per satoshi) @@ -184,8 +192,8 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA return 0, err } - // initialize Validator and return 1 as ended period - // the ended period is 1 because the just created historical sits at 0 + // initialize Validator and return 1 as ended period due + // to the created historical FP rewards starts at period 0 if _, err := k.initializeFinalityProvider(ctx, fp); err != nil { return 0, err } diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index 697644cf9..b42d8875b 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -46,6 +46,47 @@ func FuzzCheckAddFinalityProviderRewardsForBtcDelegations(f *testing.F) { }) } +func FuzzCheckIncrementFinalityProviderPeriod(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp := datagen.GenRandomAddress() + + // increment without initializing the FP + endedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp) + require.NoError(t, err, types.ErrFPCurrentRewardsNotFound.Error()) + require.Equal(t, endedPeriod, uint64(1)) + + fpCurrentRwd := datagen.GenRandomFinalityProviderCurrentRewards(r) + err = k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) + require.NoError(t, err) + + amtRwdInHistorical := fpCurrentRwd.CurrentRewards.MulInt(DecimalAccumulatedRewards).QuoInt(math.NewInt(2)) + err = k.setFinalityProviderHistoricalRewards(ctx, fp, fpCurrentRwd.Period-1, types.NewFinalityProviderHistoricalRewards(amtRwdInHistorical)) + require.NoError(t, err) + + endedPeriod, err = k.IncrementFinalityProviderPeriod(ctx, fp) + require.NoError(t, err) + require.Equal(t, endedPeriod, fpCurrentRwd.Period) + + historicalEndedPeriod, err := k.GetFinalityProviderHistoricalRewards(ctx, fp, endedPeriod) + require.NoError(t, err) + + expectedHistoricalRwd := amtRwdInHistorical.Add(fpCurrentRwd.CurrentRewards.MulInt(DecimalAccumulatedRewards).QuoInt(fpCurrentRwd.TotalActiveSat)...) + require.Equal(t, historicalEndedPeriod.CumulativeRewardsPerSat.String(), expectedHistoricalRwd.String()) + + newFPCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) + require.NoError(t, err) + require.Equal(t, newFPCurrentRwd.CurrentRewards.String(), sdk.NewCoins().String()) + require.Equal(t, newFPCurrentRwd.Period, fpCurrentRwd.Period+1) + require.Equal(t, newFPCurrentRwd.TotalActiveSat, fpCurrentRwd.TotalActiveSat) + }) +} + func FuzzCheckInitializeBTCDelegation(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) f.Fuzz(func(t *testing.T, seed int64) { From 1266bce59c0927b3e181d94e82a03dbab0a0bbe4 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 10 Dec 2024 22:00:08 -0300 Subject: [PATCH 048/132] chore: add test for calculateDelegationRewardsBetween --- testutil/datagen/incentive.go | 2 +- x/incentive/keeper/reward_tracker.go | 10 ++++- x/incentive/keeper/reward_tracker_test.go | 47 +++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/testutil/datagen/incentive.go b/testutil/datagen/incentive.go index 284e0f379..737c3367b 100644 --- a/testutil/datagen/incentive.go +++ b/testutil/datagen/incentive.go @@ -152,7 +152,7 @@ func GenRandomFinalityProviderCurrentRewards(r *rand.Rand) types.FinalityProvide } func GenRandomBTCDelegationRewardsTracker(r *rand.Rand) types.BTCDelegationRewardsTracker { - period := RandomInt(r, 100) + period := RandomInt(r, 100) + 2 activeSatoshi := RandomMathInt(r, 10000) return types.NewBTCDelegationRewardsTracker(period, activeSatoshi) } diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index a40aca562..3a67c6fe1 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -137,7 +137,15 @@ func (k Keeper) CalculateBTCDelegationRewards(ctx context.Context, fp, del sdk.A return k.calculateDelegationRewardsBetween(ctx, fp, del, btcDelRwdTracker, endPeriod) } -// calculate the rewards accrued by a delegation between two periods +// calculateDelegationRewardsBetween calculate the rewards accured of a delegation between +// two period, the endingPeriod received in param and the StartPeriodCumulativeReward of +// the BTCDelegationRewardsTracker. It gets the CumulativeRewardsPerSat of the ending +// period and subtracts the CumulativeRewardsPerSat of the starting period +// that give the total amount of rewards that one satoshi is entitle to receive +// in rewards between those two period. To get the amount this delegation should +// receive, it multiplies by the total amount of active satoshi this delegation has. +// One note, before give out the rewards it quotes by the DecimalAccumulatedRewards +// to get it ready to be sent out to the delegator reward gauge. func (k Keeper) calculateDelegationRewardsBetween( ctx context.Context, fp, del sdk.AccAddress, diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index b42d8875b..0aefad4db 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -12,6 +12,53 @@ import ( "github.com/stretchr/testify/require" ) +func FuzzCheckcalculateDelegationRewardsBetween(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp, del := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + btcRwd := datagen.GenRandomBTCDelegationRewardsTracker(r) + badEndedPeriod := btcRwd.StartPeriodCumulativeReward - 1 + require.Panics(t, func() { + _, _ = k.calculateDelegationRewardsBetween(ctx, fp, del, btcRwd, badEndedPeriod) + }) + + historicalStartPeriod := datagen.GenRandomFinalityProviderHistoricalRewards(r) + historicalStartPeriod.CumulativeRewardsPerSat = historicalStartPeriod.CumulativeRewardsPerSat.MulInt(DecimalAccumulatedRewards) + err := k.setFinalityProviderHistoricalRewards(ctx, fp, btcRwd.StartPeriodCumulativeReward, historicalStartPeriod) + require.NoError(t, err) + + endingPeriod := btcRwd.StartPeriodCumulativeReward + 1 + + // creates a bad historical ending period that has less rewards than the starting one + err = k.setFinalityProviderHistoricalRewards(ctx, fp, endingPeriod, types.NewFinalityProviderHistoricalRewards(historicalStartPeriod.CumulativeRewardsPerSat.QuoInt(math.NewInt(2)))) + require.NoError(t, err) + require.Panics(t, func() { + _, _ = k.calculateDelegationRewardsBetween(ctx, fp, del, btcRwd, endingPeriod) + }) + + // creates a correct historical rewards that has more rewards than the historical + historicalEndingPeriod := datagen.GenRandomFinalityProviderHistoricalRewards(r) + historicalEndingPeriod.CumulativeRewardsPerSat = historicalEndingPeriod.CumulativeRewardsPerSat.MulInt(DecimalAccumulatedRewards) + historicalEndingPeriod.CumulativeRewardsPerSat = historicalEndingPeriod.CumulativeRewardsPerSat.Add(historicalStartPeriod.CumulativeRewardsPerSat...) + err = k.setFinalityProviderHistoricalRewards(ctx, fp, endingPeriod, historicalEndingPeriod) + require.NoError(t, err) + + expectedRewards := historicalEndingPeriod.CumulativeRewardsPerSat.Sub(historicalStartPeriod.CumulativeRewardsPerSat...) + expectedRewards = expectedRewards.MulInt(btcRwd.TotalActiveSat) + expectedRewards = expectedRewards.QuoInt(DecimalAccumulatedRewards) + + delRewards, err := k.calculateDelegationRewardsBetween(ctx, fp, del, btcRwd, endingPeriod) + require.NoError(t, err) + require.Equal(t, expectedRewards.String(), delRewards.String()) + }) +} + func FuzzCheckAddFinalityProviderRewardsForBtcDelegations(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) From d9039dfe8cc75c2424b7f8265c9383a56698ef29 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 11 Dec 2024 13:54:12 -0300 Subject: [PATCH 049/132] chore: add godoc for calc btc rwd --- x/incentive/keeper/reward_tracker.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 3a67c6fe1..8ecbb7ed8 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -124,6 +124,9 @@ func (k Keeper) CalculateBTCDelegationRewardsAndSendToGauge(ctx context.Context, return nil } +// CalculateBTCDelegationRewards calculates the rewards entitled for this delegation +// from the starting period cumulative reward and the ending period received as parameter +// It returns the amount of rewards without decimals (it removes the DecimalAccumulatedRewards). func (k Keeper) CalculateBTCDelegationRewards(ctx context.Context, fp, del sdk.AccAddress, endPeriod uint64) (sdk.Coins, error) { btcDelRwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp, del) if err != nil { From f505c55d3257bdbe74e3724ae1665e6f3e0f7bcb Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 11 Dec 2024 14:54:12 -0300 Subject: [PATCH 050/132] chore: add initial test for CalculateBTCDelegationRewards and move decimals to types --- testutil/datagen/incentive.go | 19 ++++--- x/incentive/keeper/reward_tracker.go | 12 +--- .../keeper/reward_tracker_store_test.go | 6 +- x/incentive/keeper/reward_tracker_test.go | 56 ++++++++++++++++--- x/incentive/types/rewards.go | 8 +++ 5 files changed, 72 insertions(+), 29 deletions(-) diff --git a/testutil/datagen/incentive.go b/testutil/datagen/incentive.go index 737c3367b..31ba14955 100644 --- a/testutil/datagen/incentive.go +++ b/testutil/datagen/incentive.go @@ -8,7 +8,6 @@ import ( btcctypes "github.com/babylonlabs-io/babylon/x/btccheckpoint/types" ftypes "github.com/babylonlabs-io/babylon/x/finality/types" - "github.com/babylonlabs-io/babylon/x/incentive/types" itypes "github.com/babylonlabs-io/babylon/x/incentive/types" ) @@ -144,20 +143,26 @@ func GenRandomBTCTimestampingRewardDistInfo(r *rand.Rand) *btcctypes.RewardDistI return btcctypes.NewRewardDistInfo(best, others...) } -func GenRandomFinalityProviderCurrentRewards(r *rand.Rand) types.FinalityProviderCurrentRewards { +func GenRandomFinalityProviderCurrentRewards(r *rand.Rand) itypes.FinalityProviderCurrentRewards { rwd := GenRandomCoins(r) period := RandomInt(r, 100) + 3 activeSatoshi := RandomMathInt(r, 10000).AddRaw(10) - return types.NewFinalityProviderCurrentRewards(rwd, period, activeSatoshi) + return itypes.NewFinalityProviderCurrentRewards(rwd, period, activeSatoshi) } -func GenRandomBTCDelegationRewardsTracker(r *rand.Rand) types.BTCDelegationRewardsTracker { +func GenRandomBTCDelegationRewardsTracker(r *rand.Rand) itypes.BTCDelegationRewardsTracker { period := RandomInt(r, 100) + 2 activeSatoshi := RandomMathInt(r, 10000) - return types.NewBTCDelegationRewardsTracker(period, activeSatoshi) + return itypes.NewBTCDelegationRewardsTracker(period, activeSatoshi) } -func GenRandomFinalityProviderHistoricalRewards(r *rand.Rand) types.FinalityProviderHistoricalRewards { +func GenRandomFPHistRwd(r *rand.Rand) itypes.FinalityProviderHistoricalRewards { rwd := GenRandomCoins(r) - return types.NewFinalityProviderHistoricalRewards(rwd) + return itypes.NewFinalityProviderHistoricalRewards(rwd) +} + +func GenRandomFPHistRwdWithDecimals(r *rand.Rand) itypes.FinalityProviderHistoricalRewards { + rwd := GenRandomFPHistRwd(r) + rwd.CumulativeRewardsPerSat = rwd.CumulativeRewardsPerSat.MulInt(itypes.DecimalAccumulatedRewards) + return rwd } diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 8ecbb7ed8..9b97fc592 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -10,14 +10,6 @@ import ( sdkmath "cosmossdk.io/math" ) -var ( - // it is needed to add decimal points when reducing the rewards amount - // per sat to latter when giving out the rewards to the gauge, reduce - // the decimal points back, currently 20 decimal points are being added - // the sdkmath.Int holds a big int which support up to 2^256 integers - DecimalAccumulatedRewards, _ = sdkmath.NewIntFromString("100000000000000000000") -) - // AddFinalityProviderRewardsForBtcDelegations gets the current finality provider rewards // and adds rewards to it, without increasing the finality provider period // it also does not initiliaze the FP, so it must have been initialized prior @@ -180,7 +172,7 @@ func (k Keeper) calculateDelegationRewardsBetween( rewardsWithDecimals := differenceWithDecimals.MulInt(btcDelRwdTracker.TotalActiveSat) // note: necessary to truncate so we don't allow withdrawing more rewardsWithDecimals than owed // QuoInt already truncates - rewards := rewardsWithDecimals.QuoInt(DecimalAccumulatedRewards) + rewards := rewardsWithDecimals.QuoInt(types.DecimalAccumulatedRewards) return rewards, nil } @@ -213,7 +205,7 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA currentRewardsPerSat := sdk.NewCoins() if !fpCurrentRwd.TotalActiveSat.IsZero() { - currentRewardsPerSatWithDecimals := fpCurrentRwd.CurrentRewards.MulInt(DecimalAccumulatedRewards) + currentRewardsPerSatWithDecimals := fpCurrentRwd.CurrentRewards.MulInt(types.DecimalAccumulatedRewards) currentRewardsPerSat = currentRewardsPerSatWithDecimals.QuoInt(fpCurrentRwd.TotalActiveSat) } diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index 8f51fe267..c4f6cfc59 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -227,7 +227,7 @@ func FuzzCheckFinalityProviderHistoricalRewards(f *testing.F) { _, err := k.GetFinalityProviderHistoricalRewards(ctx, fp1, fp1Period1) require.EqualError(t, err, types.ErrFPHistoricalRewardsNotFound.Error()) - expectedHistRwdFp1 := datagen.GenRandomFinalityProviderHistoricalRewards(r) + expectedHistRwdFp1 := datagen.GenRandomFPHistRwd(r) err = k.setFinalityProviderHistoricalRewards(ctx, fp1, fp1Period1, expectedHistRwdFp1) require.NoError(t, err) @@ -237,10 +237,10 @@ func FuzzCheckFinalityProviderHistoricalRewards(f *testing.F) { // sets multiple historical for fp2 fp2Period1Historical := datagen.RandomInt(r, 10) - err = k.setFinalityProviderHistoricalRewards(ctx, fp2, fp2Period1Historical, datagen.GenRandomFinalityProviderHistoricalRewards(r)) + err = k.setFinalityProviderHistoricalRewards(ctx, fp2, fp2Period1Historical, datagen.GenRandomFPHistRwd(r)) require.NoError(t, err) fp2Period2Historical := datagen.RandomInt(r, 10) - err = k.setFinalityProviderHistoricalRewards(ctx, fp2, fp2Period2Historical, datagen.GenRandomFinalityProviderHistoricalRewards(r)) + err = k.setFinalityProviderHistoricalRewards(ctx, fp2, fp2Period2Historical, datagen.GenRandomFPHistRwd(r)) require.NoError(t, err) // sets a new current fp rwd to check the delete all diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index 0aefad4db..829287587 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -12,7 +12,45 @@ import ( "github.com/stretchr/testify/require" ) -func FuzzCheckcalculateDelegationRewardsBetween(f *testing.F) { +func FuzzCheckCalculateBTCDelegationRewards(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp, del := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + btcRwd := datagen.GenRandomBTCDelegationRewardsTracker(r) + + rwd, err := k.CalculateBTCDelegationRewards(ctx, fp, del, btcRwd.StartPeriodCumulativeReward) + require.EqualError(t, err, types.ErrBTCDelegationRewardsTrackerNotFound.Error()) + require.Equal(t, rwd, sdk.Coins{}) + + btcRwd.TotalActiveSat = math.ZeroInt() + err = k.setBTCDelegationRewardsTracker(ctx, fp, del, btcRwd) + require.NoError(t, err) + + rwd, err = k.CalculateBTCDelegationRewards(ctx, fp, del, btcRwd.StartPeriodCumulativeReward) + require.NoError(t, err) + require.Equal(t, rwd, sdk.NewCoins()) + + // sets a real one but with a bad period + btcRwd = datagen.GenRandomBTCDelegationRewardsTracker(r) + err = k.setBTCDelegationRewardsTracker(ctx, fp, del, btcRwd) + require.NoError(t, err) + + badEndedPeriod := btcRwd.StartPeriodCumulativeReward - 1 + require.Panics(t, func() { + _, _ = k.CalculateBTCDelegationRewards(ctx, fp, del, badEndedPeriod) + }) + + // Creates a correct and expected historical periods with start and ending properly set + }) +} + +func FuzzCheckCalculateDelegationRewardsBetween(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) f.Fuzz(func(t *testing.T, seed int64) { @@ -28,8 +66,8 @@ func FuzzCheckcalculateDelegationRewardsBetween(f *testing.F) { _, _ = k.calculateDelegationRewardsBetween(ctx, fp, del, btcRwd, badEndedPeriod) }) - historicalStartPeriod := datagen.GenRandomFinalityProviderHistoricalRewards(r) - historicalStartPeriod.CumulativeRewardsPerSat = historicalStartPeriod.CumulativeRewardsPerSat.MulInt(DecimalAccumulatedRewards) + historicalStartPeriod := datagen.GenRandomFPHistRwd(r) + historicalStartPeriod.CumulativeRewardsPerSat = historicalStartPeriod.CumulativeRewardsPerSat.MulInt(types.DecimalAccumulatedRewards) err := k.setFinalityProviderHistoricalRewards(ctx, fp, btcRwd.StartPeriodCumulativeReward, historicalStartPeriod) require.NoError(t, err) @@ -43,15 +81,15 @@ func FuzzCheckcalculateDelegationRewardsBetween(f *testing.F) { }) // creates a correct historical rewards that has more rewards than the historical - historicalEndingPeriod := datagen.GenRandomFinalityProviderHistoricalRewards(r) - historicalEndingPeriod.CumulativeRewardsPerSat = historicalEndingPeriod.CumulativeRewardsPerSat.MulInt(DecimalAccumulatedRewards) + historicalEndingPeriod := datagen.GenRandomFPHistRwd(r) + historicalEndingPeriod.CumulativeRewardsPerSat = historicalEndingPeriod.CumulativeRewardsPerSat.MulInt(types.DecimalAccumulatedRewards) historicalEndingPeriod.CumulativeRewardsPerSat = historicalEndingPeriod.CumulativeRewardsPerSat.Add(historicalStartPeriod.CumulativeRewardsPerSat...) err = k.setFinalityProviderHistoricalRewards(ctx, fp, endingPeriod, historicalEndingPeriod) require.NoError(t, err) expectedRewards := historicalEndingPeriod.CumulativeRewardsPerSat.Sub(historicalStartPeriod.CumulativeRewardsPerSat...) expectedRewards = expectedRewards.MulInt(btcRwd.TotalActiveSat) - expectedRewards = expectedRewards.QuoInt(DecimalAccumulatedRewards) + expectedRewards = expectedRewards.QuoInt(types.DecimalAccumulatedRewards) delRewards, err := k.calculateDelegationRewardsBetween(ctx, fp, del, btcRwd, endingPeriod) require.NoError(t, err) @@ -112,7 +150,7 @@ func FuzzCheckIncrementFinalityProviderPeriod(f *testing.F) { err = k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) require.NoError(t, err) - amtRwdInHistorical := fpCurrentRwd.CurrentRewards.MulInt(DecimalAccumulatedRewards).QuoInt(math.NewInt(2)) + amtRwdInHistorical := fpCurrentRwd.CurrentRewards.MulInt(types.DecimalAccumulatedRewards).QuoInt(math.NewInt(2)) err = k.setFinalityProviderHistoricalRewards(ctx, fp, fpCurrentRwd.Period-1, types.NewFinalityProviderHistoricalRewards(amtRwdInHistorical)) require.NoError(t, err) @@ -123,7 +161,7 @@ func FuzzCheckIncrementFinalityProviderPeriod(f *testing.F) { historicalEndedPeriod, err := k.GetFinalityProviderHistoricalRewards(ctx, fp, endedPeriod) require.NoError(t, err) - expectedHistoricalRwd := amtRwdInHistorical.Add(fpCurrentRwd.CurrentRewards.MulInt(DecimalAccumulatedRewards).QuoInt(fpCurrentRwd.TotalActiveSat)...) + expectedHistoricalRwd := amtRwdInHistorical.Add(fpCurrentRwd.CurrentRewards.MulInt(types.DecimalAccumulatedRewards).QuoInt(fpCurrentRwd.TotalActiveSat)...) require.Equal(t, historicalEndedPeriod.CumulativeRewardsPerSat.String(), expectedHistoricalRwd.String()) newFPCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fp) @@ -229,7 +267,7 @@ func TestIncrementFinalityProviderPeriod(t *testing.T) { require.Equal(t, fp1EndedPeriod, uint64(1)) // now the historical that just ended should have as cumulative rewards 4000ubbn 2_000000ubbn/500sats - checkFpHistoricalRwd(t, ctx, k, fp1, fp1EndedPeriod, newBaseCoins(4000).MulInt(DecimalAccumulatedRewards)) + checkFpHistoricalRwd(t, ctx, k, fp1, fp1EndedPeriod, newBaseCoins(4000).MulInt(types.DecimalAccumulatedRewards)) checkFpCurrentRwd(t, ctx, k, fp1, fp1EndedPeriod+1, sdk.NewCoins(), satsDelegated) fp2EndedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp2) diff --git a/x/incentive/types/rewards.go b/x/incentive/types/rewards.go index fca82ef84..f5a71c284 100644 --- a/x/incentive/types/rewards.go +++ b/x/incentive/types/rewards.go @@ -5,6 +5,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +var ( + // it is needed to add decimal points when reducing the rewards amount + // per sat to latter when giving out the rewards to the gauge, reduce + // the decimal points back, currently 20 decimal points are being added + // the sdkmath.Int holds a big int which support up to 2^256 integers + DecimalAccumulatedRewards, _ = sdkmath.NewIntFromString("100000000000000000000") +) + func NewBTCDelegationRewardsTracker(startPeriod uint64, totalSat sdkmath.Int) BTCDelegationRewardsTracker { return BTCDelegationRewardsTracker{ StartPeriodCumulativeReward: startPeriod, From 522f44b6cb43f1e60b1eadbe7bbfbcbdcd8d8b21 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 11 Dec 2024 15:04:10 -0300 Subject: [PATCH 051/132] chore: add tests for CalculateBTCDelegationRewards --- testutil/datagen/incentive.go | 7 +++++++ x/incentive/keeper/reward_tracker.go | 2 ++ x/incentive/keeper/reward_tracker_test.go | 14 ++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/testutil/datagen/incentive.go b/testutil/datagen/incentive.go index 31ba14955..18979acf5 100644 --- a/testutil/datagen/incentive.go +++ b/testutil/datagen/incentive.go @@ -166,3 +166,10 @@ func GenRandomFPHistRwdWithDecimals(r *rand.Rand) itypes.FinalityProviderHistori rwd.CumulativeRewardsPerSat = rwd.CumulativeRewardsPerSat.MulInt(itypes.DecimalAccumulatedRewards) return rwd } + +func GenRandomFPHistRwdStartAndEnd(r *rand.Rand) (start, end itypes.FinalityProviderHistoricalRewards) { + start = GenRandomFPHistRwdWithDecimals(r) + end = GenRandomFPHistRwdWithDecimals(r) + end.CumulativeRewardsPerSat = end.CumulativeRewardsPerSat.Add(start.CumulativeRewardsPerSat...) + return start, end +} diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 9b97fc592..6479ac5b8 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -99,6 +99,8 @@ func (k Keeper) btcDelegationModifiedWithPreInitDel( return k.initializeBTCDelegation(ctx, fp, del) } +// CalculateBTCDelegationRewardsAndSendToGauge calculates the rewards of the delegator based on the +// StartPeriodCumulativeReward and the received endPeriod and sends to the delegator gauge. func (k Keeper) CalculateBTCDelegationRewardsAndSendToGauge(ctx context.Context, fp, del sdk.AccAddress, endPeriod uint64) error { rewards, err := k.CalculateBTCDelegationRewards(ctx, fp, del, endPeriod) if err != nil { diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index 829287587..a3d161fe1 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -47,6 +47,20 @@ func FuzzCheckCalculateBTCDelegationRewards(f *testing.F) { }) // Creates a correct and expected historical periods with start and ending properly set + startHist, endHist := datagen.GenRandomFPHistRwdStartAndEnd(r) + err = k.setFinalityProviderHistoricalRewards(ctx, fp, btcRwd.StartPeriodCumulativeReward, startHist) + require.NoError(t, err) + endPeriod := btcRwd.StartPeriodCumulativeReward + datagen.RandomInt(r, 10) + err = k.setFinalityProviderHistoricalRewards(ctx, fp, endPeriod, endHist) + require.NoError(t, err) + + expectedRwd := endHist.CumulativeRewardsPerSat.Sub(startHist.CumulativeRewardsPerSat...) + expectedRwd = expectedRwd.MulInt(btcRwd.TotalActiveSat) + expectedRwd = expectedRwd.QuoInt(types.DecimalAccumulatedRewards) + + rwd, err = k.CalculateBTCDelegationRewards(ctx, fp, del, endPeriod) + require.NoError(t, err) + require.Equal(t, rwd.String(), expectedRwd.String()) }) } From f86922ac1b4af8541da2ba4c2b69ae4d527a5956 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 11 Dec 2024 17:16:29 -0300 Subject: [PATCH 052/132] fix: test CalculateBTCDelegationRewards --- testutil/datagen/incentive.go | 3 ++- x/incentive/keeper/reward_tracker_test.go | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/testutil/datagen/incentive.go b/testutil/datagen/incentive.go index 18979acf5..a952f53fc 100644 --- a/testutil/datagen/incentive.go +++ b/testutil/datagen/incentive.go @@ -3,6 +3,7 @@ package datagen import ( "math/rand" + "cosmossdk.io/math" sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" @@ -152,7 +153,7 @@ func GenRandomFinalityProviderCurrentRewards(r *rand.Rand) itypes.FinalityProvid func GenRandomBTCDelegationRewardsTracker(r *rand.Rand) itypes.BTCDelegationRewardsTracker { period := RandomInt(r, 100) + 2 - activeSatoshi := RandomMathInt(r, 10000) + activeSatoshi := RandomMathInt(r, 10000).Add(math.NewInt(100)) return itypes.NewBTCDelegationRewardsTracker(period, activeSatoshi) } diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index a3d161fe1..d842052ad 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -47,10 +47,14 @@ func FuzzCheckCalculateBTCDelegationRewards(f *testing.F) { }) // Creates a correct and expected historical periods with start and ending properly set + btcRwd = datagen.GenRandomBTCDelegationRewardsTracker(r) + err = k.setBTCDelegationRewardsTracker(ctx, fp, del, btcRwd) + require.NoError(t, err) + startHist, endHist := datagen.GenRandomFPHistRwdStartAndEnd(r) err = k.setFinalityProviderHistoricalRewards(ctx, fp, btcRwd.StartPeriodCumulativeReward, startHist) require.NoError(t, err) - endPeriod := btcRwd.StartPeriodCumulativeReward + datagen.RandomInt(r, 10) + endPeriod := btcRwd.StartPeriodCumulativeReward + datagen.RandomInt(r, 10) + 1 err = k.setFinalityProviderHistoricalRewards(ctx, fp, endPeriod, endHist) require.NoError(t, err) From f50d13c3bc63bb40f8afcf688fc196df7797941b Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 11 Dec 2024 17:21:40 -0300 Subject: [PATCH 053/132] chore: add test for CalculateBTCDelegationRewardsAndSendToGauge --- x/incentive/keeper/reward_tracker_test.go | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index d842052ad..c07199504 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -12,6 +12,42 @@ import ( "github.com/stretchr/testify/require" ) +func FuzzCheckCalculateBTCDelegationRewardsAndSendToGauge(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp, del := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + btcRwd := datagen.GenRandomBTCDelegationRewardsTracker(r) + err := k.setBTCDelegationRewardsTracker(ctx, fp, del, btcRwd) + require.NoError(t, err) + + startHist, endHist := datagen.GenRandomFPHistRwdStartAndEnd(r) + err = k.setFinalityProviderHistoricalRewards(ctx, fp, btcRwd.StartPeriodCumulativeReward, startHist) + require.NoError(t, err) + endPeriod := btcRwd.StartPeriodCumulativeReward + datagen.RandomInt(r, 10) + 1 + err = k.setFinalityProviderHistoricalRewards(ctx, fp, endPeriod, endHist) + require.NoError(t, err) + + expectedRwd := endHist.CumulativeRewardsPerSat.Sub(startHist.CumulativeRewardsPerSat...) + expectedRwd = expectedRwd.MulInt(btcRwd.TotalActiveSat) + expectedRwd = expectedRwd.QuoInt(types.DecimalAccumulatedRewards) + + rwdGauge := datagen.GenRandomRewardGauge(r) + k.SetRewardGauge(ctx, types.BTCDelegationType, del, rwdGauge) + + err = k.CalculateBTCDelegationRewardsAndSendToGauge(ctx, fp, del, endPeriod) + require.NoError(t, err) + + delRwdGauge := k.GetRewardGauge(ctx, types.BTCDelegationType, del) + require.Equal(t, rwdGauge.Coins.Add(expectedRwd...).String(), delRwdGauge.Coins.String()) + }) +} + func FuzzCheckCalculateBTCDelegationRewards(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) From 6cdead45c24c4ed703695796cabc7b73b424861b Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 11 Dec 2024 20:55:24 -0300 Subject: [PATCH 054/132] chore: add test for btcDelegationModifiedWithPreInitDel --- testutil/coins/margin.go | 55 ++++++++++++++++++++ testutil/coins/margin_test.go | 30 +++++++++++ x/incentive/keeper/btc_staking_gauge_test.go | 37 +++---------- x/incentive/keeper/reward_tracker.go | 9 ++++ x/incentive/keeper/reward_tracker_test.go | 46 ++++++++++++++++ 5 files changed, 147 insertions(+), 30 deletions(-) create mode 100644 testutil/coins/margin.go create mode 100644 testutil/coins/margin_test.go diff --git a/testutil/coins/margin.go b/testutil/coins/margin.go new file mode 100644 index 000000000..69617b01f --- /dev/null +++ b/testutil/coins/margin.go @@ -0,0 +1,55 @@ +package coins + +import ( + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func RequireCoinsDiffInPointOnePercentMargin(t *testing.T, c1, c2 sdk.Coins) { + require.True(t, CoinsDiffInPointOnePercentMargin(c1, c2)) +} + +func CoinsDiffInPointOnePercentMargin(c1, c2 sdk.Coins) bool { + diff, hasNeg := c1.SafeSub(c2...) + if hasNeg { + diff = AbsoluteCoins(diff) + } + margin := CalculatePointOnePercentOrMinOne(c1) + return margin.IsAllGTE(diff) +} + +func AbsoluteCoins(value sdk.Coins) sdk.Coins { + ret := sdk.NewCoins() + for _, v := range value { + ret = ret.Add(sdk.NewCoin(v.Denom, v.Amount.Abs())) + } + return ret +} + +// CalculatePointOnePercentOrMinOne transforms 10000 = 10 +// if 0.1% is of the value is less 1, sets one as value in the coin +func CalculatePointOnePercentOrMinOne(value sdk.Coins) sdk.Coins { + numerator := math.NewInt(1) + denominator := math.NewInt(1000) + result := value.MulInt(numerator).QuoInt(denominator) + return coinsAtLeastMinAmount(result, math.OneInt()) +} + +func coinsAtLeastMinAmount(value sdk.Coins, minAmt math.Int) sdk.Coins { + ret := sdk.NewCoins() + for _, v := range value { + minCoinAmt := coinAtLeastMinAmount(v, minAmt) + ret = ret.Add(minCoinAmt) + } + return ret +} + +func coinAtLeastMinAmount(v sdk.Coin, minAmt math.Int) sdk.Coin { + if v.Amount.GT(minAmt) { + return v + } + return sdk.NewCoin(v.Denom, minAmt) +} diff --git a/testutil/coins/margin_test.go b/testutil/coins/margin_test.go new file mode 100644 index 000000000..37b551ff4 --- /dev/null +++ b/testutil/coins/margin_test.go @@ -0,0 +1,30 @@ +package coins_test + +import ( + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/babylonlabs-io/babylon/testutil/coins" +) + +func TestCalculatePointOnePercent(t *testing.T) { + denom := "xsss" + result := coins.CalculatePointOnePercentOrMinOne(sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(10000)))) + require.Equal(t, sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(10))).String(), result.String()) +} + +func TestCoinsDiffInPointOnePercentMargin(t *testing.T) { + denom := "xsss" + c1 := sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(10000))) + c2 := sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(9999))) + require.True(t, coins.CoinsDiffInPointOnePercentMargin(c1, c2)) + + limitC2 := sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(9990))) + require.True(t, coins.CoinsDiffInPointOnePercentMargin(c1, limitC2)) + + badC2 := sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(9989))) + require.False(t, coins.CoinsDiffInPointOnePercentMargin(c1, badC2)) +} diff --git a/x/incentive/keeper/btc_staking_gauge_test.go b/x/incentive/keeper/btc_staking_gauge_test.go index 1115ee520..9b8ae82a5 100644 --- a/x/incentive/keeper/btc_staking_gauge_test.go +++ b/x/incentive/keeper/btc_staking_gauge_test.go @@ -4,7 +4,7 @@ import ( "math/rand" "testing" - "cosmossdk.io/math" + "github.com/babylonlabs-io/babylon/testutil/coins" "github.com/babylonlabs-io/babylon/testutil/datagen" testkeeper "github.com/babylonlabs-io/babylon/testutil/keeper" "github.com/babylonlabs-io/babylon/x/incentive/types" @@ -107,43 +107,20 @@ func FuzzRewardBTCStaking(f *testing.F) { // A little bit of rewards could be lost in the process due to precision points // so 0.1% difference can be considered okay - allowedMarginError := CalculatePointOnePercent(reward) - diff, _ := reward.SafeSub(rg.Coins...) - require.Truef(t, diff.IsAllLT(allowedMarginError), - "BTC delegation failed within the margin of error: %s\nRewards: %s\nGauge: %s", - allowedMarginError.String(), reward.String(), rg.Coins.String(), + require.Truef(t, coins.CoinsDiffInPointOnePercentMargin(reward, rg.Coins), + "BTC delegation failed within the margin of error 0.1%\nRewards: %s\nGauge: %s", + reward.String(), rg.Coins.String(), ) sumRewards = sumRewards.Add(reward...) } - allowedMarginError := CalculatePointOnePercent(sumCoinsForDels) - diff, _ := sumCoinsForDels.SafeSub(sumRewards...) - require.Truef(t, diff.IsAllLT(allowedMarginError), - "Sum of total rewards failed within the margin of error: %s\nRewards: %s\nGauge: %s", - allowedMarginError.String(), sumCoinsForDels.String(), sumRewards.String(), + require.Truef(t, coins.CoinsDiffInPointOnePercentMargin(sumCoinsForDels, sumRewards), + "Sum of total rewards failed within the margin of error 0.1%\nRewards: %s\nGauge: %s", + sumCoinsForDels.String(), sumRewards.String(), ) // assert distributedCoins is a subset of coins in gauge require.True(t, gauge.Coins.IsAllGTE(distributedCoins)) }) } - -func CalculatePointOnePercent(value sdk.Coins) sdk.Coins { - numerator := math.NewInt(1) // 0.1% as numerator - denominator := math.NewInt(1000) // 0.1% denominator - result := value.MulInt(numerator).QuoInt(denominator) - return coinsAtLeastMinAmount(result, math.OneInt()) -} - -func coinsAtLeastMinAmount(value sdk.Coins, minAmt math.Int) sdk.Coins { - ret := sdk.NewCoins() - for _, v := range value { - if v.Amount.GT(minAmt) { - ret = ret.Add(v) - continue - } - ret = ret.Add(sdk.NewCoin(v.Denom, minAmt)) - } - return ret -} diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 6479ac5b8..5c37873b5 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -71,6 +71,8 @@ func (k Keeper) sendAllBtcRewardsToGauge(ctx context.Context, del sdk.AccAddress }) } +// btcDelegationModified just calls the BTC delegation modified without +// any action to modify the delegation prior to initialization. func (k Keeper) btcDelegationModified( ctx context.Context, fp, del sdk.AccAddress, @@ -78,6 +80,13 @@ func (k Keeper) btcDelegationModified( return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { return nil }) } +// btcDelegationModifiedWithPreInitDel does the procedure when a BTC delegation has +// some modification in its total amount of active satoshi staked. This function +// increments the finality provider period (that creates a new historical) with +// the ended period, calculates the delegation reward and send to the gauge +// and calls a function prior (preInitializeDelegation) to initialize a new +// BTC delegation, which is useful to apply subtract or add the total +// amount staked by the delegation and FP. func (k Keeper) btcDelegationModifiedWithPreInitDel( ctx context.Context, fp, del sdk.AccAddress, diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index c07199504..758dca57f 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -1,17 +1,63 @@ package keeper import ( + "context" "math/rand" "testing" "cosmossdk.io/math" appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/testutil/coins" "github.com/babylonlabs-io/babylon/testutil/datagen" "github.com/babylonlabs-io/babylon/x/incentive/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) +func FuzzCheckBtcDelegationModifiedWithPreInitDel(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp, del := datagen.GenRandomAddress(), datagen.GenRandomAddress() + + count := 0 + fCount := func(ctx context.Context, fp, del sdk.AccAddress) error { + count++ + return nil + } + require.Equal(t, count, 0) + + err := k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, fCount) + require.EqualError(t, err, types.ErrBTCDelegationRewardsTrackerNotFound.Error()) + + err = k.BtcDelegationActivated(ctx, fp, del, datagen.RandomInt(r, 1000)+10) + require.NoError(t, err) + + delRwdGauge := k.GetRewardGauge(ctx, types.BTCDelegationType, del) + require.Nil(t, delRwdGauge) + + coinsToDel := datagen.GenRandomCoins(r) + err = k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp, coinsToDel) + require.NoError(t, err) + + err = k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, fCount) + require.NoError(t, err) + require.Equal(t, count, 2) + + delRwdGauge = k.GetRewardGauge(ctx, types.BTCDelegationType, del) + coins.RequireCoinsDiffInPointOnePercentMargin(t, delRwdGauge.Coins, coinsToDel) + // note: the difference here in one micro coin value is expected due to the loss of precision in the BTC reward tracking mechanism + // that needs to keep track of how much rewards 1 satoshi is entitled to receive. + // expected: "10538986AnIGK,10991059BQZFY,19858803DTFwK,18591052NPLYN,11732268RmOWl,17440819TMPYN,17161570WfgTh,17743833aMJHg,19321764evLoF,17692017eysTF,15763155fbRbV,15691503jtkIM,15782745onTeQ,19076817pycDX,10059521tfcfY,13053824tgYdv,16164439ufZLL,15295587xvzKC" + // actual : "10538987AnIGK,10991060BQZFY,19858804DTFwK,18591053NPLYN,11732269RmOWl,17440820TMPYN,17161571WfgTh,17743834aMJHg,19321765evLoF,17692018eysTF,15763156fbRbV,15691504jtkIM,15782746onTeQ,19076818pycDX,10059522tfcfY,13053825tgYdv,16164440ufZLL,15295588xvzKC" + // require.Equal(t, delRwdGauge.Coins.String(), coinsToDel.String()) + }) +} + func FuzzCheckCalculateBTCDelegationRewardsAndSendToGauge(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) From aafda528440b6de3b4da254420813e57e7a261e4 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 11 Dec 2024 21:38:26 -0300 Subject: [PATCH 055/132] chore: add test for sendAllBtcRewardsToGauge --- testutil/coins/margin.go | 8 ++ testutil/coins/margin_test.go | 9 +++ x/incentive/keeper/btc_staking_gauge_test.go | 2 +- x/incentive/keeper/grpc_query.go | 2 +- x/incentive/keeper/msg_server.go | 2 +- x/incentive/keeper/reward_gauge.go | 2 +- x/incentive/keeper/reward_tracker.go | 12 +-- x/incentive/keeper/reward_tracker_test.go | 80 ++++++++++++++++++++ 8 files changed, 107 insertions(+), 10 deletions(-) diff --git a/testutil/coins/margin.go b/testutil/coins/margin.go index 69617b01f..cb471f440 100644 --- a/testutil/coins/margin.go +++ b/testutil/coins/margin.go @@ -38,6 +38,14 @@ func CalculatePointOnePercentOrMinOne(value sdk.Coins) sdk.Coins { return coinsAtLeastMinAmount(result, math.OneInt()) } +// CalculatePercentageOfCoins if percentage is 30, transforms 100bbn = 30bbn +func CalculatePercentageOfCoins(value sdk.Coins, percentage uint64) sdk.Coins { + divisor := math.NewInt(100) + multiplier := math.NewIntFromUint64(percentage) + result := value.MulInt(multiplier).QuoInt(divisor) + return result +} + func coinsAtLeastMinAmount(value sdk.Coins, minAmt math.Int) sdk.Coins { ret := sdk.NewCoins() for _, v := range value { diff --git a/testutil/coins/margin_test.go b/testutil/coins/margin_test.go index 37b551ff4..adf36134a 100644 --- a/testutil/coins/margin_test.go +++ b/testutil/coins/margin_test.go @@ -16,6 +16,15 @@ func TestCalculatePointOnePercent(t *testing.T) { require.Equal(t, sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(10))).String(), result.String()) } +func TestCalculatePercentageOfCoins(t *testing.T) { + denom := "xsss" + result := coins.CalculatePercentageOfCoins(sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(100))), 30) + require.Equal(t, sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(30))).String(), result.String()) + + result = coins.CalculatePercentageOfCoins(sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(1560))), 30) + require.Equal(t, sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(468))).String(), result.String()) +} + func TestCoinsDiffInPointOnePercentMargin(t *testing.T) { denom := "xsss" c1 := sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(10000))) diff --git a/x/incentive/keeper/btc_staking_gauge_test.go b/x/incentive/keeper/btc_staking_gauge_test.go index 9b8ae82a5..8939ed4d4 100644 --- a/x/incentive/keeper/btc_staking_gauge_test.go +++ b/x/incentive/keeper/btc_staking_gauge_test.go @@ -81,7 +81,7 @@ func FuzzRewardBTCStaking(f *testing.F) { require.Equal(t, delRwd.TotalActiveSat.Uint64(), btcDel.TotalSat) // makes sure the rewards added reach the delegation gauge - err = k.SendBtcDelegationRewardsToGauge(ctx, fpAddr, delAddr) + err = k.BtcDelegationActivated(ctx, fpAddr, delAddr, 0) require.NoError(t, err) } fpCurrentRwd, err := k.GetFinalityProviderCurrentRewards(ctx, fpAddr) diff --git a/x/incentive/keeper/grpc_query.go b/x/incentive/keeper/grpc_query.go index 9cb775dba..bc70824db 100644 --- a/x/incentive/keeper/grpc_query.go +++ b/x/incentive/keeper/grpc_query.go @@ -27,7 +27,7 @@ func (k Keeper) RewardGauges(goCtx context.Context, req *types.QueryRewardGauges // find reward gauge for _, sType := range types.GetAllStakeholderTypes() { - if err := k.sendAllBtcDelegatorRewardsToGauge(ctx, sType, address); err != nil { + if err := k.sendAllBtcDelegationTypeToRewardsToGauge(ctx, sType, address); err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/incentive/keeper/msg_server.go b/x/incentive/keeper/msg_server.go index c8c0a6f1d..883691e77 100644 --- a/x/incentive/keeper/msg_server.go +++ b/x/incentive/keeper/msg_server.go @@ -54,7 +54,7 @@ func (ms msgServer) WithdrawReward(goCtx context.Context, req *types.MsgWithdraw return nil, status.Error(codes.InvalidArgument, err.Error()) } - if err := ms.sendAllBtcDelegatorRewardsToGauge(ctx, sType, addr); err != nil { + if err := ms.sendAllBtcDelegationTypeToRewardsToGauge(ctx, sType, addr); err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/incentive/keeper/reward_gauge.go b/x/incentive/keeper/reward_gauge.go index d6a11b167..9a4798388 100644 --- a/x/incentive/keeper/reward_gauge.go +++ b/x/incentive/keeper/reward_gauge.go @@ -9,7 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -func (k Keeper) sendAllBtcDelegatorRewardsToGauge(ctx context.Context, sType types.StakeholderType, del sdk.AccAddress) error { +func (k Keeper) sendAllBtcDelegationTypeToRewardsToGauge(ctx context.Context, sType types.StakeholderType, del sdk.AccAddress) error { if sType != types.BTCDelegationType { return nil } diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 5c37873b5..f45e9e0d6 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -46,7 +46,7 @@ func (k Keeper) FpSlashed(ctx context.Context, fp sdk.AccAddress) error { return err } - // remove all the rewards available from the ended periods + // remove all the rewards available from the just ended period keysBtcDelRwdTracker := make([][]byte, 0) if err := k.IterateBTCDelegationRewardsTracker(ctx, fp, func(fp, del sdk.AccAddress) error { keysBtcDelRwdTracker = append(keysBtcDelRwdTracker, del.Bytes()) @@ -61,18 +61,18 @@ func (k Keeper) FpSlashed(ctx context.Context, fp sdk.AccAddress) error { return nil } -func (k Keeper) SendBtcDelegationRewardsToGauge(ctx context.Context, fp, del sdk.AccAddress) error { - return k.btcDelegationModified(ctx, fp, del) -} - +// sendAllBtcRewardsToGauge iterates over all the finality providers associated +// with the delegator and withdraw the rewards available to the gauge. +// This creates new periods for each delegation and finality provider. func (k Keeper) sendAllBtcRewardsToGauge(ctx context.Context, del sdk.AccAddress) error { return k.iterBtcDelegationsByDelegator(ctx, del, func(del, fp sdk.AccAddress) error { - return k.SendBtcDelegationRewardsToGauge(ctx, fp, del) + return k.btcDelegationModified(ctx, fp, del) }) } // btcDelegationModified just calls the BTC delegation modified without // any action to modify the delegation prior to initialization. +// this could also be called SendBtcDelegationRewardsToGauge. func (k Keeper) btcDelegationModified( ctx context.Context, fp, del sdk.AccAddress, diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index 758dca57f..4fe4b676b 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -14,6 +14,86 @@ import ( "github.com/stretchr/testify/require" ) +func FuzzCheckSendAllBtcRewardsToGauge(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp1, fp2, del1, del2 := datagen.GenRandomAddress(), datagen.GenRandomAddress(), datagen.GenRandomAddress(), datagen.GenRandomAddress() + + // should not error even without any data in the trackers + // because there is no delegation pair (fp, del1) to iterate + err := k.sendAllBtcRewardsToGauge(ctx, del1) + require.NoError(t, err) + + // for fp1 30% for del1 and 70% for del 2 + del1Fp1Percentage := uint64(30) + del2Fp1Percentage := uint64(70) + err = k.BtcDelegationActivated(ctx, fp1, del1, del1Fp1Percentage) + require.NoError(t, err) + err = k.BtcDelegationActivated(ctx, fp1, del2, del2Fp1Percentage) + require.NoError(t, err) + + // for fp2 50/50% for each del + eachDelFp2Percentage := uint64(50) + err = k.BtcDelegationActivated(ctx, fp2, del1, 50) + require.NoError(t, err) + err = k.BtcDelegationActivated(ctx, fp2, del2, 50) + require.NoError(t, err) + + rwdFp1 := datagen.GenRandomCoins(r) + err = k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp1, rwdFp1) + require.NoError(t, err) + + rwdFp2 := datagen.GenRandomCoins(r) + err = k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp2, rwdFp2) + require.NoError(t, err) + + // calculates rewards for the del1 first + err = k.sendAllBtcRewardsToGauge(ctx, del1) + require.NoError(t, err) + + del1Fp1Rwds := coins.CalculatePercentageOfCoins(rwdFp1, del1Fp1Percentage) + fp2RwdForEachDel := coins.CalculatePercentageOfCoins(rwdFp2, eachDelFp2Percentage) + expectedRwdDel1 := del1Fp1Rwds.Add(fp2RwdForEachDel...) + del1RwdGauge := k.GetRewardGauge(ctx, types.BTCDelegationType, del1) + coins.RequireCoinsDiffInPointOnePercentMargin(t, expectedRwdDel1, del1RwdGauge.Coins) + + // calculates rewards for the del2 + err = k.sendAllBtcRewardsToGauge(ctx, del2) + require.NoError(t, err) + + del2Fp1Rwds := coins.CalculatePercentageOfCoins(rwdFp1, del2Fp1Percentage) + expectedRwdDel2 := del2Fp1Rwds.Add(fp2RwdForEachDel...) + del2RwdGauge := k.GetRewardGauge(ctx, types.BTCDelegationType, del2) + coins.RequireCoinsDiffInPointOnePercentMargin(t, expectedRwdDel2, del2RwdGauge.Coins) + + // check if send all the rewards again something changes, it shouldn't + err = k.sendAllBtcRewardsToGauge(ctx, del1) + require.NoError(t, err) + + newDel1RwdGauge := k.GetRewardGauge(ctx, types.BTCDelegationType, del1) + require.Equal(t, newDel1RwdGauge.Coins.String(), del1RwdGauge.Coins.String()) + + // sends new rewards for fp2 which is 50/50 + rwdFp2 = datagen.GenRandomCoins(r) + err = k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp2, rwdFp2) + require.NoError(t, err) + + err = k.sendAllBtcRewardsToGauge(ctx, del1) + require.NoError(t, err) + + lastFp2RwdForEachDel := coins.CalculatePercentageOfCoins(rwdFp2, eachDelFp2Percentage) + lastDel1RwdGauge := k.GetRewardGauge(ctx, types.BTCDelegationType, del1) + lastExpectedRwdDel1 := del1Fp1Rwds.Add(fp2RwdForEachDel...).Add(lastFp2RwdForEachDel...) + coins.RequireCoinsDiffInPointOnePercentMargin(t, lastExpectedRwdDel1, lastDel1RwdGauge.Coins) + require.Equal(t, lastFp2RwdForEachDel.String(), lastDel1RwdGauge.Coins.Sub(newDel1RwdGauge.Coins...).String()) + }) +} + func FuzzCheckBtcDelegationModifiedWithPreInitDel(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) From 9c548d27290eab84711b1adb30200de4be6d03b2 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 11 Dec 2024 22:11:23 -0300 Subject: [PATCH 056/132] chore: add test for FpSlashed --- testutil/coins/margin.go | 8 +- x/incentive/keeper/reward_tracker.go | 8 +- x/incentive/keeper/reward_tracker_test.go | 98 ++++++++++++++++++++++- 3 files changed, 110 insertions(+), 4 deletions(-) diff --git a/testutil/coins/margin.go b/testutil/coins/margin.go index cb471f440..0063b3aac 100644 --- a/testutil/coins/margin.go +++ b/testutil/coins/margin.go @@ -9,7 +9,13 @@ import ( ) func RequireCoinsDiffInPointOnePercentMargin(t *testing.T, c1, c2 sdk.Coins) { - require.True(t, CoinsDiffInPointOnePercentMargin(c1, c2)) + inMargin := CoinsDiffInPointOnePercentMargin(c1, c2) + if !inMargin { + t.Log("Coins are not in 0.1% margin") + t.Logf("c1: %s", c1.String()) + t.Logf("c2: %s", c2.String()) + } + require.True(t, inMargin) } func CoinsDiffInPointOnePercentMargin(c1, c2 sdk.Coins) bool { diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index f45e9e0d6..f2ea352af 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -40,7 +40,13 @@ func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddres }) } +// FpSlashed a slashed finality provider should withdraw all the rewards +// available to it, by iterating over all the delegations for this FP +// and sending to the gauge. After the rewards are removed, it should +// delete every rewards tracker value in the store related to this slashed +// finality provider. func (k Keeper) FpSlashed(ctx context.Context, fp sdk.AccAddress) error { + // finalize the period to get a new history with the current rewards available endedPeriod, err := k.IncrementFinalityProviderPeriod(ctx, fp) if err != nil { return err @@ -55,7 +61,7 @@ func (k Keeper) FpSlashed(ctx context.Context, fp sdk.AccAddress) error { return err } - // delete all reward tracer that correlates with the slashed finality provider. + // delete all reward tracker that correlates with the slashed finality provider. k.deleteKeysFromBTCDelegationRewardsTracker(ctx, fp, keysBtcDelRwdTracker) k.deleteAllFromFinalityProviderRwd(ctx, fp) return nil diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index 4fe4b676b..13dfdf7ff 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -14,6 +14,100 @@ import ( "github.com/stretchr/testify/require" ) +func FuzzCheckFpSlashed(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp1, fp2, del1, del2 := datagen.GenRandomAddress(), datagen.GenRandomAddress(), datagen.GenRandomAddress(), datagen.GenRandomAddress() + + // should not error even without any data in the trackers + // because there is no delegation pair (fp, del1) to iterate + err := k.FpSlashed(ctx, fp1) + require.NoError(t, err) + + // for fp1 30% for del1 and 70% for del 2 + del1Fp1Percentage := uint64(30) + del2Fp1Percentage := uint64(70) + err = k.BtcDelegationActivated(ctx, fp1, del1, del1Fp1Percentage) + require.NoError(t, err) + err = k.BtcDelegationActivated(ctx, fp1, del2, del2Fp1Percentage) + require.NoError(t, err) + + // for fp2 50/50% for each del + eachDelFp2Percentage := uint64(50) + err = k.BtcDelegationActivated(ctx, fp2, del1, eachDelFp2Percentage) + require.NoError(t, err) + err = k.BtcDelegationActivated(ctx, fp2, del2, eachDelFp2Percentage) + require.NoError(t, err) + + rwdFp1 := datagen.GenRandomCoins(r) + err = k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp1, rwdFp1) + require.NoError(t, err) + + rwdFp2 := datagen.GenRandomCoins(r) + err = k.AddFinalityProviderRewardsForBtcDelegations(ctx, fp2, rwdFp2) + require.NoError(t, err) + + // slashes the fp1 + err = k.FpSlashed(ctx, fp1) + require.NoError(t, err) + + del1Fp1Rwds := coins.CalculatePercentageOfCoins(rwdFp1, del1Fp1Percentage) + del1RwdGauge := k.GetRewardGauge(ctx, types.BTCDelegationType, del1) + coins.RequireCoinsDiffInPointOnePercentMargin(t, del1Fp1Rwds, del1RwdGauge.Coins) + + del2Fp1Rwds := coins.CalculatePercentageOfCoins(rwdFp1, del2Fp1Percentage) + del2RwdGauge := k.GetRewardGauge(ctx, types.BTCDelegationType, del2) + coins.RequireCoinsDiffInPointOnePercentMargin(t, del2Fp1Rwds, del2RwdGauge.Coins) + + // verifies that everything was deleted + _, err = k.GetBTCDelegationRewardsTracker(ctx, fp1, del1) + require.EqualError(t, err, types.ErrBTCDelegationRewardsTrackerNotFound.Error()) + _, err = k.GetBTCDelegationRewardsTracker(ctx, fp1, del2) + require.EqualError(t, err, types.ErrBTCDelegationRewardsTrackerNotFound.Error()) + _, err = k.GetFinalityProviderCurrentRewards(ctx, fp1) + require.EqualError(t, err, types.ErrFPCurrentRewardsNotFound.Error()) + _, err = k.GetFinalityProviderHistoricalRewards(ctx, fp1, 1) + require.EqualError(t, err, types.ErrFPHistoricalRewardsNotFound.Error()) + + count := 0 + err = k.iterBtcDelegationsByDelegator(ctx, del1, func(del, fp sdk.AccAddress) error { + count++ + return nil + }) + require.NoError(t, err) + require.Equal(t, count, 1) + + count = 0 + err = k.iterBtcDelegationsByDelegator(ctx, del2, func(del, fp sdk.AccAddress) error { + count++ + return nil + }) + require.NoError(t, err) + require.Equal(t, count, 1) + + // checks that nothing affected the rewards related to the other finality provider + // that wasn't slashed. + err = k.sendAllBtcRewardsToGauge(ctx, del1) + require.NoError(t, err) + + fp2RwdForEachDel := coins.CalculatePercentageOfCoins(rwdFp2, eachDelFp2Percentage) + + lastDel1RwdGauge := k.GetRewardGauge(ctx, types.BTCDelegationType, del1) + coins.RequireCoinsDiffInPointOnePercentMargin(t, del1Fp1Rwds.Add(fp2RwdForEachDel...), lastDel1RwdGauge.Coins) + + err = k.sendAllBtcRewardsToGauge(ctx, del2) + require.NoError(t, err) + + lastDel2RwdGauge := k.GetRewardGauge(ctx, types.BTCDelegationType, del2) + coins.RequireCoinsDiffInPointOnePercentMargin(t, del2Fp1Rwds.Add(fp2RwdForEachDel...), lastDel2RwdGauge.Coins) + }) +} + func FuzzCheckSendAllBtcRewardsToGauge(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) @@ -39,9 +133,9 @@ func FuzzCheckSendAllBtcRewardsToGauge(f *testing.F) { // for fp2 50/50% for each del eachDelFp2Percentage := uint64(50) - err = k.BtcDelegationActivated(ctx, fp2, del1, 50) + err = k.BtcDelegationActivated(ctx, fp2, del1, eachDelFp2Percentage) require.NoError(t, err) - err = k.BtcDelegationActivated(ctx, fp2, del2, 50) + err = k.BtcDelegationActivated(ctx, fp2, del2, eachDelFp2Percentage) require.NoError(t, err) rwdFp1 := datagen.GenRandomCoins(r) From abeda1cf81128c68a633ef385ba76f2f46939412 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 11 Dec 2024 22:17:06 -0300 Subject: [PATCH 057/132] tryfix: e2e rollback changes --- test/e2e/btc_staking_e2e_test.go | 2 +- test/e2e/btc_staking_pre_approval_e2e_test.go | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index 66c974287..5942aebc4 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -652,7 +652,7 @@ func (s *BTCStakingTestSuite) Test7BTCDelegationFeeGrant() { func (s *BTCStakingTestSuite) Test8BTCDelegationFeeGrantTyped() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - node, err := chainA.GetNodeAtIndex(0) + node, err := chainA.GetNodeAtIndex(2) s.NoError(err) wGratee, wGranter := "staker", "feePayer" diff --git a/test/e2e/btc_staking_pre_approval_e2e_test.go b/test/e2e/btc_staking_pre_approval_e2e_test.go index 7d2866641..8fcdd6d1d 100644 --- a/test/e2e/btc_staking_pre_approval_e2e_test.go +++ b/test/e2e/btc_staking_pre_approval_e2e_test.go @@ -75,7 +75,7 @@ func (s *BTCStakingPreApprovalTestSuite) TearDownSuite() { func (s *BTCStakingPreApprovalTestSuite) Test1CreateFinalityProviderAndDelegation() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - nonValidatorNode, err := chainA.GetNodeAtIndex(1) + nonValidatorNode, err := chainA.GetNodeAtIndex(2) s.NoError(err) s.cacheFP = CreateNodeFP( @@ -147,7 +147,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test1CreateFinalityProviderAndDelegatio func (s *BTCStakingPreApprovalTestSuite) Test2SubmitCovenantSignature() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - nonValidatorNode, err := chainA.GetNodeAtIndex(1) + nonValidatorNode, err := chainA.GetNodeAtIndex(2) s.NoError(err) // get last BTC delegation @@ -253,7 +253,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test2SubmitCovenantSignature() { func (s *BTCStakingPreApprovalTestSuite) Test3SendStakingTransctionInclusionProof() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - nonValidatorNode, err := chainA.GetNodeAtIndex(1) + nonValidatorNode, err := chainA.GetNodeAtIndex(2) s.NoError(err) verifiedDelegations := nonValidatorNode.QueryVerifiedDelegations() @@ -285,7 +285,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test3SendStakingTransctionInclusionProo func (s *BTCStakingPreApprovalTestSuite) Test4CommitPublicRandomnessAndSubmitFinalitySignature() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - nonValidatorNode, err := chainA.GetNodeAtIndex(1) + nonValidatorNode, err := chainA.GetNodeAtIndex(2) s.NoError(err) /* @@ -402,7 +402,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test4CommitPublicRandomnessAndSubmitFin func (s *BTCStakingPreApprovalTestSuite) Test4WithdrawReward() { chainA := s.configurer.GetChainConfig(0) - nonValidatorNode, err := chainA.GetNodeAtIndex(1) + nonValidatorNode, err := chainA.GetNodeAtIndex(2) s.NoError(err) // finality provider balance before withdraw @@ -466,7 +466,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test4WithdrawReward() { func (s *BTCStakingPreApprovalTestSuite) Test5SubmitStakerUnbonding() { chainA := s.configurer.GetChainConfig(0) chainA.WaitUntilHeight(1) - nonValidatorNode, err := chainA.GetNodeAtIndex(1) + nonValidatorNode, err := chainA.GetNodeAtIndex(2) s.NoError(err) // wait for a block so that above txs take effect nonValidatorNode.WaitForNextBlock() From 9deffc6e8d6696de8fa78855e8ef45e756b395b5 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 11 Dec 2024 22:34:14 -0300 Subject: [PATCH 058/132] fix: lint --- testutil/coins/margin_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/testutil/coins/margin_test.go b/testutil/coins/margin_test.go index adf36134a..2819bbf26 100644 --- a/testutil/coins/margin_test.go +++ b/testutil/coins/margin_test.go @@ -10,14 +10,16 @@ import ( "github.com/babylonlabs-io/babylon/testutil/coins" ) +const ( + denom = "xsss" +) + func TestCalculatePointOnePercent(t *testing.T) { - denom := "xsss" result := coins.CalculatePointOnePercentOrMinOne(sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(10000)))) require.Equal(t, sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(10))).String(), result.String()) } func TestCalculatePercentageOfCoins(t *testing.T) { - denom := "xsss" result := coins.CalculatePercentageOfCoins(sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(100))), 30) require.Equal(t, sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(30))).String(), result.String()) @@ -26,7 +28,6 @@ func TestCalculatePercentageOfCoins(t *testing.T) { } func TestCoinsDiffInPointOnePercentMargin(t *testing.T) { - denom := "xsss" c1 := sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(10000))) c2 := sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(9999))) require.True(t, coins.CoinsDiffInPointOnePercentMargin(c1, c2)) From f6713176a2b6b2ed5c3b4f358afd20fcfe45d3f6 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 12 Dec 2024 09:36:46 -0300 Subject: [PATCH 059/132] chore: add test for BtcDelegationUnbonded --- x/incentive/keeper/reward_tracker.go | 6 +++ x/incentive/keeper/reward_tracker_store.go | 3 ++ .../keeper/reward_tracker_store_test.go | 43 +++++++++++++++++++ x/incentive/types/errors.go | 13 +++--- 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index f2ea352af..7d2bae67e 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -26,6 +26,7 @@ func (k Keeper) AddFinalityProviderRewardsForBtcDelegations(ctx context.Context, return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) } +// BtcDelegationActivated adds new amount of active satoshi to the delegation and finality provider func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { amtSat := sdkmath.NewIntFromUint64(sat) return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { @@ -33,6 +34,11 @@ func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddre }) } +// BtcDelegationUnbonded it modifies the total amount of satoshi staked +// for the delegation (fp, del) and for the finality provider by subtracting. +// Since it modifies the active amount it triggers the increment of fp period, +// creationg of new historical reward, withdraw of rewards to gauge +// and initialization of a new delegation. func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { amtSat := sdkmath.NewIntFromUint64(sat) return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index 6c16838a4..65de0413b 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -240,6 +240,9 @@ func (k Keeper) subDelegationSat(ctx context.Context, fp, del sdk.AccAddress, am } btcDelRwdTracker.SubTotalActiveSat(amt) + if btcDelRwdTracker.TotalActiveSat.IsNegative() { + return types.ErrBTCDelegationRewardsTrackerNegativeAmount + } if err := k.setBTCDelegationRewardsTracker(ctx, fp, del, btcDelRwdTracker); err != nil { return err } diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index c4f6cfc59..821baa6e9 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -16,6 +16,49 @@ import ( "github.com/babylonlabs-io/babylon/x/incentive/types" ) +func FuzzCheckBtcDelegationActivated(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp1, fp2, del1 := datagen.GenRandomAddress(), datagen.GenRandomAddress(), datagen.GenRandomAddress() + + amtToActivate := datagen.RandomInt(r, 10) + 5 + fp1Del1ToUnbond := datagen.RandomInt(r, int(amtToActivate)-1) + 1 + err := k.BtcDelegationUnbonded(ctx, fp1, del1, fp1Del1ToUnbond) + require.EqualError(t, err, types.ErrBTCDelegationRewardsTrackerNotFound.Error()) + + // delegates for both pairs (fp1, del1) (fp2, del1) + err = k.BtcDelegationActivated(ctx, fp1, del1, amtToActivate) + require.NoError(t, err) + err = k.BtcDelegationActivated(ctx, fp2, del1, amtToActivate) + require.NoError(t, err) + + // unbonds more than it has, should error + err = k.BtcDelegationUnbonded(ctx, fp1, del1, amtToActivate+1) + require.EqualError(t, err, types.ErrBTCDelegationRewardsTrackerNegativeAmount.Error()) + + // normally unbonds only part of it + err = k.BtcDelegationUnbonded(ctx, fp1, del1, fp1Del1ToUnbond) + require.NoError(t, err) + + fp1Del1RwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp1, del1) + require.NoError(t, err) + require.Equal(t, fp1Del1RwdTracker.TotalActiveSat.Uint64(), amtToActivate-fp1Del1ToUnbond) + + // unbonds all + err = k.BtcDelegationUnbonded(ctx, fp2, del1, amtToActivate) + require.NoError(t, err) + + fp2Del1RwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp2, del1) + require.NoError(t, err) + require.True(t, fp2Del1RwdTracker.TotalActiveSat.IsZero()) + }) +} + func FuzzCheckBTCDelegatorToFP(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) diff --git a/x/incentive/types/errors.go b/x/incentive/types/errors.go index ba0df2360..e19195852 100644 --- a/x/incentive/types/errors.go +++ b/x/incentive/types/errors.go @@ -6,10 +6,11 @@ import ( // x/incentive module sentinel errors var ( - ErrBTCStakingGaugeNotFound = errorsmod.Register(ModuleName, 1100, "BTC staking gauge not found") - ErrRewardGaugeNotFound = errorsmod.Register(ModuleName, 1101, "reward gauge not found") - ErrNoWithdrawableCoins = errorsmod.Register(ModuleName, 1102, "no coin is withdrawable") - ErrFPCurrentRewardsNotFound = errorsmod.Register(ModuleName, 1103, "finality provider current rewards not found") - ErrFPHistoricalRewardsNotFound = errorsmod.Register(ModuleName, 1104, "finality provider historical rewards not found") - ErrBTCDelegationRewardsTrackerNotFound = errorsmod.Register(ModuleName, 1105, "BTC delegation rewards tracker not found") + ErrBTCStakingGaugeNotFound = errorsmod.Register(ModuleName, 1100, "BTC staking gauge not found") + ErrRewardGaugeNotFound = errorsmod.Register(ModuleName, 1101, "reward gauge not found") + ErrNoWithdrawableCoins = errorsmod.Register(ModuleName, 1102, "no coin is withdrawable") + ErrFPCurrentRewardsNotFound = errorsmod.Register(ModuleName, 1103, "finality provider current rewards not found") + ErrFPHistoricalRewardsNotFound = errorsmod.Register(ModuleName, 1104, "finality provider historical rewards not found") + ErrBTCDelegationRewardsTrackerNotFound = errorsmod.Register(ModuleName, 1105, "BTC delegation rewards tracker not found") + ErrBTCDelegationRewardsTrackerNegativeAmount = errorsmod.Register(ModuleName, 1106, "BTC delegation rewards tracker has a negative amount of TotalActiveSat") ) From 1f9f83530dcf41d5e225c4f563b3df4b3e840deb Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 12 Dec 2024 09:43:07 -0300 Subject: [PATCH 060/132] chore: add test for BtcDelegationActivated --- x/incentive/keeper/reward_tracker.go | 7 ++- .../keeper/reward_tracker_store_test.go | 46 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 7d2bae67e..7ec1766c1 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -26,7 +26,11 @@ func (k Keeper) AddFinalityProviderRewardsForBtcDelegations(ctx context.Context, return k.setFinalityProviderCurrentRewards(ctx, fp, fpCurrentRwd) } -// BtcDelegationActivated adds new amount of active satoshi to the delegation and finality provider +// BtcDelegationActivated adds new amount of active satoshi to the delegation +// and finality provider. Since it modifies the amount staked, it triggers +// the creation of a new period, which initializes the FP, creates +// historical reward tracker, withdraw the BTC delegation rewards to gauge +// and initializes a new delegation with the just ended period. func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { amtSat := sdkmath.NewIntFromUint64(sat) return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { @@ -39,6 +43,7 @@ func (k Keeper) BtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddre // Since it modifies the active amount it triggers the increment of fp period, // creationg of new historical reward, withdraw of rewards to gauge // and initialization of a new delegation. +// It errors out if the unbond amount is higher than the total amount staked. func (k Keeper) BtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sat uint64) error { amtSat := sdkmath.NewIntFromUint64(sat) return k.btcDelegationModifiedWithPreInitDel(ctx, fp, del, func(ctx context.Context, fp, del sdk.AccAddress) error { diff --git a/x/incentive/keeper/reward_tracker_store_test.go b/x/incentive/keeper/reward_tracker_store_test.go index 821baa6e9..f27a4271b 100644 --- a/x/incentive/keeper/reward_tracker_store_test.go +++ b/x/incentive/keeper/reward_tracker_store_test.go @@ -19,6 +19,52 @@ import ( func FuzzCheckBtcDelegationActivated(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) + f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() + r := rand.New(rand.NewSource(seed)) + + k, ctx := NewKeeperWithCtx(t) + fp1, fp2, del1 := datagen.GenRandomAddress(), datagen.GenRandomAddress(), datagen.GenRandomAddress() + + amtActivateFp1Del1 := datagen.RandomInt(r, 10) + 5 + amtActivateFp2Del1 := datagen.RandomInt(r, 4) + 1 + amtActivateBoth := datagen.RandomInt(r, 7) + 3 + + // delegates for both pairs (fp1, del1) (fp2, del1) + err := k.BtcDelegationActivated(ctx, fp1, del1, amtActivateFp1Del1) + require.NoError(t, err) + err = k.BtcDelegationActivated(ctx, fp2, del1, amtActivateFp2Del1) + require.NoError(t, err) + + // verifies the amounts + fp1Del1RwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp1, del1) + require.NoError(t, err) + require.Equal(t, fp1Del1RwdTracker.TotalActiveSat.Uint64(), amtActivateFp1Del1) + + fp2Del1RwdTracker, err := k.GetBTCDelegationRewardsTracker(ctx, fp2, del1) + require.NoError(t, err) + require.Equal(t, fp2Del1RwdTracker.TotalActiveSat.Uint64(), amtActivateFp2Del1) + + // delegates for both pairs again + err = k.BtcDelegationActivated(ctx, fp1, del1, amtActivateBoth) + require.NoError(t, err) + err = k.BtcDelegationActivated(ctx, fp2, del1, amtActivateBoth) + require.NoError(t, err) + + // verifies the amounts + fp1Del1RwdTracker, err = k.GetBTCDelegationRewardsTracker(ctx, fp1, del1) + require.NoError(t, err) + require.Equal(t, fp1Del1RwdTracker.TotalActiveSat.Uint64(), amtActivateFp1Del1+amtActivateBoth) + + fp2Del1RwdTracker, err = k.GetBTCDelegationRewardsTracker(ctx, fp2, del1) + require.NoError(t, err) + require.Equal(t, fp2Del1RwdTracker.TotalActiveSat.Uint64(), amtActivateFp2Del1+amtActivateBoth) + }) +} + +func FuzzCheckBtcDelegationUnbonded(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + f.Fuzz(func(t *testing.T, seed int64) { t.Parallel() r := rand.New(rand.NewSource(seed)) From 27d975e9e823dd0ea6a826d3aff79ca458d55d13 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 12 Dec 2024 10:13:08 -0300 Subject: [PATCH 061/132] chore: remove unnecessary comments and rename func --- x/finality/keeper/power_dist_change.go | 12 ++---------- x/incentive/keeper/grpc_query.go | 2 +- x/incentive/keeper/msg_server.go | 2 +- x/incentive/keeper/reward_gauge.go | 2 +- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index bb482f1e5..36b492af1 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -203,10 +203,6 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( fpBTCPKHex := fpBTCPK.MarshalHex() activeBTCDels[fpBTCPKHex] = append(activeBTCDels[fpBTCPKHex], btcDel) } - // Becomes active, it should withdraw the rewards available - // and create a new BTCDelegationRewardsInfo. - // TODO: research how can we charge the gas for this process during - // the withdraw of rewards. } else if delEvent.NewState == types.BTCDelegationStatus_UNBONDED { // emit expired event if it is not early unbonding if !btcDel.IsUnbondedEarly() { @@ -214,9 +210,6 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( } // add the unbonded BTC delegation to the map unbondedBTCDels[delEvent.StakingTxHash] = struct{}{} - // Becomes unbonded, it should withdraw the rewards available - // and create a new BTCDelegationRewardsInfo or delete it if does not have more sats - // for this finality provider. } case *types.EventPowerDistUpdate_SlashedFp: // record slashed fps @@ -282,7 +275,7 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( err := k.IncentiveKeeper.BtcDelegationUnbonded(ctx, fp.GetAddress(), sdk.MustAccAddressFromBech32(btcDel.StakerAddr), btcDel.TotalSat) if err != nil { - panic(err) // check if it should panic + panic(err) } } } @@ -335,11 +328,10 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( for _, d := range fpActiveBTCDels { fpDistInfo.AddBTCDel(d) - // TODO: maybe use a hook to the activated btc delegation to add new stake delAddr := sdk.MustAccAddressFromBech32(d.StakerAddr) err := k.IncentiveKeeper.BtcDelegationActivated(ctx, fpAddr, delAddr, d.TotalSat) if err != nil { - panic(err) // check if it should panic + panic(err) } } diff --git a/x/incentive/keeper/grpc_query.go b/x/incentive/keeper/grpc_query.go index bc70824db..5ceb6b7e7 100644 --- a/x/incentive/keeper/grpc_query.go +++ b/x/incentive/keeper/grpc_query.go @@ -27,7 +27,7 @@ func (k Keeper) RewardGauges(goCtx context.Context, req *types.QueryRewardGauges // find reward gauge for _, sType := range types.GetAllStakeholderTypes() { - if err := k.sendAllBtcDelegationTypeToRewardsToGauge(ctx, sType, address); err != nil { + if err := k.sendAllBtcDelegationTypeToRewardsGauge(ctx, sType, address); err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/incentive/keeper/msg_server.go b/x/incentive/keeper/msg_server.go index 883691e77..97bce041c 100644 --- a/x/incentive/keeper/msg_server.go +++ b/x/incentive/keeper/msg_server.go @@ -54,7 +54,7 @@ func (ms msgServer) WithdrawReward(goCtx context.Context, req *types.MsgWithdraw return nil, status.Error(codes.InvalidArgument, err.Error()) } - if err := ms.sendAllBtcDelegationTypeToRewardsToGauge(ctx, sType, addr); err != nil { + if err := ms.sendAllBtcDelegationTypeToRewardsGauge(ctx, sType, addr); err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/incentive/keeper/reward_gauge.go b/x/incentive/keeper/reward_gauge.go index 9a4798388..719e492a2 100644 --- a/x/incentive/keeper/reward_gauge.go +++ b/x/incentive/keeper/reward_gauge.go @@ -9,7 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -func (k Keeper) sendAllBtcDelegationTypeToRewardsToGauge(ctx context.Context, sType types.StakeholderType, del sdk.AccAddress) error { +func (k Keeper) sendAllBtcDelegationTypeToRewardsGauge(ctx context.Context, sType types.StakeholderType, del sdk.AccAddress) error { if sType != types.BTCDelegationType { return nil } From 27b4eccdc0dfe8548372f365752f3eaed4749bb3 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 12 Dec 2024 10:49:58 -0300 Subject: [PATCH 062/132] fix: set unbond btc del stupid mistake --- test/e2e/btc_staking_e2e_test.go | 4 ++-- x/finality/keeper/power_dist_change.go | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index 5942aebc4..fdfd7f665 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -222,6 +222,7 @@ func (s *BTCStakingTestSuite) Test2SubmitCovenantSignature() { s.NoError(err) for i := 0; i < int(s.covenantQuorum); i++ { + // after adding the covenant signatures it panics with "BTC delegation rewards tracker has a negative amount of TotalActiveSat" nonValidatorNode.SubmitRefundableTxWithAssertion(func() { // add covenant sigs nonValidatorNode.AddCovenantSigs( @@ -237,8 +238,7 @@ func (s *BTCStakingTestSuite) Test2SubmitCovenantSignature() { } // wait for a block so that above txs take effect - nonValidatorNode.WaitForNextBlock() - nonValidatorNode.WaitForNextBlock() + nonValidatorNode.WaitForNextBlocks(2) // ensure the BTC delegation has covenant sigs now activeDelsSet := nonValidatorNode.QueryFinalityProviderDelegations(s.cacheFP.BtcPk.MarshalHex()) diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 36b492af1..344164313 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -270,14 +270,19 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // add all BTC delegations that are not unbonded to the new finality provider for j := range dc.FinalityProviders[i].BtcDels { btcDel := *dc.FinalityProviders[i].BtcDels[j] - if _, ok := unbondedBTCDels[btcDel.StakingTxHash]; !ok { - fp.AddBTCDelDistInfo(&btcDel) + _, isUnbondedBtcDelegation := unbondedBTCDels[btcDel.StakingTxHash] + if isUnbondedBtcDelegation { + // btc delegation being unbonded err := k.IncentiveKeeper.BtcDelegationUnbonded(ctx, fp.GetAddress(), sdk.MustAccAddressFromBech32(btcDel.StakerAddr), btcDel.TotalSat) if err != nil { panic(err) } + continue } + + // if it is not unbonded add to the del dist info + fp.AddBTCDelDistInfo(&btcDel) } // process all new BTC delegations under this finality provider From 07fb9510fc751840a892e15f40ea3096aa28d1e0 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 12 Dec 2024 14:13:34 -0300 Subject: [PATCH 063/132] tryfix: vp table update events at correct order --- x/finality/keeper/power_dist_change.go | 125 ++++++++++++++++++------- 1 file changed, 93 insertions(+), 32 deletions(-) diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 344164313..7ac71d8e6 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -183,6 +183,8 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( jailedFPs := map[string]struct{}{} // a map where key is unjailed finality providers' BTC PK unjailedFPs := map[string]struct{}{} + newActiveBtcDels := make([]*btcDelWithStkTxHash, 0) + newUnbondedBtcDels := make([]*btcDelWithStkTxHash, 0) /* filter and classify all events into new/expired BTC delegations and jailed/slashed FPs @@ -192,24 +194,36 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( switch typedEvent := event.Ev.(type) { case *types.EventPowerDistUpdate_BtcDelStateUpdate: delEvent := typedEvent.BtcDelStateUpdate - btcDel, err := k.BTCStakingKeeper.GetBTCDelegation(ctx, delEvent.StakingTxHash) + delStkTxHash := delEvent.StakingTxHash + + btcDel, err := k.BTCStakingKeeper.GetBTCDelegation(ctx, delStkTxHash) if err != nil { panic(err) // only programming error } - if delEvent.NewState == types.BTCDelegationStatus_ACTIVE { + + btcDelWithStkTxHash := &btcDelWithStkTxHash{ + StakingTxHash: delStkTxHash, + BTCDelegation: btcDel, + } + + switch delEvent.NewState { + case types.BTCDelegationStatus_ACTIVE: // newly active BTC delegation // add the BTC delegation to each restaked finality provider for _, fpBTCPK := range btcDel.FpBtcPkList { fpBTCPKHex := fpBTCPK.MarshalHex() activeBTCDels[fpBTCPKHex] = append(activeBTCDels[fpBTCPKHex], btcDel) } - } else if delEvent.NewState == types.BTCDelegationStatus_UNBONDED { + newActiveBtcDels = append(newActiveBtcDels, btcDelWithStkTxHash) + case types.BTCDelegationStatus_UNBONDED: // emit expired event if it is not early unbonding if !btcDel.IsUnbondedEarly() { - types.EmitExpiredDelegationEvent(sdkCtx, delEvent.StakingTxHash) + types.EmitExpiredDelegationEvent(sdkCtx, delStkTxHash) } + // add the unbonded BTC delegation to the map - unbondedBTCDels[delEvent.StakingTxHash] = struct{}{} + unbondedBTCDels[delStkTxHash] = struct{}{} + newUnbondedBtcDels = append(newUnbondedBtcDels, btcDelWithStkTxHash) } case *types.EventPowerDistUpdate_SlashedFp: // record slashed fps @@ -247,7 +261,8 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // if this finality provider is slashed, continue to avoid // assigning delegation to it - if _, ok := slashedFPs[fpBTCPKHex]; ok { + _, isSlashed := slashedFPs[fpBTCPKHex] + if isSlashed { if err := k.IncentiveKeeper.FpSlashed(ctx, fp.GetAddress()); err != nil { panic(err) } @@ -273,14 +288,8 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( _, isUnbondedBtcDelegation := unbondedBTCDels[btcDel.StakingTxHash] if isUnbondedBtcDelegation { - // btc delegation being unbonded - err := k.IncentiveKeeper.BtcDelegationUnbonded(ctx, fp.GetAddress(), sdk.MustAccAddressFromBech32(btcDel.StakerAddr), btcDel.TotalSat) - if err != nil { - panic(err) - } continue } - // if it is not unbonded add to the del dist info fp.AddBTCDelDistInfo(&btcDel) } @@ -307,37 +316,27 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( process new BTC delegations under new finality providers in activeBTCDels */ // sort new finality providers in activeBTCDels to ensure determinism - fpBTCPKHexList := make([]string, 0, len(activeBTCDels)) + fpActiveBtcPkHexList := make([]string, 0, len(activeBTCDels)) for fpBTCPKHex := range activeBTCDels { - fpBTCPKHexList = append(fpBTCPKHexList, fpBTCPKHex) + fpActiveBtcPkHexList = append(fpActiveBtcPkHexList, fpBTCPKHex) } - sort.SliceStable(fpBTCPKHexList, func(i, j int) bool { - return fpBTCPKHexList[i] < fpBTCPKHexList[j] + sort.SliceStable(fpActiveBtcPkHexList, func(i, j int) bool { + return fpActiveBtcPkHexList[i] < fpActiveBtcPkHexList[j] }) + + // simple cache to load fp by his btc pk hex + cacheFpByBtcPkHex := map[string]*types.FinalityProvider{} + // for each new finality provider, apply the new BTC delegations to the new dist cache - for _, fpBTCPKHex := range fpBTCPKHexList { + for _, fpBTCPKHex := range fpActiveBtcPkHexList { // get the finality provider and initialise its dist info - fpBTCPK, err := bbn.NewBIP340PubKeyFromHex(fpBTCPKHex) - if err != nil { - panic(err) // only programming error - } - newFP, err := k.BTCStakingKeeper.GetFinalityProvider(ctx, *fpBTCPK) - if err != nil { - panic(err) // only programming error - } + newFP := k.getOrLoadFp(ctx, cacheFpByBtcPkHex, fpBTCPKHex) fpDistInfo := ftypes.NewFinalityProviderDistInfo(newFP) // add each BTC delegation - fpAddr := sdk.MustAccAddressFromBech32(newFP.Addr) fpActiveBTCDels := activeBTCDels[fpBTCPKHex] for _, d := range fpActiveBTCDels { fpDistInfo.AddBTCDel(d) - - delAddr := sdk.MustAccAddressFromBech32(d.StakerAddr) - err := k.IncentiveKeeper.BtcDelegationActivated(ctx, fpAddr, delAddr, d.TotalSat) - if err != nil { - panic(err) - } } // add this finality provider to the new cache if it has voting power @@ -346,6 +345,20 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( } } + k.processBtcDelegations(ctx, cacheFpByBtcPkHex, newActiveBtcDels, func(fp, del sdk.AccAddress, sats uint64) { + err := k.IncentiveKeeper.BtcDelegationActivated(ctx, fp, del, sats) + if err != nil { + panic(err) + } + }) + + k.processBtcDelegations(ctx, cacheFpByBtcPkHex, newUnbondedBtcDels, func(fp, del sdk.AccAddress, sats uint64) { + err := k.IncentiveKeeper.BtcDelegationUnbonded(ctx, fp, del, sats) + if err != nil { + panic(err) + } + }) + return newDc } @@ -378,3 +391,51 @@ func (k Keeper) votingPowerDistCacheStore(ctx context.Context) prefix.Store { storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) return prefix.NewStore(storeAdapter, ftypes.VotingPowerDistCacheKey) } + +func (k Keeper) processBtcDelegations( + ctx context.Context, + cacheFpByBtcPkHex map[string]*types.FinalityProvider, + btcDels []*btcDelWithStkTxHash, + f func(fp, del sdk.AccAddress, sats uint64), +) { + sort.SliceStable(btcDels, func(i, j int) bool { + return btcDels[i].StakingTxHash < btcDels[j].StakingTxHash + }) + + for _, btcDel := range btcDels { + delAddr := sdk.MustAccAddressFromBech32(btcDel.StakerAddr) + for _, fpBTCPK := range btcDel.FpBtcPkList { + fpBTCPKHex := fpBTCPK.MarshalHex() + fp := k.getOrLoadFp(ctx, cacheFpByBtcPkHex, fpBTCPKHex) + fpAddr := sdk.MustAccAddressFromBech32(fp.Addr) + + f(fpAddr, delAddr, btcDel.TotalSat) + } + } +} + +func (k Keeper) getOrLoadFp( + ctx context.Context, + cacheFpByBtcPkHex map[string]*types.FinalityProvider, + fpBTCPKHex string, +) *types.FinalityProvider { + fp, found := cacheFpByBtcPkHex[fpBTCPKHex] + if !found { + fpBTCPK, err := bbn.NewBIP340PubKeyFromHex(fpBTCPKHex) + if err != nil { + panic(err) // only programming error + } + fp, err = k.BTCStakingKeeper.GetFinalityProvider(ctx, *fpBTCPK) + if err != nil { + panic(err) // only programming error + } + cacheFpByBtcPkHex[fpBTCPKHex] = fp + } + + return fp +} + +type btcDelWithStkTxHash struct { + StakingTxHash string + *types.BTCDelegation +} From 3d014f5ab861ff95925bf2fc6b67ecaca4547b27 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 12 Dec 2024 15:09:08 -0300 Subject: [PATCH 064/132] chore: add more time to e2e --- test/e2e/btc_staking_e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index fdfd7f665..327e0ebcd 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -297,7 +297,7 @@ func (s *BTCStakingTestSuite) Test3CommitPublicRandomnessAndSubmitFinalitySignat return false } return resp.Status == ckpttypes.Sealed - }, time.Minute, time.Millisecond*50) + }, time.Minute*2, time.Millisecond*50) nonValidatorNode.FinalizeSealedEpochs(1, currentEpoch) // ensure the committed epoch is finalized From d189eac44717cba40903c1d06928f5cc528ca62d Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Fri, 13 Dec 2024 09:50:26 -0300 Subject: [PATCH 065/132] chore: test btc del integration --- x/finality/keeper/msg_server_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/finality/keeper/msg_server_test.go b/x/finality/keeper/msg_server_test.go index d156a54e8..43783d601 100644 --- a/x/finality/keeper/msg_server_test.go +++ b/x/finality/keeper/msg_server_test.go @@ -486,3 +486,7 @@ func TestVerifyActivationHeight(t *testing.T) { blockHeight, activationHeight, ).Error()) } + +func TestBtcDelegationRewards(t *testing.T) { + +} From 85c94c1d7519b8533fbfa126369ce2815db7c779 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Fri, 13 Dec 2024 12:40:15 -0300 Subject: [PATCH 066/132] chore: moved to use single point of gov account address --- app/keepers/keepers.go | 43 ++++++++++++----------- app/upgrades/v1/upgrades_test.go | 5 ++- testutil/btcstaking-helper/keeper.go | 20 +++++++++-- testutil/keeper/btccheckpoint.go | 5 ++- testutil/keeper/btclightclient.go | 5 ++- testutil/keeper/btcstaking.go | 5 ++- testutil/keeper/epoching.go | 5 ++- testutil/keeper/finality.go | 5 ++- testutil/keeper/incentive.go | 26 ++++++++++---- x/btccheckpoint/keeper/msg_server_test.go | 4 +-- x/btcstaking/keeper/msg_server_test.go | 4 +-- 11 files changed, 76 insertions(+), 51 deletions(-) diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 8074c41d5..b36d72fc7 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -16,6 +16,7 @@ import ( "github.com/CosmWasm/wasmd/x/wasm" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/babylonlabs-io/babylon/testutil/addr" mintkeeper "github.com/babylonlabs-io/babylon/x/mint/keeper" minttypes "github.com/babylonlabs-io/babylon/x/mint/types" "github.com/cosmos/cosmos-sdk/baseapp" @@ -218,7 +219,7 @@ func (ak *AppKeepers) InitKeepers( maccPerms, authcodec.NewBech32Codec(appparams.Bech32PrefixAccAddr), appparams.Bech32PrefixAccAddr, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) bankKeeper := bankkeeper.NewBaseKeeper( @@ -226,7 +227,7 @@ func (ak *AppKeepers) InitKeepers( runtime.NewKVStoreService(keys[banktypes.StoreKey]), accountKeeper, blockedAddress, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), logger, ) @@ -235,7 +236,7 @@ func (ak *AppKeepers) InitKeepers( runtime.NewKVStoreService(keys[stakingtypes.StoreKey]), accountKeeper, bankKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), authcodec.NewBech32Codec(appparams.Bech32PrefixValAddr), authcodec.NewBech32Codec(appparams.Bech32PrefixConsAddr), ) @@ -246,7 +247,7 @@ func (ak *AppKeepers) InitKeepers( runtime.NewKVStoreService(keys[epochingtypes.StoreKey]), bankKeeper, stakingKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) checkpointingKeeper := checkpointingkeeper.NewKeeper( @@ -271,7 +272,7 @@ func (ak *AppKeepers) InitKeepers( ak.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[consensusparamtypes.StoreKey]), - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), runtime.EventService{}, ) bApp.SetParamStore(ak.ConsensusParamsKeeper.ParamsStore) @@ -301,7 +302,7 @@ func (ak *AppKeepers) InitKeepers( ak.CircuitKeeper = circuitkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[circuittypes.StoreKey]), - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ak.AccountKeeper.AddressCodec(), ) bApp.SetCircuitBreaker(&ak.CircuitKeeper) @@ -313,7 +314,7 @@ func (ak *AppKeepers) InitKeepers( ak.AccountKeeper, ak.BankKeeper, authtypes.FeeCollectorName, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) ak.DistrKeeper = distrkeeper.NewKeeper( @@ -323,7 +324,7 @@ func (ak *AppKeepers) InitKeepers( ak.BankKeeper, ak.StakingKeeper, authtypes.FeeCollectorName, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) // set up incentive keeper @@ -333,7 +334,7 @@ func (ak *AppKeepers) InitKeepers( ak.BankKeeper, ak.AccountKeeper, &epochingKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), authtypes.FeeCollectorName, ) @@ -342,7 +343,7 @@ func (ak *AppKeepers) InitKeepers( encodingConfig.Amino, runtime.NewKVStoreService(keys[slashingtypes.StoreKey]), ak.StakingKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) ak.CrisisKeeper = crisiskeeper.NewKeeper( @@ -351,7 +352,7 @@ func (ak *AppKeepers) InitKeepers( invCheckPeriod, ak.BankKeeper, authtypes.FeeCollectorName, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ak.AccountKeeper.AddressCodec(), ) @@ -373,7 +374,7 @@ func (ak *AppKeepers) InitKeepers( appCodec, homePath, bApp, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) ak.AuthzKeeper = authzkeeper.NewKeeper( @@ -394,7 +395,7 @@ func (ak *AppKeepers) InitKeepers( // `MsgIBCSoftwareUpgrade` and `MsgRecoverClient` // https://github.com/cosmos/ibc-go/releases/tag/v8.0.0 // Gov is the proper authority for those types of messages - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) // register the proposal types @@ -421,7 +422,7 @@ func (ak *AppKeepers) InitKeepers( ak.DistrKeeper, bApp.MsgServiceRouter(), govConfig, - authtypes.NewModuleAddress(govtypes.ModuleName).String()) + addr.AccGov.String()) ak.GovKeeper = *govKeeper.SetHooks( govtypes.NewMultiGovHooks( @@ -434,7 +435,7 @@ func (ak *AppKeepers) InitKeepers( runtime.NewKVStoreService(keys[btclightclienttypes.StoreKey]), *btcConfig, &ak.IncentiveKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) btcCheckpointKeeper := btccheckpointkeeper.NewKeeper( @@ -445,7 +446,7 @@ func (ak *AppKeepers) InitKeepers( &checkpointingKeeper, &ak.IncentiveKeeper, &powLimit, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) ak.IBCFeeKeeper = ibcfeekeeper.NewKeeper( @@ -466,7 +467,7 @@ func (ak *AppKeepers) InitKeepers( ak.AccountKeeper, ak.BankKeeper, scopedTransferKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) ak.MonitorKeeper = monitorkeeper.NewKeeper( @@ -499,7 +500,7 @@ func (ak *AppKeepers) InitKeepers( &btcCheckpointKeeper, &ak.IncentiveKeeper, btcNetParams, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) // set up finality keeper @@ -509,7 +510,7 @@ func (ak *AppKeepers) InitKeepers( ak.BTCStakingKeeper, ak.IncentiveKeeper, ak.CheckpointingKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) // create evidence keeper with router @@ -543,7 +544,7 @@ func (ak *AppKeepers) InitKeepers( homePath, wasmConfig, WasmCapabilities(), - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), wasmOpts..., ) @@ -558,7 +559,7 @@ func (ak *AppKeepers) InitKeepers( appCodec, runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), ak.IBCKeeper.ClientKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ibcWasmConfig, bApp.GRPCQueryRouter(), ) diff --git a/app/upgrades/v1/upgrades_test.go b/app/upgrades/v1/upgrades_test.go index 7273cd9c0..4cd3a19f5 100644 --- a/app/upgrades/v1/upgrades_test.go +++ b/app/upgrades/v1/upgrades_test.go @@ -19,6 +19,7 @@ import ( appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/app/upgrades" "github.com/babylonlabs-io/babylon/test/e2e/util" + "github.com/babylonlabs-io/babylon/testutil/addr" "github.com/babylonlabs-io/babylon/testutil/datagen" "github.com/babylonlabs-io/babylon/testutil/sample" bbn "github.com/babylonlabs-io/babylon/types" @@ -27,8 +28,6 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/suite" "github.com/babylonlabs-io/babylon/app" @@ -118,7 +117,7 @@ func (s *UpgradeTestSuite) TestUpgrade() { // onlu gov account can store new contracts respFromGov, err := wasmMsgServer.StoreCode(s.ctx, &wasmtypes.MsgStoreCode{ - Sender: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Sender: addr.AccGov.String(), WASMByteCode: wasmContract, }) s.NoError(err) diff --git a/testutil/btcstaking-helper/keeper.go b/testutil/btcstaking-helper/keeper.go index 3ab182a57..1134a5d7b 100644 --- a/testutil/btcstaking-helper/keeper.go +++ b/testutil/btcstaking-helper/keeper.go @@ -76,10 +76,26 @@ func NewHelper( db := dbm.NewMemDB() stateStore := store.NewCommitMultiStore(db, log.NewTestLogger(t), storemetrics.NewNoOpMetrics()) - k, _ := keepertest.BTCStakingKeeperWithStore(t, db, stateStore, btclcKeeper, btccKeeper, iKeeper) + return NewHelperWithStoreAndIncentive(t, db, stateStore, btclcKeeper, btccKeeper, iKeeper) +} + +func NewHelperWithStoreAndIncentive( + t testing.TB, + db dbm.DB, + stateStore store.CommitMultiStore, + btclcKeeper *types.MockBTCLightClientKeeper, + btccKeeper *types.MockBtcCheckpointKeeper, + ictvKeeper ftypes.IncentiveKeeper, +) *Helper { + ctrl := gomock.NewController(t) + + ckptKeeper := ftypes.NewMockCheckpointingKeeper(ctrl) + ckptKeeper.EXPECT().GetLastFinalizedEpoch(gomock.Any()).Return(timestampedEpoch).AnyTimes() + + k, _ := keepertest.BTCStakingKeeperWithStore(t, db, stateStore, btclcKeeper, btccKeeper, ictvKeeper) msgSrvr := keeper.NewMsgServerImpl(*k) - fk, ctx := keepertest.FinalityKeeperWithStore(t, db, stateStore, k, iKeeper, ckptKeeper) + fk, ctx := keepertest.FinalityKeeperWithStore(t, db, stateStore, k, ictvKeeper, ckptKeeper) fMsgSrvr := fkeeper.NewMsgServerImpl(*fk) // set all parameters diff --git a/testutil/keeper/btccheckpoint.go b/testutil/keeper/btccheckpoint.go index 9049041af..69becd3df 100644 --- a/testutil/keeper/btccheckpoint.go +++ b/testutil/keeper/btccheckpoint.go @@ -15,10 +15,9 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + "github.com/babylonlabs-io/babylon/testutil/addr" "github.com/babylonlabs-io/babylon/x/btccheckpoint/keeper" btcctypes "github.com/babylonlabs-io/babylon/x/btccheckpoint/types" ) @@ -48,7 +47,7 @@ func NewBTCCheckpointKeeper( ek, ik, powLimit, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/btclightclient.go b/testutil/keeper/btclightclient.go index 711308755..afe8814ee 100644 --- a/testutil/keeper/btclightclient.go +++ b/testutil/keeper/btclightclient.go @@ -17,11 +17,10 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" bapp "github.com/babylonlabs-io/babylon/app" + "github.com/babylonlabs-io/babylon/testutil/addr" bbn "github.com/babylonlabs-io/babylon/types" btclightclientk "github.com/babylonlabs-io/babylon/x/btclightclient/keeper" btclightclientt "github.com/babylonlabs-io/babylon/x/btclightclient/types" @@ -66,7 +65,7 @@ func BTCLightClientKeeperWithCustomParams( stServ, testCfg, &MockIncentiveKeeper{}, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/btcstaking.go b/testutil/keeper/btcstaking.go index c38f00ed8..dea982a01 100644 --- a/testutil/keeper/btcstaking.go +++ b/testutil/keeper/btcstaking.go @@ -15,10 +15,9 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + "github.com/babylonlabs-io/babylon/testutil/addr" "github.com/babylonlabs-io/babylon/x/btcstaking/keeper" "github.com/babylonlabs-io/babylon/x/btcstaking/types" ) @@ -46,7 +45,7 @@ func BTCStakingKeeperWithStore( btccKeeper, iKeeper, &chaincfg.SimNetParams, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/epoching.go b/testutil/keeper/epoching.go index 716761886..2945b6e51 100644 --- a/testutil/keeper/epoching.go +++ b/testutil/keeper/epoching.go @@ -14,10 +14,9 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + "github.com/babylonlabs-io/babylon/testutil/addr" "github.com/babylonlabs-io/babylon/x/epoching/keeper" "github.com/babylonlabs-io/babylon/x/epoching/types" ) @@ -39,7 +38,7 @@ func EpochingKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { // TODO: make this compile at the moment, will fix for integrated testing nil, nil, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) // TODO: add msgServiceRouter? diff --git a/testutil/keeper/finality.go b/testutil/keeper/finality.go index c2b22e5f3..d03eb229d 100644 --- a/testutil/keeper/finality.go +++ b/testutil/keeper/finality.go @@ -14,10 +14,9 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + "github.com/babylonlabs-io/babylon/testutil/addr" "github.com/babylonlabs-io/babylon/x/finality/keeper" "github.com/babylonlabs-io/babylon/x/finality/types" ) @@ -44,7 +43,7 @@ func FinalityKeeperWithStore( bsKeeper, iKeeper, ckptKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), ) ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/incentive.go b/testutil/keeper/incentive.go index 2a6d2017b..54b9c557d 100644 --- a/testutil/keeper/incentive.go +++ b/testutil/keeper/incentive.go @@ -15,18 +15,23 @@ import ( "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + "github.com/babylonlabs-io/babylon/testutil/addr" "github.com/babylonlabs-io/babylon/x/incentive/keeper" "github.com/babylonlabs-io/babylon/x/incentive/types" ) -func IncentiveKeeper(t testing.TB, bankKeeper types.BankKeeper, accountKeeper types.AccountKeeper, epochingKeeper types.EpochingKeeper) (*keeper.Keeper, sdk.Context) { +func IncentiveKeeperWithStore( + t testing.TB, + db dbm.DB, + stateStore store.CommitMultiStore, + bankKeeper types.BankKeeper, + accountKeeper types.AccountKeeper, + epochingKeeper types.EpochingKeeper, +) (*keeper.Keeper, sdk.Context) { storeKey := storetypes.NewKVStoreKey(types.StoreKey) - db := dbm.NewMemDB() - stateStore := store.NewCommitMultiStore(db, log.NewTestLogger(t), storemetrics.NewNoOpMetrics()) stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) require.NoError(t, stateStore.LoadLatestVersion()) @@ -39,17 +44,26 @@ func IncentiveKeeper(t testing.TB, bankKeeper types.BankKeeper, accountKeeper ty bankKeeper, accountKeeper, epochingKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + addr.AccGov.String(), authtypes.FeeCollectorName, ) ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) ctx = ctx.WithHeaderInfo(header.Info{}) + return &k, ctx +} + +func IncentiveKeeper(t testing.TB, bankKeeper types.BankKeeper, accountKeeper types.AccountKeeper, epochingKeeper types.EpochingKeeper) (*keeper.Keeper, sdk.Context) { + db := dbm.NewMemDB() + stateStore := store.NewCommitMultiStore(db, log.NewTestLogger(t), storemetrics.NewNoOpMetrics()) + + k, ctx := IncentiveKeeperWithStore(t, db, stateStore, bankKeeper, accountKeeper, epochingKeeper) + // Initialize params if err := k.SetParams(ctx, types.DefaultParams()); err != nil { panic(err) } - return &k, ctx + return k, ctx } diff --git a/x/btccheckpoint/keeper/msg_server_test.go b/x/btccheckpoint/keeper/msg_server_test.go index ed5e5fb04..95aa71130 100644 --- a/x/btccheckpoint/keeper/msg_server_test.go +++ b/x/btccheckpoint/keeper/msg_server_test.go @@ -10,10 +10,10 @@ import ( "github.com/btcsuite/btcd/chaincfg" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + "github.com/babylonlabs-io/babylon/testutil/addr" dg "github.com/babylonlabs-io/babylon/testutil/datagen" keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" bbn "github.com/babylonlabs-io/babylon/types" @@ -86,7 +86,7 @@ func TestUpdateParams(t *testing.T) { // Try to update params with a different checkpoint finalization timeout msg := &btcctypes.MsgUpdateParams{ - Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Authority: addr.AccGov.String(), Params: btcctypes.Params{ CheckpointFinalizationTimeout: btcctypes.DefaultParams().CheckpointFinalizationTimeout + 1, }, diff --git a/x/btcstaking/keeper/msg_server_test.go b/x/btcstaking/keeper/msg_server_test.go index aff4d2278..77760b345 100644 --- a/x/btcstaking/keeper/msg_server_test.go +++ b/x/btcstaking/keeper/msg_server_test.go @@ -13,7 +13,6 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" @@ -21,6 +20,7 @@ import ( "google.golang.org/grpc/status" asig "github.com/babylonlabs-io/babylon/crypto/schnorr-adaptor-signature" + "github.com/babylonlabs-io/babylon/testutil/addr" testutil "github.com/babylonlabs-io/babylon/testutil/btcstaking-helper" "github.com/babylonlabs-io/babylon/testutil/datagen" testhelper "github.com/babylonlabs-io/babylon/testutil/helper" @@ -53,7 +53,7 @@ func FuzzMsgServer_UpdateParams(f *testing.F) { // Try to update params with minUnbondingTime less than or equal to checkpointFinalizationTimeout msg := &types.MsgUpdateParams{ - Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Authority: addr.AccGov.String(), Params: params, } From 1f2aeb5198be3b07f932a0a5ebc9ac1bec14a78e Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Fri, 13 Dec 2024 12:43:09 -0300 Subject: [PATCH 067/132] chore: moved to use single point of gov account address --- app/app.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/app.go b/app/app.go index 07fee6d9e..c5fbb8f3e 100644 --- a/app/app.go +++ b/app/app.go @@ -89,6 +89,7 @@ import ( ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" "github.com/spf13/cast" + "github.com/babylonlabs-io/babylon/testutil/addr" "github.com/babylonlabs-io/babylon/x/mint" minttypes "github.com/babylonlabs-io/babylon/x/mint/types" @@ -801,7 +802,7 @@ func BlockedAddresses() map[string]bool { } // allow the following addresses to receive funds - delete(modAccAddrs, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + delete(modAccAddrs, addr.AccGov.String()) return modAccAddrs } From 1e97f58a7d8210369e99d4f2c609db896a639160 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Fri, 13 Dec 2024 17:37:22 -0300 Subject: [PATCH 068/132] chore: start of integration test --- testutil/incentives-helper/keeper.go | 40 +++++++++++++++++++++++ testutil/keeper/bank.go | 45 ++++++++++++++++++++++++++ x/finality/keeper/msg_server_test.go | 6 ++-- x/finality/keeper/power_dist_change.go | 9 ++++-- 4 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 testutil/incentives-helper/keeper.go create mode 100644 testutil/keeper/bank.go diff --git a/testutil/incentives-helper/keeper.go b/testutil/incentives-helper/keeper.go new file mode 100644 index 000000000..1608cf12d --- /dev/null +++ b/testutil/incentives-helper/keeper.go @@ -0,0 +1,40 @@ +package testutil + +import ( + "testing" + + "cosmossdk.io/log" + "cosmossdk.io/store" + storemetrics "cosmossdk.io/store/metrics" + dbm "github.com/cosmos/cosmos-db" + + btcstkhelper "github.com/babylonlabs-io/babylon/testutil/btcstaking-helper" + keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" + "github.com/babylonlabs-io/babylon/x/btcstaking/types" + "github.com/babylonlabs-io/babylon/x/incentive/keeper" +) + +type Helper struct { + *btcstkhelper.Helper + IncentivesKeeper *keeper.Keeper +} + +func NewHelper( + t testing.TB, + btclcKeeper *types.MockBTCLightClientKeeper, + btccKeeper *types.MockBtcCheckpointKeeper, +) *Helper { + // ctrl := gomock.NewController(t) + + db := dbm.NewMemDB() + stateStore := store.NewCommitMultiStore(db, log.NewTestLogger(t), storemetrics.NewNoOpMetrics()) + + ictvK, _ := keepertest.IncentiveKeeperWithStore(t, db, stateStore, nil, nil, nil) + + btcstkH := btcstkhelper.NewHelperWithStoreAndIncentive(t, db, stateStore, btclcKeeper, btccKeeper, ictvK) + + return &Helper{ + Helper: btcstkH, + IncentivesKeeper: ictvK, + } +} diff --git a/testutil/keeper/bank.go b/testutil/keeper/bank.go new file mode 100644 index 000000000..551ca511c --- /dev/null +++ b/testutil/keeper/bank.go @@ -0,0 +1,45 @@ +package keeper + +import ( + "testing" + + "cosmossdk.io/log" + "cosmossdk.io/store" + storetypes "cosmossdk.io/store/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + bankk "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/require" + + "github.com/babylonlabs-io/babylon/testutil/addr" + "github.com/babylonlabs-io/babylon/x/incentive/types" +) + +func BankKeeper( + t testing.TB, + db dbm.DB, + stateStore store.CommitMultiStore, + accountKeeper banktypes.AccountKeeper, +) types.BankKeeper { + storeKey := storetypes.NewKVStoreKey(banktypes.StoreKey) + + stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) + require.NoError(t, stateStore.LoadLatestVersion()) + + registry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + + k := bankk.NewBaseKeeper( + cdc, + runtime.NewKVStoreService(storeKey), + accountKeeper, + map[string]bool{}, + addr.AccGov.String(), + log.NewNopLogger(), + ) + + return k +} diff --git a/x/finality/keeper/msg_server_test.go b/x/finality/keeper/msg_server_test.go index 43783d601..e5e6d96d1 100644 --- a/x/finality/keeper/msg_server_test.go +++ b/x/finality/keeper/msg_server_test.go @@ -487,6 +487,8 @@ func TestVerifyActivationHeight(t *testing.T) { ).Error()) } -func TestBtcDelegationRewards(t *testing.T) { +// func TestBtcDelegationRewards(t *testing.T) { +// r := rand.New(rand.NewSource(time.Now().Unix())) +// fKeeper, ctx := keepertest.FinalityKeeper(t, nil, nil, nil) -} +// } diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 7ac71d8e6..babaf24fe 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -330,7 +330,7 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // for each new finality provider, apply the new BTC delegations to the new dist cache for _, fpBTCPKHex := range fpActiveBtcPkHexList { // get the finality provider and initialise its dist info - newFP := k.getOrLoadFp(ctx, cacheFpByBtcPkHex, fpBTCPKHex) + newFP := k.loadFP(ctx, cacheFpByBtcPkHex, fpBTCPKHex) fpDistInfo := ftypes.NewFinalityProviderDistInfo(newFP) // add each BTC delegation @@ -392,6 +392,9 @@ func (k Keeper) votingPowerDistCacheStore(ctx context.Context) prefix.Store { return prefix.NewStore(storeAdapter, ftypes.VotingPowerDistCacheKey) } +// processBtcDelegations sorts the btc delegations and +// executed the function by passing the fp, delegator address +// and the total amount of satoshi in that delegation. func (k Keeper) processBtcDelegations( ctx context.Context, cacheFpByBtcPkHex map[string]*types.FinalityProvider, @@ -406,7 +409,7 @@ func (k Keeper) processBtcDelegations( delAddr := sdk.MustAccAddressFromBech32(btcDel.StakerAddr) for _, fpBTCPK := range btcDel.FpBtcPkList { fpBTCPKHex := fpBTCPK.MarshalHex() - fp := k.getOrLoadFp(ctx, cacheFpByBtcPkHex, fpBTCPKHex) + fp := k.loadFP(ctx, cacheFpByBtcPkHex, fpBTCPKHex) fpAddr := sdk.MustAccAddressFromBech32(fp.Addr) f(fpAddr, delAddr, btcDel.TotalSat) @@ -414,7 +417,7 @@ func (k Keeper) processBtcDelegations( } } -func (k Keeper) getOrLoadFp( +func (k Keeper) loadFP( ctx context.Context, cacheFpByBtcPkHex map[string]*types.FinalityProvider, fpBTCPKHex string, From f99a36ba9fd665a151ea97ac1a5fcb2edbe10507 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 15 Dec 2024 21:12:02 -0300 Subject: [PATCH 069/132] chore: created separated package for PrivSigner structure --- app/app.go | 3 ++- app/keepers/keepers.go | 3 ++- app/keepers/utils.go | 27 --------------------------- app/signer/private.go | 33 +++++++++++++++++++++++++++++++++ app/test_helpers.go | 14 +++++++------- cmd/babylond/cmd/root.go | 6 +++--- test/replay/driver.go | 8 ++++---- testutil/datagen/genesiskey.go | 4 ++-- testutil/helper/helper.go | 6 +++--- 9 files changed, 56 insertions(+), 48 deletions(-) create mode 100644 app/signer/private.go diff --git a/app/app.go b/app/app.go index 924cde78e..07fee6d9e 100644 --- a/app/app.go +++ b/app/app.go @@ -95,6 +95,7 @@ import ( "github.com/babylonlabs-io/babylon/app/ante" appkeepers "github.com/babylonlabs-io/babylon/app/keepers" appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/app/upgrades" "github.com/babylonlabs-io/babylon/client/docs" bbn "github.com/babylonlabs-io/babylon/types" @@ -206,7 +207,7 @@ func NewBabylonApp( loadLatest bool, skipUpgradeHeights map[int64]bool, invCheckPeriod uint, - privSigner *appkeepers.PrivSigner, + privSigner *signer.PrivSigner, appOpts servertypes.AppOptions, wasmOpts []wasmkeeper.Option, baseAppOptions ...func(*baseapp.BaseApp), diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index a702c15a4..8074c41d5 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -60,6 +60,7 @@ import ( ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/app/signer" bbn "github.com/babylonlabs-io/babylon/types" owasm "github.com/babylonlabs-io/babylon/wasmbinding" btccheckpointkeeper "github.com/babylonlabs-io/babylon/x/btccheckpoint/keeper" @@ -162,7 +163,7 @@ func (ak *AppKeepers) InitKeepers( homePath string, invCheckPeriod uint, skipUpgradeHeights map[int64]bool, - privSigner *PrivSigner, + privSigner *signer.PrivSigner, appOpts servertypes.AppOptions, wasmConfig wasmtypes.WasmConfig, wasmOpts []wasmkeeper.Option, diff --git a/app/keepers/utils.go b/app/keepers/utils.go index 7efe4b78a..33cdff694 100644 --- a/app/keepers/utils.go +++ b/app/keepers/utils.go @@ -7,11 +7,7 @@ import ( "path/filepath" "text/template" - cmtconfig "github.com/cometbft/cometbft/config" - cmtos "github.com/cometbft/cometbft/libs/os" "github.com/cosmos/cosmos-sdk/client/config" - - "github.com/babylonlabs-io/babylon/privval" ) const defaultConfigTemplate = `# This is a TOML config file. @@ -33,29 +29,6 @@ node = "{{ .Node }}" broadcast-mode = "{{ .BroadcastMode }}" ` -type PrivSigner struct { - WrappedPV *privval.WrappedFilePV -} - -func InitPrivSigner(nodeDir string) (*PrivSigner, error) { - nodeCfg := cmtconfig.DefaultConfig() - pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile()) - err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777) - if err != nil { - return nil, err - } - pvStateFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorStateFile()) - err = cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777) - if err != nil { - return nil, err - } - wrappedPV := privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile) - - return &PrivSigner{ - WrappedPV: wrappedPV, - }, nil -} - func CreateClientConfig(chainID string, backend string, homePath string) (*config.ClientConfig, error) { cliConf := &config.ClientConfig{ ChainID: chainID, diff --git a/app/signer/private.go b/app/signer/private.go new file mode 100644 index 000000000..8fcd1f217 --- /dev/null +++ b/app/signer/private.go @@ -0,0 +1,33 @@ +package signer + +import ( + "path/filepath" + + cmtconfig "github.com/cometbft/cometbft/config" + cmtos "github.com/cometbft/cometbft/libs/os" + + "github.com/babylonlabs-io/babylon/privval" +) + +type PrivSigner struct { + WrappedPV *privval.WrappedFilePV +} + +func InitPrivSigner(nodeDir string) (*PrivSigner, error) { + nodeCfg := cmtconfig.DefaultConfig() + pvKeyFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorKeyFile()) + err := cmtos.EnsureDir(filepath.Dir(pvKeyFile), 0777) + if err != nil { + return nil, err + } + pvStateFile := filepath.Join(nodeDir, nodeCfg.PrivValidatorStateFile()) + err = cmtos.EnsureDir(filepath.Dir(pvStateFile), 0777) + if err != nil { + return nil, err + } + wrappedPV := privval.LoadOrGenWrappedFilePV(pvKeyFile, pvStateFile) + + return &PrivSigner{ + WrappedPV: wrappedPV, + }, nil +} diff --git a/app/test_helpers.go b/app/test_helpers.go index 155223aab..e13d5e772 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -31,8 +31,8 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/require" - appkeepers "github.com/babylonlabs-io/babylon/app/keepers" appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/crypto/bls12381" "github.com/babylonlabs-io/babylon/privval" bbn "github.com/babylonlabs-io/babylon/types" @@ -49,7 +49,7 @@ type SetupOptions struct { AppOpts types.AppOptions } -func setup(t *testing.T, ps *appkeepers.PrivSigner, withGenesis bool, invCheckPeriod uint, btcConf bbn.SupportedBtcNetwork) (*BabylonApp, GenesisState) { +func setup(t *testing.T, ps *signer.PrivSigner, withGenesis bool, invCheckPeriod uint, btcConf bbn.SupportedBtcNetwork) (*BabylonApp, GenesisState) { db := dbm.NewMemDB() nodeHome := t.TempDir() @@ -83,7 +83,7 @@ func setup(t *testing.T, ps *appkeepers.PrivSigner, withGenesis bool, invCheckPe // Created Babylon application will have one validator with hardcoed amount of tokens. // This is necessary as from cosmos-sdk 0.46 it is required that there is at least // one validator in validator set during InitGenesis abci call - https://github.com/cosmos/cosmos-sdk/pull/9697 -func NewBabylonAppWithCustomOptions(t *testing.T, isCheckTx bool, privSigner *appkeepers.PrivSigner, options SetupOptions) *BabylonApp { +func NewBabylonAppWithCustomOptions(t *testing.T, isCheckTx bool, privSigner *signer.PrivSigner, options SetupOptions) *BabylonApp { t.Helper() // create validator set with single validator valKeys, err := privval.NewValidatorKeys(ed25519.GenPrivKey(), bls12381.GenPrivKey()) @@ -258,7 +258,7 @@ func SetupWithBitcoinConf(t *testing.T, isCheckTx bool, btcConf bbn.SupportedBtc } // SetupTestPrivSigner sets up a PrivSigner for testing -func SetupTestPrivSigner() (*appkeepers.PrivSigner, error) { +func SetupTestPrivSigner() (*signer.PrivSigner, error) { // Create a temporary node directory nodeDir, err := os.MkdirTemp("", "tmp-signer") if err != nil { @@ -267,7 +267,7 @@ func SetupTestPrivSigner() (*appkeepers.PrivSigner, error) { defer func() { _ = os.RemoveAll(nodeDir) }() - privSigner, _ := appkeepers.InitPrivSigner(nodeDir) + privSigner, _ := signer.InitPrivSigner(nodeDir) return privSigner, nil } @@ -276,7 +276,7 @@ func SetupTestPrivSigner() (*appkeepers.PrivSigner, error) { // of one consensus engine unit (10^6) in the default token of the babylon app from first genesis // account. A Nop logger is set in BabylonApp. // Note that the privSigner should be the 0th item of valSet -func SetupWithGenesisValSet(t *testing.T, btcConf bbn.SupportedBtcNetwork, valSet []*checkpointingtypes.GenesisKey, privSigner *appkeepers.PrivSigner, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *BabylonApp { +func SetupWithGenesisValSet(t *testing.T, btcConf bbn.SupportedBtcNetwork, valSet []*checkpointingtypes.GenesisKey, privSigner *signer.PrivSigner, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *BabylonApp { t.Helper() app, genesisState := setup(t, privSigner, true, 5, btcConf) genesisState = genesisStateWithValSet(t, app, genesisState, valSet, genAccs, balances...) @@ -309,7 +309,7 @@ func SetupWithGenesisValSet(t *testing.T, btcConf bbn.SupportedBtcNetwork, valSe return app } -func GenesisKeyFromPrivSigner(ps *appkeepers.PrivSigner) (*checkpointingtypes.GenesisKey, error) { +func GenesisKeyFromPrivSigner(ps *signer.PrivSigner) (*checkpointingtypes.GenesisKey, error) { valKeys, err := privval.NewValidatorKeys(ps.WrappedPV.GetValPrivKey(), ps.WrappedPV.GetBlsPrivKey()) if err != nil { return nil, err diff --git a/cmd/babylond/cmd/root.go b/cmd/babylond/cmd/root.go index 60a4c4a21..621bb74ed 100644 --- a/cmd/babylond/cmd/root.go +++ b/cmd/babylond/cmd/root.go @@ -8,7 +8,7 @@ import ( confixcmd "cosmossdk.io/tools/confix/cmd" "github.com/CosmWasm/wasmd/x/wasm" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - appkeepers "github.com/babylonlabs-io/babylon/app/keepers" + "github.com/babylonlabs-io/babylon/app/signer" cmtcfg "github.com/cometbft/cometbft/config" cmtcli "github.com/cometbft/cometbft/libs/cli" dbm "github.com/cosmos/cosmos-db" @@ -260,7 +260,7 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts serverty } homeDir := cast.ToString(appOpts.Get(flags.FlagHome)) - privSigner, err := appkeepers.InitPrivSigner(homeDir) + privSigner, err := signer.InitPrivSigner(homeDir) if err != nil { panic(err) } @@ -298,7 +298,7 @@ func appExport( return servertypes.ExportedApp{}, errors.New("application home not set") } - privSigner, err := appkeepers.InitPrivSigner(homePath) + privSigner, err := signer.InitPrivSigner(homePath) if err != nil { panic(err) } diff --git a/test/replay/driver.go b/test/replay/driver.go index c822d914d..2cb0f51ca 100644 --- a/test/replay/driver.go +++ b/test/replay/driver.go @@ -22,7 +22,7 @@ import ( "cosmossdk.io/math" "github.com/babylonlabs-io/babylon/app" babylonApp "github.com/babylonlabs-io/babylon/app" - appkeepers "github.com/babylonlabs-io/babylon/app/keepers" + appsigner "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/test/e2e/initialization" "github.com/babylonlabs-io/babylon/testutil/datagen" btclighttypes "github.com/babylonlabs-io/babylon/x/btclightclient/types" @@ -137,7 +137,7 @@ type FinalizedBlock struct { type BabylonAppDriver struct { App *app.BabylonApp - PrivSigner *appkeepers.PrivSigner + PrivSigner *appsigner.PrivSigner DriverAccountPrivKey cryptotypes.PrivKey DriverAccountSeqNr uint64 DriverAccountAccNr uint64 @@ -193,7 +193,7 @@ func NewBabylonAppDriver( panic(err) } - signer, err := appkeepers.InitPrivSigner(chain.Nodes[0].ConfigDir) + signer, err := appsigner.InitPrivSigner(chain.Nodes[0].ConfigDir) require.NoError(t, err) require.NotNil(t, signer) signerValAddress := signer.WrappedPV.GetAddress() @@ -732,7 +732,7 @@ func NewBlockReplayer(t *testing.T, nodeDir string) *BlockReplayer { panic(err) } - signer, err := appkeepers.InitPrivSigner(nodeDir) + signer, err := appsigner.InitPrivSigner(nodeDir) require.NoError(t, err) require.NotNil(t, signer) signerValAddress := signer.WrappedPV.GetAddress() diff --git a/testutil/datagen/genesiskey.go b/testutil/datagen/genesiskey.go index 77bffb8af..a0389d4dc 100644 --- a/testutil/datagen/genesiskey.go +++ b/testutil/datagen/genesiskey.go @@ -2,7 +2,7 @@ package datagen import ( "github.com/babylonlabs-io/babylon/app" - appkeepers "github.com/babylonlabs-io/babylon/app/keepers" + "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/crypto/bls12381" "github.com/babylonlabs-io/babylon/privval" checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" @@ -88,7 +88,7 @@ func GenesisValidatorSet(numVals int) (*GenesisValidators, error) { // GenesisValidatorSetWithPrivSigner generates a set with `numVals` genesis validators // along with the privSigner, which will be in the 0th position of the return validator set -func GenesisValidatorSetWithPrivSigner(numVals int) (*GenesisValidators, *appkeepers.PrivSigner, error) { +func GenesisValidatorSetWithPrivSigner(numVals int) (*GenesisValidators, *signer.PrivSigner, error) { ps, err := app.SetupTestPrivSigner() if err != nil { return nil, nil, err diff --git a/testutil/helper/helper.go b/testutil/helper/helper.go index 9d9219767..46ba8d9dd 100644 --- a/testutil/helper/helper.go +++ b/testutil/helper/helper.go @@ -7,7 +7,7 @@ import ( "testing" "cosmossdk.io/core/header" - appkeepers "github.com/babylonlabs-io/babylon/app/keepers" + "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/crypto/bls12381" "github.com/babylonlabs-io/babylon/testutil/datagen" checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" @@ -57,7 +57,7 @@ func NewHelper(t *testing.T) *Helper { // NewHelperWithValSet is same as NewHelper, except that it creates a set of validators // the privSigner is the 0th validator in valSet -func NewHelperWithValSet(t *testing.T, valSet *datagen.GenesisValidators, privSigner *appkeepers.PrivSigner) *Helper { +func NewHelperWithValSet(t *testing.T, valSet *datagen.GenesisValidators, privSigner *signer.PrivSigner) *Helper { // generate the genesis account signerPubKey := privSigner.WrappedPV.Key.PubKey acc := authtypes.NewBaseAccount(signerPubKey.Address().Bytes(), &cosmosed.PubKey{Key: signerPubKey.Bytes()}, 0, 0) @@ -95,7 +95,7 @@ func NewHelperWithValSet(t *testing.T, valSet *datagen.GenesisValidators, privSi // NewHelperWithValSetNoSigner is same as NewHelperWithValSet, except that the privSigner is not // included in the validator set -func NewHelperWithValSetNoSigner(t *testing.T, valSet *datagen.GenesisValidators, privSigner *appkeepers.PrivSigner) *Helper { +func NewHelperWithValSetNoSigner(t *testing.T, valSet *datagen.GenesisValidators, privSigner *signer.PrivSigner) *Helper { // generate the genesis account signerPubKey := privSigner.WrappedPV.Key.PubKey acc := authtypes.NewBaseAccount(signerPubKey.Address().Bytes(), &cosmosed.PubKey{Key: signerPubKey.Bytes()}, 0, 0) From 21364ea2810277bb741f2b6dbe1f2f2ff6065e54 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 15 Dec 2024 21:20:09 -0300 Subject: [PATCH 070/132] chore: move SetupTestPrivSigner to testutil and avoid circular dependency --- app/app_test.go | 5 ++- app/encoding.go | 3 +- app/test_helpers.go | 45 +++---------------- cmd/babylond/cmd/genhelpers/bls_add_test.go | 5 ++- .../cmd/genhelpers/bls_create_test.go | 3 +- cmd/babylond/cmd/testnet_test.go | 3 +- cmd/babylond/cmd/validate_genesis_test.go | 3 +- testutil/datagen/genesiskey.go | 10 ++--- testutil/signer/private.go | 43 ++++++++++++++++++ 9 files changed, 69 insertions(+), 51 deletions(-) create mode 100644 testutil/signer/private.go diff --git a/app/app_test.go b/app/app_test.go index 47599538d..09b305eab 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -5,6 +5,7 @@ import ( "testing" "cosmossdk.io/log" + "github.com/babylonlabs-io/babylon/testutil/signer" abci "github.com/cometbft/cometbft/abci/types" dbm "github.com/cosmos/cosmos-db" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,7 +15,7 @@ import ( func TestBabylonBlockedAddrs(t *testing.T) { db := dbm.NewMemDB() - signer, _ := SetupTestPrivSigner() + signer, _ := signer.SetupTestPrivSigner() logger := log.NewTestLogger(t) app := NewBabylonAppWithCustomOptions(t, false, signer, SetupOptions{ @@ -71,7 +72,7 @@ func TestGetMaccPerms(t *testing.T) { func TestUpgradeStateOnGenesis(t *testing.T) { db := dbm.NewMemDB() - privSigner, err := SetupTestPrivSigner() + privSigner, err := signer.SetupTestPrivSigner() require.NoError(t, err) logger := log.NewTestLogger(t) diff --git a/app/encoding.go b/app/encoding.go index 57a5b6cf5..d67c63bc2 100644 --- a/app/encoding.go +++ b/app/encoding.go @@ -10,6 +10,7 @@ import ( simsutils "github.com/cosmos/cosmos-sdk/testutil/sims" appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/testutil/signer" bbn "github.com/babylonlabs-io/babylon/types" ) @@ -27,7 +28,7 @@ func TmpAppOptions() simsutils.AppOptionsMap { } func NewTmpBabylonApp() *BabylonApp { - signer, _ := SetupTestPrivSigner() + signer, _ := signer.SetupTestPrivSigner() return NewBabylonApp( log.NewNopLogger(), dbm.NewMemDB(), diff --git a/app/test_helpers.go b/app/test_helpers.go index e13d5e772..a53305374 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -3,13 +3,13 @@ package app import ( "bytes" "encoding/json" - "os" "testing" "time" "cosmossdk.io/log" "cosmossdk.io/math" pruningtypes "cosmossdk.io/store/pruning/types" + "github.com/babylonlabs-io/babylon/testutil/signer" minttypes "github.com/babylonlabs-io/babylon/x/mint/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto/ed25519" @@ -32,7 +32,7 @@ import ( "github.com/stretchr/testify/require" appparams "github.com/babylonlabs-io/babylon/app/params" - "github.com/babylonlabs-io/babylon/app/signer" + appsigner "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/crypto/bls12381" "github.com/babylonlabs-io/babylon/privval" bbn "github.com/babylonlabs-io/babylon/types" @@ -49,7 +49,7 @@ type SetupOptions struct { AppOpts types.AppOptions } -func setup(t *testing.T, ps *signer.PrivSigner, withGenesis bool, invCheckPeriod uint, btcConf bbn.SupportedBtcNetwork) (*BabylonApp, GenesisState) { +func setup(t *testing.T, ps *appsigner.PrivSigner, withGenesis bool, invCheckPeriod uint, btcConf bbn.SupportedBtcNetwork) (*BabylonApp, GenesisState) { db := dbm.NewMemDB() nodeHome := t.TempDir() @@ -83,7 +83,7 @@ func setup(t *testing.T, ps *signer.PrivSigner, withGenesis bool, invCheckPeriod // Created Babylon application will have one validator with hardcoed amount of tokens. // This is necessary as from cosmos-sdk 0.46 it is required that there is at least // one validator in validator set during InitGenesis abci call - https://github.com/cosmos/cosmos-sdk/pull/9697 -func NewBabylonAppWithCustomOptions(t *testing.T, isCheckTx bool, privSigner *signer.PrivSigner, options SetupOptions) *BabylonApp { +func NewBabylonAppWithCustomOptions(t *testing.T, isCheckTx bool, privSigner *appsigner.PrivSigner, options SetupOptions) *BabylonApp { t.Helper() // create validator set with single validator valKeys, err := privval.NewValidatorKeys(ed25519.GenPrivKey(), bls12381.GenPrivKey()) @@ -237,7 +237,7 @@ func Setup(t *testing.T, isCheckTx bool) *BabylonApp { func SetupWithBitcoinConf(t *testing.T, isCheckTx bool, btcConf bbn.SupportedBtcNetwork) *BabylonApp { t.Helper() - ps, err := SetupTestPrivSigner() + ps, err := signer.SetupTestPrivSigner() require.NoError(t, err) valPubKey := ps.WrappedPV.Key.PubKey // generate genesis account @@ -248,7 +248,7 @@ func SetupWithBitcoinConf(t *testing.T, isCheckTx bool, btcConf bbn.SupportedBtc } ps.WrappedPV.Key.DelegatorAddress = acc.GetAddress().String() // create validator set with single validator - genesisKey, err := GenesisKeyFromPrivSigner(ps) + genesisKey, err := signer.GenesisKeyFromPrivSigner(ps) require.NoError(t, err) genesisValSet := []*checkpointingtypes.GenesisKey{genesisKey} @@ -257,26 +257,12 @@ func SetupWithBitcoinConf(t *testing.T, isCheckTx bool, btcConf bbn.SupportedBtc return app } -// SetupTestPrivSigner sets up a PrivSigner for testing -func SetupTestPrivSigner() (*signer.PrivSigner, error) { - // Create a temporary node directory - nodeDir, err := os.MkdirTemp("", "tmp-signer") - if err != nil { - return nil, err - } - defer func() { - _ = os.RemoveAll(nodeDir) - }() - privSigner, _ := signer.InitPrivSigner(nodeDir) - return privSigner, nil -} - // SetupWithGenesisValSet initializes a new BabylonApp with a validator set and genesis accounts // that also act as delegators. For simplicity, each validator is bonded with a delegation // of one consensus engine unit (10^6) in the default token of the babylon app from first genesis // account. A Nop logger is set in BabylonApp. // Note that the privSigner should be the 0th item of valSet -func SetupWithGenesisValSet(t *testing.T, btcConf bbn.SupportedBtcNetwork, valSet []*checkpointingtypes.GenesisKey, privSigner *signer.PrivSigner, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *BabylonApp { +func SetupWithGenesisValSet(t *testing.T, btcConf bbn.SupportedBtcNetwork, valSet []*checkpointingtypes.GenesisKey, privSigner *appsigner.PrivSigner, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *BabylonApp { t.Helper() app, genesisState := setup(t, privSigner, true, 5, btcConf) genesisState = genesisStateWithValSet(t, app, genesisState, valSet, genAccs, balances...) @@ -309,23 +295,6 @@ func SetupWithGenesisValSet(t *testing.T, btcConf bbn.SupportedBtcNetwork, valSe return app } -func GenesisKeyFromPrivSigner(ps *signer.PrivSigner) (*checkpointingtypes.GenesisKey, error) { - valKeys, err := privval.NewValidatorKeys(ps.WrappedPV.GetValPrivKey(), ps.WrappedPV.GetBlsPrivKey()) - if err != nil { - return nil, err - } - valPubkey, err := cryptocodec.FromCmtPubKeyInterface(valKeys.ValPubkey) - if err != nil { - return nil, err - } - return checkpointingtypes.NewGenesisKey( - ps.WrappedPV.GetAddress(), - &valKeys.BlsPubkey, - valKeys.PoP, - &cosmosed.PubKey{Key: valPubkey.Bytes()}, - ) -} - // createRandomAccounts is a strategy used by addTestAddrs() in order to generated addresses in random order. func createRandomAccounts(accNum int) []sdk.AccAddress { testAddrs := make([]sdk.AccAddress, accNum) diff --git a/cmd/babylond/cmd/genhelpers/bls_add_test.go b/cmd/babylond/cmd/genhelpers/bls_add_test.go index 949b5dd14..52e50dfcc 100644 --- a/cmd/babylond/cmd/genhelpers/bls_add_test.go +++ b/cmd/babylond/cmd/genhelpers/bls_add_test.go @@ -35,6 +35,7 @@ import ( "github.com/babylonlabs-io/babylon/privval" "github.com/babylonlabs-io/babylon/testutil/cli" "github.com/babylonlabs-io/babylon/testutil/datagen" + "github.com/babylonlabs-io/babylon/testutil/signer" "github.com/babylonlabs-io/babylon/x/checkpointing/types" ) @@ -75,7 +76,7 @@ func Test_CmdCreateAddWithoutGentx(t *testing.T) { require.NoError(t, err) db := dbm.NewMemDB() - signer, err := app.SetupTestPrivSigner() + signer, err := signer.SetupTestPrivSigner() require.NoError(t, err) bbn := app.NewBabylonAppWithCustomOptions(t, false, signer, app.SetupOptions{ Logger: logger, @@ -117,7 +118,7 @@ func Test_CmdCreateAddWithoutGentx(t *testing.T) { // error is expected if adding duplicate func Test_CmdAddBlsWithGentx(t *testing.T) { db := dbm.NewMemDB() - signer, err := app.SetupTestPrivSigner() + signer, err := signer.SetupTestPrivSigner() require.NoError(t, err) bbn := app.NewBabylonAppWithCustomOptions(t, false, signer, app.SetupOptions{ Logger: log.NewNopLogger(), diff --git a/cmd/babylond/cmd/genhelpers/bls_create_test.go b/cmd/babylond/cmd/genhelpers/bls_create_test.go index c036794ac..5b171fa90 100644 --- a/cmd/babylond/cmd/genhelpers/bls_create_test.go +++ b/cmd/babylond/cmd/genhelpers/bls_create_test.go @@ -25,6 +25,7 @@ import ( "github.com/babylonlabs-io/babylon/app" "github.com/babylonlabs-io/babylon/cmd/babylond/cmd/genhelpers" "github.com/babylonlabs-io/babylon/privval" + "github.com/babylonlabs-io/babylon/testutil/signer" "github.com/babylonlabs-io/babylon/x/checkpointing/types" ) @@ -34,7 +35,7 @@ func Test_CmdCreateBls(t *testing.T) { cfg, err := genutiltest.CreateDefaultCometConfig(home) require.NoError(t, err) - signer, err := app.SetupTestPrivSigner() + signer, err := signer.SetupTestPrivSigner() require.NoError(t, err) bbn := app.NewBabylonAppWithCustomOptions(t, false, signer, app.SetupOptions{ Logger: logger, diff --git a/cmd/babylond/cmd/testnet_test.go b/cmd/babylond/cmd/testnet_test.go index f379b1357..be1002310 100644 --- a/cmd/babylond/cmd/testnet_test.go +++ b/cmd/babylond/cmd/testnet_test.go @@ -18,6 +18,7 @@ import ( "github.com/stretchr/testify/require" "github.com/babylonlabs-io/babylon/app" + "github.com/babylonlabs-io/babylon/testutil/signer" ) func Test_TestnetCmd(t *testing.T) { @@ -26,7 +27,7 @@ func Test_TestnetCmd(t *testing.T) { cfg, err := genutiltest.CreateDefaultCometConfig(home) require.NoError(t, err) - signer, err := app.SetupTestPrivSigner() + signer, err := signer.SetupTestPrivSigner() require.NoError(t, err) bbn := app.NewBabylonAppWithCustomOptions(t, false, signer, app.SetupOptions{ Logger: logger, diff --git a/cmd/babylond/cmd/validate_genesis_test.go b/cmd/babylond/cmd/validate_genesis_test.go index 1248d596d..feb82fe99 100644 --- a/cmd/babylond/cmd/validate_genesis_test.go +++ b/cmd/babylond/cmd/validate_genesis_test.go @@ -8,6 +8,7 @@ import ( dbm "github.com/cosmos/cosmos-db" + "github.com/babylonlabs-io/babylon/testutil/signer" checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" "github.com/cosmos/cosmos-sdk/x/genutil" @@ -89,7 +90,7 @@ func generateTestGenesisState(t *testing.T, home string, n int) (*app.BabylonApp logger := log.NewNopLogger() cfg, _ := genutiltest.CreateDefaultCometConfig(home) - signer, err := app.SetupTestPrivSigner() + signer, err := signer.SetupTestPrivSigner() require.NoError(t, err) bbn := app.NewBabylonAppWithCustomOptions(t, false, signer, app.SetupOptions{ Logger: logger, diff --git a/testutil/datagen/genesiskey.go b/testutil/datagen/genesiskey.go index a0389d4dc..dbc39dda2 100644 --- a/testutil/datagen/genesiskey.go +++ b/testutil/datagen/genesiskey.go @@ -1,10 +1,10 @@ package datagen import ( - "github.com/babylonlabs-io/babylon/app" - "github.com/babylonlabs-io/babylon/app/signer" + appsigner "github.com/babylonlabs-io/babylon/app/signer" "github.com/babylonlabs-io/babylon/crypto/bls12381" "github.com/babylonlabs-io/babylon/privval" + "github.com/babylonlabs-io/babylon/testutil/signer" checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" cmtcrypto "github.com/cometbft/cometbft/crypto" cmted25519 "github.com/cometbft/cometbft/crypto/ed25519" @@ -88,12 +88,12 @@ func GenesisValidatorSet(numVals int) (*GenesisValidators, error) { // GenesisValidatorSetWithPrivSigner generates a set with `numVals` genesis validators // along with the privSigner, which will be in the 0th position of the return validator set -func GenesisValidatorSetWithPrivSigner(numVals int) (*GenesisValidators, *signer.PrivSigner, error) { - ps, err := app.SetupTestPrivSigner() +func GenesisValidatorSetWithPrivSigner(numVals int) (*GenesisValidators, *appsigner.PrivSigner, error) { + ps, err := signer.SetupTestPrivSigner() if err != nil { return nil, nil, err } - signerGenesisKey, err := app.GenesisKeyFromPrivSigner(ps) + signerGenesisKey, err := signer.GenesisKeyFromPrivSigner(ps) if err != nil { return nil, nil, err } diff --git a/testutil/signer/private.go b/testutil/signer/private.go new file mode 100644 index 000000000..a4f39cb3a --- /dev/null +++ b/testutil/signer/private.go @@ -0,0 +1,43 @@ +package signer + +import ( + "os" + + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + cosmosed "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + + "github.com/babylonlabs-io/babylon/app/signer" + "github.com/babylonlabs-io/babylon/privval" + checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" +) + +// SetupTestPrivSigner sets up a PrivSigner for testing +func SetupTestPrivSigner() (*signer.PrivSigner, error) { + // Create a temporary node directory + nodeDir, err := os.MkdirTemp("", "tmp-signer") + if err != nil { + return nil, err + } + defer func() { + _ = os.RemoveAll(nodeDir) + }() + privSigner, _ := signer.InitPrivSigner(nodeDir) + return privSigner, nil +} + +func GenesisKeyFromPrivSigner(ps *signer.PrivSigner) (*checkpointingtypes.GenesisKey, error) { + valKeys, err := privval.NewValidatorKeys(ps.WrappedPV.GetValPrivKey(), ps.WrappedPV.GetBlsPrivKey()) + if err != nil { + return nil, err + } + valPubkey, err := cryptocodec.FromCmtPubKeyInterface(valKeys.ValPubkey) + if err != nil { + return nil, err + } + return checkpointingtypes.NewGenesisKey( + ps.WrappedPV.GetAddress(), + &valKeys.BlsPubkey, + valKeys.PoP, + &cosmosed.PubKey{Key: valPubkey.Bytes()}, + ) +} From 3696a42b8adac42b1dd093e89d9448903f86625a Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 15 Dec 2024 21:28:10 -0300 Subject: [PATCH 071/132] chore: moved constant used module accounts to appparams --- app/app.go | 2 +- app/keepers/keepers.go | 42 +++++++++++------------ app/params/addr.go | 11 ++++++ app/upgrades/v1/upgrades_test.go | 4 +-- testutil/keeper/btccheckpoint.go | 5 ++- testutil/keeper/btclightclient.go | 5 ++- testutil/keeper/btcstaking.go | 5 ++- testutil/keeper/epoching.go | 5 ++- testutil/keeper/finality.go | 5 ++- testutil/keeper/incentive.go | 4 +-- x/btccheckpoint/keeper/msg_server_test.go | 4 +-- x/btcstaking/keeper/msg_server_test.go | 4 +-- x/mint/module_test.go | 3 +- 13 files changed, 52 insertions(+), 47 deletions(-) create mode 100644 app/params/addr.go diff --git a/app/app.go b/app/app.go index 07fee6d9e..ca1173dc5 100644 --- a/app/app.go +++ b/app/app.go @@ -801,7 +801,7 @@ func BlockedAddresses() map[string]bool { } // allow the following addresses to receive funds - delete(modAccAddrs, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + delete(modAccAddrs, appparams.AccGov.String()) return modAccAddrs } diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 8074c41d5..10187dc14 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -218,7 +218,7 @@ func (ak *AppKeepers) InitKeepers( maccPerms, authcodec.NewBech32Codec(appparams.Bech32PrefixAccAddr), appparams.Bech32PrefixAccAddr, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) bankKeeper := bankkeeper.NewBaseKeeper( @@ -226,7 +226,7 @@ func (ak *AppKeepers) InitKeepers( runtime.NewKVStoreService(keys[banktypes.StoreKey]), accountKeeper, blockedAddress, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), logger, ) @@ -235,7 +235,7 @@ func (ak *AppKeepers) InitKeepers( runtime.NewKVStoreService(keys[stakingtypes.StoreKey]), accountKeeper, bankKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), authcodec.NewBech32Codec(appparams.Bech32PrefixValAddr), authcodec.NewBech32Codec(appparams.Bech32PrefixConsAddr), ) @@ -246,7 +246,7 @@ func (ak *AppKeepers) InitKeepers( runtime.NewKVStoreService(keys[epochingtypes.StoreKey]), bankKeeper, stakingKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) checkpointingKeeper := checkpointingkeeper.NewKeeper( @@ -271,7 +271,7 @@ func (ak *AppKeepers) InitKeepers( ak.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[consensusparamtypes.StoreKey]), - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), runtime.EventService{}, ) bApp.SetParamStore(ak.ConsensusParamsKeeper.ParamsStore) @@ -301,7 +301,7 @@ func (ak *AppKeepers) InitKeepers( ak.CircuitKeeper = circuitkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[circuittypes.StoreKey]), - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ak.AccountKeeper.AddressCodec(), ) bApp.SetCircuitBreaker(&ak.CircuitKeeper) @@ -313,7 +313,7 @@ func (ak *AppKeepers) InitKeepers( ak.AccountKeeper, ak.BankKeeper, authtypes.FeeCollectorName, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) ak.DistrKeeper = distrkeeper.NewKeeper( @@ -323,7 +323,7 @@ func (ak *AppKeepers) InitKeepers( ak.BankKeeper, ak.StakingKeeper, authtypes.FeeCollectorName, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) // set up incentive keeper @@ -333,7 +333,7 @@ func (ak *AppKeepers) InitKeepers( ak.BankKeeper, ak.AccountKeeper, &epochingKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), authtypes.FeeCollectorName, ) @@ -342,7 +342,7 @@ func (ak *AppKeepers) InitKeepers( encodingConfig.Amino, runtime.NewKVStoreService(keys[slashingtypes.StoreKey]), ak.StakingKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) ak.CrisisKeeper = crisiskeeper.NewKeeper( @@ -351,7 +351,7 @@ func (ak *AppKeepers) InitKeepers( invCheckPeriod, ak.BankKeeper, authtypes.FeeCollectorName, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ak.AccountKeeper.AddressCodec(), ) @@ -373,7 +373,7 @@ func (ak *AppKeepers) InitKeepers( appCodec, homePath, bApp, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) ak.AuthzKeeper = authzkeeper.NewKeeper( @@ -394,7 +394,7 @@ func (ak *AppKeepers) InitKeepers( // `MsgIBCSoftwareUpgrade` and `MsgRecoverClient` // https://github.com/cosmos/ibc-go/releases/tag/v8.0.0 // Gov is the proper authority for those types of messages - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) // register the proposal types @@ -421,7 +421,7 @@ func (ak *AppKeepers) InitKeepers( ak.DistrKeeper, bApp.MsgServiceRouter(), govConfig, - authtypes.NewModuleAddress(govtypes.ModuleName).String()) + appparams.AccGov.String()) ak.GovKeeper = *govKeeper.SetHooks( govtypes.NewMultiGovHooks( @@ -434,7 +434,7 @@ func (ak *AppKeepers) InitKeepers( runtime.NewKVStoreService(keys[btclightclienttypes.StoreKey]), *btcConfig, &ak.IncentiveKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) btcCheckpointKeeper := btccheckpointkeeper.NewKeeper( @@ -445,7 +445,7 @@ func (ak *AppKeepers) InitKeepers( &checkpointingKeeper, &ak.IncentiveKeeper, &powLimit, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) ak.IBCFeeKeeper = ibcfeekeeper.NewKeeper( @@ -466,7 +466,7 @@ func (ak *AppKeepers) InitKeepers( ak.AccountKeeper, ak.BankKeeper, scopedTransferKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) ak.MonitorKeeper = monitorkeeper.NewKeeper( @@ -499,7 +499,7 @@ func (ak *AppKeepers) InitKeepers( &btcCheckpointKeeper, &ak.IncentiveKeeper, btcNetParams, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) // set up finality keeper @@ -509,7 +509,7 @@ func (ak *AppKeepers) InitKeepers( ak.BTCStakingKeeper, ak.IncentiveKeeper, ak.CheckpointingKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) // create evidence keeper with router @@ -543,7 +543,7 @@ func (ak *AppKeepers) InitKeepers( homePath, wasmConfig, WasmCapabilities(), - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), wasmOpts..., ) @@ -558,7 +558,7 @@ func (ak *AppKeepers) InitKeepers( appCodec, runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), ak.IBCKeeper.ClientKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ibcWasmConfig, bApp.GRPCQueryRouter(), ) diff --git a/app/params/addr.go b/app/params/addr.go new file mode 100644 index 000000000..4c9b7cbe0 --- /dev/null +++ b/app/params/addr.go @@ -0,0 +1,11 @@ +package params + +import ( + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +var ( + AccGov = authtypes.NewModuleAddress(govtypes.ModuleName) + AccFeeCollector = authtypes.NewModuleAddress(authtypes.FeeCollectorName) +) diff --git a/app/upgrades/v1/upgrades_test.go b/app/upgrades/v1/upgrades_test.go index 7273cd9c0..b183910d7 100644 --- a/app/upgrades/v1/upgrades_test.go +++ b/app/upgrades/v1/upgrades_test.go @@ -27,8 +27,6 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/suite" "github.com/babylonlabs-io/babylon/app" @@ -118,7 +116,7 @@ func (s *UpgradeTestSuite) TestUpgrade() { // onlu gov account can store new contracts respFromGov, err := wasmMsgServer.StoreCode(s.ctx, &wasmtypes.MsgStoreCode{ - Sender: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Sender: appparams.AccGov.String(), WASMByteCode: wasmContract, }) s.NoError(err) diff --git a/testutil/keeper/btccheckpoint.go b/testutil/keeper/btccheckpoint.go index 9049041af..1f090b030 100644 --- a/testutil/keeper/btccheckpoint.go +++ b/testutil/keeper/btccheckpoint.go @@ -15,10 +15,9 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/x/btccheckpoint/keeper" btcctypes "github.com/babylonlabs-io/babylon/x/btccheckpoint/types" ) @@ -48,7 +47,7 @@ func NewBTCCheckpointKeeper( ek, ik, powLimit, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/btclightclient.go b/testutil/keeper/btclightclient.go index 711308755..0e51ca06f 100644 --- a/testutil/keeper/btclightclient.go +++ b/testutil/keeper/btclightclient.go @@ -17,11 +17,10 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" bapp "github.com/babylonlabs-io/babylon/app" + appparams "github.com/babylonlabs-io/babylon/app/params" bbn "github.com/babylonlabs-io/babylon/types" btclightclientk "github.com/babylonlabs-io/babylon/x/btclightclient/keeper" btclightclientt "github.com/babylonlabs-io/babylon/x/btclightclient/types" @@ -66,7 +65,7 @@ func BTCLightClientKeeperWithCustomParams( stServ, testCfg, &MockIncentiveKeeper{}, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/btcstaking.go b/testutil/keeper/btcstaking.go index c38f00ed8..43f160caf 100644 --- a/testutil/keeper/btcstaking.go +++ b/testutil/keeper/btcstaking.go @@ -15,10 +15,9 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/x/btcstaking/keeper" "github.com/babylonlabs-io/babylon/x/btcstaking/types" ) @@ -46,7 +45,7 @@ func BTCStakingKeeperWithStore( btccKeeper, iKeeper, &chaincfg.SimNetParams, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/epoching.go b/testutil/keeper/epoching.go index 716761886..21c26badb 100644 --- a/testutil/keeper/epoching.go +++ b/testutil/keeper/epoching.go @@ -14,10 +14,9 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/x/epoching/keeper" "github.com/babylonlabs-io/babylon/x/epoching/types" ) @@ -39,7 +38,7 @@ func EpochingKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { // TODO: make this compile at the moment, will fix for integrated testing nil, nil, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) // TODO: add msgServiceRouter? diff --git a/testutil/keeper/finality.go b/testutil/keeper/finality.go index c2b22e5f3..7e97ce1e2 100644 --- a/testutil/keeper/finality.go +++ b/testutil/keeper/finality.go @@ -14,10 +14,9 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/x/finality/keeper" "github.com/babylonlabs-io/babylon/x/finality/types" ) @@ -44,7 +43,7 @@ func FinalityKeeperWithStore( bsKeeper, iKeeper, ckptKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), ) ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/incentive.go b/testutil/keeper/incentive.go index 2a6d2017b..bd274cdfb 100644 --- a/testutil/keeper/incentive.go +++ b/testutil/keeper/incentive.go @@ -15,9 +15,9 @@ import ( "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/x/incentive/keeper" "github.com/babylonlabs-io/babylon/x/incentive/types" ) @@ -39,7 +39,7 @@ func IncentiveKeeper(t testing.TB, bankKeeper types.BankKeeper, accountKeeper ty bankKeeper, accountKeeper, epochingKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), + appparams.AccGov.String(), authtypes.FeeCollectorName, ) diff --git a/x/btccheckpoint/keeper/msg_server_test.go b/x/btccheckpoint/keeper/msg_server_test.go index ed5e5fb04..4db217c11 100644 --- a/x/btccheckpoint/keeper/msg_server_test.go +++ b/x/btccheckpoint/keeper/msg_server_test.go @@ -10,10 +10,10 @@ import ( "github.com/btcsuite/btcd/chaincfg" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + appparams "github.com/babylonlabs-io/babylon/app/params" dg "github.com/babylonlabs-io/babylon/testutil/datagen" keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" bbn "github.com/babylonlabs-io/babylon/types" @@ -86,7 +86,7 @@ func TestUpdateParams(t *testing.T) { // Try to update params with a different checkpoint finalization timeout msg := &btcctypes.MsgUpdateParams{ - Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Authority: appparams.AccGov.String(), Params: btcctypes.Params{ CheckpointFinalizationTimeout: btcctypes.DefaultParams().CheckpointFinalizationTimeout + 1, }, diff --git a/x/btcstaking/keeper/msg_server_test.go b/x/btcstaking/keeper/msg_server_test.go index aff4d2278..86730c967 100644 --- a/x/btcstaking/keeper/msg_server_test.go +++ b/x/btcstaking/keeper/msg_server_test.go @@ -13,13 +13,13 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + appparams "github.com/babylonlabs-io/babylon/app/params" asig "github.com/babylonlabs-io/babylon/crypto/schnorr-adaptor-signature" testutil "github.com/babylonlabs-io/babylon/testutil/btcstaking-helper" "github.com/babylonlabs-io/babylon/testutil/datagen" @@ -53,7 +53,7 @@ func FuzzMsgServer_UpdateParams(f *testing.F) { // Try to update params with minUnbondingTime less than or equal to checkpointFinalizationTimeout msg := &types.MsgUpdateParams{ - Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Authority: appparams.AccGov.String(), Params: params, } diff --git a/x/mint/module_test.go b/x/mint/module_test.go index 7b71495b9..fad0cb363 100644 --- a/x/mint/module_test.go +++ b/x/mint/module_test.go @@ -3,6 +3,7 @@ package mint_test import ( "testing" + appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/testutil/helper" "github.com/babylonlabs-io/babylon/x/mint/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -16,6 +17,6 @@ func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { acc := app.AccountKeeper.GetAccount(ctx, authtypes.NewModuleAddress(types.ModuleName)) require.NotNil(t, acc) - feeColl := app.AccountKeeper.GetAccount(ctx, authtypes.NewModuleAddress(authtypes.FeeCollectorName)) + feeColl := app.AccountKeeper.GetAccount(ctx, appparams.AccFeeCollector) require.Equal(t, "bbn17xpfvakm2amg962yls6f84z3kell8c5l88j35y", feeColl.GetAddress().String()) } From 1d53ecb45e2894e3d5b241bb35f0be7c7eb477d7 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 15 Dec 2024 21:30:09 -0300 Subject: [PATCH 072/132] chore: add #348 to changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6d6937c7..59a9833c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [#316](https://github.com/babylonlabs-io/babylon/pull/316) Add testnet upgrade data - [#326](https://github.com/babylonlabs-io/babylon/pull/326) docs: btcstaking: Update btcstaking module docs to include EOI +- [#348](https://github.com/babylonlabs-io/babylon/pull/348) refactory `PrivateSigner` +and module account vars in appparams ### Bug fixes From 96f5a1fd34d6b09697bbb7fa7b4f5090fc864d2f Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Sun, 15 Dec 2024 21:47:12 -0300 Subject: [PATCH 073/132] chore: add comment back --- x/incentive/keeper/btc_staking_gauge.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/incentive/keeper/btc_staking_gauge.go b/x/incentive/keeper/btc_staking_gauge.go index 10f316026..f1daebaad 100644 --- a/x/incentive/keeper/btc_staking_gauge.go +++ b/x/incentive/keeper/btc_staking_gauge.go @@ -20,6 +20,7 @@ func (k Keeper) RewardBTCStaking(ctx context.Context, height uint64, dc *ftypes. panic("failed to get a reward gauge at previous height") } + // reward each of the finality provider and its BTC delegations in proportion for i, fp := range dc.FinalityProviders { // only reward the first NumActiveFps finality providers // note that ApplyActiveFinalityProviders is called before saving `dc` From 3f75d16694ea5806adeabd6efa06fa7217cc1d33 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 16 Dec 2024 09:02:11 -0300 Subject: [PATCH 074/132] chore: remove commented line --- testutil/incentives-helper/keeper.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/testutil/incentives-helper/keeper.go b/testutil/incentives-helper/keeper.go index 1608cf12d..dbcc9f2fb 100644 --- a/testutil/incentives-helper/keeper.go +++ b/testutil/incentives-helper/keeper.go @@ -24,13 +24,10 @@ func NewHelper( btclcKeeper *types.MockBTCLightClientKeeper, btccKeeper *types.MockBtcCheckpointKeeper, ) *Helper { - // ctrl := gomock.NewController(t) - db := dbm.NewMemDB() stateStore := store.NewCommitMultiStore(db, log.NewTestLogger(t), storemetrics.NewNoOpMetrics()) ictvK, _ := keepertest.IncentiveKeeperWithStore(t, db, stateStore, nil, nil, nil) - btcstkH := btcstkhelper.NewHelperWithStoreAndIncentive(t, db, stateStore, btclcKeeper, btccKeeper, ictvK) return &Helper{ From 9ee3ba50f54f8f09257aef4a8e925da010c814a4 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 16 Dec 2024 12:38:38 -0300 Subject: [PATCH 075/132] fix: process unbonded BTC delegations events only once --- x/finality/keeper/power_dist_change.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index babaf24fe..648c11e6b 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -176,7 +176,7 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // of BTC delegations that newly become active under this provider activeBTCDels := map[string][]*types.BTCDelegation{} // a map where key is unbonded BTC delegation's staking tx hash - unbondedBTCDels := map[string]struct{}{} + unbondedBTCDels := map[string]*btcDelWithStkTxHash{} // a map where key is slashed finality providers' BTC PK slashedFPs := map[string]struct{}{} // a map where key is jailed finality providers' BTC PK @@ -222,8 +222,7 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( } // add the unbonded BTC delegation to the map - unbondedBTCDels[delStkTxHash] = struct{}{} - newUnbondedBtcDels = append(newUnbondedBtcDels, btcDelWithStkTxHash) + unbondedBTCDels[delStkTxHash] = btcDelWithStkTxHash } case *types.EventPowerDistUpdate_SlashedFp: // record slashed fps @@ -286,8 +285,14 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( for j := range dc.FinalityProviders[i].BtcDels { btcDel := *dc.FinalityProviders[i].BtcDels[j] - _, isUnbondedBtcDelegation := unbondedBTCDels[btcDel.StakingTxHash] + btcDelUnbondedWithStkTxHash, isUnbondedBtcDelegation := unbondedBTCDels[btcDel.StakingTxHash] if isUnbondedBtcDelegation { + // the list of new unbonded BTC delegations needs to be added + // at this point, due to possible duplication of Unbonding BTC events + // Early unbond and expiration. When the unbonded BTC delegation is + // processed the seccond time, the FP already doesn't have this delegation + // inside their FinalityProviderDistInfo.BtcDels list. + newUnbondedBtcDels = append(newUnbondedBtcDels, btcDelUnbondedWithStkTxHash) continue } // if it is not unbonded add to the del dist info From 067232ee4403caa5aaf8bd4fe5c93a7ca50e8af9 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 16 Dec 2024 17:06:51 -0300 Subject: [PATCH 076/132] chore: add integration test for early unbond --- app/app.go | 8 +- app/app_test.go | 2 +- testutil/btcstaking-helper/keeper.go | 40 ++++--- testutil/incentives-helper/keeper.go | 26 +++-- testutil/keeper/account.go | 45 ++++++++ testutil/keeper/bank.go | 3 +- x/btcstaking/types/btc_delegation.go | 5 + x/btcstaking/types/btcstaking.go | 5 + x/finality/keeper/msg_server_test.go | 150 +++++++++++++++++++++++++++ 9 files changed, 246 insertions(+), 38 deletions(-) create mode 100644 testutil/keeper/account.go diff --git a/app/app.go b/app/app.go index ca1173dc5..9aae06a99 100644 --- a/app/app.go +++ b/app/app.go @@ -142,7 +142,7 @@ var ( // DefaultNodeHome default home directories for the application daemon DefaultNodeHome string // fee collector account, module accounts and their permissions - maccPerms = map[string][]string{ + MaccPerms = map[string][]string{ authtypes.FeeCollectorName: nil, // fee collector account distrtypes.ModuleName: nil, minttypes.ModuleName: {authtypes.Minter}, @@ -254,7 +254,7 @@ func NewBabylonApp( &btcConfig, encCfg, bApp, - maccPerms, + MaccPerms, homePath, invCheckPeriod, skipUpgradeHeights, @@ -639,7 +639,7 @@ func (app *BabylonApp) LoadHeight(height int64) error { // ModuleAccountAddrs returns all the app's module account addresses. func (app *BabylonApp) ModuleAccountAddrs() map[string]bool { modAccAddrs := make(map[string]bool) - for acc := range maccPerms { + for acc := range MaccPerms { modAccAddrs[authtypes.NewModuleAddress(acc).String()] = true } @@ -787,7 +787,7 @@ func (app *BabylonApp) setupUpgradeHandlers() { // GetMaccPerms returns a copy of the module account permissions func GetMaccPerms() map[string][]string { dupMaccPerms := make(map[string][]string) - for k, v := range maccPerms { + for k, v := range MaccPerms { dupMaccPerms[k] = v } return dupMaccPerms diff --git a/app/app_test.go b/app/app_test.go index 09b305eab..fa497865f 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -67,7 +67,7 @@ func TestBabylonBlockedAddrs(t *testing.T) { func TestGetMaccPerms(t *testing.T) { dup := GetMaccPerms() - require.Equal(t, maccPerms, dup, "duplicated module account permissions differed from actual module account permissions") + require.Equal(t, MaccPerms, dup, "duplicated module account permissions differed from actual module account permissions") } func TestUpgradeStateOnGenesis(t *testing.T) { diff --git a/testutil/btcstaking-helper/keeper.go b/testutil/btcstaking-helper/keeper.go index 1134a5d7b..2abac8fcd 100644 --- a/testutil/btcstaking-helper/keeper.go +++ b/testutil/btcstaking-helper/keeper.go @@ -45,10 +45,10 @@ type Helper struct { FinalityKeeper *fkeeper.Keeper FMsgServer ftypes.MsgServer - BTCLightClientKeeper *types.MockBTCLightClientKeeper - BTCCheckpointKeeper *types.MockBtcCheckpointKeeper - CheckpointingKeeper *ftypes.MockCheckpointingKeeper - Net *chaincfg.Params + BTCLightClientKeeper *types.MockBTCLightClientKeeper + CheckpointingKeeperForBtcStaking *types.MockBtcCheckpointKeeper + CheckpointingKeeperForFinality *ftypes.MockCheckpointingKeeper + Net *chaincfg.Params } type UnbondingTxInfo struct { @@ -70,13 +70,13 @@ func NewHelper( iKeeper.EXPECT().BtcDelegationUnbonded(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() iKeeper.EXPECT().FpSlashed(gomock.Any(), gomock.Any()).AnyTimes() - ckptKeeper := ftypes.NewMockCheckpointingKeeper(ctrl) - ckptKeeper.EXPECT().GetLastFinalizedEpoch(gomock.Any()).Return(timestampedEpoch).AnyTimes() - db := dbm.NewMemDB() stateStore := store.NewCommitMultiStore(db, log.NewTestLogger(t), storemetrics.NewNoOpMetrics()) - return NewHelperWithStoreAndIncentive(t, db, stateStore, btclcKeeper, btccKeeper, iKeeper) + ckptKeeper := ftypes.NewMockCheckpointingKeeper(ctrl) + ckptKeeper.EXPECT().GetLastFinalizedEpoch(gomock.Any()).Return(timestampedEpoch).AnyTimes() + + return NewHelperWithStoreAndIncentive(t, db, stateStore, btclcKeeper, btccKeeper, ckptKeeper, iKeeper) } func NewHelperWithStoreAndIncentive( @@ -84,18 +84,14 @@ func NewHelperWithStoreAndIncentive( db dbm.DB, stateStore store.CommitMultiStore, btclcKeeper *types.MockBTCLightClientKeeper, - btccKeeper *types.MockBtcCheckpointKeeper, + btccKForBtcStaking *types.MockBtcCheckpointKeeper, + btccKForFinality *ftypes.MockCheckpointingKeeper, ictvKeeper ftypes.IncentiveKeeper, ) *Helper { - ctrl := gomock.NewController(t) - - ckptKeeper := ftypes.NewMockCheckpointingKeeper(ctrl) - ckptKeeper.EXPECT().GetLastFinalizedEpoch(gomock.Any()).Return(timestampedEpoch).AnyTimes() - - k, _ := keepertest.BTCStakingKeeperWithStore(t, db, stateStore, btclcKeeper, btccKeeper, ictvKeeper) + k, _ := keepertest.BTCStakingKeeperWithStore(t, db, stateStore, btclcKeeper, btccKForBtcStaking, ictvKeeper) msgSrvr := keeper.NewMsgServerImpl(*k) - fk, ctx := keepertest.FinalityKeeperWithStore(t, db, stateStore, k, ictvKeeper, ckptKeeper) + fk, ctx := keepertest.FinalityKeeperWithStore(t, db, stateStore, k, ictvKeeper, btccKForFinality) fMsgSrvr := fkeeper.NewMsgServerImpl(*fk) // set all parameters @@ -116,10 +112,10 @@ func NewHelperWithStoreAndIncentive( FinalityKeeper: fk, FMsgServer: fMsgSrvr, - BTCLightClientKeeper: btclcKeeper, - BTCCheckpointKeeper: btccKeeper, - CheckpointingKeeper: ckptKeeper, - Net: &chaincfg.SimNetParams, + BTCLightClientKeeper: btclcKeeper, + CheckpointingKeeperForBtcStaking: btccKForBtcStaking, + CheckpointingKeeperForFinality: btccKForFinality, + Net: &chaincfg.SimNetParams, } } @@ -164,7 +160,7 @@ func (h *Helper) GenAndApplyCustomParams( params := btcctypes.DefaultParams() params.CheckpointFinalizationTimeout = finalizationTimeout - h.BTCCheckpointKeeper.EXPECT().GetParams(gomock.Any()).Return(params).AnyTimes() + h.CheckpointingKeeperForBtcStaking.EXPECT().GetParams(gomock.Any()).Return(params).AnyTimes() // randomise covenant committee covenantSKs, covenantPKs, err := datagen.GenRandomBTCKeyPairs(r, 5) @@ -595,7 +591,7 @@ func (h *Helper) CommitPubRandList( epoch = timestampedEpoch + 1 } - h.CheckpointingKeeper.EXPECT().GetEpoch(gomock.Any()).Return(&epochingtypes.Epoch{EpochNumber: epoch}).Times(1) + h.CheckpointingKeeperForFinality.EXPECT().GetEpoch(gomock.Any()).Return(&epochingtypes.Epoch{EpochNumber: epoch}).Times(1) _, err = h.FMsgServer.CommitPubRandList(h.Ctx, msg) h.NoError(err) diff --git a/testutil/incentives-helper/keeper.go b/testutil/incentives-helper/keeper.go index dbcc9f2fb..5ccd7bacf 100644 --- a/testutil/incentives-helper/keeper.go +++ b/testutil/incentives-helper/keeper.go @@ -7,31 +7,39 @@ import ( "cosmossdk.io/store" storemetrics "cosmossdk.io/store/metrics" dbm "github.com/cosmos/cosmos-db" + bankk "github.com/cosmos/cosmos-sdk/x/bank/keeper" btcstkhelper "github.com/babylonlabs-io/babylon/testutil/btcstaking-helper" keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" - "github.com/babylonlabs-io/babylon/x/btcstaking/types" + bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" + ftypes "github.com/babylonlabs-io/babylon/x/finality/types" "github.com/babylonlabs-io/babylon/x/incentive/keeper" ) -type Helper struct { +type IncentiveHelper struct { *btcstkhelper.Helper + BankKeeper bankk.Keeper IncentivesKeeper *keeper.Keeper } -func NewHelper( +func NewIncentiveHelper( t testing.TB, - btclcKeeper *types.MockBTCLightClientKeeper, - btccKeeper *types.MockBtcCheckpointKeeper, -) *Helper { + btclcKeeper *bstypes.MockBTCLightClientKeeper, + btccKForBtcStaking *bstypes.MockBtcCheckpointKeeper, + btccKForFinality *ftypes.MockCheckpointingKeeper, +) *IncentiveHelper { db := dbm.NewMemDB() stateStore := store.NewCommitMultiStore(db, log.NewTestLogger(t), storemetrics.NewNoOpMetrics()) - ictvK, _ := keepertest.IncentiveKeeperWithStore(t, db, stateStore, nil, nil, nil) - btcstkH := btcstkhelper.NewHelperWithStoreAndIncentive(t, db, stateStore, btclcKeeper, btccKeeper, ictvK) + accK := keepertest.AccountKeeper(t, db, stateStore) + bankK := keepertest.BankKeeper(t, db, stateStore, accK) - return &Helper{ + ictvK, _ := keepertest.IncentiveKeeperWithStore(t, db, stateStore, bankK, accK, nil) + btcstkH := btcstkhelper.NewHelperWithStoreAndIncentive(t, db, stateStore, btclcKeeper, btccKForBtcStaking, btccKForFinality, ictvK) + + return &IncentiveHelper{ Helper: btcstkH, + BankKeeper: bankK, IncentivesKeeper: ictvK, } } diff --git a/testutil/keeper/account.go b/testutil/keeper/account.go new file mode 100644 index 000000000..58605c432 --- /dev/null +++ b/testutil/keeper/account.go @@ -0,0 +1,45 @@ +package keeper + +import ( + "testing" + + "cosmossdk.io/store" + storetypes "cosmossdk.io/store/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec" + accountk "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/stretchr/testify/require" + + "github.com/babylonlabs-io/babylon/app" + appparams "github.com/babylonlabs-io/babylon/app/params" +) + +func AccountKeeper( + t testing.TB, + db dbm.DB, + stateStore store.CommitMultiStore, +) accountk.AccountKeeper { + storeKey := storetypes.NewKVStoreKey(authtypes.StoreKey) + + stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) + require.NoError(t, stateStore.LoadLatestVersion()) + + registry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + + k := accountk.NewAccountKeeper( + cdc, + runtime.NewKVStoreService(storeKey), + authtypes.ProtoBaseAccount, + app.MaccPerms, + authcodec.NewBech32Codec(appparams.Bech32PrefixAccAddr), + appparams.Bech32PrefixAccAddr, + appparams.AccGov.String(), + ) + + return k +} diff --git a/testutil/keeper/bank.go b/testutil/keeper/bank.go index b2dc0662b..11f9749c3 100644 --- a/testutil/keeper/bank.go +++ b/testutil/keeper/bank.go @@ -15,7 +15,6 @@ import ( "github.com/stretchr/testify/require" appparams "github.com/babylonlabs-io/babylon/app/params" - "github.com/babylonlabs-io/babylon/x/incentive/types" ) func BankKeeper( @@ -23,7 +22,7 @@ func BankKeeper( db dbm.DB, stateStore store.CommitMultiStore, accountKeeper banktypes.AccountKeeper, -) types.BankKeeper { +) bankk.Keeper { storeKey := storetypes.NewKVStoreKey(banktypes.StoreKey) stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) diff --git a/x/btcstaking/types/btc_delegation.go b/x/btcstaking/types/btc_delegation.go index aba0e8c87..9faf519a1 100644 --- a/x/btcstaking/types/btc_delegation.go +++ b/x/btcstaking/types/btc_delegation.go @@ -59,6 +59,11 @@ func (d *BTCDelegation) GetFpIdx(fpBTCPK *bbn.BIP340PubKey) int { return -1 } +// Address returns the bech32 fp address +func (d *BTCDelegation) Address() sdk.AccAddress { + return sdk.MustAccAddressFromBech32(d.StakerAddr) +} + func (d *BTCDelegation) GetCovSlashingAdaptorSig( covBTCPK *bbn.BIP340PubKey, valIdx int, diff --git a/x/btcstaking/types/btcstaking.go b/x/btcstaking/types/btcstaking.go index b7cdfa49d..8675de6e5 100644 --- a/x/btcstaking/types/btcstaking.go +++ b/x/btcstaking/types/btcstaking.go @@ -17,6 +17,11 @@ func (fp *FinalityProvider) IsJailed() bool { return fp.Jailed } +// Address returns the bech32 fp address +func (fp *FinalityProvider) Address() sdk.AccAddress { + return sdk.MustAccAddressFromBech32(fp.Addr) +} + func (fp *FinalityProvider) ValidateBasic() error { // ensure fields are non-empty and well-formatted if _, err := sdk.AccAddressFromBech32(fp.Addr); err != nil { diff --git a/x/finality/keeper/msg_server_test.go b/x/finality/keeper/msg_server_test.go index e5e6d96d1..205c36260 100644 --- a/x/finality/keeper/msg_server_test.go +++ b/x/finality/keeper/msg_server_test.go @@ -12,8 +12,10 @@ import ( "github.com/stretchr/testify/require" "github.com/babylonlabs-io/babylon/testutil/datagen" + testutil "github.com/babylonlabs-io/babylon/testutil/incentives-helper" keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" bbn "github.com/babylonlabs-io/babylon/types" + btclctypes "github.com/babylonlabs-io/babylon/x/btclightclient/types" bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" epochingtypes "github.com/babylonlabs-io/babylon/x/epoching/types" "github.com/babylonlabs-io/babylon/x/finality/keeper" @@ -492,3 +494,151 @@ func TestVerifyActivationHeight(t *testing.T) { // fKeeper, ctx := keepertest.FinalityKeeper(t, nil, nil, nil) // } + +func TestBtcDelegationRewardsEarlyUnbondingAndExpire(t *testing.T) { + r := rand.New(rand.NewSource(time.Now().Unix())) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + btclcKeeper := bstypes.NewMockBTCLightClientKeeper(ctrl) + btccKForBtcStaking := bstypes.NewMockBtcCheckpointKeeper(ctrl) + + btccKForFinality := types.NewMockCheckpointingKeeper(ctrl) + epochNumber := uint64(10) + + btccKForFinality.EXPECT().GetEpoch(gomock.Any()).Return(&epochingtypes.Epoch{EpochNumber: epochNumber}).AnyTimes() + btccKForFinality.EXPECT().GetLastFinalizedEpoch(gomock.Any()).Return(epochNumber).AnyTimes() + h := testutil.NewIncentiveHelper(t, btclcKeeper, btccKForBtcStaking, btccKForFinality) + // set all parameters + covenantSKs, _ := h.GenAndApplyParams(r) + covenantQuorum := h.BTCStakingKeeper.GetParams(h.Ctx).CovenantQuorum + + // commit some public randomness + finalityParams := h.FinalityKeeper.GetParams(h.Ctx) + finalityParams.FinalityActivationHeight = 0 + err := h.FinalityKeeper.SetParams(h.Ctx, finalityParams) + h.NoError(err) + + // generate and insert new finality provider + usePreApproval := false + stakingValue := int64(2 * 10e8) + + fpSK, fpPK, fp := h.CreateFinalityProvider(r) + delSK, _, err := datagen.GenRandomBTCKeyPair(r) + h.NoError(err) + + startHeight := uint64(0) + numPubRand := uint64(200) + randListInfo, msgCommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(r, fpSK, startHeight, numPubRand) + require.NoError(t, err) + + _, err = h.FMsgServer.CommitPubRandList(h.Ctx, msgCommitPubRandList) + require.NoError(t, err) + + // generate a vote + blockHeight := startHeight + uint64(1) + blockAppHash := datagen.GenRandomByteArray(r, 32) + signer := datagen.GenRandomAccount().Address + msg, err := datagen.NewMsgAddFinalitySig( + signer, + fpSK, + startHeight, + blockHeight, + randListInfo, + blockAppHash, + ) + require.NoError(t, err) + + // add vote and it should work + _, err = h.FMsgServer.AddFinalitySig(h.Ctx, msg) + require.Error(t, err) + + changeAddress, err := datagen.GenRandomBTCAddress(r, h.Net) + require.NoError(t, err) + + stakingTxHash, msgCreateBTCDel, _, _, _, unbondingInfo, err := h.CreateDelegationWithBtcBlockHeight( + r, + delSK, + fpPK, + changeAddress.EncodeAddress(), + stakingValue, + 1000, + 0, + 0, + usePreApproval, + false, + 10, + 30, + ) + h.NoError(err) + + // ensure consistency between the msg and the BTC delegation in DB + actualDel, err := h.BTCStakingKeeper.GetBTCDelegation(h.Ctx, stakingTxHash) + h.NoError(err) + + require.Equal(h.T(), msgCreateBTCDel.StakerAddr, actualDel.StakerAddr) + require.Equal(h.T(), msgCreateBTCDel.Pop, actualDel.Pop) + require.Equal(h.T(), msgCreateBTCDel.StakingTx, actualDel.StakingTx) + require.Equal(h.T(), msgCreateBTCDel.SlashingTx, actualDel.SlashingTx) + + // add covenant signatures to activate delegation + msgs := h.GenerateCovenantSignaturesMessages(r, covenantSKs, msgCreateBTCDel, actualDel) + + tipHeight := uint32(30) + h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: tipHeight}).AnyTimes() + + for _, msg := range msgs { + _, err = h.MsgServer.AddCovenantSigs(h.Ctx, msg) + h.NoError(err) + } + + actualDel, err = h.BTCStakingKeeper.GetBTCDelegation(h.Ctx, stakingTxHash) + h.NoError(err) + + status := actualDel.GetStatus(tipHeight, covenantQuorum) + require.Equal(t, status, bstypes.BTCDelegationStatus_ACTIVE) + + // process the events as active btc delegation + h.BTCStakingKeeper.IndexBTCHeight(h.Ctx) + h.FinalityKeeper.UpdatePowerDist(h.Ctx) + + btcDel, err := h.IncentivesKeeper.GetBTCDelegationRewardsTracker(h.Ctx, fp.Address(), actualDel.Address()) + h.NoError(err) + require.Equal(t, btcDel.TotalActiveSat.Uint64(), uint64(stakingValue)) + + // Unbond with early unbonding + tipHeight = uint32(45) + h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: tipHeight}).AnyTimes() + + msgUndelegate := &bstypes.MsgBTCUndelegate{ + Signer: datagen.GenRandomAccount().Address, + StakingTxHash: stakingTxHash, + StakeSpendingTx: actualDel.BtcUndelegation.UnbondingTx, + StakeSpendingTxInclusionProof: unbondingInfo.UnbondingTxInclusionProof, + } + + // early unbond + _, err = h.MsgServer.BTCUndelegate(h.Ctx, msgUndelegate) + h.NoError(err) + + // ensure the BTC delegation is unbonded + actualDel, err = h.BTCStakingKeeper.GetBTCDelegation(h.Ctx, stakingTxHash) + h.NoError(err) + status = actualDel.GetStatus(tipHeight, covenantQuorum) + require.Equal(t, bstypes.BTCDelegationStatus_UNBONDED, status) + + // increases one bbn block + headerInfo := h.Ctx.HeaderInfo() + headerInfo.Height += 1 + h.Ctx = h.Ctx.WithHeaderInfo(headerInfo) + h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: tipHeight}).AnyTimes() + + // process the events as early unbonding btc delegation + h.BTCStakingKeeper.IndexBTCHeight(h.Ctx) + h.FinalityKeeper.UpdatePowerDist(h.Ctx) + + btcDel, err = h.IncentivesKeeper.GetBTCDelegationRewardsTracker(h.Ctx, fp.Address(), actualDel.Address()) + h.NoError(err) + require.True(t, btcDel.TotalActiveSat.IsZero()) + +} From a2a5c8e376fac39610247bb3892b3d062f1887dc Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 16 Dec 2024 17:33:01 -0300 Subject: [PATCH 077/132] chore: reach expire BTC staking tx --- x/finality/keeper/msg_server_test.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/x/finality/keeper/msg_server_test.go b/x/finality/keeper/msg_server_test.go index 205c36260..5ba362e34 100644 --- a/x/finality/keeper/msg_server_test.go +++ b/x/finality/keeper/msg_server_test.go @@ -522,6 +522,7 @@ func TestBtcDelegationRewardsEarlyUnbondingAndExpire(t *testing.T) { // generate and insert new finality provider usePreApproval := false stakingValue := int64(2 * 10e8) + stakingTime := uint16(1000) fpSK, fpPK, fp := h.CreateFinalityProvider(r) delSK, _, err := datagen.GenRandomBTCKeyPair(r) @@ -562,7 +563,7 @@ func TestBtcDelegationRewardsEarlyUnbondingAndExpire(t *testing.T) { fpPK, changeAddress.EncodeAddress(), stakingValue, - 1000, + stakingTime, 0, 0, usePreApproval, @@ -627,7 +628,8 @@ func TestBtcDelegationRewardsEarlyUnbondingAndExpire(t *testing.T) { status = actualDel.GetStatus(tipHeight, covenantQuorum) require.Equal(t, bstypes.BTCDelegationStatus_UNBONDED, status) - // increases one bbn block + // increases one bbn block to get the voting power distribution cache + // from the previous block headerInfo := h.Ctx.HeaderInfo() headerInfo.Height += 1 h.Ctx = h.Ctx.WithHeaderInfo(headerInfo) @@ -641,4 +643,21 @@ func TestBtcDelegationRewardsEarlyUnbondingAndExpire(t *testing.T) { h.NoError(err) require.True(t, btcDel.TotalActiveSat.IsZero()) + // reaches the btc block of expire + // an unbond event will be processed + // but should not reduce the TotalActiveSat again + headerInfo = h.Ctx.HeaderInfo() + headerInfo.Height += 1 + h.Ctx = h.Ctx.WithHeaderInfo(headerInfo) + + tipHeight += uint32(stakingTime) + h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: tipHeight}).AnyTimes() + + // process the events as expired btc delegation + h.BTCStakingKeeper.IndexBTCHeight(h.Ctx) + h.FinalityKeeper.UpdatePowerDist(h.Ctx) + + btcDel, err = h.IncentivesKeeper.GetBTCDelegationRewardsTracker(h.Ctx, fp.Address(), actualDel.Address()) + h.NoError(err) + require.True(t, btcDel.TotalActiveSat.IsZero()) } From 139781b02a2c5f5f275742caa7c471aca60d9170 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 16 Dec 2024 18:09:48 -0300 Subject: [PATCH 078/132] chore: add test to check early unbonding + expire event --- testutil/btcstaking-helper/keeper.go | 4 + testutil/incentives-helper/keeper.go | 167 +++++++++++++++++++++++++++ x/finality/keeper/msg_server_test.go | 139 ++++------------------ 3 files changed, 191 insertions(+), 119 deletions(-) diff --git a/testutil/btcstaking-helper/keeper.go b/testutil/btcstaking-helper/keeper.go index 2abac8fcd..ebb1a5bef 100644 --- a/testutil/btcstaking-helper/keeper.go +++ b/testutil/btcstaking-helper/keeper.go @@ -127,6 +127,10 @@ func (h *Helper) NoError(err error) { require.NoError(h.t, err) } +func (h *Helper) Equal(expected, actual interface{}) { + require.Equal(h.t, expected, actual) +} + func (h *Helper) Error(err error, msgAndArgs ...any) { require.Error(h.t, err, msgAndArgs...) } diff --git a/testutil/incentives-helper/keeper.go b/testutil/incentives-helper/keeper.go index 5ccd7bacf..5e97356df 100644 --- a/testutil/incentives-helper/keeper.go +++ b/testutil/incentives-helper/keeper.go @@ -1,16 +1,25 @@ package testutil import ( + "math/rand" "testing" "cosmossdk.io/log" "cosmossdk.io/store" storemetrics "cosmossdk.io/store/metrics" + "github.com/btcsuite/btcd/btcec/v2" dbm "github.com/cosmos/cosmos-db" + sdk "github.com/cosmos/cosmos-sdk/types" bankk "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "github.com/golang/mock/gomock" btcstkhelper "github.com/babylonlabs-io/babylon/testutil/btcstaking-helper" + testutil "github.com/babylonlabs-io/babylon/testutil/btcstaking-helper" + "github.com/babylonlabs-io/babylon/testutil/datagen" keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" + btclctypes "github.com/babylonlabs-io/babylon/x/btclightclient/types" + "github.com/babylonlabs-io/babylon/x/btcstaking/types" bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" ftypes "github.com/babylonlabs-io/babylon/x/finality/types" "github.com/babylonlabs-io/babylon/x/incentive/keeper" @@ -43,3 +52,161 @@ func NewIncentiveHelper( IncentivesKeeper: ictvK, } } + +func (h *IncentiveHelper) SetFinalityActivationHeight(newActivationHeight uint64) { + finalityParams := h.FinalityKeeper.GetParams(h.Ctx) + finalityParams.FinalityActivationHeight = newActivationHeight + err := h.FinalityKeeper.SetParams(h.Ctx, finalityParams) + h.NoError(err) +} + +func (h *IncentiveHelper) CreateBtcDelegation( + r *rand.Rand, + fpPK *secp256k1.PublicKey, + stakingValue int64, + stakingTime uint16, +) ( + stakingTxHash string, msgCreateBTCDel *bstypes.MsgCreateBTCDelegation, actualDel *bstypes.BTCDelegation, unbondingInfo *btcstkhelper.UnbondingTxInfo, +) { + changeAddress, err := datagen.GenRandomBTCAddress(r, h.Net) + h.NoError(err) + + delSK, _, err := datagen.GenRandomBTCKeyPair(r) + h.NoError(err) + + stakingTxHash, msgCreateBTCDel, _, _, _, unbondingInfo, err = h.CreateDelegationWithBtcBlockHeight( + r, + delSK, + fpPK, + changeAddress.EncodeAddress(), + stakingValue, + stakingTime, + 0, + 0, + false, + false, + 10, + 30, + ) + h.NoError(err) + + // ensure consistency between the msg and the BTC delegation in DB + actualDel, err = h.BTCStakingKeeper.GetBTCDelegation(h.Ctx, stakingTxHash) + h.NoError(err) + + h.Equal(msgCreateBTCDel.StakerAddr, actualDel.StakerAddr) + h.Equal(msgCreateBTCDel.Pop, actualDel.Pop) + h.Equal(msgCreateBTCDel.StakingTx, actualDel.StakingTx) + h.Equal(msgCreateBTCDel.SlashingTx, actualDel.SlashingTx) + + return stakingTxHash, msgCreateBTCDel, actualDel, unbondingInfo +} + +func (h *IncentiveHelper) CreateActiveBtcDelegation( + r *rand.Rand, + covenantSKs []*secp256k1.PrivateKey, + fpPK *secp256k1.PublicKey, + stakingValue int64, + stakingTime uint16, + btcLightClientTipHeight uint32, +) ( + stakingTxHash string, actualDel *bstypes.BTCDelegation, unbondingInfo *btcstkhelper.UnbondingTxInfo, +) { + stakingTxHash, msgCreateBTCDel, actualDel, unbondingInfo := h.CreateBtcDelegation(r, fpPK, stakingValue, stakingTime) + + h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: btcLightClientTipHeight}).AnyTimes() + + h.GenerateAndSendCovenantSignatures(r, covenantSKs, msgCreateBTCDel, actualDel) + h.EqualBtcDelegationStatus(stakingTxHash, btcLightClientTipHeight, bstypes.BTCDelegationStatus_ACTIVE) + return stakingTxHash, actualDel, unbondingInfo +} + +func (h *IncentiveHelper) EqualBtcDelRwdTrackerActiveSat(fp, del sdk.AccAddress, expectedSatAmount uint64) { + btcDel, err := h.IncentivesKeeper.GetBTCDelegationRewardsTracker(h.Ctx, fp, del) + h.NoError(err) + h.Equal(btcDel.TotalActiveSat.Uint64(), expectedSatAmount) +} + +func (h *IncentiveHelper) BtcUndelegate( + stakingTxHash string, + del *bstypes.BTCDelegation, + unbondingInfo *testutil.UnbondingTxInfo, + btcLightClientTipHeight uint32, +) { + msgUndelegate := &bstypes.MsgBTCUndelegate{ + Signer: datagen.GenRandomAccount().Address, + StakingTxHash: stakingTxHash, + StakeSpendingTx: del.BtcUndelegation.UnbondingTx, + StakeSpendingTxInclusionProof: unbondingInfo.UnbondingTxInclusionProof, + } + + // early unbond + _, err := h.MsgServer.BTCUndelegate(h.Ctx, msgUndelegate) + h.NoError(err) + + h.EqualBtcDelegationStatus(stakingTxHash, btcLightClientTipHeight, bstypes.BTCDelegationStatus_UNBONDED) +} + +func (h *IncentiveHelper) GenerateAndSendCovenantSignatures( + r *rand.Rand, + covenantSKs []*btcec.PrivateKey, + msgCreateBTCDel *types.MsgCreateBTCDelegation, + del *types.BTCDelegation, +) { + covMsgs := h.GenerateCovenantSignaturesMessages(r, covenantSKs, msgCreateBTCDel, del) + for _, msg := range covMsgs { + _, err := h.MsgServer.AddCovenantSigs(h.Ctx, msg) + h.NoError(err) + } +} + +func (h *IncentiveHelper) EqualBtcDelegationStatus( + stakingTxHashStr string, + tipHeight uint32, + expectedStatus bstypes.BTCDelegationStatus, +) { + actualDel, err := h.BTCStakingKeeper.GetBTCDelegation(h.Ctx, stakingTxHashStr) + h.NoError(err) + + covenantQuorum := h.BTCStakingKeeper.GetParams(h.Ctx).CovenantQuorum + + status := actualDel.GetStatus(tipHeight, covenantQuorum) + h.Equal(expectedStatus, status) +} + +func (h *IncentiveHelper) CtxAddBlkHeight(blocksToAdd int64) { + headerInfo := h.Ctx.HeaderInfo() + headerInfo.Height += blocksToAdd + h.Ctx = h.Ctx.WithHeaderInfo(headerInfo) +} + +func (h *IncentiveHelper) FpAddPubRand(r *rand.Rand, sk *btcec.PrivateKey, startHeight uint64) *datagen.RandListInfo { + numPubRand := uint64(200) + randListInfo, msgCommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(r, sk, startHeight, numPubRand) + h.NoError(err) + + _, err = h.FMsgServer.CommitPubRandList(h.Ctx, msgCommitPubRandList) + h.NoError(err) + return randListInfo +} + +func (h *IncentiveHelper) FpAddPubRandAndFinalitySig(r *rand.Rand, sk *btcec.PrivateKey, startHeight uint64) { + randListInfo := h.FpAddPubRand(r, sk, startHeight) + + // generate a vote + blockHeight := startHeight + uint64(1) + blockAppHash := datagen.GenRandomByteArray(r, 32) + signer := datagen.GenRandomAccount().Address + msg, err := datagen.NewMsgAddFinalitySig( + signer, + sk, + startHeight, + blockHeight, + randListInfo, + blockAppHash, + ) + h.NoError(err) + + _, err = h.FMsgServer.AddFinalitySig(h.Ctx, msg) + h.NoError(err) +} diff --git a/x/finality/keeper/msg_server_test.go b/x/finality/keeper/msg_server_test.go index 5ba362e34..812315808 100644 --- a/x/finality/keeper/msg_server_test.go +++ b/x/finality/keeper/msg_server_test.go @@ -503,161 +503,62 @@ func TestBtcDelegationRewardsEarlyUnbondingAndExpire(t *testing.T) { btclcKeeper := bstypes.NewMockBTCLightClientKeeper(ctrl) btccKForBtcStaking := bstypes.NewMockBtcCheckpointKeeper(ctrl) - btccKForFinality := types.NewMockCheckpointingKeeper(ctrl) epochNumber := uint64(10) - + btccKForFinality := types.NewMockCheckpointingKeeper(ctrl) btccKForFinality.EXPECT().GetEpoch(gomock.Any()).Return(&epochingtypes.Epoch{EpochNumber: epochNumber}).AnyTimes() btccKForFinality.EXPECT().GetLastFinalizedEpoch(gomock.Any()).Return(epochNumber).AnyTimes() + h := testutil.NewIncentiveHelper(t, btclcKeeper, btccKForBtcStaking, btccKForFinality) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) - covenantQuorum := h.BTCStakingKeeper.GetParams(h.Ctx).CovenantQuorum - - // commit some public randomness - finalityParams := h.FinalityKeeper.GetParams(h.Ctx) - finalityParams.FinalityActivationHeight = 0 - err := h.FinalityKeeper.SetParams(h.Ctx, finalityParams) - h.NoError(err) + h.SetFinalityActivationHeight(0) // generate and insert new finality provider - usePreApproval := false stakingValue := int64(2 * 10e8) stakingTime := uint16(1000) fpSK, fpPK, fp := h.CreateFinalityProvider(r) - delSK, _, err := datagen.GenRandomBTCKeyPair(r) - h.NoError(err) - + // commit some public randomness startHeight := uint64(0) - numPubRand := uint64(200) - randListInfo, msgCommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(r, fpSK, startHeight, numPubRand) - require.NoError(t, err) - - _, err = h.FMsgServer.CommitPubRandList(h.Ctx, msgCommitPubRandList) - require.NoError(t, err) - - // generate a vote - blockHeight := startHeight + uint64(1) - blockAppHash := datagen.GenRandomByteArray(r, 32) - signer := datagen.GenRandomAccount().Address - msg, err := datagen.NewMsgAddFinalitySig( - signer, - fpSK, - startHeight, - blockHeight, - randListInfo, - blockAppHash, - ) - require.NoError(t, err) - - // add vote and it should work - _, err = h.FMsgServer.AddFinalitySig(h.Ctx, msg) - require.Error(t, err) - - changeAddress, err := datagen.GenRandomBTCAddress(r, h.Net) - require.NoError(t, err) + h.FpAddPubRand(r, fpSK, startHeight) + btcLightClientTipHeight := uint32(30) - stakingTxHash, msgCreateBTCDel, _, _, _, unbondingInfo, err := h.CreateDelegationWithBtcBlockHeight( - r, - delSK, - fpPK, - changeAddress.EncodeAddress(), - stakingValue, - stakingTime, - 0, - 0, - usePreApproval, - false, - 10, - 30, - ) - h.NoError(err) - - // ensure consistency between the msg and the BTC delegation in DB - actualDel, err := h.BTCStakingKeeper.GetBTCDelegation(h.Ctx, stakingTxHash) - h.NoError(err) - - require.Equal(h.T(), msgCreateBTCDel.StakerAddr, actualDel.StakerAddr) - require.Equal(h.T(), msgCreateBTCDel.Pop, actualDel.Pop) - require.Equal(h.T(), msgCreateBTCDel.StakingTx, actualDel.StakingTx) - require.Equal(h.T(), msgCreateBTCDel.SlashingTx, actualDel.SlashingTx) - - // add covenant signatures to activate delegation - msgs := h.GenerateCovenantSignaturesMessages(r, covenantSKs, msgCreateBTCDel, actualDel) - - tipHeight := uint32(30) - h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: tipHeight}).AnyTimes() - - for _, msg := range msgs { - _, err = h.MsgServer.AddCovenantSigs(h.Ctx, msg) - h.NoError(err) - } - - actualDel, err = h.BTCStakingKeeper.GetBTCDelegation(h.Ctx, stakingTxHash) - h.NoError(err) - - status := actualDel.GetStatus(tipHeight, covenantQuorum) - require.Equal(t, status, bstypes.BTCDelegationStatus_ACTIVE) + stakingTxHash, del, unbondingInfo := h.CreateActiveBtcDelegation(r, covenantSKs, fpPK, stakingValue, stakingTime, btcLightClientTipHeight) // process the events as active btc delegation h.BTCStakingKeeper.IndexBTCHeight(h.Ctx) h.FinalityKeeper.UpdatePowerDist(h.Ctx) - btcDel, err := h.IncentivesKeeper.GetBTCDelegationRewardsTracker(h.Ctx, fp.Address(), actualDel.Address()) - h.NoError(err) - require.Equal(t, btcDel.TotalActiveSat.Uint64(), uint64(stakingValue)) - - // Unbond with early unbonding - tipHeight = uint32(45) - h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: tipHeight}).AnyTimes() - - msgUndelegate := &bstypes.MsgBTCUndelegate{ - Signer: datagen.GenRandomAccount().Address, - StakingTxHash: stakingTxHash, - StakeSpendingTx: actualDel.BtcUndelegation.UnbondingTx, - StakeSpendingTxInclusionProof: unbondingInfo.UnbondingTxInclusionProof, - } + h.EqualBtcDelRwdTrackerActiveSat(fp.Address(), del.Address(), uint64(stakingValue)) - // early unbond - _, err = h.MsgServer.BTCUndelegate(h.Ctx, msgUndelegate) - h.NoError(err) + // Execute early unbonding + btcLightClientTipHeight = uint32(45) + h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: btcLightClientTipHeight}).AnyTimes() - // ensure the BTC delegation is unbonded - actualDel, err = h.BTCStakingKeeper.GetBTCDelegation(h.Ctx, stakingTxHash) - h.NoError(err) - status = actualDel.GetStatus(tipHeight, covenantQuorum) - require.Equal(t, bstypes.BTCDelegationStatus_UNBONDED, status) + h.BtcUndelegate(stakingTxHash, del, unbondingInfo, btcLightClientTipHeight) // increases one bbn block to get the voting power distribution cache // from the previous block - headerInfo := h.Ctx.HeaderInfo() - headerInfo.Height += 1 - h.Ctx = h.Ctx.WithHeaderInfo(headerInfo) - h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: tipHeight}).AnyTimes() + h.CtxAddBlkHeight(1) + h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: btcLightClientTipHeight}).AnyTimes() // process the events as early unbonding btc delegation h.BTCStakingKeeper.IndexBTCHeight(h.Ctx) h.FinalityKeeper.UpdatePowerDist(h.Ctx) - btcDel, err = h.IncentivesKeeper.GetBTCDelegationRewardsTracker(h.Ctx, fp.Address(), actualDel.Address()) - h.NoError(err) - require.True(t, btcDel.TotalActiveSat.IsZero()) + h.EqualBtcDelRwdTrackerActiveSat(fp.Address(), del.Address(), 0) - // reaches the btc block of expire + // reaches the btc block of expire BTC delegation // an unbond event will be processed // but should not reduce the TotalActiveSat again - headerInfo = h.Ctx.HeaderInfo() - headerInfo.Height += 1 - h.Ctx = h.Ctx.WithHeaderInfo(headerInfo) + h.CtxAddBlkHeight(1) - tipHeight += uint32(stakingTime) - h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: tipHeight}).AnyTimes() + btcLightClientTipHeight += uint32(stakingTime) + h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: btcLightClientTipHeight}).AnyTimes() // process the events as expired btc delegation h.BTCStakingKeeper.IndexBTCHeight(h.Ctx) h.FinalityKeeper.UpdatePowerDist(h.Ctx) - btcDel, err = h.IncentivesKeeper.GetBTCDelegationRewardsTracker(h.Ctx, fp.Address(), actualDel.Address()) - h.NoError(err) - require.True(t, btcDel.TotalActiveSat.IsZero()) + h.EqualBtcDelRwdTrackerActiveSat(fp.Address(), del.Address(), 0) } From 01479f330ea98f1813eda655a4a56c5232680874 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Mon, 16 Dec 2024 23:03:47 -0300 Subject: [PATCH 079/132] chore: add integration test for incentives and rewards --- testutil/incentives-helper/keeper.go | 29 ++-------- x/finality/keeper/msg_server_test.go | 83 ++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 29 deletions(-) diff --git a/testutil/incentives-helper/keeper.go b/testutil/incentives-helper/keeper.go index 5e97356df..9f2012e77 100644 --- a/testutil/incentives-helper/keeper.go +++ b/testutil/incentives-helper/keeper.go @@ -65,6 +65,7 @@ func (h *IncentiveHelper) CreateBtcDelegation( fpPK *secp256k1.PublicKey, stakingValue int64, stakingTime uint16, + btcLightClientTipHeight uint32, ) ( stakingTxHash string, msgCreateBTCDel *bstypes.MsgCreateBTCDelegation, actualDel *bstypes.BTCDelegation, unbondingInfo *btcstkhelper.UnbondingTxInfo, ) { @@ -86,7 +87,7 @@ func (h *IncentiveHelper) CreateBtcDelegation( false, false, 10, - 30, + btcLightClientTipHeight, ) h.NoError(err) @@ -112,9 +113,10 @@ func (h *IncentiveHelper) CreateActiveBtcDelegation( ) ( stakingTxHash string, actualDel *bstypes.BTCDelegation, unbondingInfo *btcstkhelper.UnbondingTxInfo, ) { - stakingTxHash, msgCreateBTCDel, actualDel, unbondingInfo := h.CreateBtcDelegation(r, fpPK, stakingValue, stakingTime) + stakingTxHash, msgCreateBTCDel, actualDel, unbondingInfo := h.CreateBtcDelegation(r, fpPK, stakingValue, stakingTime, btcLightClientTipHeight) - h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: btcLightClientTipHeight}).AnyTimes() + bsParams := h.BTCStakingKeeper.GetParams(h.Ctx) + h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Any()).Return(&btclctypes.BTCHeaderInfo{Height: btcLightClientTipHeight}).MaxTimes(len(bsParams.CovenantPks) * 2) h.GenerateAndSendCovenantSignatures(r, covenantSKs, msgCreateBTCDel, actualDel) h.EqualBtcDelegationStatus(stakingTxHash, btcLightClientTipHeight, bstypes.BTCDelegationStatus_ACTIVE) @@ -189,24 +191,3 @@ func (h *IncentiveHelper) FpAddPubRand(r *rand.Rand, sk *btcec.PrivateKey, start h.NoError(err) return randListInfo } - -func (h *IncentiveHelper) FpAddPubRandAndFinalitySig(r *rand.Rand, sk *btcec.PrivateKey, startHeight uint64) { - randListInfo := h.FpAddPubRand(r, sk, startHeight) - - // generate a vote - blockHeight := startHeight + uint64(1) - blockAppHash := datagen.GenRandomByteArray(r, 32) - signer := datagen.GenRandomAccount().Address - msg, err := datagen.NewMsgAddFinalitySig( - signer, - sk, - startHeight, - blockHeight, - randListInfo, - blockAppHash, - ) - h.NoError(err) - - _, err = h.FMsgServer.AddFinalitySig(h.Ctx, msg) - h.NoError(err) -} diff --git a/x/finality/keeper/msg_server_test.go b/x/finality/keeper/msg_server_test.go index 812315808..6dc2ae3cb 100644 --- a/x/finality/keeper/msg_server_test.go +++ b/x/finality/keeper/msg_server_test.go @@ -8,9 +8,12 @@ import ( "time" "cosmossdk.io/core/header" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/testutil/datagen" testutil "github.com/babylonlabs-io/babylon/testutil/incentives-helper" keepertest "github.com/babylonlabs-io/babylon/testutil/keeper" @@ -20,6 +23,7 @@ import ( epochingtypes "github.com/babylonlabs-io/babylon/x/epoching/types" "github.com/babylonlabs-io/babylon/x/finality/keeper" "github.com/babylonlabs-io/babylon/x/finality/types" + ictvtypes "github.com/babylonlabs-io/babylon/x/incentive/types" ) func setupMsgServer(t testing.TB) (*keeper.Keeper, types.MsgServer, context.Context) { @@ -489,11 +493,80 @@ func TestVerifyActivationHeight(t *testing.T) { ).Error()) } -// func TestBtcDelegationRewards(t *testing.T) { -// r := rand.New(rand.NewSource(time.Now().Unix())) -// fKeeper, ctx := keepertest.FinalityKeeper(t, nil, nil, nil) +func TestBtcDelegationRewards(t *testing.T) { + r := rand.New(rand.NewSource(time.Now().Unix())) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + btcLightClientTipHeight := uint32(30) + + btclcKeeper := bstypes.NewMockBTCLightClientKeeper(ctrl) + btccKForBtcStaking := bstypes.NewMockBtcCheckpointKeeper(ctrl) + + epochNumber := uint64(10) + btccKForFinality := types.NewMockCheckpointingKeeper(ctrl) + btccKForFinality.EXPECT().GetEpoch(gomock.Any()).Return(&epochingtypes.Epoch{EpochNumber: epochNumber}).AnyTimes() + btccKForFinality.EXPECT().GetLastFinalizedEpoch(gomock.Any()).Return(epochNumber).AnyTimes() + + h := testutil.NewIncentiveHelper(t, btclcKeeper, btccKForBtcStaking, btccKForFinality) + // set all parameters + covenantSKs, _ := h.GenAndApplyParams(r) + h.SetFinalityActivationHeight(0) -// } + // generate and insert new finality provider + stakingValueFp1Del1 := int64(2 * 10e8) + stakingValueFp1Del2 := int64(4 * 10e8) + stakingTime := uint16(1000) + + fp1SK, fp1PK, fp1 := h.CreateFinalityProvider(r) + // commit some public randomness + startHeight := uint64(0) + h.FpAddPubRand(r, fp1SK, startHeight) + + _, fp1Del1, _ := h.CreateActiveBtcDelegation(r, covenantSKs, fp1PK, stakingValueFp1Del1, stakingTime, btcLightClientTipHeight) + _, fp1Del2, _ := h.CreateActiveBtcDelegation(r, covenantSKs, fp1PK, stakingValueFp1Del2, stakingTime, btcLightClientTipHeight) + + // process the events of the activated BTC delegations + h.BTCStakingKeeper.IndexBTCHeight(h.Ctx) + h.FinalityKeeper.UpdatePowerDist(h.Ctx) + + fp1CurrentRwd, err := h.IncentivesKeeper.GetFinalityProviderCurrentRewards(h.Ctx, fp1.Address()) + h.NoError(err) + h.Equal(stakingValueFp1Del1+stakingValueFp1Del2, fp1CurrentRwd.TotalActiveSat.Int64()) + + fp1Del1RwdTracker, err := h.IncentivesKeeper.GetBTCDelegationRewardsTracker(h.Ctx, fp1.Address(), fp1Del1.Address()) + h.NoError(err) + h.Equal(stakingValueFp1Del1, fp1Del1RwdTracker.TotalActiveSat.Int64()) + + fp1Del2RwdTracker, err := h.IncentivesKeeper.GetBTCDelegationRewardsTracker(h.Ctx, fp1.Address(), fp1Del2.Address()) + h.NoError(err) + h.Equal(stakingValueFp1Del2, fp1Del2RwdTracker.TotalActiveSat.Int64()) + + // fp1, del1 => 2_00000000 + // fp1, del2 => 4_00000000 + + // if 1500ubbn are added as reward + // del1 should receive 1/3 => 500 + // del2 should receive 2/3 => 1000 + rwdFp1 := sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, math.NewInt(1500))) + err = h.IncentivesKeeper.AddFinalityProviderRewardsForBtcDelegations(h.Ctx, fp1.Address(), rwdFp1) + h.NoError(err) + + rwdFp1Del1 := sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, math.NewInt(500))) + rwdFp1Del2 := sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, math.NewInt(1000))) + + fp1Del1Rwd, err := h.IncentivesKeeper.RewardGauges(h.Ctx, &ictvtypes.QueryRewardGaugesRequest{ + Address: fp1Del1.Address().String(), + }) + h.NoError(err) + h.Equal(fp1Del1Rwd.RewardGauges[ictvtypes.BTCDelegationType.String()].Coins.String(), rwdFp1Del1.String()) + + fp1Del2Rwd, err := h.IncentivesKeeper.RewardGauges(h.Ctx, &ictvtypes.QueryRewardGaugesRequest{ + Address: fp1Del2.Address().String(), + }) + h.NoError(err) + h.Equal(fp1Del2Rwd.RewardGauges[ictvtypes.BTCDelegationType.String()].Coins.String(), rwdFp1Del2.String()) +} func TestBtcDelegationRewardsEarlyUnbondingAndExpire(t *testing.T) { r := rand.New(rand.NewSource(time.Now().Unix())) @@ -515,7 +588,7 @@ func TestBtcDelegationRewardsEarlyUnbondingAndExpire(t *testing.T) { // generate and insert new finality provider stakingValue := int64(2 * 10e8) - stakingTime := uint16(1000) + stakingTime := uint16(1001) fpSK, fpPK, fp := h.CreateFinalityProvider(r) // commit some public randomness From e6d1884069c5c8cad7b7a37444ed94a37f450bd4 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 17 Dec 2024 09:33:39 -0300 Subject: [PATCH 080/132] chore: rollback to private maccperms --- app/app.go | 8 ++++---- app/app_test.go | 2 +- testutil/keeper/account.go | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/app.go b/app/app.go index 9aae06a99..ca1173dc5 100644 --- a/app/app.go +++ b/app/app.go @@ -142,7 +142,7 @@ var ( // DefaultNodeHome default home directories for the application daemon DefaultNodeHome string // fee collector account, module accounts and their permissions - MaccPerms = map[string][]string{ + maccPerms = map[string][]string{ authtypes.FeeCollectorName: nil, // fee collector account distrtypes.ModuleName: nil, minttypes.ModuleName: {authtypes.Minter}, @@ -254,7 +254,7 @@ func NewBabylonApp( &btcConfig, encCfg, bApp, - MaccPerms, + maccPerms, homePath, invCheckPeriod, skipUpgradeHeights, @@ -639,7 +639,7 @@ func (app *BabylonApp) LoadHeight(height int64) error { // ModuleAccountAddrs returns all the app's module account addresses. func (app *BabylonApp) ModuleAccountAddrs() map[string]bool { modAccAddrs := make(map[string]bool) - for acc := range MaccPerms { + for acc := range maccPerms { modAccAddrs[authtypes.NewModuleAddress(acc).String()] = true } @@ -787,7 +787,7 @@ func (app *BabylonApp) setupUpgradeHandlers() { // GetMaccPerms returns a copy of the module account permissions func GetMaccPerms() map[string][]string { dupMaccPerms := make(map[string][]string) - for k, v := range MaccPerms { + for k, v := range maccPerms { dupMaccPerms[k] = v } return dupMaccPerms diff --git a/app/app_test.go b/app/app_test.go index fa497865f..09b305eab 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -67,7 +67,7 @@ func TestBabylonBlockedAddrs(t *testing.T) { func TestGetMaccPerms(t *testing.T) { dup := GetMaccPerms() - require.Equal(t, MaccPerms, dup, "duplicated module account permissions differed from actual module account permissions") + require.Equal(t, maccPerms, dup, "duplicated module account permissions differed from actual module account permissions") } func TestUpgradeStateOnGenesis(t *testing.T) { diff --git a/testutil/keeper/account.go b/testutil/keeper/account.go index 58605c432..f4d7a8e9a 100644 --- a/testutil/keeper/account.go +++ b/testutil/keeper/account.go @@ -35,7 +35,7 @@ func AccountKeeper( cdc, runtime.NewKVStoreService(storeKey), authtypes.ProtoBaseAccount, - app.MaccPerms, + app.GetMaccPerms(), authcodec.NewBech32Codec(appparams.Bech32PrefixAccAddr), appparams.Bech32PrefixAccAddr, appparams.AccGov.String(), From 3504b67998d5715e00f89f7a017f49f208bd347c Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 17 Dec 2024 10:28:29 -0300 Subject: [PATCH 081/132] chore: address pr comments --- proto/babylon/incentive/rewards.proto | 2 +- x/btcstaking/types/btc_delegation.go | 2 +- x/incentive/types/rewards.pb.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/proto/babylon/incentive/rewards.proto b/proto/babylon/incentive/rewards.proto index 1243c8d15..c322e15b1 100644 --- a/proto/babylon/incentive/rewards.proto +++ b/proto/babylon/incentive/rewards.proto @@ -12,7 +12,7 @@ option go_package = "github.com/babylonlabs-io/babylon/x/incentive/types"; // The period is ommited here and should be part of the key used to store this structure. // Key: Prefix + Finality provider bech32 address + Period. message FinalityProviderHistoricalRewards { - // The cumulative rewards of that finality provider at some specific period + // The cumulative rewards of that finality provider per sat until that period // This coins will aways increase the value, never be reduced due to keep acumulation // and when the cumulative rewards will be used to distribute rewards, 2 periods will // be loaded, calculate the difference and multiplied by the total sat amount delegated diff --git a/x/btcstaking/types/btc_delegation.go b/x/btcstaking/types/btc_delegation.go index 9faf519a1..3c8d1ec97 100644 --- a/x/btcstaking/types/btc_delegation.go +++ b/x/btcstaking/types/btc_delegation.go @@ -59,7 +59,7 @@ func (d *BTCDelegation) GetFpIdx(fpBTCPK *bbn.BIP340PubKey) int { return -1 } -// Address returns the bech32 fp address +// Address returns the bech32 BTC staker address func (d *BTCDelegation) Address() sdk.AccAddress { return sdk.MustAccAddressFromBech32(d.StakerAddr) } diff --git a/x/incentive/types/rewards.pb.go b/x/incentive/types/rewards.pb.go index fd890a830..f026a5e11 100644 --- a/x/incentive/types/rewards.pb.go +++ b/x/incentive/types/rewards.pb.go @@ -32,7 +32,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // The period is ommited here and should be part of the key used to store this structure. // Key: Prefix + Finality provider bech32 address + Period. type FinalityProviderHistoricalRewards struct { - // The cumulative rewards of that finality provider at some specific period + // The cumulative rewards of that finality provider per sat until that period // This coins will aways increase the value, never be reduced due to keep acumulation // and when the cumulative rewards will be used to distribute rewards, 2 periods will // be loaded, calculate the difference and multiplied by the total sat amount delegated From b5f77941263d270347e51e16915524b86944cc5c Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 17 Dec 2024 14:34:15 -0300 Subject: [PATCH 082/132] chore: add e2e test to BTC rewards active btc delegations with covenant signatures --- test/e2e/btc_rewards_distribution_e2e_test.go | 452 ++++++++++++++++++ test/e2e/btc_staking_e2e_test.go | 20 +- test/e2e/btc_staking_pre_approval_e2e_test.go | 2 +- .../configurer/chain/commands_btcstaking.go | 171 ++++++- .../configurer/chain/queries_btcstaking.go | 11 + test/e2e/e2e_test.go | 7 +- 6 files changed, 654 insertions(+), 9 deletions(-) create mode 100644 test/e2e/btc_rewards_distribution_e2e_test.go diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go new file mode 100644 index 000000000..032fdaa78 --- /dev/null +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -0,0 +1,452 @@ +package e2e + +import ( + "fmt" + "math" + "math/rand" + "testing" + "time" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/chaincfg" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + "github.com/babylonlabs-io/babylon/test/e2e/configurer" + "github.com/babylonlabs-io/babylon/test/e2e/configurer/chain" + "github.com/babylonlabs-io/babylon/testutil/datagen" + bbn "github.com/babylonlabs-io/babylon/types" + bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" +) + +type BtcRewardsDistribution struct { + suite.Suite + + r *rand.Rand + net *chaincfg.Params + + fp1BTCSK *btcec.PrivateKey + fp2BTCSK *btcec.PrivateKey + del1BTCSK *btcec.PrivateKey + del2BTCSK *btcec.PrivateKey + + fp1 *bstypes.FinalityProvider + fp2 *bstypes.FinalityProvider + + // Staking amount of each delegation + // 3 Delegations will start closely and possibly in the same block + // (fp1, del1), (fp1, del2), (fp2, del1) + + // (fp1, del1) fp1Del1StakingAmt => 2_00000000 + // (fp1, del2) fp1Del2StakingAmt => 4_00000000 + // (fp2, del1) fp2Del2StakingAmt => 2_00000000 + // for this top configure the reward distribution should + // be 25%, 50%, 25% respectively (if they will be processed in the same block) + fp1Del1StakingAmt int64 + fp1Del2StakingAmt int64 + fp2Del1StakingAmt int64 + + // The lastet delegation will come right after (fp1, del2) and (fp2, del1) + // had withdraw his rewards, and stake 6_00000000 to (fp2, del2) receive the same + // amount of rewards as the sum of rewards (fp1, del2) and (fp2, del1) + fp2Del2StakingAmt int64 + + // bech32 address of the delegators + del1Addr string + del2Addr string + + covenantSKs []*btcec.PrivateKey + covenantWallets []string + + covenantQuorum uint32 + configurer configurer.Configurer +} + +func (s *BtcRewardsDistribution) SetupSuite() { + s.T().Log("setting up e2e integration test suite...") + var err error + + s.r = rand.New(rand.NewSource(time.Now().Unix())) + s.net = &chaincfg.SimNetParams + s.fp1BTCSK, _, _ = datagen.GenRandomBTCKeyPair(s.r) + s.fp2BTCSK, _, _ = datagen.GenRandomBTCKeyPair(s.r) + s.del1BTCSK, _, _ = datagen.GenRandomBTCKeyPair(s.r) + s.del2BTCSK, _, _ = datagen.GenRandomBTCKeyPair(s.r) + + s.fp1Del1StakingAmt = int64(2 * 10e8) + s.fp1Del2StakingAmt = int64(4 * 10e8) + s.fp2Del1StakingAmt = int64(2 * 10e8) + s.fp2Del2StakingAmt = int64(6 * 10e8) + + covenantSKs, _, covenantQuorum := bstypes.DefaultCovenantCommittee() + s.covenantSKs = covenantSKs + s.covenantQuorum = covenantQuorum + + s.configurer, err = configurer.NewBTCStakingConfigurer(s.T(), true) + s.NoError(err) + err = s.configurer.ConfigureChains() + s.NoError(err) + err = s.configurer.RunSetup() + s.NoError(err) +} + +// Test1CreateFinalityProviders creates all finality providers +func (s *BtcRewardsDistribution) Test1CreateFinalityProviders() { + chainA := s.configurer.GetChainConfig(0) + chainA.WaitUntilHeight(1) + + n1, err := chainA.GetNodeAtIndex(1) + s.NoError(err) + n2, err := chainA.GetNodeAtIndex(2) + s.NoError(err) + + s.fp1 = CreateNodeFP( + s.T(), + s.r, + s.fp1BTCSK, + n1, + ) + + s.fp2 = CreateNodeFP( + s.T(), + s.r, + s.fp2BTCSK, + n2, + ) +} + +// Test2CreateFinalityProviders creates the first 3 btc delegations +// with the same values, but different satoshi staked amounts +func (s *BtcRewardsDistribution) Test2CreateFirstBtcDelegations() { + chainA := s.configurer.GetChainConfig(0) + chainA.WaitUntilHeight(1) + + n1, err := chainA.GetNodeAtIndex(1) + s.NoError(err) + + wDel1, wDel2 := "del1", "del2" + s.del1Addr = n1.KeysAdd(wDel1) + s.del2Addr = n1.KeysAdd(wDel2) + + n1.BankMultiSendFromNode([]string{s.del1Addr, s.del2Addr}, "100000ubbn") + + stakingTimeBlocks := uint16(math.MaxUint16) + + // fp1Del1 + s.CreateBTCDelegationAndCheck(n1, wDel1, s.fp1, s.del1BTCSK, s.del1Addr, stakingTimeBlocks, s.fp1Del1StakingAmt) + // fp1Del2 + s.CreateBTCDelegationAndCheck(n1, wDel2, s.fp1, s.del2BTCSK, s.del2Addr, stakingTimeBlocks, s.fp1Del2StakingAmt) + // fp2Del1 + s.CreateBTCDelegationAndCheck(n1, wDel1, s.fp2, s.del1BTCSK, s.del1Addr, stakingTimeBlocks, s.fp2Del1StakingAmt) +} + +// Test3SubmitCovenantSignature covenant approves all the 3 BTC delegation +func (s *BtcRewardsDistribution) Test3SubmitCovenantSignature() { + n2, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(2) + s.NoError(err) + + params := n2.QueryBTCStakingParams() + + covAddrs := make([]string, params.CovenantQuorum) + covWallets := make([]string, params.CovenantQuorum) + for i := 0; i < int(params.CovenantQuorum); i++ { + covWallet := fmt.Sprintf("cov%d", i) + covWallets[i] = covWallet + covAddrs[i] = n2.KeysAdd(covWallet) + } + s.covenantWallets = covWallets + + n2.BankMultiSendFromNode(covAddrs, "100000ubbn") + + pendingDelsResp := n2.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) + s.Equal(len(pendingDelsResp), 3) + + for _, pendingDelResp := range pendingDelsResp { + pendingDel, err := ParseRespBTCDelToBTCDel(pendingDelResp) + s.NoError(err) + + SendCovenantSigsToPendingDel(s.r, s.T(), n2, s.net, s.covenantSKs, s.covenantWallets, pendingDel) + + n2.WaitForNextBlock() + } + + // wait for a block so that above txs take effect + n2.WaitForNextBlock() + + // ensure the BTC delegation has covenant sigs now + activeDelsSet := n2.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) + s.Len(activeDelsSet, 3) + for _, activeDel := range activeDelsSet { + s.True(activeDel.Active) + } +} + +// // Test2CommitPublicRandomnessAndSubmitFinalitySignature is an end-to-end +// // test for user story 3: finality provider commits public randomness and submits +// // finality signature, such that blocks can be finalised. +// func (s *BtcRewardsDistribution) Test3CommitPublicRandomnessAndSubmitFinalitySignature() { +// chainA := s.configurer.GetChainConfig(0) +// chainA.WaitUntilHeight(1) +// nonValidatorNode, err := chainA.GetNodeAtIndex(2) +// s.NoError(err) + +// /* +// commit a number of public randomness +// */ +// // commit public randomness list +// numPubRand := uint64(100) +// commitStartHeight := uint64(1) +// randListInfo, msgCommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp1BTCSK, commitStartHeight, numPubRand) +// s.NoError(err) +// nonValidatorNode.CommitPubRandList( +// msgCommitPubRandList.FpBtcPk, +// msgCommitPubRandList.StartHeight, +// msgCommitPubRandList.NumPubRand, +// msgCommitPubRandList.Commitment, +// msgCommitPubRandList.Sig, +// ) + +// // no reward gauge for finality provider and delegation yet +// fpBabylonAddr, err := sdk.AccAddressFromBech32(s.fp1.Addr) +// s.NoError(err) + +// _, err = nonValidatorNode.QueryRewardGauge(fpBabylonAddr) +// s.ErrorContains(err, itypes.ErrRewardGaugeNotFound.Error()) +// delBabylonAddr := fpBabylonAddr + +// // finalize epochs from 1 to the current epoch +// currentEpoch, err := nonValidatorNode.QueryCurrentEpoch() +// s.NoError(err) + +// // wait until the end epoch is sealed +// s.Eventually(func() bool { +// resp, err := nonValidatorNode.QueryRawCheckpoint(currentEpoch) +// if err != nil { +// return false +// } +// return resp.Status == ckpttypes.Sealed +// }, time.Minute*2, time.Millisecond*50) +// nonValidatorNode.FinalizeSealedEpochs(1, currentEpoch) + +// // ensure the committed epoch is finalized +// lastFinalizedEpoch := uint64(0) +// s.Eventually(func() bool { +// lastFinalizedEpoch, err = nonValidatorNode.QueryLastFinalizedEpoch() +// if err != nil { +// return false +// } +// return lastFinalizedEpoch >= currentEpoch +// }, time.Minute, time.Millisecond*50) + +// // ensure btc staking is activated +// var activatedHeight uint64 +// s.Eventually(func() bool { +// activatedHeight, err = nonValidatorNode.QueryActivatedHeight() +// if err != nil { +// return false +// } +// return activatedHeight > 0 +// }, time.Minute*3, time.Millisecond*50) +// s.T().Logf("the activated height is %d", activatedHeight) + +// /* +// submit finality signature +// */ +// // get block to vote +// blockToVote, err := nonValidatorNode.QueryBlock(int64(activatedHeight)) +// s.NoError(err) +// appHash := blockToVote.AppHash + +// idx := activatedHeight - commitStartHeight +// msgToSign := append(sdk.Uint64ToBigEndian(activatedHeight), appHash...) +// // generate EOTS signature +// sig, err := eots.Sign(s.fp1BTCSK, randListInfo.SRList[idx], msgToSign) +// s.NoError(err) +// eotsSig := bbn.NewSchnorrEOTSSigFromModNScalar(sig) + +// nonValidatorNode.SubmitRefundableTxWithAssertion(func() { +// // submit finality signature +// nonValidatorNode.AddFinalitySig(s.fp1.BtcPk, activatedHeight, &randListInfo.PRList[idx], *randListInfo.ProofList[idx].ToProto(), appHash, eotsSig) + +// // ensure vote is eventually cast +// var finalizedBlocks []*ftypes.IndexedBlock +// s.Eventually(func() bool { +// finalizedBlocks = nonValidatorNode.QueryListBlocks(ftypes.QueriedBlockStatus_FINALIZED) +// return len(finalizedBlocks) > 0 +// }, time.Minute, time.Millisecond*50) +// s.Equal(activatedHeight, finalizedBlocks[0].Height) +// s.Equal(appHash.Bytes(), finalizedBlocks[0].AppHash) +// s.T().Logf("the block %d is finalized", activatedHeight) +// }, true) + +// // ensure finality provider has received rewards after the block is finalised +// // unexpected status code: 500, body: {"code":13,"message":"negative coin amount: -20910810810810","details":[]} +// fpRewardGauges, err := nonValidatorNode.QueryRewardGauge(fpBabylonAddr) +// s.NoError(err) +// fpRewardGauge, ok := fpRewardGauges[itypes.FinalityProviderType.String()] +// s.True(ok) +// s.True(fpRewardGauge.Coins.IsAllPositive()) +// // ensure BTC delegation has received rewards after the block is finalised +// btcDelRewardGauges, err := nonValidatorNode.QueryRewardGauge(delBabylonAddr) +// s.NoError(err) +// btcDelRewardGauge, ok := btcDelRewardGauges[itypes.BTCDelegationType.String()] +// s.True(ok) +// s.True(btcDelRewardGauge.Coins.IsAllPositive()) +// s.T().Logf("the finality provider received rewards for providing finality") +// } + +// func (s *BtcRewardsDistribution) Test4WithdrawReward() { +// chainA := s.configurer.GetChainConfig(0) +// nonValidatorNode, err := chainA.GetNodeAtIndex(2) +// s.NoError(err) + +// // finality provider balance before withdraw +// fpBabylonAddr, err := sdk.AccAddressFromBech32(s.fp1.Addr) +// s.NoError(err) +// delBabylonAddr := fpBabylonAddr + +// fpBalance, err := nonValidatorNode.QueryBalances(fpBabylonAddr.String()) +// s.NoError(err) +// // finality provider reward gauge should not be fully withdrawn +// fpRgs, err := nonValidatorNode.QueryRewardGauge(fpBabylonAddr) +// s.NoError(err) +// fpRg := fpRgs[itypes.FinalityProviderType.String()] +// s.T().Logf("finality provider's withdrawable reward before withdrawing: %s", convertToRewardGauge(fpRg).GetWithdrawableCoins().String()) +// s.False(convertToRewardGauge(fpRg).IsFullyWithdrawn()) + +// // withdraw finality provider reward +// nonValidatorNode.WithdrawReward(itypes.FinalityProviderType.String(), initialization.ValidatorWalletName) +// nonValidatorNode.WaitForNextBlock() + +// // balance after withdrawing finality provider reward +// fpBalance2, err := nonValidatorNode.QueryBalances(fpBabylonAddr.String()) +// s.NoError(err) +// s.T().Logf("fpBalance2: %s; fpBalance: %s", fpBalance2.String(), fpBalance.String()) +// s.True(fpBalance2.IsAllGT(fpBalance)) +// // finality provider reward gauge should be fully withdrawn now +// fpRgs2, err := nonValidatorNode.QueryRewardGauge(fpBabylonAddr) +// s.NoError(err) +// fpRg2 := fpRgs2[itypes.FinalityProviderType.String()] +// s.T().Logf("finality provider's withdrawable reward after withdrawing: %s", convertToRewardGauge(fpRg2).GetWithdrawableCoins().String()) +// s.True(convertToRewardGauge(fpRg2).IsFullyWithdrawn()) + +// // BTC delegation balance before withdraw +// btcDelBalance, err := nonValidatorNode.QueryBalances(delBabylonAddr.String()) +// s.NoError(err) +// // BTC delegation reward gauge should not be fully withdrawn +// btcDelRgs, err := nonValidatorNode.QueryRewardGauge(delBabylonAddr) +// s.NoError(err) +// btcDelRg := btcDelRgs[itypes.BTCDelegationType.String()] +// s.T().Logf("BTC delegation's withdrawable reward before withdrawing: %s", convertToRewardGauge(btcDelRg).GetWithdrawableCoins().String()) +// s.False(convertToRewardGauge(btcDelRg).IsFullyWithdrawn()) + +// // withdraw BTC delegation reward +// nonValidatorNode.WithdrawReward(itypes.BTCDelegationType.String(), initialization.ValidatorWalletName) +// nonValidatorNode.WaitForNextBlock() + +// // balance after withdrawing BTC delegation reward +// btcDelBalance2, err := nonValidatorNode.QueryBalances(delBabylonAddr.String()) +// s.NoError(err) +// s.T().Logf("btcDelBalance2: %s; btcDelBalance: %s", btcDelBalance2.String(), btcDelBalance.String()) +// s.True(btcDelBalance2.IsAllGT(btcDelBalance)) +// // BTC delegation reward gauge should be fully withdrawn now +// btcDelRgs2, err := nonValidatorNode.QueryRewardGauge(delBabylonAddr) +// s.NoError(err) +// btcDelRg2 := btcDelRgs2[itypes.BTCDelegationType.String()] +// s.T().Logf("BTC delegation's withdrawable reward after withdrawing: %s", convertToRewardGauge(btcDelRg2).GetWithdrawableCoins().String()) +// s.True(convertToRewardGauge(btcDelRg2).IsFullyWithdrawn()) +// } + +func (s *BtcRewardsDistribution) CreateBTCDelegationAndCheck( + n *chain.NodeConfig, + wDel string, + fp *bstypes.FinalityProvider, + btcStakerSK *btcec.PrivateKey, + delAddr string, + stakingTimeBlocks uint16, + stakingSatAmt int64, +) { + n.CreateBTCDelegationAndCheck(s.r, s.T(), s.net, wDel, fp, btcStakerSK, delAddr, stakingTimeBlocks, stakingSatAmt) +} + +func SendCovenantSigsToPendingDel( + r *rand.Rand, + t testing.TB, + n *chain.NodeConfig, + btcNet *chaincfg.Params, + covenantSKs []*btcec.PrivateKey, + covWallets []string, + pendingDel *bstypes.BTCDelegation, +) { + require.Len(t, pendingDel.CovenantSigs, 0) + + params := n.QueryBTCStakingParams() + slashingTx := pendingDel.SlashingTx + stakingTx := pendingDel.StakingTx + + stakingMsgTx, err := bbn.NewBTCTxFromBytes(stakingTx) + require.NoError(t, err) + stakingTxHash := stakingMsgTx.TxHash().String() + + fpBTCPKs, err := bbn.NewBTCPKsFromBIP340PKs(pendingDel.FpBtcPkList) + require.NoError(t, err) + + stakingInfo, err := pendingDel.GetStakingInfo(params, btcNet) + require.NoError(t, err) + + stakingSlashingPathInfo, err := stakingInfo.SlashingPathSpendInfo() + require.NoError(t, err) + + /* + generate and insert new covenant signature, in order to activate the BTC delegation + */ + // covenant signatures on slashing tx + covenantSlashingSigs, err := datagen.GenCovenantAdaptorSigs( + covenantSKs, + fpBTCPKs, + stakingMsgTx, + stakingSlashingPathInfo.GetPkScriptPath(), + slashingTx, + ) + require.NoError(t, err) + + // cov Schnorr sigs on unbonding signature + unbondingPathInfo, err := stakingInfo.UnbondingPathSpendInfo() + require.NoError(t, err) + unbondingTx, err := bbn.NewBTCTxFromBytes(pendingDel.BtcUndelegation.UnbondingTx) + require.NoError(t, err) + + covUnbondingSigs, err := datagen.GenCovenantUnbondingSigs( + covenantSKs, + stakingMsgTx, + pendingDel.StakingOutputIdx, + unbondingPathInfo.GetPkScriptPath(), + unbondingTx, + ) + require.NoError(t, err) + + unbondingInfo, err := pendingDel.GetUnbondingInfo(params, btcNet) + require.NoError(t, err) + unbondingSlashingPathInfo, err := unbondingInfo.SlashingPathSpendInfo() + require.NoError(t, err) + covenantUnbondingSlashingSigs, err := datagen.GenCovenantAdaptorSigs( + covenantSKs, + fpBTCPKs, + unbondingTx, + unbondingSlashingPathInfo.GetPkScriptPath(), + pendingDel.BtcUndelegation.SlashingTx, + ) + require.NoError(t, err) + + for i := 0; i < int(params.CovenantQuorum); i++ { + // add covenant sigs + n.AddCovenantSigs( + covWallets[i], + covenantSlashingSigs[i].CovPk, + stakingTxHash, + covenantSlashingSigs[i].AdaptorSigs, + bbn.NewBIP340SignatureFromBTCSig(covUnbondingSigs[i]), + covenantUnbondingSlashingSigs[i].AdaptorSigs, + ) + } +} diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index 327e0ebcd..21605f5e1 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -5,6 +5,7 @@ import ( "fmt" "math" "math/rand" + "strings" "testing" "time" @@ -225,7 +226,7 @@ func (s *BTCStakingTestSuite) Test2SubmitCovenantSignature() { // after adding the covenant signatures it panics with "BTC delegation rewards tracker has a negative amount of TotalActiveSat" nonValidatorNode.SubmitRefundableTxWithAssertion(func() { // add covenant sigs - nonValidatorNode.AddCovenantSigs( + nonValidatorNode.AddCovenantSigsFromVal( covenantSlashingSigs[i].CovPk, stakingTxHash, covenantSlashingSigs[i].AdaptorSigs, @@ -888,7 +889,8 @@ func CreateNodeFP( t *testing.T, r *rand.Rand, fpSk *btcec.PrivateKey, - node *chain.NodeConfig) (newFP *bstypes.FinalityProvider) { + node *chain.NodeConfig, +) (newFP *bstypes.FinalityProvider) { // the node is the new FP nodeAddr, err := sdk.AccAddressFromBech32(node.PublicAddress) require.NoError(t, err) @@ -896,6 +898,8 @@ func CreateNodeFP( newFP, err = datagen.GenRandomFinalityProviderWithBTCBabylonSKs(r, fpSk, nodeAddr) require.NoError(t, err) + previousFps := node.QueryFinalityProviders() + // use a higher commission to ensure the reward is more than tx fee of a finality sig commission := sdkmath.LegacyNewDecWithPrec(20, 2) newFP.Commission = &commission @@ -906,11 +910,17 @@ func CreateNodeFP( // query the existence of finality provider and assert equivalence actualFps := node.QueryFinalityProviders() - require.Len(t, actualFps, 1) + require.Len(t, actualFps, len(previousFps)+1) - equalFinalityProviderResp(t, newFP, actualFps[0]) + for _, fpResp := range actualFps { + if !strings.EqualFold(fpResp.Addr, newFP.Addr) { + continue + } + equalFinalityProviderResp(t, newFP, fpResp) + return newFP + } - return newFP + return nil } // CovenantBTCPKs returns the covenantBTCPks as slice from parameters diff --git a/test/e2e/btc_staking_pre_approval_e2e_test.go b/test/e2e/btc_staking_pre_approval_e2e_test.go index 78d1b42c9..ca1251072 100644 --- a/test/e2e/btc_staking_pre_approval_e2e_test.go +++ b/test/e2e/btc_staking_pre_approval_e2e_test.go @@ -221,7 +221,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test2SubmitCovenantSignature() { for i := 0; i < int(s.covenantQuorum); i++ { nonValidatorNode.SubmitRefundableTxWithAssertion(func() { - nonValidatorNode.AddCovenantSigs( + nonValidatorNode.AddCovenantSigsFromVal( covenantSlashingSigs[i].CovPk, stakingTxHash, covenantSlashingSigs[i].AdaptorSigs, diff --git a/test/e2e/configurer/chain/commands_btcstaking.go b/test/e2e/configurer/chain/commands_btcstaking.go index d5f864861..7146c3412 100644 --- a/test/e2e/configurer/chain/commands_btcstaking.go +++ b/test/e2e/configurer/chain/commands_btcstaking.go @@ -3,20 +3,27 @@ package chain import ( "encoding/hex" "fmt" + "math/rand" "strconv" "strings" + "testing" "github.com/stretchr/testify/require" + "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" sdkmath "cosmossdk.io/math" cmtcrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" asig "github.com/babylonlabs-io/babylon/crypto/schnorr-adaptor-signature" "github.com/babylonlabs-io/babylon/test/e2e/containers" + "github.com/babylonlabs-io/babylon/test/e2e/initialization" + "github.com/babylonlabs-io/babylon/testutil/datagen" bbn "github.com/babylonlabs-io/babylon/types" bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" ) @@ -122,7 +129,18 @@ func (n *NodeConfig) CreateBTCDelegation( return outBuff.String() } -func (n *NodeConfig) AddCovenantSigs(covPK *bbn.BIP340PubKey, stakingTxHash string, slashingSigs [][]byte, unbondingSig *bbn.BIP340Signature, unbondingSlashingSigs [][]byte) { +func (n *NodeConfig) AddCovenantSigsFromVal(covPK *bbn.BIP340PubKey, stakingTxHash string, slashingSigs [][]byte, unbondingSig *bbn.BIP340Signature, unbondingSlashingSigs [][]byte) { + n.AddCovenantSigs("val", covPK, stakingTxHash, slashingSigs, unbondingSig, unbondingSlashingSigs) +} + +func (n *NodeConfig) AddCovenantSigs( + fromWalletName string, + covPK *bbn.BIP340PubKey, + stakingTxHash string, + slashingSigs [][]byte, + unbondingSig *bbn.BIP340Signature, + unbondingSlashingSigs [][]byte, +) { n.LogActionF("adding covenant signature") covPKHex := covPK.MarshalHex() @@ -147,7 +165,7 @@ func (n *NodeConfig) AddCovenantSigs(covPK *bbn.BIP340PubKey, stakingTxHash stri cmd = append(cmd, unbondingSlashingSigStr) // used key - cmd = append(cmd, "--from=val") + cmd = append(cmd, fmt.Sprintf("--from=%s", fromWalletName)) // gas cmd = append(cmd, "--gas=auto", "--gas-adjustment=2") @@ -262,3 +280,152 @@ func (n *NodeConfig) AddBTCDelegationInclusionProof( require.NoError(n.t, err) n.LogActionF("successfully added inclusion proof") } + +// BTCStakingUnbondSlashInfo generate BTC information to create BTC delegation. +func (n *NodeConfig) BTCStakingUnbondSlashInfo( + r *rand.Rand, + t testing.TB, + btcNet *chaincfg.Params, + params *bstypes.Params, + fp *bstypes.FinalityProvider, + btcStakerSK *btcec.PrivateKey, + stakingTimeBlocks uint16, + stakingSatAmt int64, +) ( + testStakingInfo *datagen.TestStakingSlashingInfo, + stakingTx []byte, + txInclusionProof *bstypes.InclusionProof, + testUnbondingInfo *datagen.TestUnbondingSlashingInfo, + delegatorSig *bbn.BIP340Signature, +) { + covenantBTCPKs := CovenantBTCPKs(params) + // required unbonding time + unbondingTime := params.UnbondingTimeBlocks + + testStakingInfo = datagen.GenBTCStakingSlashingInfo( + r, + t, + btcNet, + btcStakerSK, + []*btcec.PublicKey{fp.BtcPk.MustToBTCPK()}, + covenantBTCPKs, + params.CovenantQuorum, + stakingTimeBlocks, + stakingSatAmt, + params.SlashingPkScript, + params.SlashingRate, + uint16(unbondingTime), + ) + + // submit staking tx to Bitcoin and get inclusion proof + currentBtcTipResp, err := n.QueryTip() + require.NoError(t, err) + currentBtcTip, err := ParseBTCHeaderInfoResponseToInfo(currentBtcTipResp) + require.NoError(t, err) + + stakingMsgTx := testStakingInfo.StakingTx + + blockWithStakingTx := datagen.CreateBlockWithTransaction(r, currentBtcTip.Header.ToBlockHeader(), stakingMsgTx) + n.InsertHeader(&blockWithStakingTx.HeaderBytes) + // make block k-deep + for i := 0; i < initialization.BabylonBtcConfirmationPeriod; i++ { + n.InsertNewEmptyBtcHeader(r) + } + inclusionProof := bstypes.NewInclusionProofFromSpvProof(blockWithStakingTx.SpvProof) + + // generate BTC undelegation stuff + stkTxHash := testStakingInfo.StakingTx.TxHash() + unbondingValue := stakingSatAmt - datagen.UnbondingTxFee + testUnbondingInfo = datagen.GenBTCUnbondingSlashingInfo( + r, + t, + btcNet, + btcStakerSK, + []*btcec.PublicKey{fp.BtcPk.MustToBTCPK()}, + covenantBTCPKs, + params.CovenantQuorum, + wire.NewOutPoint(&stkTxHash, datagen.StakingOutIdx), + stakingTimeBlocks, + unbondingValue, + params.SlashingPkScript, + params.SlashingRate, + uint16(unbondingTime), + ) + + stakingSlashingPathInfo, err := testStakingInfo.StakingInfo.SlashingPathSpendInfo() + require.NoError(t, err) + + delegatorSig, err = testStakingInfo.SlashingTx.Sign( + stakingMsgTx, + datagen.StakingOutIdx, + stakingSlashingPathInfo.GetPkScriptPath(), + btcStakerSK, + ) + require.NoError(t, err) + + return testStakingInfo, blockWithStakingTx.SpvProof.BtcTransaction, inclusionProof, testUnbondingInfo, delegatorSig +} + +func (n *NodeConfig) CreateBTCDelegationAndCheck( + r *rand.Rand, + t testing.TB, + btcNet *chaincfg.Params, + walletNameSender string, + fp *bstypes.FinalityProvider, + btcStakerSK *btcec.PrivateKey, + delAddr string, + stakingTimeBlocks uint16, + stakingSatAmt int64, +) { + // BTC staking params, BTC delegation key pairs and PoP + params := n.QueryBTCStakingParams() + + // NOTE: we use the node's address for the BTC delegation + del1Addr := sdk.MustAccAddressFromBech32(delAddr) + popDel1, err := bstypes.NewPoPBTC(del1Addr, btcStakerSK) + require.NoError(t, err) + + testStakingInfo, stakingTx, inclusionProof, testUnbondingInfo, delegatorSig := n.BTCStakingUnbondSlashInfo(r, t, btcNet, params, fp, btcStakerSK, stakingTimeBlocks, stakingSatAmt) + + delUnbondingSlashingSig, err := testUnbondingInfo.GenDelSlashingTxSig(btcStakerSK) + require.NoError(t, err) + + // submit the message for creating BTC delegation + n.CreateBTCDelegation( + bbn.NewBIP340PubKeyFromBTCPK(btcStakerSK.PubKey()), + popDel1, + stakingTx, + inclusionProof, + fp.BtcPk, + stakingTimeBlocks, + btcutil.Amount(stakingSatAmt), + testStakingInfo.SlashingTx, + delegatorSig, + testUnbondingInfo.UnbondingTx, + testUnbondingInfo.SlashingTx, + uint16(params.UnbondingTimeBlocks), + btcutil.Amount(testUnbondingInfo.UnbondingInfo.UnbondingOutput.Value), + delUnbondingSlashingSig, + walletNameSender, + false, + ) + + // wait for a block so that above txs take effect + n.WaitForNextBlock() + + // check if the address matches + btcDelegationResp := n.QueryBtcDelegation(testStakingInfo.StakingTx.TxHash().String()) + require.NotNil(t, btcDelegationResp) + require.Equal(t, btcDelegationResp.BtcDelegation.StakerAddr, delAddr) + require.Equal(t, btcStakerSK.PubKey().SerializeCompressed()[1:], btcDelegationResp.BtcDelegation.BtcPk.MustToBTCPK().SerializeCompressed()[1:]) +} + +// CovenantBTCPKs returns the covenantBTCPks as slice from parameters +func CovenantBTCPKs(params *bstypes.Params) []*btcec.PublicKey { + // get covenant BTC PKs + covenantBTCPKs := make([]*btcec.PublicKey, len(params.CovenantPks)) + for i, covenantPK := range params.CovenantPks { + covenantBTCPKs[i] = covenantPK.MustToBTCPK() + } + return covenantBTCPKs +} diff --git a/test/e2e/configurer/chain/queries_btcstaking.go b/test/e2e/configurer/chain/queries_btcstaking.go index cff41ecee..100136261 100644 --- a/test/e2e/configurer/chain/queries_btcstaking.go +++ b/test/e2e/configurer/chain/queries_btcstaking.go @@ -195,3 +195,14 @@ func (n *NodeConfig) QueryIndexedBlock(height uint64) *ftypes.IndexedBlock { return resp.Block } + +func (n *NodeConfig) QueryFinalityProvidersDelegations(fpsBTCPK ...string) []*bstypes.BTCDelegationResponse { + pendingDelsResp := make([]*bstypes.BTCDelegationResponse, 0) + for _, fpBTCPK := range fpsBTCPK { + fpDelsResp := n.QueryFinalityProviderDelegations(fpBTCPK) + for _, fpDel := range fpDelsResp { + pendingDelsResp = append(pendingDelsResp, fpDel.Dels...) + } + } + return pendingDelsResp +} diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 71a3f8402..8af894aa0 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -20,11 +20,16 @@ func TestBTCTimestampingTestSuite(t *testing.T) { } // TestBTCStakingTestSuite tests BTC staking protocol end-to-end - func TestBTCStakingTestSuite(t *testing.T) { suite.Run(t, new(BTCStakingTestSuite)) } +// TestBTCRewardsDistribution tests BTC staking rewards distribution end-to-end +// that involves x/btcstaking, x/finality, x/incentives and x/mint to give out rewards. +func TestBTCRewardsDistribution(t *testing.T) { + suite.Run(t, new(BtcRewardsDistribution)) +} + func TestBTCStakingPreApprovalTestSuite(t *testing.T) { suite.Run(t, new(BTCStakingPreApprovalTestSuite)) } From e0cab3acea6a14f01386b062ccb2dce9a4d7f849 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 17 Dec 2024 16:58:46 -0300 Subject: [PATCH 083/132] chore: stuck at e2e btc staking activation height --- test/e2e/btc_rewards_distribution_e2e_test.go | 191 ++++++++---------- test/e2e/btc_staking_e2e_test.go | 1 - .../configurer/chain/commands_btcstaking.go | 34 ++++ test/e2e/configurer/chain/queries.go | 40 ++++ 4 files changed, 157 insertions(+), 109 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 032fdaa78..69c3725ce 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -17,6 +17,7 @@ import ( "github.com/babylonlabs-io/babylon/testutil/datagen" bbn "github.com/babylonlabs-io/babylon/types" bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" + ftypes "github.com/babylonlabs-io/babylon/x/finality/types" ) type BtcRewardsDistribution struct { @@ -181,119 +182,93 @@ func (s *BtcRewardsDistribution) Test3SubmitCovenantSignature() { } } -// // Test2CommitPublicRandomnessAndSubmitFinalitySignature is an end-to-end -// // test for user story 3: finality provider commits public randomness and submits -// // finality signature, such that blocks can be finalised. -// func (s *BtcRewardsDistribution) Test3CommitPublicRandomnessAndSubmitFinalitySignature() { -// chainA := s.configurer.GetChainConfig(0) -// chainA.WaitUntilHeight(1) -// nonValidatorNode, err := chainA.GetNodeAtIndex(2) -// s.NoError(err) +// Test3CommitPublicRandomnessAndSealed commits public randomness for +// each finality provider and seals the epoch. +func (s *BtcRewardsDistribution) Test3CommitPublicRandomnessAndSealed() { + chainA := s.configurer.GetChainConfig(0) + n1, err := chainA.GetNodeAtIndex(1) + s.NoError(err) + n2, err := chainA.GetNodeAtIndex(2) + s.NoError(err) -// /* -// commit a number of public randomness -// */ -// // commit public randomness list -// numPubRand := uint64(100) -// commitStartHeight := uint64(1) -// randListInfo, msgCommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp1BTCSK, commitStartHeight, numPubRand) -// s.NoError(err) -// nonValidatorNode.CommitPubRandList( -// msgCommitPubRandList.FpBtcPk, -// msgCommitPubRandList.StartHeight, -// msgCommitPubRandList.NumPubRand, -// msgCommitPubRandList.Commitment, -// msgCommitPubRandList.Sig, -// ) - -// // no reward gauge for finality provider and delegation yet -// fpBabylonAddr, err := sdk.AccAddressFromBech32(s.fp1.Addr) -// s.NoError(err) + /* + commit a number of public randomness + */ + // commit public randomness list + numPubRand := uint64(100) + commitStartHeight := uint64(1) -// _, err = nonValidatorNode.QueryRewardGauge(fpBabylonAddr) -// s.ErrorContains(err, itypes.ErrRewardGaugeNotFound.Error()) -// delBabylonAddr := fpBabylonAddr + fp1RandListInfo, fp1CommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp1BTCSK, commitStartHeight, numPubRand) + s.NoError(err) + fp2RandListInfo, fp2CommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp2BTCSK, commitStartHeight, numPubRand) + s.NoError(err) -// // finalize epochs from 1 to the current epoch -// currentEpoch, err := nonValidatorNode.QueryCurrentEpoch() -// s.NoError(err) + n1.CommitPubRandList( + fp1CommitPubRandList.FpBtcPk, + fp1CommitPubRandList.StartHeight, + fp1CommitPubRandList.NumPubRand, + fp1CommitPubRandList.Commitment, + fp1CommitPubRandList.Sig, + ) + n2.CommitPubRandList( + fp2CommitPubRandList.FpBtcPk, + fp2CommitPubRandList.StartHeight, + fp2CommitPubRandList.NumPubRand, + fp2CommitPubRandList.Commitment, + fp2CommitPubRandList.Sig, + ) -// // wait until the end epoch is sealed -// s.Eventually(func() bool { -// resp, err := nonValidatorNode.QueryRawCheckpoint(currentEpoch) -// if err != nil { -// return false -// } -// return resp.Status == ckpttypes.Sealed -// }, time.Minute*2, time.Millisecond*50) -// nonValidatorNode.FinalizeSealedEpochs(1, currentEpoch) - -// // ensure the committed epoch is finalized -// lastFinalizedEpoch := uint64(0) -// s.Eventually(func() bool { -// lastFinalizedEpoch, err = nonValidatorNode.QueryLastFinalizedEpoch() -// if err != nil { -// return false -// } -// return lastFinalizedEpoch >= currentEpoch -// }, time.Minute, time.Millisecond*50) - -// // ensure btc staking is activated -// var activatedHeight uint64 -// s.Eventually(func() bool { -// activatedHeight, err = nonValidatorNode.QueryActivatedHeight() -// if err != nil { -// return false -// } -// return activatedHeight > 0 -// }, time.Minute*3, time.Millisecond*50) -// s.T().Logf("the activated height is %d", activatedHeight) - -// /* -// submit finality signature -// */ -// // get block to vote -// blockToVote, err := nonValidatorNode.QueryBlock(int64(activatedHeight)) -// s.NoError(err) -// appHash := blockToVote.AppHash + n1.WaitUntilCurrentEpochIsSealedAndFinalized() + activatedHeight := n1.WaitFinalityIsActivated() -// idx := activatedHeight - commitStartHeight -// msgToSign := append(sdk.Uint64ToBigEndian(activatedHeight), appHash...) -// // generate EOTS signature -// sig, err := eots.Sign(s.fp1BTCSK, randListInfo.SRList[idx], msgToSign) -// s.NoError(err) -// eotsSig := bbn.NewSchnorrEOTSSigFromModNScalar(sig) - -// nonValidatorNode.SubmitRefundableTxWithAssertion(func() { -// // submit finality signature -// nonValidatorNode.AddFinalitySig(s.fp1.BtcPk, activatedHeight, &randListInfo.PRList[idx], *randListInfo.ProofList[idx].ToProto(), appHash, eotsSig) - -// // ensure vote is eventually cast -// var finalizedBlocks []*ftypes.IndexedBlock -// s.Eventually(func() bool { -// finalizedBlocks = nonValidatorNode.QueryListBlocks(ftypes.QueriedBlockStatus_FINALIZED) -// return len(finalizedBlocks) > 0 -// }, time.Minute, time.Millisecond*50) -// s.Equal(activatedHeight, finalizedBlocks[0].Height) -// s.Equal(appHash.Bytes(), finalizedBlocks[0].AppHash) -// s.T().Logf("the block %d is finalized", activatedHeight) -// }, true) - -// // ensure finality provider has received rewards after the block is finalised -// // unexpected status code: 500, body: {"code":13,"message":"negative coin amount: -20910810810810","details":[]} -// fpRewardGauges, err := nonValidatorNode.QueryRewardGauge(fpBabylonAddr) -// s.NoError(err) -// fpRewardGauge, ok := fpRewardGauges[itypes.FinalityProviderType.String()] -// s.True(ok) -// s.True(fpRewardGauge.Coins.IsAllPositive()) -// // ensure BTC delegation has received rewards after the block is finalised -// btcDelRewardGauges, err := nonValidatorNode.QueryRewardGauge(delBabylonAddr) -// s.NoError(err) -// btcDelRewardGauge, ok := btcDelRewardGauges[itypes.BTCDelegationType.String()] -// s.True(ok) -// s.True(btcDelRewardGauge.Coins.IsAllPositive()) -// s.T().Logf("the finality provider received rewards for providing finality") -// } + /* + submit finality signature + */ + idx := activatedHeight - commitStartHeight + + n1.AddFinalitySignatureToBlock( + s.fp1BTCSK, + s.fp1.BtcPk, + activatedHeight, + fp1RandListInfo.SRList[idx], + &fp1RandListInfo.PRList[idx], + *fp1RandListInfo.ProofList[idx].ToProto(), + ) + + appHash := n2.AddFinalitySignatureToBlock( + s.fp2BTCSK, + s.fp2.BtcPk, + activatedHeight, + fp2RandListInfo.SRList[idx], + &fp2RandListInfo.PRList[idx], + *fp2RandListInfo.ProofList[idx].ToProto(), + ) + + // ensure vote is eventually cast + var finalizedBlocks []*ftypes.IndexedBlock + s.Eventually(func() bool { + finalizedBlocks = n1.QueryListBlocks(ftypes.QueriedBlockStatus_FINALIZED) + return len(finalizedBlocks) > 0 + }, time.Minute, time.Millisecond*50) + + s.Equal(activatedHeight, finalizedBlocks[0].Height) + s.Equal(appHash.Bytes(), finalizedBlocks[0].AppHash) + s.T().Logf("the block %d is finalized", activatedHeight) + + // // ensure finality provider has received rewards after the block is finalised + // fpRewardGauges, err := n1.QueryRewardGauge(fpBabylonAddr) + // s.NoError(err) + // fpRewardGauge, ok := fpRewardGauges[itypes.FinalityProviderType.String()] + // s.True(ok) + // s.True(fpRewardGauge.Coins.IsAllPositive()) + // // ensure BTC delegation has received rewards after the block is finalised + // btcDelRewardGauges, err := n1.QueryRewardGauge(delBabylonAddr) + // s.NoError(err) + // btcDelRewardGauge, ok := btcDelRewardGauges[itypes.BTCDelegationType.String()] + // s.True(ok) + // s.True(btcDelRewardGauge.Coins.IsAllPositive()) + // s.T().Logf("the finality provider received rewards for providing finality") +} // func (s *BtcRewardsDistribution) Test4WithdrawReward() { // chainA := s.configurer.GetChainConfig(0) diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index 21605f5e1..fcca727cd 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -353,7 +353,6 @@ func (s *BTCStakingTestSuite) Test3CommitPublicRandomnessAndSubmitFinalitySignat }, true) // ensure finality provider has received rewards after the block is finalised - // unexpected status code: 500, body: {"code":13,"message":"negative coin amount: -20910810810810","details":[]} fpRewardGauges, err := nonValidatorNode.QueryRewardGauge(fpBabylonAddr) s.NoError(err) fpRewardGauge, ok := fpRewardGauges[itypes.FinalityProviderType.String()] diff --git a/test/e2e/configurer/chain/commands_btcstaking.go b/test/e2e/configurer/chain/commands_btcstaking.go index 7146c3412..989c604a6 100644 --- a/test/e2e/configurer/chain/commands_btcstaking.go +++ b/test/e2e/configurer/chain/commands_btcstaking.go @@ -8,6 +8,7 @@ import ( "strings" "testing" + "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/stretchr/testify/require" "github.com/btcsuite/btcd/btcec/v2" @@ -17,9 +18,11 @@ import ( "github.com/btcsuite/btcd/wire" sdkmath "cosmossdk.io/math" + "github.com/cometbft/cometbft/libs/bytes" cmtcrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/babylonlabs-io/babylon/crypto/eots" asig "github.com/babylonlabs-io/babylon/crypto/schnorr-adaptor-signature" "github.com/babylonlabs-io/babylon/test/e2e/containers" "github.com/babylonlabs-io/babylon/test/e2e/initialization" @@ -420,6 +423,37 @@ func (n *NodeConfig) CreateBTCDelegationAndCheck( require.Equal(t, btcStakerSK.PubKey().SerializeCompressed()[1:], btcDelegationResp.BtcDelegation.BtcPk.MustToBTCPK().SerializeCompressed()[1:]) } +func (n *NodeConfig) AddFinalitySignatureToBlock( + fpBTCSK *secp256k1.PrivateKey, + fpBTCPK *bbn.BIP340PubKey, + blockHeight uint64, + privateRand *secp256k1.ModNScalar, + pubRand *bbn.SchnorrPubRand, + proof cmtcrypto.Proof, +) (blockVotedAppHash bytes.HexBytes) { + blockToVote, err := n.QueryBlock(int64(blockHeight)) + require.NoError(n.t, err) + appHash := blockToVote.AppHash + + msgToSign := append(sdk.Uint64ToBigEndian(blockHeight), appHash...) + // generate EOTS signature + fp1Sig, err := eots.Sign(fpBTCSK, privateRand, msgToSign) + require.NoError(n.t, err) + + finalitySig := bbn.NewSchnorrEOTSSigFromModNScalar(fp1Sig) + + // submit finality signature + n.AddFinalitySig( + fpBTCPK, + blockHeight, + pubRand, + proof, + appHash, + finalitySig, + ) + return appHash +} + // CovenantBTCPKs returns the covenantBTCPks as slice from parameters func CovenantBTCPKs(params *bstypes.Params) []*btcec.PublicKey { // get covenant BTC PKs diff --git a/test/e2e/configurer/chain/queries.go b/test/e2e/configurer/chain/queries.go index 37ba3fbe6..d751049ca 100644 --- a/test/e2e/configurer/chain/queries.go +++ b/test/e2e/configurer/chain/queries.go @@ -408,3 +408,43 @@ func (n *NodeConfig) QueryTx(txHash string, overallFlags ...string) sdk.TxRespon return txResp } + +func (n *NodeConfig) WaitUntilCurrentEpochIsSealedAndFinalized() { + // finalize epochs from 1 to the current epoch + currentEpoch, err := n.QueryCurrentEpoch() + require.NoError(n.t, err) + + // wait until the end epoch is sealed + require.Eventually(n.t, func() bool { + resp, err := n.QueryRawCheckpoint(currentEpoch) + if err != nil { + return false + } + return resp.Status == ct.Sealed + }, time.Minute*2, time.Millisecond*50) + n.FinalizeSealedEpochs(1, currentEpoch) + + // ensure the committed epoch is finalized + lastFinalizedEpoch := uint64(0) + require.Eventually(n.t, func() bool { + lastFinalizedEpoch, err = n.QueryLastFinalizedEpoch() + if err != nil { + return false + } + return lastFinalizedEpoch >= currentEpoch + }, time.Minute, time.Millisecond*50) +} + +func (n *NodeConfig) WaitFinalityIsActivated() (activatedHeight uint64) { + var err error + require.Eventually(n.t, func() bool { + activatedHeight, err = n.QueryActivatedHeight() + if err != nil { + return false + } + // TODO: check why never becomes active with fps and commited pub rand + return activatedHeight > 0 + }, time.Minute*5, time.Millisecond*50) + n.t.Logf("the activated height is %d", activatedHeight) + return activatedHeight +} From 9d7fad6c58e2242a0991baf754814c2a3330315e Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 17 Dec 2024 22:06:21 -0300 Subject: [PATCH 084/132] chore: stuck at activated height --- test/e2e/btc_rewards_distribution_e2e_test.go | 70 ++++++++-------- test/e2e/btc_staking_e2e_test.go | 80 +++---------------- .../configurer/chain/commands_btcstaking.go | 4 +- test/e2e/configurer/chain/queries.go | 4 +- test/e2e/e2e_test.go | 4 +- 5 files changed, 56 insertions(+), 106 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 69c3725ce..fe0556c31 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -59,8 +59,7 @@ type BtcRewardsDistribution struct { covenantSKs []*btcec.PrivateKey covenantWallets []string - covenantQuorum uint32 - configurer configurer.Configurer + configurer configurer.Configurer } func (s *BtcRewardsDistribution) SetupSuite() { @@ -74,14 +73,13 @@ func (s *BtcRewardsDistribution) SetupSuite() { s.del1BTCSK, _, _ = datagen.GenRandomBTCKeyPair(s.r) s.del2BTCSK, _, _ = datagen.GenRandomBTCKeyPair(s.r) - s.fp1Del1StakingAmt = int64(2 * 10e8) + s.fp1Del1StakingAmt = int64(9 * 10e8) s.fp1Del2StakingAmt = int64(4 * 10e8) s.fp2Del1StakingAmt = int64(2 * 10e8) s.fp2Del2StakingAmt = int64(6 * 10e8) - covenantSKs, _, covenantQuorum := bstypes.DefaultCovenantCommittee() + covenantSKs, _, _ := bstypes.DefaultCovenantCommittee() s.covenantSKs = covenantSKs - s.covenantQuorum = covenantQuorum s.configurer, err = configurer.NewBTCStakingConfigurer(s.T(), true) s.NoError(err) @@ -107,6 +105,7 @@ func (s *BtcRewardsDistribution) Test1CreateFinalityProviders() { s.fp1BTCSK, n1, ) + s.NotNil(s.fp1) s.fp2 = CreateNodeFP( s.T(), @@ -114,68 +113,69 @@ func (s *BtcRewardsDistribution) Test1CreateFinalityProviders() { s.fp2BTCSK, n2, ) + s.NotNil(s.fp2) + + actualFps := n2.QueryFinalityProviders() + s.Len(actualFps, 2) } // Test2CreateFinalityProviders creates the first 3 btc delegations // with the same values, but different satoshi staked amounts func (s *BtcRewardsDistribution) Test2CreateFirstBtcDelegations() { - chainA := s.configurer.GetChainConfig(0) - chainA.WaitUntilHeight(1) - - n1, err := chainA.GetNodeAtIndex(1) + n0, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(0) s.NoError(err) wDel1, wDel2 := "del1", "del2" - s.del1Addr = n1.KeysAdd(wDel1) - s.del2Addr = n1.KeysAdd(wDel2) + s.del1Addr = n0.KeysAdd(wDel1) + s.del2Addr = n0.KeysAdd(wDel2) - n1.BankMultiSendFromNode([]string{s.del1Addr, s.del2Addr}, "100000ubbn") + n0.BankMultiSendFromNode([]string{s.del1Addr, s.del2Addr}, "100000ubbn") stakingTimeBlocks := uint16(math.MaxUint16) // fp1Del1 - s.CreateBTCDelegationAndCheck(n1, wDel1, s.fp1, s.del1BTCSK, s.del1Addr, stakingTimeBlocks, s.fp1Del1StakingAmt) + s.CreateBTCDelegationAndCheck(n0, wDel1, s.fp1, s.del1BTCSK, s.del1Addr, stakingTimeBlocks, s.fp1Del1StakingAmt) // fp1Del2 - s.CreateBTCDelegationAndCheck(n1, wDel2, s.fp1, s.del2BTCSK, s.del2Addr, stakingTimeBlocks, s.fp1Del2StakingAmt) + s.CreateBTCDelegationAndCheck(n0, wDel2, s.fp1, s.del2BTCSK, s.del2Addr, stakingTimeBlocks, s.fp1Del2StakingAmt) // fp2Del1 - s.CreateBTCDelegationAndCheck(n1, wDel1, s.fp2, s.del1BTCSK, s.del1Addr, stakingTimeBlocks, s.fp2Del1StakingAmt) + s.CreateBTCDelegationAndCheck(n0, wDel1, s.fp2, s.del1BTCSK, s.del1Addr, stakingTimeBlocks, s.fp2Del1StakingAmt) } // Test3SubmitCovenantSignature covenant approves all the 3 BTC delegation func (s *BtcRewardsDistribution) Test3SubmitCovenantSignature() { - n2, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(2) + n1, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(1) s.NoError(err) - params := n2.QueryBTCStakingParams() + params := n1.QueryBTCStakingParams() covAddrs := make([]string, params.CovenantQuorum) covWallets := make([]string, params.CovenantQuorum) for i := 0; i < int(params.CovenantQuorum); i++ { covWallet := fmt.Sprintf("cov%d", i) covWallets[i] = covWallet - covAddrs[i] = n2.KeysAdd(covWallet) + covAddrs[i] = n1.KeysAdd(covWallet) } s.covenantWallets = covWallets - n2.BankMultiSendFromNode(covAddrs, "100000ubbn") + n1.BankMultiSendFromNode(covAddrs, "100000ubbn") - pendingDelsResp := n2.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) + pendingDelsResp := n1.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) s.Equal(len(pendingDelsResp), 3) for _, pendingDelResp := range pendingDelsResp { pendingDel, err := ParseRespBTCDelToBTCDel(pendingDelResp) s.NoError(err) - SendCovenantSigsToPendingDel(s.r, s.T(), n2, s.net, s.covenantSKs, s.covenantWallets, pendingDel) + SendCovenantSigsToPendingDel(s.r, s.T(), n1, s.net, s.covenantSKs, s.covenantWallets, pendingDel) - n2.WaitForNextBlock() + n1.WaitForNextBlock() } // wait for a block so that above txs take effect - n2.WaitForNextBlock() + n1.WaitForNextBlock() // ensure the BTC delegation has covenant sigs now - activeDelsSet := n2.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) + activeDelsSet := n1.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) s.Len(activeDelsSet, 3) for _, activeDel := range activeDelsSet { s.True(activeDel.Active) @@ -195,14 +195,11 @@ func (s *BtcRewardsDistribution) Test3CommitPublicRandomnessAndSealed() { commit a number of public randomness */ // commit public randomness list - numPubRand := uint64(100) + numPubRand := uint64(150) commitStartHeight := uint64(1) fp1RandListInfo, fp1CommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp1BTCSK, commitStartHeight, numPubRand) s.NoError(err) - fp2RandListInfo, fp2CommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp2BTCSK, commitStartHeight, numPubRand) - s.NoError(err) - n1.CommitPubRandList( fp1CommitPubRandList.FpBtcPk, fp1CommitPubRandList.StartHeight, @@ -210,6 +207,14 @@ func (s *BtcRewardsDistribution) Test3CommitPublicRandomnessAndSealed() { fp1CommitPubRandList.Commitment, fp1CommitPubRandList.Sig, ) + + n1.WaitUntilCurrentEpochIsSealedAndFinalized() + + // activated height is never returned + activatedHeight := n1.WaitFinalityIsActivated() + + fp2RandListInfo, fp2CommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp2BTCSK, commitStartHeight, numPubRand) + s.NoError(err) n2.CommitPubRandList( fp2CommitPubRandList.FpBtcPk, fp2CommitPubRandList.StartHeight, @@ -217,16 +222,13 @@ func (s *BtcRewardsDistribution) Test3CommitPublicRandomnessAndSealed() { fp2CommitPubRandList.Commitment, fp2CommitPubRandList.Sig, ) - - n1.WaitUntilCurrentEpochIsSealedAndFinalized() - activatedHeight := n1.WaitFinalityIsActivated() - + // latestBlock := n1.LatestBlockNumber() /* submit finality signature */ idx := activatedHeight - commitStartHeight - n1.AddFinalitySignatureToBlock( + appHash := n1.AddFinalitySignatureToBlock( s.fp1BTCSK, s.fp1.BtcPk, activatedHeight, @@ -235,7 +237,7 @@ func (s *BtcRewardsDistribution) Test3CommitPublicRandomnessAndSealed() { *fp1RandListInfo.ProofList[idx].ToProto(), ) - appHash := n2.AddFinalitySignatureToBlock( + n2.AddFinalitySignatureToBlock( s.fp2BTCSK, s.fp2.BtcPk, activatedHeight, diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index fcca727cd..b12d6343b 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -29,7 +29,6 @@ import ( "github.com/babylonlabs-io/babylon/testutil/datagen" bbn "github.com/babylonlabs-io/babylon/types" bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" - ckpttypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" ftypes "github.com/babylonlabs-io/babylon/x/finality/types" itypes "github.com/babylonlabs-io/babylon/x/incentive/types" ) @@ -91,47 +90,23 @@ func (s *BTCStakingTestSuite) Test1CreateFinalityProviderAndDelegation() { /* create a random BTC delegation under this finality provider */ - // BTC staking params, BTC delegation key pairs and PoP - params := nonValidatorNode.QueryBTCStakingParams() - - // required unbonding time - unbondingTime := params.UnbondingTimeBlocks - - // NOTE: we use the node's address for the BTC delegation - stakerAddr := sdk.MustAccAddressFromBech32(nonValidatorNode.PublicAddress) - pop, err := bstypes.NewPoPBTC(stakerAddr, s.delBTCSK) - s.NoError(err) // generate staking tx and slashing tx stakingTimeBlocks := uint16(math.MaxUint16) - testStakingInfo, stakingTx, inclusionProof, testUnbondingInfo, delegatorSig := s.BTCStakingUnbondSlashInfo(nonValidatorNode, params, stakingTimeBlocks, s.cacheFP) - - delUnbondingSlashingSig, err := testUnbondingInfo.GenDelSlashingTxSig(s.delBTCSK) - s.NoError(err) - // submit the message for creating BTC delegation - nonValidatorNode.CreateBTCDelegation( - bbn.NewBIP340PubKeyFromBTCPK(s.delBTCSK.PubKey()), - pop, - stakingTx, - inclusionProof, - s.cacheFP.BtcPk, - stakingTimeBlocks, - btcutil.Amount(s.stakingValue), - testStakingInfo.SlashingTx, - delegatorSig, - testUnbondingInfo.UnbondingTx, - testUnbondingInfo.SlashingTx, - uint16(unbondingTime), - btcutil.Amount(testUnbondingInfo.UnbondingInfo.UnbondingOutput.Value), - delUnbondingSlashingSig, + // NOTE: we use the node's address for the BTC delegation + testStakingInfo := nonValidatorNode.CreateBTCDelegationAndCheck( + s.r, + s.T(), + s.net, nonValidatorNode.WalletName, - false, + s.cacheFP, + s.delBTCSK, + nonValidatorNode.PublicAddress, + stakingTimeBlocks, + s.stakingValue, ) - // wait for a block so that above txs take effect - nonValidatorNode.WaitForNextBlock() - pendingDelSet := nonValidatorNode.QueryFinalityProviderDelegations(s.cacheFP.BtcPk.MarshalHex()) s.Len(pendingDelSet, 1) pendingDels := pendingDelSet[0] @@ -287,40 +262,11 @@ func (s *BTCStakingTestSuite) Test3CommitPublicRandomnessAndSubmitFinalitySignat s.ErrorContains(err, itypes.ErrRewardGaugeNotFound.Error()) delBabylonAddr := fpBabylonAddr - // finalize epochs from 1 to the current epoch - currentEpoch, err := nonValidatorNode.QueryCurrentEpoch() - s.NoError(err) - - // wait until the end epoch is sealed - s.Eventually(func() bool { - resp, err := nonValidatorNode.QueryRawCheckpoint(currentEpoch) - if err != nil { - return false - } - return resp.Status == ckpttypes.Sealed - }, time.Minute*2, time.Millisecond*50) - nonValidatorNode.FinalizeSealedEpochs(1, currentEpoch) - - // ensure the committed epoch is finalized - lastFinalizedEpoch := uint64(0) - s.Eventually(func() bool { - lastFinalizedEpoch, err = nonValidatorNode.QueryLastFinalizedEpoch() - if err != nil { - return false - } - return lastFinalizedEpoch >= currentEpoch - }, time.Minute, time.Millisecond*50) + nonValidatorNode.WaitUntilCurrentEpochIsSealedAndFinalized() // ensure btc staking is activated - var activatedHeight uint64 - s.Eventually(func() bool { - activatedHeight, err = nonValidatorNode.QueryActivatedHeight() - if err != nil { - return false - } - return activatedHeight > 0 - }, time.Minute*3, time.Millisecond*50) - s.T().Logf("the activated height is %d", activatedHeight) + // check how this does not errors out + activatedHeight := nonValidatorNode.WaitFinalityIsActivated() /* submit finality signature diff --git a/test/e2e/configurer/chain/commands_btcstaking.go b/test/e2e/configurer/chain/commands_btcstaking.go index 989c604a6..6eedf3dd8 100644 --- a/test/e2e/configurer/chain/commands_btcstaking.go +++ b/test/e2e/configurer/chain/commands_btcstaking.go @@ -379,7 +379,7 @@ func (n *NodeConfig) CreateBTCDelegationAndCheck( delAddr string, stakingTimeBlocks uint16, stakingSatAmt int64, -) { +) (testStakingInfo *datagen.TestStakingSlashingInfo) { // BTC staking params, BTC delegation key pairs and PoP params := n.QueryBTCStakingParams() @@ -421,6 +421,8 @@ func (n *NodeConfig) CreateBTCDelegationAndCheck( require.NotNil(t, btcDelegationResp) require.Equal(t, btcDelegationResp.BtcDelegation.StakerAddr, delAddr) require.Equal(t, btcStakerSK.PubKey().SerializeCompressed()[1:], btcDelegationResp.BtcDelegation.BtcPk.MustToBTCPK().SerializeCompressed()[1:]) + + return testStakingInfo } func (n *NodeConfig) AddFinalitySignatureToBlock( diff --git a/test/e2e/configurer/chain/queries.go b/test/e2e/configurer/chain/queries.go index d751049ca..ae5009961 100644 --- a/test/e2e/configurer/chain/queries.go +++ b/test/e2e/configurer/chain/queries.go @@ -442,9 +442,9 @@ func (n *NodeConfig) WaitFinalityIsActivated() (activatedHeight uint64) { if err != nil { return false } - // TODO: check why never becomes active with fps and commited pub rand + // TODO: check why never becomes active with fps and committed pub rand return activatedHeight > 0 - }, time.Minute*5, time.Millisecond*50) + }, time.Minute*3, time.Millisecond*50) n.t.Logf("the activated height is %d", activatedHeight) return activatedHeight } diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 8af894aa0..68773fe4a 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -24,9 +24,9 @@ func TestBTCStakingTestSuite(t *testing.T) { suite.Run(t, new(BTCStakingTestSuite)) } -// TestBTCRewardsDistribution tests BTC staking rewards distribution end-to-end +// TestRewardsDistributionBTC tests BTC staking rewards distribution end-to-end // that involves x/btcstaking, x/finality, x/incentives and x/mint to give out rewards. -func TestBTCRewardsDistribution(t *testing.T) { +func TestRewardsDistributionBTC(t *testing.T) { suite.Run(t, new(BtcRewardsDistribution)) } From dcee28ef1438a50c6fdc060b4e559993aa3151a3 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 17 Dec 2024 22:57:03 -0300 Subject: [PATCH 085/132] chore: add new status event BTCDelegationStatus_EXPIRED --- proto/babylon/btcstaking/v1/btcstaking.proto | 14 +- x/btcstaking/keeper/btc_delegations.go | 8 +- x/btcstaking/keeper/genesis_test.go | 4 +- x/btcstaking/keeper/msg_server.go | 6 +- x/btcstaking/types/btc_delegation.go | 12 +- x/btcstaking/types/btcstaking.pb.go | 195 ++++++++++--------- x/btcstaking/types/events.go | 2 +- x/finality/keeper/power_dist_change.go | 25 ++- x/finality/keeper/power_dist_change_test.go | 12 +- 9 files changed, 147 insertions(+), 131 deletions(-) diff --git a/proto/babylon/btcstaking/v1/btcstaking.proto b/proto/babylon/btcstaking/v1/btcstaking.proto index f11aec5b2..50acad4da 100644 --- a/proto/babylon/btcstaking/v1/btcstaking.proto +++ b/proto/babylon/btcstaking/v1/btcstaking.proto @@ -167,8 +167,8 @@ message BTCDelegatorDelegationIndex { // BTCDelegationStatus is the status of a delegation. // There are two possible valid state transition paths for a BTC delegation: -// - PENDING -> ACTIVE -> UNBONDED -// - PENDING -> VERIFIED -> ACTIVE -> UNBONDED +// - PENDING -> ACTIVE -> UNBONDED -> EXPIRED +// - PENDING -> VERIFIED -> ACTIVE -> UNBONDED/EXPIRED // and one invalid state transition path: // - PENDING -> VERIFIED -> UNBONDED i.e the staker unbonded before // activating delegation on Babylon chain. @@ -183,12 +183,14 @@ enum BTCDelegationStatus { VERIFIED = 1; // ACTIVE defines a delegation that has voting power ACTIVE = 2; - // UNBONDED defines a delegation no longer has voting power: - // - either reaching the end of staking transaction timelock - // - or receiving unbonding tx with signatures from staker and covenant committee + // UNBONDED defines a delegation no longer has voting power + // by receiving unbonding tx with signatures from staker and covenant committee UNBONDED = 3; + // EXPIRED defines a delegation no longer has voting power + // for reaching the end of staking transaction timelock + EXPIRED = 4; // ANY is any of the above status - ANY = 4; + ANY = 5; } // SignatureInfo is a BIP-340 signature together with its signer's BIP-340 PK diff --git a/x/btcstaking/keeper/btc_delegations.go b/x/btcstaking/keeper/btc_delegations.go index 0c2357ff3..5cfb64b2e 100644 --- a/x/btcstaking/keeper/btc_delegations.go +++ b/x/btcstaking/keeper/btc_delegations.go @@ -70,16 +70,16 @@ func (k Keeper) AddBTCDelegation( panic(fmt.Errorf("failed to emit EventBTCDelegationInclusionProofReceived for the new pending BTC delegation: %w", err)) } - // record event that the BTC delegation will become unbonded at EndHeight-w + // record event that the BTC delegation will become expired (unbonded) at EndHeight-w // This event will be generated to subscribers as block event, when the // btc light client block height will reach btcDel.EndHeight-wValue - unbondedEvent := types.NewEventPowerDistUpdateWithBTCDel(&types.EventBTCDelegationStateUpdate{ + expiredEvent := types.NewEventPowerDistUpdateWithBTCDel(&types.EventBTCDelegationStateUpdate{ StakingTxHash: stakingTxHash.String(), - NewState: types.BTCDelegationStatus_UNBONDED, + NewState: types.BTCDelegationStatus_EXPIRED, }) // NOTE: we should have verified that EndHeight > btcTip.Height + unbonding_time - k.addPowerDistUpdateEvent(ctx, btcDel.EndHeight-btcDel.UnbondingTime, unbondedEvent) + k.addPowerDistUpdateEvent(ctx, btcDel.EndHeight-btcDel.UnbondingTime, expiredEvent) } return nil diff --git a/x/btcstaking/keeper/genesis_test.go b/x/btcstaking/keeper/genesis_test.go index 9bec4f07f..5f7b65938 100644 --- a/x/btcstaking/keeper/genesis_test.go +++ b/x/btcstaking/keeper/genesis_test.go @@ -103,10 +103,10 @@ func TestExportGenesis(t *testing.T) { DelBtcPk: del.BtcPk, } - // record event that the BTC delegation will become unbonded at EndHeight-w + // record event that the BTC delegation will become expired (unbonded) at EndHeight-w unbondedEvent := types.NewEventPowerDistUpdateWithBTCDel(&types.EventBTCDelegationStateUpdate{ StakingTxHash: stakingTxHash.String(), - NewState: types.BTCDelegationStatus_UNBONDED, + NewState: types.BTCDelegationStatus_EXPIRED, }) // events diff --git a/x/btcstaking/keeper/msg_server.go b/x/btcstaking/keeper/msg_server.go index 3a08512a6..0c9895d43 100644 --- a/x/btcstaking/keeper/msg_server.go +++ b/x/btcstaking/keeper/msg_server.go @@ -394,13 +394,13 @@ func (ms msgServer) AddBTCDelegationInclusionProof( ms.addPowerDistUpdateEvent(ctx, timeInfo.TipHeight, activeEvent) // record event that the BTC delegation will become unbonded at EndHeight-w - unbondedEvent := types.NewEventPowerDistUpdateWithBTCDel(&types.EventBTCDelegationStateUpdate{ + expiredEvent := types.NewEventPowerDistUpdateWithBTCDel(&types.EventBTCDelegationStateUpdate{ StakingTxHash: req.StakingTxHash, - NewState: types.BTCDelegationStatus_UNBONDED, + NewState: types.BTCDelegationStatus_EXPIRED, }) // NOTE: we should have verified that EndHeight > btcTip.Height + min_unbonding_time - ms.addPowerDistUpdateEvent(ctx, btcDel.EndHeight-params.UnbondingTimeBlocks, unbondedEvent) + ms.addPowerDistUpdateEvent(ctx, btcDel.EndHeight-params.UnbondingTimeBlocks, expiredEvent) // at this point, the BTC delegation inclusion proof is verified and is not duplicated // thus, we can safely consider this message as refundable diff --git a/x/btcstaking/types/btc_delegation.go b/x/btcstaking/types/btc_delegation.go index 3c8d1ec97..690724720 100644 --- a/x/btcstaking/types/btc_delegation.go +++ b/x/btcstaking/types/btc_delegation.go @@ -29,6 +29,8 @@ func NewBTCDelegationStatusFromString(statusStr string) (BTCDelegationStatus, er return BTCDelegationStatus_ACTIVE, nil case "unbonded": return BTCDelegationStatus_UNBONDED, nil + case "expired": + return BTCDelegationStatus_EXPIRED, nil case "any": return BTCDelegationStatus_ANY, nil default: @@ -132,12 +134,18 @@ func (d *BTCDelegation) GetStatus( // At this point we already have covenant quorum and inclusion proof, // we can check the status based on the BTC height - if btcHeight < d.StartHeight || btcHeight+d.UnbondingTime > d.EndHeight { + if btcHeight < d.StartHeight { // staking tx's timelock has not begun, or is less than unbonding time BTC - // blocks left, or is expired + // blocks left return BTCDelegationStatus_UNBONDED } + // if the endheight is lower than the btc height + unbonding time + // the btc delegation should be considered expired + if btcHeight+d.UnbondingTime > d.EndHeight { + return BTCDelegationStatus_EXPIRED + } + // - we have covenant quorum // - we have inclusion proof // - we are not unbonded early diff --git a/x/btcstaking/types/btcstaking.pb.go b/x/btcstaking/types/btcstaking.pb.go index 03eb03051..bef35b3f6 100644 --- a/x/btcstaking/types/btcstaking.pb.go +++ b/x/btcstaking/types/btcstaking.pb.go @@ -30,8 +30,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // BTCDelegationStatus is the status of a delegation. // There are two possible valid state transition paths for a BTC delegation: -// - PENDING -> ACTIVE -> UNBONDED -// - PENDING -> VERIFIED -> ACTIVE -> UNBONDED +// - PENDING -> ACTIVE -> UNBONDED -> EXPIRED +// - PENDING -> VERIFIED -> ACTIVE -> UNBONDED/EXPIRED // and one invalid state transition path: // - PENDING -> VERIFIED -> UNBONDED i.e the staker unbonded before // activating delegation on Babylon chain. @@ -48,12 +48,14 @@ const ( BTCDelegationStatus_VERIFIED BTCDelegationStatus = 1 // ACTIVE defines a delegation that has voting power BTCDelegationStatus_ACTIVE BTCDelegationStatus = 2 - // UNBONDED defines a delegation no longer has voting power: - // - either reaching the end of staking transaction timelock - // - or receiving unbonding tx with signatures from staker and covenant committee + // UNBONDED defines a delegation no longer has voting power + // by receiving unbonding tx with signatures from staker and covenant committee BTCDelegationStatus_UNBONDED BTCDelegationStatus = 3 + // EXPIRED defines a delegation no longer has voting power + // for reaching the end of staking transaction timelock + BTCDelegationStatus_EXPIRED BTCDelegationStatus = 4 // ANY is any of the above status - BTCDelegationStatus_ANY BTCDelegationStatus = 4 + BTCDelegationStatus_ANY BTCDelegationStatus = 5 ) var BTCDelegationStatus_name = map[int32]string{ @@ -61,7 +63,8 @@ var BTCDelegationStatus_name = map[int32]string{ 1: "VERIFIED", 2: "ACTIVE", 3: "UNBONDED", - 4: "ANY", + 4: "EXPIRED", + 5: "ANY", } var BTCDelegationStatus_value = map[string]int32{ @@ -69,7 +72,8 @@ var BTCDelegationStatus_value = map[string]int32{ "VERIFIED": 1, "ACTIVE": 2, "UNBONDED": 3, - "ANY": 4, + "EXPIRED": 4, + "ANY": 5, } func (x BTCDelegationStatus) String() string { @@ -927,94 +931,95 @@ func init() { } var fileDescriptor_3851ae95ccfaf7db = []byte{ - // 1388 bytes of a gzipped FileDescriptorProto + // 1398 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xdd, 0x6e, 0xdb, 0x46, - 0x16, 0x36, 0x25, 0xf9, 0xef, 0x48, 0xb2, 0x95, 0x89, 0xd6, 0xcb, 0xc4, 0x58, 0xdb, 0xab, 0xcd, - 0x06, 0xc2, 0x6e, 0x2c, 0xc5, 0x4e, 0x80, 0xcd, 0xb6, 0x68, 0x01, 0xcb, 0x72, 0x1a, 0xa1, 0x89, - 0xad, 0x52, 0xb2, 0x8b, 0x16, 0x28, 0x58, 0x8a, 0x1c, 0x53, 0x53, 0x49, 0x1c, 0x96, 0x33, 0x52, - 0xe5, 0xa7, 0x68, 0x0b, 0xf4, 0x21, 0xfa, 0x00, 0xb9, 0xec, 0x03, 0xe4, 0x32, 0x08, 0x7a, 0x51, - 0xf8, 0xc2, 0x28, 0x92, 0x17, 0x29, 0x66, 0x38, 0x22, 0x69, 0xd7, 0x4e, 0x9d, 0xd8, 0x77, 0x9c, - 0xf3, 0xf7, 0x1d, 0x7e, 0xe7, 0x9b, 0x19, 0x12, 0xee, 0x76, 0xac, 0xce, 0x51, 0x9f, 0x7a, 0xd5, - 0x0e, 0xb7, 0x19, 0xb7, 0x7a, 0xc4, 0x73, 0xab, 0xa3, 0x8d, 0xc4, 0xaa, 0xe2, 0x07, 0x94, 0x53, - 0xf4, 0x37, 0x15, 0x57, 0x49, 0x78, 0x46, 0x1b, 0xb7, 0x8b, 0x2e, 0x75, 0xa9, 0x8c, 0xa8, 0x8a, - 0xa7, 0x30, 0xf8, 0xf6, 0x2d, 0x9b, 0xb2, 0x01, 0x65, 0x66, 0xe8, 0x08, 0x17, 0xca, 0x75, 0x27, - 0x5c, 0x55, 0x63, 0xac, 0x0e, 0xe6, 0xd6, 0x46, 0xf5, 0x14, 0xda, 0xed, 0xd5, 0xf3, 0xbb, 0xf2, - 0xa9, 0xaf, 0x02, 0xee, 0x25, 0x02, 0xec, 0x2e, 0xb6, 0x7b, 0x3e, 0x25, 0x1e, 0x57, 0x9d, 0xc7, - 0x86, 0x30, 0xba, 0xf4, 0x53, 0x06, 0x0a, 0x8f, 0x89, 0x67, 0xf5, 0x09, 0x3f, 0x6a, 0x06, 0x74, - 0x44, 0x1c, 0x1c, 0xa0, 0x7b, 0x90, 0xb1, 0x1c, 0x27, 0xd0, 0xb5, 0x35, 0xad, 0x3c, 0x5f, 0xd3, - 0x5f, 0x3d, 0x5f, 0x2f, 0xaa, 0x4e, 0xb7, 0x1c, 0x27, 0xc0, 0x8c, 0xb5, 0x78, 0x40, 0x3c, 0xd7, - 0x90, 0x51, 0x68, 0x07, 0xb2, 0x0e, 0x66, 0x76, 0x40, 0x7c, 0x4e, 0xa8, 0xa7, 0xa7, 0xd6, 0xb4, - 0x72, 0x76, 0xf3, 0x5f, 0x15, 0x95, 0x11, 0x33, 0x22, 0xdf, 0xa6, 0x52, 0x8f, 0x43, 0x8d, 0x64, - 0x1e, 0x7a, 0x06, 0x60, 0xd3, 0xc1, 0x80, 0x30, 0x26, 0xaa, 0xa4, 0x25, 0xf4, 0xfa, 0xf1, 0xc9, - 0xea, 0x72, 0x58, 0x88, 0x39, 0xbd, 0x0a, 0xa1, 0xd5, 0x81, 0xc5, 0xbb, 0x95, 0xa7, 0xd8, 0xb5, - 0xec, 0xa3, 0x3a, 0xb6, 0x5f, 0x3d, 0x5f, 0x07, 0x85, 0x53, 0xc7, 0xb6, 0x91, 0x28, 0x80, 0xf6, - 0x60, 0xa6, 0xc3, 0x6d, 0xd3, 0xef, 0xe9, 0x99, 0x35, 0xad, 0x9c, 0xab, 0x3d, 0x3a, 0x3e, 0x59, - 0x7d, 0xe8, 0x12, 0xde, 0x1d, 0x76, 0x2a, 0x36, 0x1d, 0x54, 0x15, 0x4b, 0x7d, 0xab, 0xc3, 0xd6, - 0x09, 0x9d, 0x2c, 0xab, 0xfc, 0xc8, 0xc7, 0xac, 0x52, 0x6b, 0x34, 0x1f, 0x3c, 0xbc, 0xdf, 0x1c, - 0x76, 0x3e, 0xc5, 0x47, 0xc6, 0x74, 0x87, 0xdb, 0xcd, 0x1e, 0xfa, 0x08, 0xd2, 0x3e, 0xf5, 0xf5, - 0x69, 0xf9, 0x7a, 0xff, 0xad, 0x9c, 0x3b, 0xf4, 0x4a, 0x33, 0xa0, 0xf4, 0x70, 0xef, 0xb0, 0x49, - 0x19, 0xc3, 0xb2, 0x8f, 0x5a, 0x7b, 0xdb, 0x10, 0x79, 0xe8, 0x21, 0x2c, 0xb1, 0xbe, 0xc5, 0xba, - 0xd8, 0x31, 0x55, 0xaa, 0xd9, 0xc5, 0xc4, 0xed, 0x72, 0x7d, 0x66, 0x4d, 0x2b, 0x67, 0x8c, 0xa2, - 0xf2, 0xd6, 0x42, 0xe7, 0x13, 0xe9, 0x43, 0xf7, 0x00, 0x45, 0x59, 0xdc, 0x9e, 0x64, 0xcc, 0xae, - 0x69, 0xe5, 0xbc, 0x51, 0x98, 0x64, 0x70, 0x5b, 0x45, 0x2f, 0xc1, 0xcc, 0x37, 0x16, 0xe9, 0x63, - 0x47, 0x9f, 0x5b, 0xd3, 0xca, 0x73, 0x86, 0x5a, 0xa1, 0xfb, 0x50, 0xec, 0x12, 0xb7, 0x8b, 0x19, - 0x37, 0x47, 0x94, 0x63, 0x67, 0x52, 0x67, 0x5e, 0xd6, 0x41, 0xca, 0x77, 0x20, 0x5c, 0x61, 0xa5, - 0xd2, 0xaf, 0x29, 0xd0, 0xcf, 0xca, 0xe2, 0x73, 0xc2, 0xbb, 0xcf, 0x30, 0xb7, 0x12, 0xd4, 0x6a, - 0xd7, 0x43, 0xed, 0x12, 0xcc, 0xa8, 0x8e, 0x52, 0x92, 0x0b, 0xb5, 0x42, 0xff, 0x84, 0xdc, 0x88, - 0x72, 0xe2, 0xb9, 0xa6, 0x4f, 0xbf, 0xc3, 0x81, 0x14, 0x45, 0xc6, 0xc8, 0x86, 0xb6, 0xa6, 0x30, - 0xbd, 0x85, 0xd6, 0xcc, 0x3b, 0xd3, 0x3a, 0xfd, 0x97, 0xb4, 0xce, 0x5c, 0x8a, 0xd6, 0xd9, 0x0b, - 0x69, 0xfd, 0x65, 0x16, 0xf2, 0xb5, 0xf6, 0x76, 0x1d, 0xf7, 0xb1, 0x6b, 0x49, 0xd5, 0xff, 0x1f, - 0xb2, 0x42, 0x3e, 0x38, 0x30, 0x2f, 0xb5, 0xe3, 0x20, 0x0c, 0x16, 0xc6, 0xc4, 0x18, 0x52, 0xd7, - 0xaa, 0xf0, 0xf4, 0x7b, 0x2a, 0xfc, 0x2b, 0x58, 0x38, 0xf4, 0xcd, 0xb0, 0x25, 0xb3, 0x4f, 0x98, - 0x18, 0x41, 0xfa, 0x4a, 0x7d, 0x65, 0x0f, 0xfd, 0x9a, 0xe8, 0xec, 0x29, 0x61, 0x52, 0x0c, 0xaa, - 0x0d, 0x93, 0x93, 0x01, 0x56, 0xd3, 0xca, 0x2a, 0x5b, 0x9b, 0x0c, 0xb0, 0x0a, 0x09, 0x78, 0x72, - 0x67, 0x85, 0x21, 0x01, 0x57, 0xb3, 0xfc, 0x07, 0x00, 0xf6, 0xce, 0x4c, 0x6a, 0x1e, 0x7b, 0x6a, - 0x40, 0x68, 0x19, 0xe6, 0x39, 0xe5, 0x56, 0xdf, 0x64, 0x16, 0x97, 0x9b, 0x28, 0x63, 0xcc, 0x49, - 0x43, 0xcb, 0x92, 0xb9, 0x51, 0x07, 0x63, 0xb9, 0x79, 0x72, 0xc6, 0xfc, 0x04, 0x7f, 0x2c, 0x45, - 0xa5, 0xdc, 0x74, 0xc8, 0xfd, 0x21, 0x37, 0x89, 0x33, 0xd6, 0x41, 0x89, 0x2a, 0xf4, 0xec, 0x49, - 0x47, 0xc3, 0x19, 0xa3, 0x4d, 0xc8, 0x4a, 0xa1, 0xa9, 0x6a, 0x59, 0x39, 0xc2, 0x1b, 0xc7, 0x27, - 0xab, 0x42, 0x20, 0x2d, 0xe5, 0x69, 0x8f, 0x0d, 0x60, 0xd1, 0x33, 0xfa, 0x1a, 0xf2, 0x4e, 0x28, - 0x1d, 0x1a, 0x98, 0x8c, 0xb8, 0x7a, 0x4e, 0x66, 0x7d, 0x78, 0x7c, 0xb2, 0xfa, 0xbf, 0x77, 0x23, - 0xb8, 0x45, 0x5c, 0xcf, 0xe2, 0xc3, 0x00, 0x1b, 0xb9, 0xa8, 0x62, 0x8b, 0xb8, 0x68, 0x1f, 0xf2, - 0x36, 0x1d, 0x61, 0xcf, 0xf2, 0xb8, 0x00, 0x60, 0x7a, 0x7e, 0x2d, 0x5d, 0xce, 0x6e, 0xde, 0xbf, - 0x40, 0x0c, 0xdb, 0x2a, 0x76, 0xcb, 0xb1, 0xfc, 0xb0, 0x42, 0x58, 0x95, 0x19, 0xb9, 0x49, 0x99, - 0x16, 0x71, 0x19, 0xfa, 0x37, 0x2c, 0x0c, 0xbd, 0x0e, 0xf5, 0x9c, 0x68, 0x7a, 0x0b, 0x92, 0x96, - 0x7c, 0x64, 0x95, 0xf3, 0xfb, 0x0c, 0x0a, 0x42, 0x3e, 0x43, 0xcf, 0x89, 0x36, 0x88, 0xbe, 0x28, - 0xd5, 0x78, 0xf7, 0x82, 0x06, 0x6a, 0xed, 0xed, 0xfd, 0x44, 0xb4, 0xb1, 0xd8, 0xe1, 0x76, 0xd2, - 0x20, 0x90, 0x7d, 0x2b, 0xb0, 0x06, 0xcc, 0x1c, 0xe1, 0x40, 0xde, 0x2c, 0x85, 0x10, 0x39, 0xb4, - 0x1e, 0x84, 0x46, 0x74, 0x07, 0x16, 0x04, 0x32, 0x27, 0xfe, 0x44, 0x1a, 0x37, 0x64, 0x58, 0xae, - 0xc3, 0xed, 0x36, 0xf1, 0xd5, 0xf6, 0xfd, 0x18, 0x96, 0xea, 0x13, 0xb6, 0xf6, 0x27, 0x9d, 0x37, - 0xbc, 0x43, 0x2a, 0xf2, 0x99, 0x2f, 0x84, 0x25, 0xf7, 0xa7, 0x18, 0xa8, 0x3c, 0x1a, 0x8d, 0x9c, - 0xb4, 0xb6, 0x84, 0xb1, 0x3d, 0x2e, 0xfd, 0x98, 0x81, 0xc5, 0x33, 0x1d, 0x0b, 0xcd, 0x26, 0xa8, - 0x99, 0xe4, 0x65, 0x63, 0x62, 0xfe, 0x24, 0x95, 0xd4, 0x65, 0xa4, 0xf2, 0x2d, 0x2c, 0x25, 0xa4, - 0x32, 0xc9, 0x16, 0x9a, 0x49, 0x5f, 0x5d, 0x33, 0xc5, 0x58, 0x33, 0xaa, 0xb2, 0xd0, 0xce, 0x21, - 0x2c, 0xc5, 0xda, 0x49, 0x20, 0x32, 0x79, 0x0e, 0xbc, 0x8f, 0x88, 0x8a, 0x91, 0x88, 0x62, 0x18, - 0x86, 0x6c, 0x58, 0x8e, 0x70, 0x62, 0xea, 0x18, 0x71, 0xc3, 0x43, 0x67, 0x5a, 0x82, 0xdd, 0xb9, - 0x00, 0x2c, 0xaa, 0x2e, 0xc6, 0x66, 0xe8, 0x93, 0x42, 0xd1, 0x34, 0x5b, 0xc4, 0x95, 0xa7, 0x8d, - 0x0b, 0x7a, 0xcc, 0x5f, 0x8c, 0x42, 0xbc, 0x43, 0x2a, 0x8f, 0x95, 0xec, 0xe6, 0xfa, 0x05, 0x08, - 0xe7, 0x2b, 0xc4, 0x88, 0xc7, 0x71, 0xca, 0x5e, 0x6a, 0xc1, 0xdf, 0xe3, 0x1b, 0x81, 0x06, 0xf1, - 0xd5, 0xc0, 0xd0, 0x23, 0xc8, 0x38, 0xb8, 0xcf, 0x74, 0xed, 0xad, 0x6f, 0x74, 0xea, 0x3e, 0x31, - 0x64, 0x46, 0x69, 0x17, 0x96, 0xcf, 0x2f, 0xda, 0xf0, 0x1c, 0x3c, 0x46, 0x55, 0x28, 0xc6, 0x07, - 0x99, 0xd9, 0xb5, 0x58, 0x37, 0xa4, 0x4e, 0x00, 0xe5, 0x8c, 0x1b, 0xd1, 0x91, 0xf6, 0xc4, 0x62, - 0x5d, 0xc1, 0x46, 0xe9, 0x67, 0x0d, 0xf2, 0xa7, 0x98, 0x43, 0x4f, 0x20, 0x75, 0x0d, 0xf7, 0x7f, - 0xca, 0xef, 0xa1, 0x67, 0x90, 0x16, 0xb2, 0x4c, 0x5d, 0x5d, 0x96, 0xa2, 0x4e, 0xe9, 0x7b, 0x0d, - 0x6e, 0x5d, 0xa8, 0x28, 0x71, 0x67, 0xda, 0x74, 0x74, 0x2d, 0x9f, 0x2e, 0x36, 0x1d, 0x35, 0x7b, - 0x62, 0xfb, 0x5a, 0x21, 0x4a, 0x28, 0xf5, 0x94, 0xa4, 0x30, 0x6b, 0x45, 0xc8, 0xac, 0xf4, 0x42, - 0x83, 0x5b, 0x2d, 0xdc, 0xc7, 0x36, 0x27, 0x23, 0x3c, 0x51, 0xf2, 0x8e, 0xf8, 0xa4, 0xf2, 0x6c, - 0x8c, 0xee, 0xc2, 0xe2, 0x99, 0x59, 0x84, 0x1f, 0x01, 0x46, 0xfe, 0xd4, 0x18, 0x50, 0x1b, 0xe6, - 0xa3, 0xdb, 0xf5, 0xca, 0x17, 0xfe, 0xac, 0xba, 0x58, 0xd1, 0x3a, 0xdc, 0x0c, 0xb0, 0xd8, 0x04, - 0x01, 0x76, 0x4c, 0x55, 0x9f, 0xf5, 0xc2, 0x33, 0xc2, 0x28, 0x44, 0xae, 0xc7, 0x22, 0xbc, 0xd5, - 0x2b, 0x75, 0x60, 0xa1, 0xe1, 0xd9, 0xfd, 0xa1, 0x38, 0x33, 0xe5, 0x87, 0x00, 0xfa, 0x00, 0xd2, - 0x3d, 0x7c, 0x24, 0x5b, 0xce, 0x6e, 0x96, 0x93, 0x12, 0x4d, 0xfc, 0x6a, 0x8c, 0x36, 0x2a, 0xed, - 0xc0, 0xf2, 0x98, 0x65, 0x0b, 0x0d, 0x8a, 0x06, 0x44, 0x12, 0x2a, 0xc2, 0xb4, 0x2f, 0x8a, 0x84, - 0xaf, 0x63, 0x84, 0x8b, 0xff, 0xb4, 0xe0, 0xe6, 0x29, 0x49, 0xb7, 0xb8, 0xc5, 0x87, 0x0c, 0x65, - 0x61, 0xb6, 0xb9, 0xb3, 0x5b, 0x6f, 0xec, 0x7e, 0x52, 0x98, 0x42, 0x39, 0x98, 0x3b, 0xd8, 0x31, - 0x1a, 0x8f, 0x1b, 0x3b, 0xf5, 0x82, 0x86, 0x00, 0x66, 0xb6, 0xb6, 0xdb, 0x8d, 0x83, 0x9d, 0x42, - 0x4a, 0x78, 0xf6, 0x77, 0x6b, 0x7b, 0xbb, 0xf5, 0x9d, 0x7a, 0x21, 0x8d, 0x66, 0x21, 0xbd, 0xb5, - 0xfb, 0x45, 0x21, 0x53, 0xdb, 0x7d, 0xf1, 0x7a, 0x45, 0x7b, 0xf9, 0x7a, 0x45, 0xfb, 0xfd, 0xf5, - 0x8a, 0xf6, 0xc3, 0x9b, 0x95, 0xa9, 0x97, 0x6f, 0x56, 0xa6, 0x7e, 0x7b, 0xb3, 0x32, 0xf5, 0xe5, - 0x25, 0x08, 0x1c, 0x27, 0xff, 0xb5, 0x24, 0x9b, 0x9d, 0x19, 0xf9, 0xf7, 0xf4, 0xe0, 0x8f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x69, 0x4c, 0x8a, 0x3d, 0x24, 0x0e, 0x00, 0x00, + 0x16, 0x36, 0x25, 0xf9, 0xef, 0x48, 0xb2, 0x95, 0x89, 0xd6, 0xab, 0xc4, 0x58, 0xdb, 0xab, 0xcd, + 0x06, 0x42, 0x1b, 0x4b, 0xb1, 0x13, 0xa0, 0x69, 0x8b, 0x16, 0xb0, 0x2c, 0xa5, 0x11, 0x9a, 0xd8, + 0x2a, 0x25, 0xbb, 0x3f, 0x40, 0xc1, 0x50, 0xe4, 0x98, 0x9a, 0x4a, 0xe2, 0xb0, 0x9c, 0x91, 0x2a, + 0x3f, 0x45, 0x5b, 0xa0, 0x0f, 0xd1, 0x07, 0xc8, 0x65, 0x1f, 0x20, 0x97, 0x41, 0xd0, 0x8b, 0xc2, + 0x17, 0x46, 0x91, 0xbc, 0x48, 0x31, 0xc3, 0x11, 0x49, 0xbb, 0x76, 0xea, 0xc4, 0xbe, 0xe3, 0x9c, + 0xbf, 0xef, 0xf0, 0x3b, 0xdf, 0xcc, 0x90, 0x70, 0xbb, 0x63, 0x76, 0x0e, 0xfb, 0xd4, 0xad, 0x74, + 0xb8, 0xc5, 0xb8, 0xd9, 0x23, 0xae, 0x53, 0x19, 0x6d, 0xc4, 0x56, 0x65, 0xcf, 0xa7, 0x9c, 0xa2, + 0x7f, 0xa9, 0xb8, 0x72, 0xcc, 0x33, 0xda, 0xb8, 0x99, 0x77, 0xa8, 0x43, 0x65, 0x44, 0x45, 0x3c, + 0x05, 0xc1, 0x37, 0x6f, 0x58, 0x94, 0x0d, 0x28, 0x33, 0x02, 0x47, 0xb0, 0x50, 0xae, 0x5b, 0xc1, + 0xaa, 0x12, 0x61, 0x75, 0x30, 0x37, 0x37, 0x2a, 0x27, 0xd0, 0x6e, 0xae, 0x9e, 0xdd, 0x95, 0x47, + 0x3d, 0x15, 0x70, 0x27, 0x16, 0x60, 0x75, 0xb1, 0xd5, 0xf3, 0x28, 0x71, 0xb9, 0xea, 0x3c, 0x32, + 0x04, 0xd1, 0xc5, 0x5f, 0x52, 0x90, 0x7b, 0x48, 0x5c, 0xb3, 0x4f, 0xf8, 0x61, 0xd3, 0xa7, 0x23, + 0x62, 0x63, 0x1f, 0xdd, 0x81, 0x94, 0x69, 0xdb, 0x7e, 0x41, 0x5b, 0xd3, 0x4a, 0xf3, 0xd5, 0xc2, + 0xcb, 0x67, 0xeb, 0x79, 0xd5, 0xe9, 0x96, 0x6d, 0xfb, 0x98, 0xb1, 0x16, 0xf7, 0x89, 0xeb, 0xe8, + 0x32, 0x0a, 0xd5, 0x21, 0x6d, 0x63, 0x66, 0xf9, 0xc4, 0xe3, 0x84, 0xba, 0x85, 0xc4, 0x9a, 0x56, + 0x4a, 0x6f, 0xfe, 0xaf, 0xac, 0x32, 0x22, 0x46, 0xe4, 0xdb, 0x94, 0x6b, 0x51, 0xa8, 0x1e, 0xcf, + 0x43, 0x4f, 0x00, 0x2c, 0x3a, 0x18, 0x10, 0xc6, 0x44, 0x95, 0xa4, 0x84, 0x5e, 0x3f, 0x3a, 0x5e, + 0x5d, 0x0e, 0x0a, 0x31, 0xbb, 0x57, 0x26, 0xb4, 0x32, 0x30, 0x79, 0xb7, 0xfc, 0x18, 0x3b, 0xa6, + 0x75, 0x58, 0xc3, 0xd6, 0xcb, 0x67, 0xeb, 0xa0, 0x70, 0x6a, 0xd8, 0xd2, 0x63, 0x05, 0xd0, 0x2e, + 0xcc, 0x74, 0xb8, 0x65, 0x78, 0xbd, 0x42, 0x6a, 0x4d, 0x2b, 0x65, 0xaa, 0x0f, 0x8e, 0x8e, 0x57, + 0xef, 0x3b, 0x84, 0x77, 0x87, 0x9d, 0xb2, 0x45, 0x07, 0x15, 0xc5, 0x52, 0xdf, 0xec, 0xb0, 0x75, + 0x42, 0x27, 0xcb, 0x0a, 0x3f, 0xf4, 0x30, 0x2b, 0x57, 0x1b, 0xcd, 0x7b, 0xf7, 0xef, 0x36, 0x87, + 0x9d, 0xcf, 0xf1, 0xa1, 0x3e, 0xdd, 0xe1, 0x56, 0xb3, 0x87, 0x3e, 0x81, 0xa4, 0x47, 0xbd, 0xc2, + 0xb4, 0x7c, 0xbd, 0xf7, 0xcb, 0x67, 0x0e, 0xbd, 0xdc, 0xf4, 0x29, 0x3d, 0xd8, 0x3d, 0x68, 0x52, + 0xc6, 0xb0, 0xec, 0xa3, 0xda, 0xde, 0xd6, 0x45, 0x1e, 0xba, 0x0f, 0x4b, 0xac, 0x6f, 0xb2, 0x2e, + 0xb6, 0x0d, 0x95, 0x6a, 0x74, 0x31, 0x71, 0xba, 0xbc, 0x30, 0xb3, 0xa6, 0x95, 0x52, 0x7a, 0x5e, + 0x79, 0xab, 0x81, 0xf3, 0x91, 0xf4, 0xa1, 0x3b, 0x80, 0xc2, 0x2c, 0x6e, 0x4d, 0x32, 0x66, 0xd7, + 0xb4, 0x52, 0x56, 0xcf, 0x4d, 0x32, 0xb8, 0xa5, 0xa2, 0x97, 0x60, 0xe6, 0x3b, 0x93, 0xf4, 0xb1, + 0x5d, 0x98, 0x5b, 0xd3, 0x4a, 0x73, 0xba, 0x5a, 0xa1, 0xbb, 0x90, 0xef, 0x12, 0xa7, 0x8b, 0x19, + 0x37, 0x46, 0x94, 0x63, 0x7b, 0x52, 0x67, 0x5e, 0xd6, 0x41, 0xca, 0xb7, 0x2f, 0x5c, 0x41, 0xa5, + 0xe2, 0xef, 0x09, 0x28, 0x9c, 0x96, 0xc5, 0x97, 0x84, 0x77, 0x9f, 0x60, 0x6e, 0xc6, 0xa8, 0xd5, + 0xae, 0x86, 0xda, 0x25, 0x98, 0x51, 0x1d, 0x25, 0x24, 0x17, 0x6a, 0x85, 0xfe, 0x0b, 0x99, 0x11, + 0xe5, 0xc4, 0x75, 0x0c, 0x8f, 0xfe, 0x80, 0x7d, 0x29, 0x8a, 0x94, 0x9e, 0x0e, 0x6c, 0x4d, 0x61, + 0x7a, 0x03, 0xad, 0xa9, 0xb7, 0xa6, 0x75, 0xfa, 0x1f, 0x69, 0x9d, 0xb9, 0x10, 0xad, 0xb3, 0xe7, + 0xd2, 0xfa, 0xdb, 0x2c, 0x64, 0xab, 0xed, 0xed, 0x1a, 0xee, 0x63, 0xc7, 0x94, 0xaa, 0xff, 0x10, + 0xd2, 0x42, 0x3e, 0xd8, 0x37, 0x2e, 0xb4, 0xe3, 0x20, 0x08, 0x16, 0xc6, 0xd8, 0x18, 0x12, 0x57, + 0xaa, 0xf0, 0xe4, 0x3b, 0x2a, 0xfc, 0x5b, 0x58, 0x38, 0xf0, 0x8c, 0xa0, 0x25, 0xa3, 0x4f, 0x98, + 0x18, 0x41, 0xf2, 0x52, 0x7d, 0xa5, 0x0f, 0xbc, 0xaa, 0xe8, 0xec, 0x31, 0x61, 0x52, 0x0c, 0xaa, + 0x0d, 0x83, 0x93, 0x01, 0x56, 0xd3, 0x4a, 0x2b, 0x5b, 0x9b, 0x0c, 0xb0, 0x0a, 0xf1, 0x79, 0x7c, + 0x67, 0x05, 0x21, 0x3e, 0x57, 0xb3, 0xfc, 0x0f, 0x00, 0x76, 0x4f, 0x4d, 0x6a, 0x1e, 0xbb, 0x6a, + 0x40, 0x68, 0x19, 0xe6, 0x39, 0xe5, 0x66, 0xdf, 0x60, 0x26, 0x97, 0x9b, 0x28, 0xa5, 0xcf, 0x49, + 0x43, 0xcb, 0x94, 0xb9, 0x61, 0x07, 0x63, 0xb9, 0x79, 0x32, 0xfa, 0xfc, 0x04, 0x7f, 0x2c, 0x45, + 0xa5, 0xdc, 0x74, 0xc8, 0xbd, 0x21, 0x37, 0x88, 0x3d, 0x2e, 0x80, 0x12, 0x55, 0xe0, 0xd9, 0x95, + 0x8e, 0x86, 0x3d, 0x46, 0x9b, 0x90, 0x96, 0x42, 0x53, 0xd5, 0xd2, 0x72, 0x84, 0xd7, 0x8e, 0x8e, + 0x57, 0x85, 0x40, 0x5a, 0xca, 0xd3, 0x1e, 0xeb, 0xc0, 0xc2, 0x67, 0xf4, 0x14, 0xb2, 0x76, 0x20, + 0x1d, 0xea, 0x1b, 0x8c, 0x38, 0x85, 0x8c, 0xcc, 0xfa, 0xf8, 0xe8, 0x78, 0xf5, 0x83, 0xb7, 0x23, + 0xb8, 0x45, 0x1c, 0xd7, 0xe4, 0x43, 0x1f, 0xeb, 0x99, 0xb0, 0x62, 0x8b, 0x38, 0x68, 0x0f, 0xb2, + 0x16, 0x1d, 0x61, 0xd7, 0x74, 0xb9, 0x00, 0x60, 0x85, 0xec, 0x5a, 0xb2, 0x94, 0xde, 0xbc, 0x7b, + 0x8e, 0x18, 0xb6, 0x55, 0xec, 0x96, 0x6d, 0x7a, 0x41, 0x85, 0xa0, 0x2a, 0xd3, 0x33, 0x93, 0x32, + 0x2d, 0xe2, 0x30, 0xf4, 0x7f, 0x58, 0x18, 0xba, 0x1d, 0xea, 0xda, 0xe1, 0xf4, 0x16, 0x24, 0x2d, + 0xd9, 0xd0, 0x2a, 0xe7, 0xf7, 0x05, 0xe4, 0x84, 0x7c, 0x86, 0xae, 0x1d, 0x6e, 0x90, 0xc2, 0xa2, + 0x54, 0xe3, 0xed, 0x73, 0x1a, 0xa8, 0xb6, 0xb7, 0xf7, 0x62, 0xd1, 0xfa, 0x62, 0x87, 0x5b, 0x71, + 0x83, 0x40, 0xf6, 0x4c, 0xdf, 0x1c, 0x30, 0x63, 0x84, 0x7d, 0x79, 0xb3, 0xe4, 0x02, 0xe4, 0xc0, + 0xba, 0x1f, 0x18, 0xd1, 0x2d, 0x58, 0x10, 0xc8, 0x9c, 0x78, 0x13, 0x69, 0x5c, 0x93, 0x61, 0x99, + 0x0e, 0xb7, 0xda, 0xc4, 0x53, 0xdb, 0xf7, 0x53, 0x58, 0xaa, 0x4d, 0xd8, 0xda, 0x9b, 0x74, 0xde, + 0x70, 0x0f, 0xa8, 0xc8, 0x67, 0x9e, 0x10, 0x96, 0xdc, 0x9f, 0x62, 0xa0, 0xf2, 0x68, 0xd4, 0x33, + 0xd2, 0xda, 0x12, 0xc6, 0xf6, 0xb8, 0xf8, 0x73, 0x0a, 0x16, 0x4f, 0x75, 0x2c, 0x34, 0x1b, 0xa3, + 0x66, 0x92, 0x97, 0x8e, 0x88, 0xf9, 0x9b, 0x54, 0x12, 0x17, 0x91, 0xca, 0xf7, 0xb0, 0x14, 0x93, + 0xca, 0x24, 0x5b, 0x68, 0x26, 0x79, 0x79, 0xcd, 0xe4, 0x23, 0xcd, 0xa8, 0xca, 0x42, 0x3b, 0x07, + 0xb0, 0x14, 0x69, 0x27, 0x86, 0xc8, 0xe4, 0x39, 0xf0, 0x2e, 0x22, 0xca, 0x87, 0x22, 0x8a, 0x60, + 0x18, 0xb2, 0x60, 0x39, 0xc4, 0x89, 0xa8, 0x63, 0xc4, 0x09, 0x0e, 0x9d, 0x69, 0x09, 0x76, 0xeb, + 0x1c, 0xb0, 0xb0, 0xba, 0x18, 0x9b, 0x5e, 0x98, 0x14, 0x0a, 0xa7, 0xd9, 0x22, 0x8e, 0x3c, 0x6d, + 0x1c, 0x28, 0x44, 0xfc, 0x45, 0x28, 0xc4, 0x3d, 0xa0, 0xf2, 0x58, 0x49, 0x6f, 0xae, 0x9f, 0x83, + 0x70, 0xb6, 0x42, 0xf4, 0x68, 0x1c, 0x27, 0xec, 0xc5, 0x16, 0xfc, 0x3b, 0xba, 0x11, 0xa8, 0x1f, + 0x5d, 0x0d, 0x0c, 0x3d, 0x80, 0x94, 0x8d, 0xfb, 0xac, 0xa0, 0xbd, 0xf1, 0x8d, 0x4e, 0xdc, 0x27, + 0xba, 0xcc, 0x28, 0xee, 0xc0, 0xf2, 0xd9, 0x45, 0x1b, 0xae, 0x8d, 0xc7, 0xa8, 0x02, 0xf9, 0xe8, + 0x20, 0x33, 0xba, 0x26, 0xeb, 0x06, 0xd4, 0x09, 0xa0, 0x8c, 0x7e, 0x2d, 0x3c, 0xd2, 0x1e, 0x99, + 0xac, 0x2b, 0xd8, 0x28, 0xfe, 0xaa, 0x41, 0xf6, 0x04, 0x73, 0xe8, 0x11, 0x24, 0xae, 0xe0, 0xfe, + 0x4f, 0x78, 0x3d, 0xf4, 0x04, 0x92, 0x42, 0x96, 0x89, 0xcb, 0xcb, 0x52, 0xd4, 0x29, 0xfe, 0xa8, + 0xc1, 0x8d, 0x73, 0x15, 0x25, 0xee, 0x4c, 0x8b, 0x8e, 0xae, 0xe4, 0xd3, 0xc5, 0xa2, 0xa3, 0x66, + 0x4f, 0x6c, 0x5f, 0x33, 0x40, 0x09, 0xa4, 0x9e, 0x90, 0x14, 0xa6, 0xcd, 0x10, 0x99, 0x15, 0x9f, + 0x6b, 0x70, 0xa3, 0x85, 0xfb, 0xd8, 0xe2, 0x64, 0x84, 0x27, 0x4a, 0xae, 0x8b, 0x4f, 0x2a, 0xd7, + 0xc2, 0xe8, 0x36, 0x2c, 0x9e, 0x9a, 0x45, 0xf0, 0x11, 0xa0, 0x67, 0x4f, 0x8c, 0x01, 0xb5, 0x61, + 0x3e, 0xbc, 0x5d, 0x2f, 0x7d, 0xe1, 0xcf, 0xaa, 0x8b, 0x15, 0xad, 0xc3, 0x75, 0x1f, 0x8b, 0x4d, + 0xe0, 0x63, 0xdb, 0x50, 0xf5, 0x59, 0x2f, 0x38, 0x23, 0xf4, 0x5c, 0xe8, 0x7a, 0x28, 0xc2, 0x5b, + 0xbd, 0x62, 0x07, 0x16, 0x1a, 0xae, 0xd5, 0x1f, 0x8a, 0x33, 0x53, 0x7e, 0x08, 0xa0, 0x8f, 0x20, + 0xd9, 0xc3, 0x87, 0xb2, 0xe5, 0xf4, 0x66, 0x29, 0x2e, 0xd1, 0xd8, 0xaf, 0xc6, 0x68, 0xa3, 0xdc, + 0xf6, 0x4d, 0x97, 0x99, 0x96, 0xd0, 0xa0, 0x68, 0x40, 0x24, 0xa1, 0x3c, 0x4c, 0x7b, 0xa2, 0x48, + 0xf0, 0x3a, 0x7a, 0xb0, 0x78, 0xef, 0x29, 0x5c, 0x3f, 0x21, 0xe9, 0x16, 0x37, 0xf9, 0x90, 0xa1, + 0x34, 0xcc, 0x36, 0xeb, 0x3b, 0xb5, 0xc6, 0xce, 0x67, 0xb9, 0x29, 0x94, 0x81, 0xb9, 0xfd, 0xba, + 0xde, 0x78, 0xd8, 0xa8, 0xd7, 0x72, 0x1a, 0x02, 0x98, 0xd9, 0xda, 0x6e, 0x37, 0xf6, 0xeb, 0xb9, + 0x84, 0xf0, 0xec, 0xed, 0x54, 0x77, 0x77, 0x6a, 0xf5, 0x5a, 0x2e, 0x29, 0x92, 0xea, 0x5f, 0x35, + 0x1b, 0x7a, 0xbd, 0x96, 0x4b, 0xa1, 0x59, 0x48, 0x6e, 0xed, 0x7c, 0x9d, 0x9b, 0xae, 0xee, 0x3c, + 0x7f, 0xb5, 0xa2, 0xbd, 0x78, 0xb5, 0xa2, 0xfd, 0xf9, 0x6a, 0x45, 0xfb, 0xe9, 0xf5, 0xca, 0xd4, + 0x8b, 0xd7, 0x2b, 0x53, 0x7f, 0xbc, 0x5e, 0x99, 0xfa, 0xe6, 0x02, 0x6c, 0x8e, 0xe3, 0x3f, 0x5e, + 0x92, 0xda, 0xce, 0x8c, 0xfc, 0x95, 0xba, 0xf7, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf6, 0xf0, + 0x69, 0x33, 0x31, 0x0e, 0x00, 0x00, } func (m *FinalityProvider) Marshal() (dAtA []byte, err error) { diff --git a/x/btcstaking/types/events.go b/x/btcstaking/types/events.go index 55a476e7e..73b087676 100644 --- a/x/btcstaking/types/events.go +++ b/x/btcstaking/types/events.go @@ -141,7 +141,7 @@ func NewExpiredDelegationEvent( ) *EventBTCDelegationExpired { return &EventBTCDelegationExpired{ StakingTxHash: stakingTxHash, - NewState: BTCDelegationStatus_UNBONDED.String(), + NewState: BTCDelegationStatus_EXPIRED.String(), } } diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 648c11e6b..94d0d3ac2 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -176,7 +176,7 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // of BTC delegations that newly become active under this provider activeBTCDels := map[string][]*types.BTCDelegation{} // a map where key is unbonded BTC delegation's staking tx hash - unbondedBTCDels := map[string]*btcDelWithStkTxHash{} + unbondedBTCDels := map[string]struct{}{} // a map where key is slashed finality providers' BTC PK slashedFPs := map[string]struct{}{} // a map where key is jailed finality providers' BTC PK @@ -216,13 +216,18 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( } newActiveBtcDels = append(newActiveBtcDels, btcDelWithStkTxHash) case types.BTCDelegationStatus_UNBONDED: - // emit expired event if it is not early unbonding + newUnbondedBtcDels = append(newUnbondedBtcDels, btcDelWithStkTxHash) + // add the unbonded BTC delegation to the map + unbondedBTCDels[delStkTxHash] = struct{}{} + case types.BTCDelegationStatus_EXPIRED: + types.EmitExpiredDelegationEvent(sdkCtx, delStkTxHash) + if !btcDel.IsUnbondedEarly() { - types.EmitExpiredDelegationEvent(sdkCtx, delStkTxHash) + // only adds to the new unbonded list if it hasn't + // previously unbonded with types.BTCDelegationStatus_UNBONDED + newUnbondedBtcDels = append(newUnbondedBtcDels, btcDelWithStkTxHash) + unbondedBTCDels[delStkTxHash] = struct{}{} } - - // add the unbonded BTC delegation to the map - unbondedBTCDels[delStkTxHash] = btcDelWithStkTxHash } case *types.EventPowerDistUpdate_SlashedFp: // record slashed fps @@ -285,14 +290,8 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( for j := range dc.FinalityProviders[i].BtcDels { btcDel := *dc.FinalityProviders[i].BtcDels[j] - btcDelUnbondedWithStkTxHash, isUnbondedBtcDelegation := unbondedBTCDels[btcDel.StakingTxHash] + _, isUnbondedBtcDelegation := unbondedBTCDels[btcDel.StakingTxHash] if isUnbondedBtcDelegation { - // the list of new unbonded BTC delegations needs to be added - // at this point, due to possible duplication of Unbonding BTC events - // Early unbond and expiration. When the unbonded BTC delegation is - // processed the seccond time, the FP already doesn't have this delegation - // inside their FinalityProviderDistInfo.BtcDels list. - newUnbondedBtcDels = append(newUnbondedBtcDels, btcDelUnbondedWithStkTxHash) continue } // if it is not unbonded add to the del dist info diff --git a/x/finality/keeper/power_dist_change_test.go b/x/finality/keeper/power_dist_change_test.go index 932718f62..4a2d1a623 100644 --- a/x/finality/keeper/power_dist_change_test.go +++ b/x/finality/keeper/power_dist_change_test.go @@ -421,6 +421,7 @@ func FuzzBTCDelegationEvents_NoPreApproval(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) f.Fuzz(func(t *testing.T, seed int64) { + t.Parallel() r := rand.New(rand.NewSource(seed)) ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -469,14 +470,14 @@ func FuzzBTCDelegationEvents_NoPreApproval(f *testing.F) { events := h.BTCStakingKeeper.GetAllPowerDistUpdateEvents(h.Ctx, btcTip.Height, btcTip.Height) require.Len(t, events, 0) - // the BTC delegation will be unbonded at end height - unbonding_time + // the BTC delegation will be expired at end height - unbonding_time unbondedHeight := actualDel.EndHeight - stakingParams.UnbondingTimeBlocks events = h.BTCStakingKeeper.GetAllPowerDistUpdateEvents(h.Ctx, unbondedHeight, unbondedHeight) require.Len(t, events, 1) btcDelStateUpdate := events[0].GetBtcDelStateUpdate() require.NotNil(t, btcDelStateUpdate) require.Equal(t, stakingTxHash, btcDelStateUpdate.StakingTxHash) - require.Equal(t, types.BTCDelegationStatus_UNBONDED, btcDelStateUpdate.NewState) + require.Equal(t, types.BTCDelegationStatus_EXPIRED, btcDelStateUpdate.NewState) // ensure this finality provider does not have voting power at the current height babylonHeight := datagen.RandomInt(r, 10) + 1 @@ -625,7 +626,7 @@ func FuzzBTCDelegationEvents_WithPreApproval(f *testing.F) { btcDelStateUpdate = events[0].GetBtcDelStateUpdate() require.NotNil(t, btcDelStateUpdate) require.Equal(t, stakingTxHash, btcDelStateUpdate.StakingTxHash) - require.Equal(t, types.BTCDelegationStatus_UNBONDED, btcDelStateUpdate.NewState) + require.Equal(t, types.BTCDelegationStatus_EXPIRED, btcDelStateUpdate.NewState) // ensure this finality provider does not have voting power at the current height // due to no timestamped randomness @@ -664,6 +665,7 @@ func FuzzBTCDelegationEvents_WithPreApproval(f *testing.F) { } func TestDoNotGenerateDuplicateEventsAfterHavingCovenantQuorum(t *testing.T) { + t.Parallel() r := rand.New(rand.NewSource(time.Now().UnixNano())) ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -710,14 +712,14 @@ func TestDoNotGenerateDuplicateEventsAfterHavingCovenantQuorum(t *testing.T) { events := h.BTCStakingKeeper.GetAllPowerDistUpdateEvents(h.Ctx, btcTip.Height, btcTip.Height) require.Len(t, events, 0) - // the BTC delegation will be unbonded at end height - unbonding_time + // the BTC delegation will be expired (unbonded) at end height - unbonding_time unbondedHeight := actualDel.EndHeight - stakingParams.UnbondingTimeBlocks events = h.BTCStakingKeeper.GetAllPowerDistUpdateEvents(h.Ctx, unbondedHeight, unbondedHeight) require.Len(t, events, 1) btcDelStateUpdate := events[0].GetBtcDelStateUpdate() require.NotNil(t, btcDelStateUpdate) require.Equal(t, expectedStakingTxHash, btcDelStateUpdate.StakingTxHash) - require.Equal(t, types.BTCDelegationStatus_UNBONDED, btcDelStateUpdate.NewState) + require.Equal(t, types.BTCDelegationStatus_EXPIRED, btcDelStateUpdate.NewState) // ensure this finality provider does not have voting power at the current height babylonHeight := datagen.RandomInt(r, 10) + 1 From b3decf70c61c7615bb569f0d16146402bda34aee Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Tue, 17 Dec 2024 23:05:41 -0300 Subject: [PATCH 086/132] chore: add new e2e test that currently fails to activate finality --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ Makefile | 3 +++ test/e2e/e2e_test.go | 4 ++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76942b528..e6064f8cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -138,6 +138,28 @@ jobs: run: | make test-e2e-cache-btc-staking + e2e-run-btc-rewards: + needs: [e2e-docker-build-babylon] + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Download babylon artifact + uses: actions/download-artifact@v4 + with: + name: babylond-${{ github.sha }} + path: /tmp + - name: Docker load babylond + run: | + docker load < /tmp/docker-babylond.tar.gz + - name: Cache Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + - name: Run e2e TestBTCRewardsDistribution + run: | + make test-e2e-cache-btc-rewards + e2e-run-btc-staking-pre-approval: needs: [e2e-docker-build-babylon] runs-on: ubuntu-22.04 diff --git a/Makefile b/Makefile index 58415f25f..5083406e3 100644 --- a/Makefile +++ b/Makefile @@ -280,6 +280,9 @@ test-e2e-cache-btc-timestamping-phase-2-rly: test-e2e-cache-btc-staking: go test -run TestBTCStakingTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e +test-e2e-cache-btc-rewards: + go test -run TestBTCRewardsDistribution -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e + test-e2e-cache-btc-staking-pre-approval: go test -run TestBTCStakingPreApprovalTestSuite -mod=readonly -timeout=60m -v $(PACKAGES_E2E) --tags=e2e diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 68773fe4a..8af894aa0 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -24,9 +24,9 @@ func TestBTCStakingTestSuite(t *testing.T) { suite.Run(t, new(BTCStakingTestSuite)) } -// TestRewardsDistributionBTC tests BTC staking rewards distribution end-to-end +// TestBTCRewardsDistribution tests BTC staking rewards distribution end-to-end // that involves x/btcstaking, x/finality, x/incentives and x/mint to give out rewards. -func TestRewardsDistributionBTC(t *testing.T) { +func TestBTCRewardsDistribution(t *testing.T) { suite.Run(t, new(BtcRewardsDistribution)) } From bdf7c153d3d84f763b93fa41797074a7f627f933 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 18 Dec 2024 09:03:06 -0300 Subject: [PATCH 087/132] fix: set btc delegations to active prior to commit pub rand and check if btcstaking is active --- test/e2e/btc_rewards_distribution_e2e_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index fe0556c31..eaf8987b3 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -182,9 +182,9 @@ func (s *BtcRewardsDistribution) Test3SubmitCovenantSignature() { } } -// Test3CommitPublicRandomnessAndSealed commits public randomness for +// Test4CommitPublicRandomnessAndSealed commits public randomness for // each finality provider and seals the epoch. -func (s *BtcRewardsDistribution) Test3CommitPublicRandomnessAndSealed() { +func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { chainA := s.configurer.GetChainConfig(0) n1, err := chainA.GetNodeAtIndex(1) s.NoError(err) From 8d324ddf3dbc9d1a069a68245998c64945b0f70e Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 18 Dec 2024 10:02:31 -0300 Subject: [PATCH 088/132] chore: add check for rewards amounts --- test/e2e/btc_rewards_distribution_e2e_test.go | 111 ++++++++++++++---- test/e2e/configurer/chain/queries.go | 3 +- 2 files changed, 87 insertions(+), 27 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index eaf8987b3..669ad5498 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -7,17 +7,21 @@ import ( "testing" "time" + sdkmath "cosmossdk.io/math" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/chaincfg" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/babylonlabs-io/babylon/test/e2e/configurer" "github.com/babylonlabs-io/babylon/test/e2e/configurer/chain" + "github.com/babylonlabs-io/babylon/testutil/coins" "github.com/babylonlabs-io/babylon/testutil/datagen" bbn "github.com/babylonlabs-io/babylon/types" bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" ftypes "github.com/babylonlabs-io/babylon/x/finality/types" + itypes "github.com/babylonlabs-io/babylon/x/incentive/types" ) type BtcRewardsDistribution struct { @@ -73,7 +77,7 @@ func (s *BtcRewardsDistribution) SetupSuite() { s.del1BTCSK, _, _ = datagen.GenRandomBTCKeyPair(s.r) s.del2BTCSK, _, _ = datagen.GenRandomBTCKeyPair(s.r) - s.fp1Del1StakingAmt = int64(9 * 10e8) + s.fp1Del1StakingAmt = int64(2 * 10e8) s.fp1Del2StakingAmt = int64(4 * 10e8) s.fp2Del1StakingAmt = int64(2 * 10e8) s.fp2Del2StakingAmt = int64(6 * 10e8) @@ -200,6 +204,9 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { fp1RandListInfo, fp1CommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp1BTCSK, commitStartHeight, numPubRand) s.NoError(err) + fp2RandListInfo, fp2CommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp2BTCSK, commitStartHeight, numPubRand) + s.NoError(err) + n1.CommitPubRandList( fp1CommitPubRandList.FpBtcPk, fp1CommitPubRandList.StartHeight, @@ -208,13 +215,6 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { fp1CommitPubRandList.Sig, ) - n1.WaitUntilCurrentEpochIsSealedAndFinalized() - - // activated height is never returned - activatedHeight := n1.WaitFinalityIsActivated() - - fp2RandListInfo, fp2CommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp2BTCSK, commitStartHeight, numPubRand) - s.NoError(err) n2.CommitPubRandList( fp2CommitPubRandList.FpBtcPk, fp2CommitPubRandList.StartHeight, @@ -222,10 +222,13 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { fp2CommitPubRandList.Commitment, fp2CommitPubRandList.Sig, ) - // latestBlock := n1.LatestBlockNumber() - /* - submit finality signature - */ + + n1.WaitUntilCurrentEpochIsSealedAndFinalized() + + // activated height is never returned + activatedHeight := n1.WaitFinalityIsActivated() + + // submit finality signature idx := activatedHeight - commitStartHeight appHash := n1.AddFinalitySignatureToBlock( @@ -256,20 +259,78 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { s.Equal(activatedHeight, finalizedBlocks[0].Height) s.Equal(appHash.Bytes(), finalizedBlocks[0].AppHash) s.T().Logf("the block %d is finalized", activatedHeight) +} + +// Test5CheckRewardsFirstDelegations verifies the rewards independent of mint amounts +func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { + n1, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(1) + s.NoError(err) + + // comments on ubbn amounts are for the following mint config + // babylond q mint inflation + // 0.080000000000000000 + // babylond q mint annual-provisions + // 720000000000.000000000000000000 + + // Current setup of voting power + // (fp1, del1) => 2_00000000 + // (fp1, del2) => 4_00000000 + // (fp2, del1) => 2_00000000 + + // The sum per bech32 address will be + // (fp1) => 6_00000000 + // (fp2) => 2_00000000 + // (del1) => 4_00000000 + // (del2) => 4_00000000 + + // The rewards distributed for the finality providers should be fp1 => 3x, fp2 => 1x + fp1RewardGauges, err := n1.QueryRewardGauge(s.fp1.Address()) + s.NoError(err) + fp1RewardGauge, ok := fp1RewardGauges[itypes.FinalityProviderType.String()] + s.True(ok) + s.True(fp1RewardGauge.Coins.IsAllPositive()) // 2674ubbn + + fp2RewardGauges, err := n1.QueryRewardGauge(s.fp2.Address()) + s.NoError(err) + fp2RewardGauge, ok := fp2RewardGauges[itypes.FinalityProviderType.String()] + s.True(ok) + s.True(fp2RewardGauge.Coins.IsAllPositive()) // 891ubbn + + coins.RequireCoinsDiffInPointOnePercentMargin( + s.T(), + fp2RewardGauge.Coins.MulInt(sdkmath.NewIntFromUint64(3)), // 2673 + fp1RewardGauge.Coins, + ) + + // The rewards distributed to the delegators should be the same for each delegator + btcDel1RewardGauges, err := n1.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del1Addr)) + s.NoError(err) + btcDel1RewardGauge, ok := btcDel1RewardGauges[itypes.BTCDelegationType.String()] + s.True(ok) + s.True(btcDel1RewardGauge.Coins.IsAllPositive()) // 7130ubbn + + btcDel2RewardGauges, err := n1.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del2Addr)) + s.NoError(err) + btcDel2RewardGauge, ok := btcDel2RewardGauges[itypes.BTCDelegationType.String()] + s.True(ok) + s.True(btcDel2RewardGauge.Coins.IsAllPositive()) // 7130ubbn + + s.Equal(btcDel1RewardGauge.Coins.String(), btcDel2RewardGauge.Coins.String()) + + // Withdraw the reward just for del2 + del2BalanceBeforeWithdraw, err := n1.QueryBalances(s.del2Addr) + s.NoError(err) + + n1.WithdrawReward(itypes.BTCDelegationType.String(), s.del2Addr) + n1.WaitForNextBlock() + + del2BalanceAfterWithdraw, err := n1.QueryBalances(s.del2Addr) + s.NoError(err) + + s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(btcDel2RewardGauge.Coins...).String()) +} - // // ensure finality provider has received rewards after the block is finalised - // fpRewardGauges, err := n1.QueryRewardGauge(fpBabylonAddr) - // s.NoError(err) - // fpRewardGauge, ok := fpRewardGauges[itypes.FinalityProviderType.String()] - // s.True(ok) - // s.True(fpRewardGauge.Coins.IsAllPositive()) - // // ensure BTC delegation has received rewards after the block is finalised - // btcDelRewardGauges, err := n1.QueryRewardGauge(delBabylonAddr) - // s.NoError(err) - // btcDelRewardGauge, ok := btcDelRewardGauges[itypes.BTCDelegationType.String()] - // s.True(ok) - // s.True(btcDelRewardGauge.Coins.IsAllPositive()) - // s.T().Logf("the finality provider received rewards for providing finality") +func (s *BtcRewardsDistribution) Test6WithdrawReward() { } // func (s *BtcRewardsDistribution) Test4WithdrawReward() { diff --git a/test/e2e/configurer/chain/queries.go b/test/e2e/configurer/chain/queries.go index ae5009961..67585b867 100644 --- a/test/e2e/configurer/chain/queries.go +++ b/test/e2e/configurer/chain/queries.go @@ -442,9 +442,8 @@ func (n *NodeConfig) WaitFinalityIsActivated() (activatedHeight uint64) { if err != nil { return false } - // TODO: check why never becomes active with fps and committed pub rand return activatedHeight > 0 - }, time.Minute*3, time.Millisecond*50) + }, time.Minute*2, time.Millisecond*50) n.t.Logf("the activated height is %d", activatedHeight) return activatedHeight } From e9c8050cd3b9b78043a54aca9e5d7f64e2af63ba Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 18 Dec 2024 10:34:48 -0300 Subject: [PATCH 089/132] fix: lint and test --- test/e2e/btc_rewards_distribution_e2e_test.go | 130 +++++++----------- x/incentive/keeper/reward_tracker.go | 4 +- x/incentive/keeper/reward_tracker_test.go | 8 +- 3 files changed, 57 insertions(+), 85 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 669ad5498..804df3122 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -4,6 +4,7 @@ import ( "fmt" "math" "math/rand" + "strings" "testing" "time" @@ -24,6 +25,10 @@ import ( itypes "github.com/babylonlabs-io/babylon/x/incentive/types" ) +const ( + stakingTimeBlocks = uint16(math.MaxUint16) +) + type BtcRewardsDistribution struct { suite.Suite @@ -47,13 +52,20 @@ type BtcRewardsDistribution struct { // (fp2, del1) fp2Del2StakingAmt => 2_00000000 // for this top configure the reward distribution should // be 25%, 50%, 25% respectively (if they will be processed in the same block) + // since the rewards distribution is by their bech32 address the delegations + // are combined the voting power and each delegator should receive the same + // amount of rewards, finality providers on the other hand will have different amounts + // fp2 with 2_00000000 and fp1 with 6_00000000. This means the fp1 will + // receive 3x the amount of rewards then fp2. fp1Del1StakingAmt int64 fp1Del2StakingAmt int64 fp2Del1StakingAmt int64 - // The lastet delegation will come right after (fp1, del2) and (fp2, del1) - // had withdraw his rewards, and stake 6_00000000 to (fp2, del2) receive the same - // amount of rewards as the sum of rewards (fp1, del2) and (fp2, del1) + // The lastet delegation will come right after (del2) had withdraw his rewards + // and stake 6_00000000 to (fp2, del2). Since the rewards are combined by + // their bech32 address, del2 will have 10_00000000 and del1 will have 4_00000000 + // as voting power, meaning that del1 will receive only 40% of the amount of rewards + // that del2 will receive once every delegation is active fp2Del2StakingAmt int64 // bech32 address of the delegators @@ -135,14 +147,12 @@ func (s *BtcRewardsDistribution) Test2CreateFirstBtcDelegations() { n0.BankMultiSendFromNode([]string{s.del1Addr, s.del2Addr}, "100000ubbn") - stakingTimeBlocks := uint16(math.MaxUint16) - // fp1Del1 - s.CreateBTCDelegationAndCheck(n0, wDel1, s.fp1, s.del1BTCSK, s.del1Addr, stakingTimeBlocks, s.fp1Del1StakingAmt) + s.CreateBTCDelegationAndCheck(n0, wDel1, s.fp1, s.del1BTCSK, s.del1Addr, s.fp1Del1StakingAmt) // fp1Del2 - s.CreateBTCDelegationAndCheck(n0, wDel2, s.fp1, s.del2BTCSK, s.del2Addr, stakingTimeBlocks, s.fp1Del2StakingAmt) + s.CreateBTCDelegationAndCheck(n0, wDel2, s.fp1, s.del2BTCSK, s.del2Addr, s.fp1Del2StakingAmt) // fp2Del1 - s.CreateBTCDelegationAndCheck(n0, wDel1, s.fp2, s.del1BTCSK, s.del1Addr, stakingTimeBlocks, s.fp2Del1StakingAmt) + s.CreateBTCDelegationAndCheck(n0, wDel1, s.fp2, s.del1BTCSK, s.del1Addr, s.fp2Del1StakingAmt) } // Test3SubmitCovenantSignature covenant approves all the 3 BTC delegation @@ -266,12 +276,6 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { n1, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(1) s.NoError(err) - // comments on ubbn amounts are for the following mint config - // babylond q mint inflation - // 0.080000000000000000 - // babylond q mint annual-provisions - // 720000000000.000000000000000000 - // Current setup of voting power // (fp1, del1) => 2_00000000 // (fp1, del2) => 4_00000000 @@ -298,7 +302,7 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { coins.RequireCoinsDiffInPointOnePercentMargin( s.T(), - fp2RewardGauge.Coins.MulInt(sdkmath.NewIntFromUint64(3)), // 2673 + fp2RewardGauge.Coins.MulInt(sdkmath.NewIntFromUint64(3)), // 2673ubbn fp1RewardGauge.Coins, ) @@ -330,70 +334,39 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(btcDel2RewardGauge.Coins...).String()) } -func (s *BtcRewardsDistribution) Test6WithdrawReward() { -} +func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { + n2, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(2) + s.NoError(err) + + wDel2 := "del2" + // fp2Del2 + s.CreateBTCDelegationAndCheck(n2, wDel2, s.fp2, s.del2BTCSK, s.del2Addr, s.fp2Del2StakingAmt) + + allDelegations := n2.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) + s.Equal(len(allDelegations), 4) + + for _, delegation := range allDelegations { + if !strings.EqualFold(delegation.StatusDesc, bstypes.BTCDelegationStatus_PENDING.String()) { + continue + } + pendingDel, err := ParseRespBTCDelToBTCDel(delegation) + s.NoError(err) -// func (s *BtcRewardsDistribution) Test4WithdrawReward() { -// chainA := s.configurer.GetChainConfig(0) -// nonValidatorNode, err := chainA.GetNodeAtIndex(2) -// s.NoError(err) - -// // finality provider balance before withdraw -// fpBabylonAddr, err := sdk.AccAddressFromBech32(s.fp1.Addr) -// s.NoError(err) -// delBabylonAddr := fpBabylonAddr - -// fpBalance, err := nonValidatorNode.QueryBalances(fpBabylonAddr.String()) -// s.NoError(err) -// // finality provider reward gauge should not be fully withdrawn -// fpRgs, err := nonValidatorNode.QueryRewardGauge(fpBabylonAddr) -// s.NoError(err) -// fpRg := fpRgs[itypes.FinalityProviderType.String()] -// s.T().Logf("finality provider's withdrawable reward before withdrawing: %s", convertToRewardGauge(fpRg).GetWithdrawableCoins().String()) -// s.False(convertToRewardGauge(fpRg).IsFullyWithdrawn()) - -// // withdraw finality provider reward -// nonValidatorNode.WithdrawReward(itypes.FinalityProviderType.String(), initialization.ValidatorWalletName) -// nonValidatorNode.WaitForNextBlock() - -// // balance after withdrawing finality provider reward -// fpBalance2, err := nonValidatorNode.QueryBalances(fpBabylonAddr.String()) -// s.NoError(err) -// s.T().Logf("fpBalance2: %s; fpBalance: %s", fpBalance2.String(), fpBalance.String()) -// s.True(fpBalance2.IsAllGT(fpBalance)) -// // finality provider reward gauge should be fully withdrawn now -// fpRgs2, err := nonValidatorNode.QueryRewardGauge(fpBabylonAddr) -// s.NoError(err) -// fpRg2 := fpRgs2[itypes.FinalityProviderType.String()] -// s.T().Logf("finality provider's withdrawable reward after withdrawing: %s", convertToRewardGauge(fpRg2).GetWithdrawableCoins().String()) -// s.True(convertToRewardGauge(fpRg2).IsFullyWithdrawn()) - -// // BTC delegation balance before withdraw -// btcDelBalance, err := nonValidatorNode.QueryBalances(delBabylonAddr.String()) -// s.NoError(err) -// // BTC delegation reward gauge should not be fully withdrawn -// btcDelRgs, err := nonValidatorNode.QueryRewardGauge(delBabylonAddr) -// s.NoError(err) -// btcDelRg := btcDelRgs[itypes.BTCDelegationType.String()] -// s.T().Logf("BTC delegation's withdrawable reward before withdrawing: %s", convertToRewardGauge(btcDelRg).GetWithdrawableCoins().String()) -// s.False(convertToRewardGauge(btcDelRg).IsFullyWithdrawn()) - -// // withdraw BTC delegation reward -// nonValidatorNode.WithdrawReward(itypes.BTCDelegationType.String(), initialization.ValidatorWalletName) -// nonValidatorNode.WaitForNextBlock() - -// // balance after withdrawing BTC delegation reward -// btcDelBalance2, err := nonValidatorNode.QueryBalances(delBabylonAddr.String()) -// s.NoError(err) -// s.T().Logf("btcDelBalance2: %s; btcDelBalance: %s", btcDelBalance2.String(), btcDelBalance.String()) -// s.True(btcDelBalance2.IsAllGT(btcDelBalance)) -// // BTC delegation reward gauge should be fully withdrawn now -// btcDelRgs2, err := nonValidatorNode.QueryRewardGauge(delBabylonAddr) -// s.NoError(err) -// btcDelRg2 := btcDelRgs2[itypes.BTCDelegationType.String()] -// s.T().Logf("BTC delegation's withdrawable reward after withdrawing: %s", convertToRewardGauge(btcDelRg2).GetWithdrawableCoins().String()) -// s.True(convertToRewardGauge(btcDelRg2).IsFullyWithdrawn()) -// } + SendCovenantSigsToPendingDel(s.r, s.T(), n2, s.net, s.covenantSKs, s.covenantWallets, pendingDel) + + n2.WaitForNextBlock() + } + + // wait for a block so that above txs take effect + n2.WaitForNextBlock() + + // ensure the BTC delegation has covenant sigs now + allDelegations = n2.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) + s.Len(allDelegations, 4) + for _, activeDel := range allDelegations { + s.True(activeDel.Active) + } +} func (s *BtcRewardsDistribution) CreateBTCDelegationAndCheck( n *chain.NodeConfig, @@ -401,7 +374,6 @@ func (s *BtcRewardsDistribution) CreateBTCDelegationAndCheck( fp *bstypes.FinalityProvider, btcStakerSK *btcec.PrivateKey, delAddr string, - stakingTimeBlocks uint16, stakingSatAmt int64, ) { n.CreateBTCDelegationAndCheck(s.r, s.T(), s.net, wDel, fp, btcStakerSK, delAddr, stakingTimeBlocks, stakingSatAmt) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 7ec1766c1..06e8ca305 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -157,7 +157,7 @@ func (k Keeper) CalculateBTCDelegationRewards(ctx context.Context, fp, del sdk.A return sdk.NewCoins(), nil } - return k.calculateDelegationRewardsBetween(ctx, fp, del, btcDelRwdTracker, endPeriod) + return k.calculateDelegationRewardsBetween(ctx, fp, btcDelRwdTracker, endPeriod) } // calculateDelegationRewardsBetween calculate the rewards accured of a delegation between @@ -171,7 +171,7 @@ func (k Keeper) CalculateBTCDelegationRewards(ctx context.Context, fp, del sdk.A // to get it ready to be sent out to the delegator reward gauge. func (k Keeper) calculateDelegationRewardsBetween( ctx context.Context, - fp, del sdk.AccAddress, + fp sdk.AccAddress, btcDelRwdTracker types.BTCDelegationRewardsTracker, endingPeriod uint64, ) (sdk.Coins, error) { diff --git a/x/incentive/keeper/reward_tracker_test.go b/x/incentive/keeper/reward_tracker_test.go index 13dfdf7ff..d81a911df 100644 --- a/x/incentive/keeper/reward_tracker_test.go +++ b/x/incentive/keeper/reward_tracker_test.go @@ -332,12 +332,12 @@ func FuzzCheckCalculateDelegationRewardsBetween(f *testing.F) { r := rand.New(rand.NewSource(seed)) k, ctx := NewKeeperWithCtx(t) - fp, del := datagen.GenRandomAddress(), datagen.GenRandomAddress() + fp := datagen.GenRandomAddress() btcRwd := datagen.GenRandomBTCDelegationRewardsTracker(r) badEndedPeriod := btcRwd.StartPeriodCumulativeReward - 1 require.Panics(t, func() { - _, _ = k.calculateDelegationRewardsBetween(ctx, fp, del, btcRwd, badEndedPeriod) + _, _ = k.calculateDelegationRewardsBetween(ctx, fp, btcRwd, badEndedPeriod) }) historicalStartPeriod := datagen.GenRandomFPHistRwd(r) @@ -351,7 +351,7 @@ func FuzzCheckCalculateDelegationRewardsBetween(f *testing.F) { err = k.setFinalityProviderHistoricalRewards(ctx, fp, endingPeriod, types.NewFinalityProviderHistoricalRewards(historicalStartPeriod.CumulativeRewardsPerSat.QuoInt(math.NewInt(2)))) require.NoError(t, err) require.Panics(t, func() { - _, _ = k.calculateDelegationRewardsBetween(ctx, fp, del, btcRwd, endingPeriod) + _, _ = k.calculateDelegationRewardsBetween(ctx, fp, btcRwd, endingPeriod) }) // creates a correct historical rewards that has more rewards than the historical @@ -365,7 +365,7 @@ func FuzzCheckCalculateDelegationRewardsBetween(f *testing.F) { expectedRewards = expectedRewards.MulInt(btcRwd.TotalActiveSat) expectedRewards = expectedRewards.QuoInt(types.DecimalAccumulatedRewards) - delRewards, err := k.calculateDelegationRewardsBetween(ctx, fp, del, btcRwd, endingPeriod) + delRewards, err := k.calculateDelegationRewardsBetween(ctx, fp, btcRwd, endingPeriod) require.NoError(t, err) require.Equal(t, expectedRewards.String(), delRewards.String()) }) From 318993b33a33e4a0e82aa2c66fb938be9efa085b Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 18 Dec 2024 10:58:25 -0300 Subject: [PATCH 090/132] chore: set wallet name for delegations const --- test/e2e/btc_rewards_distribution_e2e_test.go | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 804df3122..258096d26 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -27,6 +27,8 @@ import ( const ( stakingTimeBlocks = uint16(math.MaxUint16) + wDel1 = "del1" + wDel2 = "del2" ) type BtcRewardsDistribution struct { @@ -141,7 +143,6 @@ func (s *BtcRewardsDistribution) Test2CreateFirstBtcDelegations() { n0, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(0) s.NoError(err) - wDel1, wDel2 := "del1", "del2" s.del1Addr = n0.KeysAdd(wDel1) s.del2Addr = n0.KeysAdd(wDel2) @@ -273,7 +274,7 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { // Test5CheckRewardsFirstDelegations verifies the rewards independent of mint amounts func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { - n1, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(1) + n0, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(0) s.NoError(err) // Current setup of voting power @@ -288,13 +289,13 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { // (del2) => 4_00000000 // The rewards distributed for the finality providers should be fp1 => 3x, fp2 => 1x - fp1RewardGauges, err := n1.QueryRewardGauge(s.fp1.Address()) + fp1RewardGauges, err := n0.QueryRewardGauge(s.fp1.Address()) s.NoError(err) fp1RewardGauge, ok := fp1RewardGauges[itypes.FinalityProviderType.String()] s.True(ok) s.True(fp1RewardGauge.Coins.IsAllPositive()) // 2674ubbn - fp2RewardGauges, err := n1.QueryRewardGauge(s.fp2.Address()) + fp2RewardGauges, err := n0.QueryRewardGauge(s.fp2.Address()) s.NoError(err) fp2RewardGauge, ok := fp2RewardGauges[itypes.FinalityProviderType.String()] s.True(ok) @@ -307,13 +308,13 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { ) // The rewards distributed to the delegators should be the same for each delegator - btcDel1RewardGauges, err := n1.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del1Addr)) + btcDel1RewardGauges, err := n0.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del1Addr)) s.NoError(err) btcDel1RewardGauge, ok := btcDel1RewardGauges[itypes.BTCDelegationType.String()] s.True(ok) s.True(btcDel1RewardGauge.Coins.IsAllPositive()) // 7130ubbn - btcDel2RewardGauges, err := n1.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del2Addr)) + btcDel2RewardGauges, err := n0.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del2Addr)) s.NoError(err) btcDel2RewardGauge, ok := btcDel2RewardGauges[itypes.BTCDelegationType.String()] s.True(ok) @@ -322,13 +323,13 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { s.Equal(btcDel1RewardGauge.Coins.String(), btcDel2RewardGauge.Coins.String()) // Withdraw the reward just for del2 - del2BalanceBeforeWithdraw, err := n1.QueryBalances(s.del2Addr) + del2BalanceBeforeWithdraw, err := n0.QueryBalances(s.del2Addr) s.NoError(err) - n1.WithdrawReward(itypes.BTCDelegationType.String(), s.del2Addr) - n1.WaitForNextBlock() + n0.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) + n0.WaitForNextBlock() - del2BalanceAfterWithdraw, err := n1.QueryBalances(s.del2Addr) + del2BalanceAfterWithdraw, err := n0.QueryBalances(s.del2Addr) s.NoError(err) s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(btcDel2RewardGauge.Coins...).String()) @@ -338,7 +339,6 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { n2, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(2) s.NoError(err) - wDel2 := "del2" // fp2Del2 s.CreateBTCDelegationAndCheck(n2, wDel2, s.fp2, s.del2BTCSK, s.del2Addr, s.fp2Del2StakingAmt) @@ -368,6 +368,9 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { } } +func (s *BtcRewardsDistribution) Test7FinalityVoteBlock() { +} + func (s *BtcRewardsDistribution) CreateBTCDelegationAndCheck( n *chain.NodeConfig, wDel string, From 2087c8a7b336e5fd33418c15ba067d61f4c14508 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 18 Dec 2024 12:38:05 -0300 Subject: [PATCH 091/132] fix: covenant sigs from correct node --- test/e2e/btc_rewards_distribution_e2e_test.go | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 258096d26..6ad5302d3 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -140,20 +140,22 @@ func (s *BtcRewardsDistribution) Test1CreateFinalityProviders() { // Test2CreateFinalityProviders creates the first 3 btc delegations // with the same values, but different satoshi staked amounts func (s *BtcRewardsDistribution) Test2CreateFirstBtcDelegations() { - n0, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(0) + n2, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(2) s.NoError(err) - s.del1Addr = n0.KeysAdd(wDel1) - s.del2Addr = n0.KeysAdd(wDel2) + s.del1Addr = n2.KeysAdd(wDel1) + s.del2Addr = n2.KeysAdd(wDel2) - n0.BankMultiSendFromNode([]string{s.del1Addr, s.del2Addr}, "100000ubbn") + n2.BankMultiSendFromNode([]string{s.del1Addr, s.del2Addr}, "100000ubbn") // fp1Del1 - s.CreateBTCDelegationAndCheck(n0, wDel1, s.fp1, s.del1BTCSK, s.del1Addr, s.fp1Del1StakingAmt) + s.CreateBTCDelegationAndCheck(n2, wDel1, s.fp1, s.del1BTCSK, s.del1Addr, s.fp1Del1StakingAmt) // fp1Del2 - s.CreateBTCDelegationAndCheck(n0, wDel2, s.fp1, s.del2BTCSK, s.del2Addr, s.fp1Del2StakingAmt) + s.CreateBTCDelegationAndCheck(n2, wDel2, s.fp1, s.del2BTCSK, s.del2Addr, s.fp1Del2StakingAmt) // fp2Del1 - s.CreateBTCDelegationAndCheck(n0, wDel1, s.fp2, s.del1BTCSK, s.del1Addr, s.fp2Del1StakingAmt) + s.CreateBTCDelegationAndCheck(n2, wDel1, s.fp2, s.del1BTCSK, s.del1Addr, s.fp2Del1StakingAmt) + + n2.WaitForNextBlock() } // Test3SubmitCovenantSignature covenant approves all the 3 BTC delegation @@ -274,7 +276,7 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { // Test5CheckRewardsFirstDelegations verifies the rewards independent of mint amounts func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { - n0, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(0) + n2, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(2) s.NoError(err) // Current setup of voting power @@ -289,13 +291,13 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { // (del2) => 4_00000000 // The rewards distributed for the finality providers should be fp1 => 3x, fp2 => 1x - fp1RewardGauges, err := n0.QueryRewardGauge(s.fp1.Address()) + fp1RewardGauges, err := n2.QueryRewardGauge(s.fp1.Address()) s.NoError(err) fp1RewardGauge, ok := fp1RewardGauges[itypes.FinalityProviderType.String()] s.True(ok) s.True(fp1RewardGauge.Coins.IsAllPositive()) // 2674ubbn - fp2RewardGauges, err := n0.QueryRewardGauge(s.fp2.Address()) + fp2RewardGauges, err := n2.QueryRewardGauge(s.fp2.Address()) s.NoError(err) fp2RewardGauge, ok := fp2RewardGauges[itypes.FinalityProviderType.String()] s.True(ok) @@ -308,13 +310,13 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { ) // The rewards distributed to the delegators should be the same for each delegator - btcDel1RewardGauges, err := n0.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del1Addr)) + btcDel1RewardGauges, err := n2.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del1Addr)) s.NoError(err) btcDel1RewardGauge, ok := btcDel1RewardGauges[itypes.BTCDelegationType.String()] s.True(ok) s.True(btcDel1RewardGauge.Coins.IsAllPositive()) // 7130ubbn - btcDel2RewardGauges, err := n0.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del2Addr)) + btcDel2RewardGauges, err := n2.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del2Addr)) s.NoError(err) btcDel2RewardGauge, ok := btcDel2RewardGauges[itypes.BTCDelegationType.String()] s.True(ok) @@ -323,20 +325,24 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { s.Equal(btcDel1RewardGauge.Coins.String(), btcDel2RewardGauge.Coins.String()) // Withdraw the reward just for del2 - del2BalanceBeforeWithdraw, err := n0.QueryBalances(s.del2Addr) + del2BalanceBeforeWithdraw, err := n2.QueryBalances(s.del2Addr) s.NoError(err) - n0.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) - n0.WaitForNextBlock() + n2.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) + n2.WaitForNextBlock() - del2BalanceAfterWithdraw, err := n0.QueryBalances(s.del2Addr) + del2BalanceAfterWithdraw, err := n2.QueryBalances(s.del2Addr) s.NoError(err) s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(btcDel2RewardGauge.Coins...).String()) } func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { - n2, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(2) + chainA := s.configurer.GetChainConfig(0) + n2, err := chainA.GetNodeAtIndex(2) + s.NoError(err) + // covenants are at n1 + n1, err := chainA.GetNodeAtIndex(1) s.NoError(err) // fp2Del2 @@ -352,7 +358,7 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { pendingDel, err := ParseRespBTCDelToBTCDel(delegation) s.NoError(err) - SendCovenantSigsToPendingDel(s.r, s.T(), n2, s.net, s.covenantSKs, s.covenantWallets, pendingDel) + SendCovenantSigsToPendingDel(s.r, s.T(), n1, s.net, s.covenantSKs, s.covenantWallets, pendingDel) n2.WaitForNextBlock() } From c9e8f8ad8106fa980928ea3bd088df2ff38b7679 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 18 Dec 2024 12:41:18 -0300 Subject: [PATCH 092/132] chore: correct usage of nodes --- test/e2e/btc_rewards_distribution_e2e_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 6ad5302d3..b3474b75a 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -360,14 +360,14 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { SendCovenantSigsToPendingDel(s.r, s.T(), n1, s.net, s.covenantSKs, s.covenantWallets, pendingDel) - n2.WaitForNextBlock() + n1.WaitForNextBlock() } // wait for a block so that above txs take effect - n2.WaitForNextBlock() + n1.WaitForNextBlock() // ensure the BTC delegation has covenant sigs now - allDelegations = n2.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) + allDelegations = n1.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) s.Len(allDelegations, 4) for _, activeDel := range allDelegations { s.True(activeDel.Active) From 99acf6cb421986462772cb44eb0d883ff6e6de2c Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 18 Dec 2024 13:00:28 -0300 Subject: [PATCH 093/132] chore: add finality vote to another block --- test/e2e/btc_rewards_distribution_e2e_test.go | 86 ++++++++++++++++--- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index b3474b75a..3c3533443 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -77,6 +77,11 @@ type BtcRewardsDistribution struct { covenantSKs []*btcec.PrivateKey covenantWallets []string + finalityIdx uint64 + finalityBlockHeightVoted uint64 + fp1RandListInfo *datagen.RandListInfo + fp2RandListInfo *datagen.RandListInfo + configurer configurer.Configurer } @@ -217,8 +222,11 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { fp1RandListInfo, fp1CommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp1BTCSK, commitStartHeight, numPubRand) s.NoError(err) + s.fp1RandListInfo = fp1RandListInfo + fp2RandListInfo, fp2CommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp2BTCSK, commitStartHeight, numPubRand) s.NoError(err) + s.fp2RandListInfo = fp2RandListInfo n1.CommitPubRandList( fp1CommitPubRandList.FpBtcPk, @@ -239,27 +247,27 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { n1.WaitUntilCurrentEpochIsSealedAndFinalized() // activated height is never returned - activatedHeight := n1.WaitFinalityIsActivated() + s.finalityBlockHeightVoted = n1.WaitFinalityIsActivated() // submit finality signature - idx := activatedHeight - commitStartHeight + s.finalityIdx = s.finalityBlockHeightVoted - commitStartHeight appHash := n1.AddFinalitySignatureToBlock( s.fp1BTCSK, s.fp1.BtcPk, - activatedHeight, - fp1RandListInfo.SRList[idx], - &fp1RandListInfo.PRList[idx], - *fp1RandListInfo.ProofList[idx].ToProto(), + s.finalityBlockHeightVoted, + s.fp1RandListInfo.SRList[s.finalityIdx], + &s.fp1RandListInfo.PRList[s.finalityIdx], + *s.fp1RandListInfo.ProofList[s.finalityIdx].ToProto(), ) n2.AddFinalitySignatureToBlock( s.fp2BTCSK, s.fp2.BtcPk, - activatedHeight, - fp2RandListInfo.SRList[idx], - &fp2RandListInfo.PRList[idx], - *fp2RandListInfo.ProofList[idx].ToProto(), + s.finalityBlockHeightVoted, + s.fp2RandListInfo.SRList[s.finalityIdx], + &s.fp2RandListInfo.PRList[s.finalityIdx], + *s.fp2RandListInfo.ProofList[s.finalityIdx].ToProto(), ) // ensure vote is eventually cast @@ -269,9 +277,11 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { return len(finalizedBlocks) > 0 }, time.Minute, time.Millisecond*50) - s.Equal(activatedHeight, finalizedBlocks[0].Height) + n2.WaitForNextBlocks(2) + + s.Equal(s.finalityBlockHeightVoted, finalizedBlocks[0].Height) s.Equal(appHash.Bytes(), finalizedBlocks[0].AppHash) - s.T().Logf("the block %d is finalized", activatedHeight) + s.T().Logf("the block %d is finalized", s.finalityBlockHeightVoted) } // Test5CheckRewardsFirstDelegations verifies the rewards independent of mint amounts @@ -337,6 +347,9 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(btcDel2RewardGauge.Coins...).String()) } +// Test6ActiveLastDelegation creates a new btc delegation +// (fp2, del2) with 6_00000000 sats and sends the covenant signatures +// needed. func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { chainA := s.configurer.GetChainConfig(0) n2, err := chainA.GetNodeAtIndex(2) @@ -374,9 +387,58 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { } } +// Test7FinalityVoteBlock votes in one more block from both finality providers func (s *BtcRewardsDistribution) Test7FinalityVoteBlock() { + chainA := s.configurer.GetChainConfig(0) + n2, err := chainA.GetNodeAtIndex(2) + s.NoError(err) + // covenants are at n1 + n1, err := chainA.GetNodeAtIndex(1) + s.NoError(err) + + n1.WaitUntilCurrentEpochIsSealedAndFinalized() + + // submit finality signature + s.finalityIdx++ + s.finalityBlockHeightVoted++ + + appHash := n1.AddFinalitySignatureToBlock( + s.fp1BTCSK, + s.fp1.BtcPk, + s.finalityBlockHeightVoted, + s.fp1RandListInfo.SRList[s.finalityIdx], + &s.fp1RandListInfo.PRList[s.finalityIdx], + *s.fp1RandListInfo.ProofList[s.finalityIdx].ToProto(), + ) + + n2.AddFinalitySignatureToBlock( + s.fp2BTCSK, + s.fp2.BtcPk, + s.finalityBlockHeightVoted, + s.fp2RandListInfo.SRList[s.finalityIdx], + &s.fp2RandListInfo.PRList[s.finalityIdx], + *s.fp2RandListInfo.ProofList[s.finalityIdx].ToProto(), + ) + + // ensure vote is eventually cast + var finalizedBlocks []*ftypes.IndexedBlock + s.Eventually(func() bool { + finalizedBlocks = n1.QueryListBlocks(ftypes.QueriedBlockStatus_FINALIZED) + return len(finalizedBlocks) > 0 + }, time.Minute, time.Millisecond*50) + + n2.WaitForNextBlocks(2) + + s.Equal(s.finalityBlockHeightVoted, finalizedBlocks[0].Height) + s.Equal(appHash.Bytes(), finalizedBlocks[0].AppHash) + s.T().Logf("the block %d is finalized", s.finalityBlockHeightVoted) +} + +func (s *BtcRewardsDistribution) Test8CheckRewards() { } +// TODO(rafilx): Slash a FP and expect rewards to be withdraw. + func (s *BtcRewardsDistribution) CreateBTCDelegationAndCheck( n *chain.NodeConfig, wDel string, From beffe5ef0c3dec67860e41e63c56e2376a6a8307 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 18 Dec 2024 13:43:38 -0300 Subject: [PATCH 094/132] chore: add sort of node by name on creation --- test/e2e/configurer/chain/chain.go | 4 ++++ test/e2e/configurer/chain/queries.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/test/e2e/configurer/chain/chain.go b/test/e2e/configurer/chain/chain.go index 76ac1f72c..d27ce0c76 100644 --- a/test/e2e/configurer/chain/chain.go +++ b/test/e2e/configurer/chain/chain.go @@ -3,6 +3,7 @@ package chain import ( "encoding/hex" "fmt" + "sort" "strings" "testing" "time" @@ -76,6 +77,9 @@ func (c *Config) CreateNode(initNode *initialization.Node) *NodeConfig { t: c.t, } c.NodeConfigs = append(c.NodeConfigs, nodeConfig) + sort.Slice(c.NodeConfigs, func(i, j int) bool { + return c.NodeConfigs[i].Name > c.NodeConfigs[j].Name + }) return nodeConfig } diff --git a/test/e2e/configurer/chain/queries.go b/test/e2e/configurer/chain/queries.go index 67585b867..ebe0e06e3 100644 --- a/test/e2e/configurer/chain/queries.go +++ b/test/e2e/configurer/chain/queries.go @@ -421,7 +421,7 @@ func (n *NodeConfig) WaitUntilCurrentEpochIsSealedAndFinalized() { return false } return resp.Status == ct.Sealed - }, time.Minute*2, time.Millisecond*50) + }, time.Minute*5, time.Millisecond*50) n.FinalizeSealedEpochs(1, currentEpoch) // ensure the committed epoch is finalized From 3c97ab11c7bc440a731c7dcc09fdde32853ca003 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 18 Dec 2024 16:46:54 -0300 Subject: [PATCH 095/132] tryfix: check rewards seccond time --- test/e2e/btc_rewards_distribution_e2e_test.go | 196 ++++++++++++++---- test/e2e/btc_staking_e2e_test.go | 2 +- .../configurer/chain/commands_btcstaking.go | 2 +- test/e2e/configurer/chain/node.go | 15 +- test/e2e/configurer/chain/queries.go | 6 +- test/e2e/initialization/config.go | 1 + 6 files changed, 172 insertions(+), 50 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 3c3533443..87faaa874 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -29,6 +29,7 @@ const ( stakingTimeBlocks = uint16(math.MaxUint16) wDel1 = "del1" wDel2 = "del2" + numPubRand = uint64(250) ) type BtcRewardsDistribution struct { @@ -74,14 +75,22 @@ type BtcRewardsDistribution struct { del1Addr string del2Addr string + // covenant helpers covenantSKs []*btcec.PrivateKey covenantWallets []string + // finality helpers finalityIdx uint64 finalityBlockHeightVoted uint64 fp1RandListInfo *datagen.RandListInfo fp2RandListInfo *datagen.RandListInfo + // reward helpers + fp1LastRewardGauge *itypes.RewardGaugesResponse + fp2LastRewardGauge *itypes.RewardGaugesResponse + btcDel2LastRewardGauge *itypes.RewardGaugesResponse + btcDel1LastRewardGauge *itypes.RewardGaugesResponse + configurer configurer.Configurer } @@ -181,6 +190,9 @@ func (s *BtcRewardsDistribution) Test3SubmitCovenantSignature() { n1.BankMultiSendFromNode(covAddrs, "100000ubbn") + // tx bank send needs to take effect + n1.WaitForNextBlock() + pendingDelsResp := n1.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) s.Equal(len(pendingDelsResp), 3) @@ -217,7 +229,6 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { commit a number of public randomness */ // commit public randomness list - numPubRand := uint64(150) commitStartHeight := uint64(1) fp1RandListInfo, fp1CommitPubRandList, err := datagen.GenRandomMsgCommitPubRandList(s.r, s.fp1BTCSK, commitStartHeight, numPubRand) @@ -244,7 +255,7 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { fp2CommitPubRandList.Sig, ) - n1.WaitUntilCurrentEpochIsSealedAndFinalized() + n1.WaitUntilCurrentEpochIsSealedAndFinalized(1) // activated height is never returned s.finalityBlockHeightVoted = n1.WaitFinalityIsActivated() @@ -270,6 +281,8 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { *s.fp2RandListInfo.ProofList[s.finalityIdx].ToProto(), ) + n2.WaitForNextBlocks(2) + // ensure vote is eventually cast var finalizedBlocks []*ftypes.IndexedBlock s.Eventually(func() bool { @@ -277,8 +290,6 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { return len(finalizedBlocks) > 0 }, time.Minute, time.Millisecond*50) - n2.WaitForNextBlocks(2) - s.Equal(s.finalityBlockHeightVoted, finalizedBlocks[0].Height) s.Equal(appHash.Bytes(), finalizedBlocks[0].AppHash) s.T().Logf("the block %d is finalized", s.finalityBlockHeightVoted) @@ -301,40 +312,22 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { // (del2) => 4_00000000 // The rewards distributed for the finality providers should be fp1 => 3x, fp2 => 1x - fp1RewardGauges, err := n2.QueryRewardGauge(s.fp1.Address()) - s.NoError(err) - fp1RewardGauge, ok := fp1RewardGauges[itypes.FinalityProviderType.String()] - s.True(ok) - s.True(fp1RewardGauge.Coins.IsAllPositive()) // 2674ubbn - - fp2RewardGauges, err := n2.QueryRewardGauge(s.fp2.Address()) - s.NoError(err) - fp2RewardGauge, ok := fp2RewardGauges[itypes.FinalityProviderType.String()] - s.True(ok) - s.True(fp2RewardGauge.Coins.IsAllPositive()) // 891ubbn - + s.UpdateRewardGauges(n2) + // fp1 ~2674ubbn + // fp2 ~891ubbn coins.RequireCoinsDiffInPointOnePercentMargin( s.T(), - fp2RewardGauge.Coins.MulInt(sdkmath.NewIntFromUint64(3)), // 2673ubbn - fp1RewardGauge.Coins, + s.fp2LastRewardGauge.Coins.MulInt(sdkmath.NewIntFromUint64(3)), // ~2673ubbn + s.fp1LastRewardGauge.Coins, ) // The rewards distributed to the delegators should be the same for each delegator - btcDel1RewardGauges, err := n2.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del1Addr)) - s.NoError(err) - btcDel1RewardGauge, ok := btcDel1RewardGauges[itypes.BTCDelegationType.String()] - s.True(ok) - s.True(btcDel1RewardGauge.Coins.IsAllPositive()) // 7130ubbn + // del1 ~7130ubbn + // del2 ~7130ubbn + s.Equal(s.btcDel1LastRewardGauge.Coins.String(), s.btcDel2LastRewardGauge.Coins.String()) + // note that the rewards will not be precise as more or less blocks were produced and given out rewards. - btcDel2RewardGauges, err := n2.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del2Addr)) - s.NoError(err) - btcDel2RewardGauge, ok := btcDel2RewardGauges[itypes.BTCDelegationType.String()] - s.True(ok) - s.True(btcDel2RewardGauge.Coins.IsAllPositive()) // 7130ubbn - - s.Equal(btcDel1RewardGauge.Coins.String(), btcDel2RewardGauge.Coins.String()) - - // Withdraw the reward just for del2 + // Withdraw the reward just for del2 to check it is possible del2BalanceBeforeWithdraw, err := n2.QueryBalances(s.del2Addr) s.NoError(err) @@ -344,7 +337,7 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { del2BalanceAfterWithdraw, err := n2.QueryBalances(s.del2Addr) s.NoError(err) - s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(btcDel2RewardGauge.Coins...).String()) + s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(s.btcDel2LastRewardGauge.Coins...).String()) } // Test6ActiveLastDelegation creates a new btc delegation @@ -364,17 +357,19 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { allDelegations := n2.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) s.Equal(len(allDelegations), 4) + pendingDels := make([]*bstypes.BTCDelegationResponse, 0) for _, delegation := range allDelegations { if !strings.EqualFold(delegation.StatusDesc, bstypes.BTCDelegationStatus_PENDING.String()) { continue } - pendingDel, err := ParseRespBTCDelToBTCDel(delegation) - s.NoError(err) + pendingDels = append(pendingDels, delegation) + } - SendCovenantSigsToPendingDel(s.r, s.T(), n1, s.net, s.covenantSKs, s.covenantWallets, pendingDel) + s.Equal(len(pendingDels), 1) + pendingDel, err := ParseRespBTCDelToBTCDel(pendingDels[0]) + s.NoError(err) - n1.WaitForNextBlock() - } + SendCovenantSigsToPendingDel(s.r, s.T(), n1, s.net, s.covenantSKs, s.covenantWallets, pendingDel) // wait for a block so that above txs take effect n1.WaitForNextBlock() @@ -385,6 +380,12 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { for _, activeDel := range allDelegations { s.True(activeDel.Active) } + + // cache the reward gauges prior to the BTC delegation is active, so it + // can calculate the rewards properly based on the difference + // even then it could be that a block is mined between the query of this + // 4 address, but the difference would be very small + // s.UpdateRewardGauges() } // Test7FinalityVoteBlock votes in one more block from both finality providers @@ -396,7 +397,11 @@ func (s *BtcRewardsDistribution) Test7FinalityVoteBlock() { n1, err := chainA.GetNodeAtIndex(1) s.NoError(err) - n1.WaitUntilCurrentEpochIsSealedAndFinalized() + lastFinalizedEpoch, err := n1.QueryLastFinalizedEpoch() + s.NoError(err) + lastFinalizedEpoch++ + + n1.WaitUntilCurrentEpochIsSealedAndFinalized(lastFinalizedEpoch) // submit finality signature s.finalityIdx++ @@ -420,25 +425,128 @@ func (s *BtcRewardsDistribution) Test7FinalityVoteBlock() { *s.fp2RandListInfo.ProofList[s.finalityIdx].ToProto(), ) + n2.WaitForNextBlocks(2) + // ensure vote is eventually cast var finalizedBlocks []*ftypes.IndexedBlock s.Eventually(func() bool { finalizedBlocks = n1.QueryListBlocks(ftypes.QueriedBlockStatus_FINALIZED) - return len(finalizedBlocks) > 0 + return len(finalizedBlocks) > 1 }, time.Minute, time.Millisecond*50) - n2.WaitForNextBlocks(2) - - s.Equal(s.finalityBlockHeightVoted, finalizedBlocks[0].Height) - s.Equal(appHash.Bytes(), finalizedBlocks[0].AppHash) + lastFinalizedBlock := finalizedBlocks[len(finalizedBlocks)-1] + s.Equal(s.finalityBlockHeightVoted, lastFinalizedBlock.Height) + s.Equal(appHash.Bytes(), lastFinalizedBlock.AppHash) s.T().Logf("the block %d is finalized", s.finalityBlockHeightVoted) } +// Test8CheckRewards verifies the rewards of all the delegations +// and finality provider func (s *BtcRewardsDistribution) Test8CheckRewards() { + n2, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(2) + s.NoError(err) + + // updates the cache of the suite + // s.UpdateRewardGauges(n2) + + // Current setup of voting power + // (fp1, del1) => 2_00000000 + // (fp1, del2) => 4_00000000 + // (fp2, del1) => 2_00000000 + // (fp2, del2) => 6_00000000 + + // The sum per bech32 address will be + // (fp1) => 6_00000000 + // (fp2) => 8_00000000 + // (del1) => 4_00000000 + // (del2) => 10_00000000 + + // Current rewards for each FP + // fp1 ~5364ubbn + // fp2 ~1787ubbn + // del1 ~11625ubbn + // del2 ~16989ubbn + fp1RewardGaugePrev, fp2RewardGaugePrev, btcDel1RewardGaugePrev, btcDel2RewardGaugePrev := s.QueryRewardGauges(n2) + // wait a few block of rewards + n2.WaitForNextBlocks(20) + fp1RewardGauge, fp2RewardGauge, btcDel1RewardGauge, btcDel2RewardGauge := s.QueryRewardGauges(n2) + + // since varius block were created, it is needed to get the difference + // from a certain point where all the delegations were active to properly + // calculate the distribution with the voting power structure with 4 BTC delegations active + // Note: if a new block is mined during the query of reward gauges, the calculation might be a + // bit off by some ubbn + fp1DiffRewards := fp1RewardGauge.Coins.Sub(fp1RewardGaugePrev.Coins...) + fp2DiffRewards := fp2RewardGauge.Coins.Sub(fp2RewardGaugePrev.Coins...) + del1DiffRewards := btcDel1RewardGauge.Coins.Sub(btcDel1RewardGaugePrev.Coins...) + del2DiffRewards := btcDel2RewardGauge.Coins.Sub(btcDel2RewardGaugePrev.Coins...) + + fp1DiffRewardsStr := fp1DiffRewards.String() + fp2DiffRewardsStr := fp2DiffRewards.String() + del1DiffRewardsStr := del1DiffRewards.String() + del2DiffRewardsStr := del2DiffRewards.String() + + s.NotEmpty(fp1DiffRewardsStr) + s.NotEmpty(fp2DiffRewardsStr) + s.NotEmpty(del1DiffRewardsStr) + s.NotEmpty(del2DiffRewardsStr) + + // s.Equal(btcDel1RewardGauge.Coins.String(), btcDel2RewardGauge.Coins.String()) + + // // Withdraw the reward just for del2 + // del2BalanceBeforeWithdraw, err := n2.QueryBalances(s.del2Addr) + // s.NoError(err) + + // n2.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) + // n2.WaitForNextBlock() + + // del2BalanceAfterWithdraw, err := n2.QueryBalances(s.del2Addr) + // s.NoError(err) + + // s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(btcDel2RewardGauge.Coins...).String()) } // TODO(rafilx): Slash a FP and expect rewards to be withdraw. +// UpdateRewardGauges update the current reward gauges on the test suite +func (s *BtcRewardsDistribution) UpdateRewardGauges(n *chain.NodeConfig) { + s.fp1LastRewardGauge, s.fp2LastRewardGauge, s.btcDel1LastRewardGauge, s.btcDel2LastRewardGauge = s.QueryRewardGauges(n) +} + +func (s *BtcRewardsDistribution) QueryRewardGauges(n *chain.NodeConfig) ( + fp1, fp2, del1, del2 *itypes.RewardGaugesResponse, +) { + n.WaitForNextBlockWithSleep50ms() + + // tries to query all in the same block + fp1RewardGauges, errFp1 := n.QueryRewardGauge(s.fp1.Address()) + fp2RewardGauges, errFp2 := n.QueryRewardGauge(s.fp2.Address()) + btcDel1RewardGauges, errDel1 := n.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del1Addr)) + btcDel2RewardGauges, errDel2 := n.QueryRewardGauge(sdk.MustAccAddressFromBech32(s.del2Addr)) + s.NoError(errFp1) + s.NoError(errFp2) + s.NoError(errDel1) + s.NoError(errDel2) + + fp1RewardGauge, ok := fp1RewardGauges[itypes.FinalityProviderType.String()] + s.True(ok) + s.True(fp1RewardGauge.Coins.IsAllPositive()) + + fp2RewardGauge, ok := fp2RewardGauges[itypes.FinalityProviderType.String()] + s.True(ok) + s.True(fp2RewardGauge.Coins.IsAllPositive()) + + btcDel1RewardGauge, ok := btcDel1RewardGauges[itypes.BTCDelegationType.String()] + s.True(ok) + s.True(btcDel1RewardGauge.Coins.IsAllPositive()) + + btcDel2RewardGauge, ok := btcDel2RewardGauges[itypes.BTCDelegationType.String()] + s.True(ok) + s.True(btcDel2RewardGauge.Coins.IsAllPositive()) + + return fp1RewardGauge, fp2RewardGauge, btcDel1RewardGauge, btcDel2RewardGauge +} + func (s *BtcRewardsDistribution) CreateBTCDelegationAndCheck( n *chain.NodeConfig, wDel string, diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index b12d6343b..3a37a3940 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -262,7 +262,7 @@ func (s *BTCStakingTestSuite) Test3CommitPublicRandomnessAndSubmitFinalitySignat s.ErrorContains(err, itypes.ErrRewardGaugeNotFound.Error()) delBabylonAddr := fpBabylonAddr - nonValidatorNode.WaitUntilCurrentEpochIsSealedAndFinalized() + nonValidatorNode.WaitUntilCurrentEpochIsSealedAndFinalized(1) // ensure btc staking is activated // check how this does not errors out diff --git a/test/e2e/configurer/chain/commands_btcstaking.go b/test/e2e/configurer/chain/commands_btcstaking.go index 6eedf3dd8..df908ed4b 100644 --- a/test/e2e/configurer/chain/commands_btcstaking.go +++ b/test/e2e/configurer/chain/commands_btcstaking.go @@ -144,7 +144,7 @@ func (n *NodeConfig) AddCovenantSigs( unbondingSig *bbn.BIP340Signature, unbondingSlashingSigs [][]byte, ) { - n.LogActionF("adding covenant signature") + n.LogActionF("adding covenant signature from nodeName: %s", n.Name) covPKHex := covPK.MarshalHex() diff --git a/test/e2e/configurer/chain/node.go b/test/e2e/configurer/chain/node.go index af2787e9c..9fc069616 100644 --- a/test/e2e/configurer/chain/node.go +++ b/test/e2e/configurer/chain/node.go @@ -120,9 +120,13 @@ func (n *NodeConfig) LatestBlockNumber() uint64 { } func (n *NodeConfig) WaitForCondition(doneCondition func() bool, errorMsg string) { + n.WaitForConditionWithPause(doneCondition, errorMsg, waitUntilRepeatPauseTime) +} + +func (n *NodeConfig) WaitForConditionWithPause(doneCondition func() bool, errorMsg string, pause time.Duration) { for i := 0; i < waitUntilrepeatMax; i++ { if !doneCondition() { - time.Sleep(waitUntilRepeatPauseTime) + time.Sleep(pause) continue } return @@ -154,6 +158,15 @@ func (n *NodeConfig) WaitForNextBlocks(numberOfBlocks uint64) { }, fmt.Sprintf("Timed out waiting for block %d. Current height is: %d", latest, blockToWait)) } +func (n *NodeConfig) WaitForNextBlockWithSleep50ms() { + latest := n.LatestBlockNumber() + blockToWait := latest + 1 + n.WaitForConditionWithPause(func() bool { + newLatest := n.LatestBlockNumber() + return newLatest > blockToWait + }, fmt.Sprintf("Timed out waiting for block %d. Current height is: %d", latest, blockToWait), time.Millisecond*50) +} + func (n *NodeConfig) extractOperatorAddressIfValidator() error { if !n.IsValidator { n.t.Logf("node (%s) is not a validator, skipping", n.Name) diff --git a/test/e2e/configurer/chain/queries.go b/test/e2e/configurer/chain/queries.go index ebe0e06e3..a0cdd668d 100644 --- a/test/e2e/configurer/chain/queries.go +++ b/test/e2e/configurer/chain/queries.go @@ -409,7 +409,7 @@ func (n *NodeConfig) QueryTx(txHash string, overallFlags ...string) sdk.TxRespon return txResp } -func (n *NodeConfig) WaitUntilCurrentEpochIsSealedAndFinalized() { +func (n *NodeConfig) WaitUntilCurrentEpochIsSealedAndFinalized(startEpoch uint64) (lastFinalizedEpoch uint64) { // finalize epochs from 1 to the current epoch currentEpoch, err := n.QueryCurrentEpoch() require.NoError(n.t, err) @@ -422,10 +422,9 @@ func (n *NodeConfig) WaitUntilCurrentEpochIsSealedAndFinalized() { } return resp.Status == ct.Sealed }, time.Minute*5, time.Millisecond*50) - n.FinalizeSealedEpochs(1, currentEpoch) + n.FinalizeSealedEpochs(startEpoch, currentEpoch) // ensure the committed epoch is finalized - lastFinalizedEpoch := uint64(0) require.Eventually(n.t, func() bool { lastFinalizedEpoch, err = n.QueryLastFinalizedEpoch() if err != nil { @@ -433,6 +432,7 @@ func (n *NodeConfig) WaitUntilCurrentEpochIsSealedAndFinalized() { } return lastFinalizedEpoch >= currentEpoch }, time.Minute, time.Millisecond*50) + return lastFinalizedEpoch } func (n *NodeConfig) WaitFinalityIsActivated() (activatedHeight uint64) { diff --git a/test/e2e/initialization/config.go b/test/e2e/initialization/config.go index 1b5101a64..003aeee5a 100644 --- a/test/e2e/initialization/config.go +++ b/test/e2e/initialization/config.go @@ -358,6 +358,7 @@ func updateBtccheckpointGenesis(btccheckpointGenState *btccheckpointtypes.Genesi func updateFinalityGenesis(finalityGenState *finalitytypes.GenesisState) { finalityGenState.Params = finalitytypes.DefaultParams() finalityGenState.Params.FinalityActivationHeight = 0 + finalityGenState.Params.SignedBlocksWindow = 2000 } func updateGenUtilGenesis(c *internalChain) func(*genutiltypes.GenesisState) { From 955c4985bba7023f0755c72f971e3f8c3c6e1e99 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 18 Dec 2024 17:02:32 -0300 Subject: [PATCH 096/132] tryfix: add fp voting every now and then --- test/e2e/btc_rewards_distribution_e2e_test.go | 45 ++++++++++++++++--- test/e2e/initialization/config.go | 3 +- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 87faaa874..04e31b1c3 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -11,6 +11,7 @@ import ( sdkmath "cosmossdk.io/math" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/chaincfg" + "github.com/cometbft/cometbft/libs/bytes" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -354,6 +355,8 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { // fp2Del2 s.CreateBTCDelegationAndCheck(n2, wDel2, s.fp2, s.del2BTCSK, s.del2Addr, s.fp2Del2StakingAmt) + s.AddFinalityVote() + allDelegations := n2.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) s.Equal(len(allDelegations), 4) @@ -374,6 +377,8 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { // wait for a block so that above txs take effect n1.WaitForNextBlock() + s.AddFinalityVote() + // ensure the BTC delegation has covenant sigs now allDelegations = n1.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) s.Len(allDelegations, 4) @@ -397,11 +402,10 @@ func (s *BtcRewardsDistribution) Test7FinalityVoteBlock() { n1, err := chainA.GetNodeAtIndex(1) s.NoError(err) - lastFinalizedEpoch, err := n1.QueryLastFinalizedEpoch() - s.NoError(err) - lastFinalizedEpoch++ - - n1.WaitUntilCurrentEpochIsSealedAndFinalized(lastFinalizedEpoch) + // lastFinalizedEpoch, err := n1.QueryLastFinalizedEpoch() + // s.NoError(err) + // lastFinalizedEpoch++ + // n1.WaitUntilCurrentEpochIsSealedAndFinalized(lastFinalizedEpoch) // submit finality signature s.finalityIdx++ @@ -508,6 +512,37 @@ func (s *BtcRewardsDistribution) Test8CheckRewards() { // TODO(rafilx): Slash a FP and expect rewards to be withdraw. +func (s *BtcRewardsDistribution) AddFinalityVote() (appHash bytes.HexBytes) { + chainA := s.configurer.GetChainConfig(0) + n2, err := chainA.GetNodeAtIndex(2) + s.NoError(err) + n1, err := chainA.GetNodeAtIndex(1) + s.NoError(err) + + s.finalityIdx++ + s.finalityBlockHeightVoted++ + + appHash = n1.AddFinalitySignatureToBlock( + s.fp1BTCSK, + s.fp1.BtcPk, + s.finalityBlockHeightVoted, + s.fp1RandListInfo.SRList[s.finalityIdx], + &s.fp1RandListInfo.PRList[s.finalityIdx], + *s.fp1RandListInfo.ProofList[s.finalityIdx].ToProto(), + ) + + n2.AddFinalitySignatureToBlock( + s.fp2BTCSK, + s.fp2.BtcPk, + s.finalityBlockHeightVoted, + s.fp2RandListInfo.SRList[s.finalityIdx], + &s.fp2RandListInfo.PRList[s.finalityIdx], + *s.fp2RandListInfo.ProofList[s.finalityIdx].ToProto(), + ) + + return appHash +} + // UpdateRewardGauges update the current reward gauges on the test suite func (s *BtcRewardsDistribution) UpdateRewardGauges(n *chain.NodeConfig) { s.fp1LastRewardGauge, s.fp2LastRewardGauge, s.btcDel1LastRewardGauge, s.btcDel2LastRewardGauge = s.QueryRewardGauges(n) diff --git a/test/e2e/initialization/config.go b/test/e2e/initialization/config.go index 003aeee5a..4ce287fdc 100644 --- a/test/e2e/initialization/config.go +++ b/test/e2e/initialization/config.go @@ -358,7 +358,8 @@ func updateBtccheckpointGenesis(btccheckpointGenState *btccheckpointtypes.Genesi func updateFinalityGenesis(finalityGenState *finalitytypes.GenesisState) { finalityGenState.Params = finalitytypes.DefaultParams() finalityGenState.Params.FinalityActivationHeight = 0 - finalityGenState.Params.SignedBlocksWindow = 2000 + finalityGenState.Params.SignedBlocksWindow = 500 + finalityGenState.Params.MinSignedPerWindow = sdkmath.LegacyMustNewDecFromStr("0.005000000000000000") } func updateGenUtilGenesis(c *internalChain) func(*genutiltypes.GenesisState) { From 5cd7bd71b1a79973f9660d3c44f0c95a26017b52 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Wed, 18 Dec 2024 20:00:57 -0300 Subject: [PATCH 097/132] tryfix: add fp voting every block, fails due to acc sequence --- test/e2e/btc_rewards_distribution_e2e_test.go | 55 ++++++++----------- test/e2e/initialization/config.go | 3 +- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 04e31b1c3..191bc48dd 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -30,7 +30,9 @@ const ( stakingTimeBlocks = uint16(math.MaxUint16) wDel1 = "del1" wDel2 = "del2" - numPubRand = uint64(250) + wFp1 = "fp1" + wFp2 = "fp2" + numPubRand = uint64(350) ) type BtcRewardsDistribution struct { @@ -283,6 +285,7 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { ) n2.WaitForNextBlocks(2) + s.AddFinalityVote() // ensure vote is eventually cast var finalizedBlocks []*ftypes.IndexedBlock @@ -355,7 +358,7 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { // fp2Del2 s.CreateBTCDelegationAndCheck(n2, wDel2, s.fp2, s.del2BTCSK, s.del2Addr, s.fp2Del2StakingAmt) - s.AddFinalityVote() + s.AddFinalityVoteUntilCurrentHeight() allDelegations := n2.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) s.Equal(len(allDelegations), 4) @@ -374,12 +377,12 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { SendCovenantSigsToPendingDel(s.r, s.T(), n1, s.net, s.covenantSKs, s.covenantWallets, pendingDel) - // wait for a block so that above txs take effect + // wait for a block so that covenant txs take effect n1.WaitForNextBlock() - s.AddFinalityVote() + s.AddFinalityVoteUntilCurrentHeight() - // ensure the BTC delegation has covenant sigs now + // ensure that all BTC delegation are active allDelegations = n1.QueryFinalityProvidersDelegations(s.fp1.BtcPk.MarshalHex(), s.fp2.BtcPk.MarshalHex()) s.Len(allDelegations, 4) for _, activeDel := range allDelegations { @@ -396,8 +399,8 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { // Test7FinalityVoteBlock votes in one more block from both finality providers func (s *BtcRewardsDistribution) Test7FinalityVoteBlock() { chainA := s.configurer.GetChainConfig(0) - n2, err := chainA.GetNodeAtIndex(2) - s.NoError(err) + // n2, err := chainA.GetNodeAtIndex(2) + // s.NoError(err) // covenants are at n1 n1, err := chainA.GetNodeAtIndex(1) s.NoError(err) @@ -407,29 +410,8 @@ func (s *BtcRewardsDistribution) Test7FinalityVoteBlock() { // lastFinalizedEpoch++ // n1.WaitUntilCurrentEpochIsSealedAndFinalized(lastFinalizedEpoch) - // submit finality signature - s.finalityIdx++ - s.finalityBlockHeightVoted++ - - appHash := n1.AddFinalitySignatureToBlock( - s.fp1BTCSK, - s.fp1.BtcPk, - s.finalityBlockHeightVoted, - s.fp1RandListInfo.SRList[s.finalityIdx], - &s.fp1RandListInfo.PRList[s.finalityIdx], - *s.fp1RandListInfo.ProofList[s.finalityIdx].ToProto(), - ) - - n2.AddFinalitySignatureToBlock( - s.fp2BTCSK, - s.fp2.BtcPk, - s.finalityBlockHeightVoted, - s.fp2RandListInfo.SRList[s.finalityIdx], - &s.fp2RandListInfo.PRList[s.finalityIdx], - *s.fp2RandListInfo.ProofList[s.finalityIdx].ToProto(), - ) - - n2.WaitForNextBlocks(2) + appHash := s.AddFinalityVote() + n1.WaitForNextBlock() // ensure vote is eventually cast var finalizedBlocks []*ftypes.IndexedBlock @@ -472,7 +454,7 @@ func (s *BtcRewardsDistribution) Test8CheckRewards() { // del2 ~16989ubbn fp1RewardGaugePrev, fp2RewardGaugePrev, btcDel1RewardGaugePrev, btcDel2RewardGaugePrev := s.QueryRewardGauges(n2) // wait a few block of rewards - n2.WaitForNextBlocks(20) + n2.WaitForNextBlocks(10) fp1RewardGauge, fp2RewardGauge, btcDel1RewardGauge, btcDel2RewardGauge := s.QueryRewardGauges(n2) // since varius block were created, it is needed to get the difference @@ -512,6 +494,17 @@ func (s *BtcRewardsDistribution) Test8CheckRewards() { // TODO(rafilx): Slash a FP and expect rewards to be withdraw. +func (s *BtcRewardsDistribution) AddFinalityVoteUntilCurrentHeight() { + chainA := s.configurer.GetChainConfig(0) + n2, err := chainA.GetNodeAtIndex(2) + s.NoError(err) + currentBlock := n2.LatestBlockNumber() + + for s.finalityBlockHeightVoted < currentBlock { + s.AddFinalityVote() + } +} + func (s *BtcRewardsDistribution) AddFinalityVote() (appHash bytes.HexBytes) { chainA := s.configurer.GetChainConfig(0) n2, err := chainA.GetNodeAtIndex(2) diff --git a/test/e2e/initialization/config.go b/test/e2e/initialization/config.go index 4ce287fdc..70b07562b 100644 --- a/test/e2e/initialization/config.go +++ b/test/e2e/initialization/config.go @@ -358,8 +358,9 @@ func updateBtccheckpointGenesis(btccheckpointGenState *btccheckpointtypes.Genesi func updateFinalityGenesis(finalityGenState *finalitytypes.GenesisState) { finalityGenState.Params = finalitytypes.DefaultParams() finalityGenState.Params.FinalityActivationHeight = 0 + finalityGenState.Params.FinalitySigTimeout = 5 finalityGenState.Params.SignedBlocksWindow = 500 - finalityGenState.Params.MinSignedPerWindow = sdkmath.LegacyMustNewDecFromStr("0.005000000000000000") + finalityGenState.Params.MinSignedPerWindow = sdkmath.LegacyMustNewDecFromStr("0.000500000000000000") } func updateGenUtilGenesis(c *internalChain) func(*genutiltypes.GenesisState) { From f670bd5149e36f5ec26b4274a733f21ea8342b96 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 00:35:12 -0300 Subject: [PATCH 098/132] chore: add accounts query and option to add sequence and account number to finality vote --- test/e2e/btc_rewards_distribution_e2e_test.go | 39 +++++++++++++++++-- test/e2e/btc_staking_e2e_test.go | 2 +- test/e2e/btc_staking_pre_approval_e2e_test.go | 4 +- .../configurer/chain/commands_btcstaking.go | 35 ++++++++++++++--- test/e2e/configurer/chain/queries.go | 19 +++++++++ test/e2e/initialization/config.go | 6 +-- 6 files changed, 90 insertions(+), 15 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 191bc48dd..8ec64653b 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -285,7 +285,7 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { ) n2.WaitForNextBlocks(2) - s.AddFinalityVote() + s.AddFinalityVote([]string{}, []string{}) // ensure vote is eventually cast var finalizedBlocks []*ftypes.IndexedBlock @@ -410,7 +410,7 @@ func (s *BtcRewardsDistribution) Test7FinalityVoteBlock() { // lastFinalizedEpoch++ // n1.WaitUntilCurrentEpochIsSealedAndFinalized(lastFinalizedEpoch) - appHash := s.AddFinalityVote() + appHash := s.AddFinalityVote([]string{}, []string{}) n1.WaitForNextBlock() // ensure vote is eventually cast @@ -496,16 +496,45 @@ func (s *BtcRewardsDistribution) Test8CheckRewards() { func (s *BtcRewardsDistribution) AddFinalityVoteUntilCurrentHeight() { chainA := s.configurer.GetChainConfig(0) + n1, err := chainA.GetNodeAtIndex(1) + s.NoError(err) n2, err := chainA.GetNodeAtIndex(2) s.NoError(err) + currentBlock := n2.LatestBlockNumber() + accN1, err := n1.QueryAccount(s.fp1.Addr) + s.NoError(err) + accN2, err := n1.QueryAccount(s.fp2.Addr) + s.NoError(err) + + accNumberN1 := accN1.GetAccountNumber() + accSequenceN1 := accN1.GetSequence() + + accNumberN2 := accN2.GetAccountNumber() + accSequenceN2 := accN2.GetSequence() + for s.finalityBlockHeightVoted < currentBlock { - s.AddFinalityVote() + n1Flags := []string{ + "--from=val", + "--offline", + fmt.Sprintf("--account-number=%d", accNumberN1), + fmt.Sprintf("--sequence=%d", accSequenceN1), + } + n2Flags := []string{ + "--from=val", + "--offline", + fmt.Sprintf("--account-number=%d", accNumberN2), + fmt.Sprintf("--sequence=%d", accSequenceN2), + } + s.AddFinalityVote(n1Flags, n2Flags) + + accSequenceN1++ + accSequenceN2++ } } -func (s *BtcRewardsDistribution) AddFinalityVote() (appHash bytes.HexBytes) { +func (s *BtcRewardsDistribution) AddFinalityVote(flagsN1, flagsN2 []string) (appHash bytes.HexBytes) { chainA := s.configurer.GetChainConfig(0) n2, err := chainA.GetNodeAtIndex(2) s.NoError(err) @@ -522,6 +551,7 @@ func (s *BtcRewardsDistribution) AddFinalityVote() (appHash bytes.HexBytes) { s.fp1RandListInfo.SRList[s.finalityIdx], &s.fp1RandListInfo.PRList[s.finalityIdx], *s.fp1RandListInfo.ProofList[s.finalityIdx].ToProto(), + flagsN1..., ) n2.AddFinalitySignatureToBlock( @@ -531,6 +561,7 @@ func (s *BtcRewardsDistribution) AddFinalityVote() (appHash bytes.HexBytes) { s.fp2RandListInfo.SRList[s.finalityIdx], &s.fp2RandListInfo.PRList[s.finalityIdx], *s.fp2RandListInfo.ProofList[s.finalityIdx].ToProto(), + flagsN2..., ) return appHash diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index 3a37a3940..c074997e9 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -285,7 +285,7 @@ func (s *BTCStakingTestSuite) Test3CommitPublicRandomnessAndSubmitFinalitySignat nonValidatorNode.SubmitRefundableTxWithAssertion(func() { // submit finality signature - nonValidatorNode.AddFinalitySig(s.cacheFP.BtcPk, activatedHeight, &randListInfo.PRList[idx], *randListInfo.ProofList[idx].ToProto(), appHash, eotsSig) + nonValidatorNode.AddFinalitySigFromVal(s.cacheFP.BtcPk, activatedHeight, &randListInfo.PRList[idx], *randListInfo.ProofList[idx].ToProto(), appHash, eotsSig) // ensure vote is eventually cast var finalizedBlocks []*ftypes.IndexedBlock diff --git a/test/e2e/btc_staking_pre_approval_e2e_test.go b/test/e2e/btc_staking_pre_approval_e2e_test.go index ca1251072..77651f8b7 100644 --- a/test/e2e/btc_staking_pre_approval_e2e_test.go +++ b/test/e2e/btc_staking_pre_approval_e2e_test.go @@ -368,7 +368,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test4CommitPublicRandomnessAndSubmitFin eotsSig := bbn.NewSchnorrEOTSSigFromModNScalar(sig) // submit finality signature nonValidatorNode.SubmitRefundableTxWithAssertion(func() { - nonValidatorNode.AddFinalitySig(s.cacheFP.BtcPk, activatedHeight, &randListInfo.PRList[idx], *randListInfo.ProofList[idx].ToProto(), appHash, eotsSig) + nonValidatorNode.AddFinalitySigFromVal(s.cacheFP.BtcPk, activatedHeight, &randListInfo.PRList[idx], *randListInfo.ProofList[idx].ToProto(), appHash, eotsSig) // ensure vote is eventually cast var finalizedBlocks []*ftypes.IndexedBlock @@ -386,7 +386,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test4CommitPublicRandomnessAndSubmitFin _, pk, err := datagen.GenRandomBTCKeyPair(s.r) s.NoError(err) btcPK := bbn.NewBIP340PubKeyFromBTCPK(pk) - nonValidatorNode.AddFinalitySig(btcPK, activatedHeight, &randListInfo.PRList[idx], *randListInfo.ProofList[idx].ToProto(), appHash, eotsSig) + nonValidatorNode.AddFinalitySigFromVal(btcPK, activatedHeight, &randListInfo.PRList[idx], *randListInfo.ProofList[idx].ToProto(), appHash, eotsSig) nonValidatorNode.WaitForNextBlock() }, false) diff --git a/test/e2e/configurer/chain/commands_btcstaking.go b/test/e2e/configurer/chain/commands_btcstaking.go index df908ed4b..bd7963eb9 100644 --- a/test/e2e/configurer/chain/commands_btcstaking.go +++ b/test/e2e/configurer/chain/commands_btcstaking.go @@ -213,7 +213,15 @@ func (n *NodeConfig) CommitPubRandList(fpBTCPK *bbn.BIP340PubKey, startHeight ui n.LogActionF("successfully committed public randomness list") } -func (n *NodeConfig) AddFinalitySig(fpBTCPK *bbn.BIP340PubKey, blockHeight uint64, pubRand *bbn.SchnorrPubRand, proof cmtcrypto.Proof, appHash []byte, finalitySig *bbn.SchnorrEOTSSig) { +func (n *NodeConfig) AddFinalitySig( + fpBTCPK *bbn.BIP340PubKey, + blockHeight uint64, + pubRand *bbn.SchnorrPubRand, + proof cmtcrypto.Proof, + appHash []byte, + finalitySig *bbn.SchnorrEOTSSig, + overallFlags ...string, +) { n.LogActionF("add finality signature") fpBTCPKHex := fpBTCPK.MarshalHex() @@ -225,10 +233,25 @@ func (n *NodeConfig) AddFinalitySig(fpBTCPK *bbn.BIP340PubKey, blockHeight uint6 appHashHex := hex.EncodeToString(appHash) finalitySigHex := finalitySig.ToHexStr() - cmd := []string{"babylond", "tx", "finality", "add-finality-sig", fpBTCPKHex, blockHeightStr, pubRandHex, proofHex, appHashHex, finalitySigHex, "--from=val", "--gas=500000"} - _, _, err = n.containerManager.ExecTxCmd(n.t, n.chainId, n.Name, cmd) + cmd := []string{"babylond", "tx", "finality", "add-finality-sig", fpBTCPKHex, blockHeightStr, pubRandHex, proofHex, appHashHex, finalitySigHex, "--gas=500000"} + additionalArgs := []string{fmt.Sprintf("--chain-id=%s", n.chainId), "--gas-prices=0.002ubbn", "-b=sync", "--yes", "--keyring-backend=test", "--log_format=json", "--home=/home/babylon/babylondata"} + cmd = append(cmd, additionalArgs...) + + outBuff, _, err := n.containerManager.ExecCmd(n.t, n.Name, append(cmd, overallFlags...), "code: 0") require.NoError(n.t, err) - n.LogActionF("successfully added finality signature") + n.LogActionF("successfully added finality signature: %s", outBuff.String()) +} + +func (n *NodeConfig) AddFinalitySigFromVal( + fpBTCPK *bbn.BIP340PubKey, + blockHeight uint64, + pubRand *bbn.SchnorrPubRand, + proof cmtcrypto.Proof, + appHash []byte, + finalitySig *bbn.SchnorrEOTSSig, + overallFlags ...string, +) { + n.AddFinalitySig(fpBTCPK, blockHeight, pubRand, proof, appHash, finalitySig, append(overallFlags, "--from=val")...) } func (n *NodeConfig) AddCovenantUnbondingSigs( @@ -432,6 +455,7 @@ func (n *NodeConfig) AddFinalitySignatureToBlock( privateRand *secp256k1.ModNScalar, pubRand *bbn.SchnorrPubRand, proof cmtcrypto.Proof, + overallFlags ...string, ) (blockVotedAppHash bytes.HexBytes) { blockToVote, err := n.QueryBlock(int64(blockHeight)) require.NoError(n.t, err) @@ -445,13 +469,14 @@ func (n *NodeConfig) AddFinalitySignatureToBlock( finalitySig := bbn.NewSchnorrEOTSSigFromModNScalar(fp1Sig) // submit finality signature - n.AddFinalitySig( + n.AddFinalitySigFromVal( fpBTCPK, blockHeight, pubRand, proof, appHash, finalitySig, + overallFlags..., ) return appHash } diff --git a/test/e2e/configurer/chain/queries.go b/test/e2e/configurer/chain/queries.go index a0cdd668d..50406341e 100644 --- a/test/e2e/configurer/chain/queries.go +++ b/test/e2e/configurer/chain/queries.go @@ -93,6 +93,25 @@ func (n *NodeConfig) QueryModuleAddress(name string) (sdk.AccAddress, error) { return account.GetAddress(), nil } +// QueryAccount returns the account given the address +func (n *NodeConfig) QueryAccount(address string) (sdk.AccountI, error) { + path := fmt.Sprintf("/cosmos/auth/v1beta1/accounts/%s", address) + bz, err := n.QueryGRPCGateway(path, url.Values{}) + require.NoError(n.t, err) + + var resp authtypes.QueryAccountResponse + if err := util.Cdc.UnmarshalJSON(bz, &resp); err != nil { + return nil, err + } + + var account sdk.AccountI + if err := util.EncodingConfig.InterfaceRegistry.UnpackAny(resp.Account, &account); err != nil { + return nil, err + } + + return account, nil +} + // QueryBalances returns balances at the address. func (n *NodeConfig) QueryBalances(address string) (sdk.Coins, error) { path := fmt.Sprintf("cosmos/bank/v1beta1/balances/%s", address) diff --git a/test/e2e/initialization/config.go b/test/e2e/initialization/config.go index 70b07562b..53be9e6b7 100644 --- a/test/e2e/initialization/config.go +++ b/test/e2e/initialization/config.go @@ -358,9 +358,9 @@ func updateBtccheckpointGenesis(btccheckpointGenState *btccheckpointtypes.Genesi func updateFinalityGenesis(finalityGenState *finalitytypes.GenesisState) { finalityGenState.Params = finalitytypes.DefaultParams() finalityGenState.Params.FinalityActivationHeight = 0 - finalityGenState.Params.FinalitySigTimeout = 5 - finalityGenState.Params.SignedBlocksWindow = 500 - finalityGenState.Params.MinSignedPerWindow = sdkmath.LegacyMustNewDecFromStr("0.000500000000000000") + finalityGenState.Params.FinalitySigTimeout = 3 + finalityGenState.Params.SignedBlocksWindow = 300 + finalityGenState.Params.MinSignedPerWindow = sdkmath.LegacyMustNewDecFromStr("0.000005000000000000") } func updateGenUtilGenesis(c *internalChain) func(*genutiltypes.GenesisState) { From 6dd660cb0ccc5fec13434e6c14b874aac2234a06 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 00:39:52 -0300 Subject: [PATCH 099/132] chore: remove from val duplicated --- test/e2e/btc_rewards_distribution_e2e_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 8ec64653b..600a6c7d8 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -516,13 +516,11 @@ func (s *BtcRewardsDistribution) AddFinalityVoteUntilCurrentHeight() { for s.finalityBlockHeightVoted < currentBlock { n1Flags := []string{ - "--from=val", "--offline", fmt.Sprintf("--account-number=%d", accNumberN1), fmt.Sprintf("--sequence=%d", accSequenceN1), } n2Flags := []string{ - "--from=val", "--offline", fmt.Sprintf("--account-number=%d", accNumberN2), fmt.Sprintf("--sequence=%d", accSequenceN2), From 4e7ce2992af55c7354e131a6439c37f9db069673 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 01:07:23 -0300 Subject: [PATCH 100/132] tryfix: add specific address for finality providers --- test/e2e/btc_rewards_distribution_e2e_test.go | 89 ++++++++++++------- test/e2e/btc_staking_e2e_test.go | 44 ++++++++- test/e2e/btc_staking_pre_approval_e2e_test.go | 2 +- .../configurer/chain/commands_btcstaking.go | 2 +- test/e2e/initialization/config.go | 2 +- test/e2e/software_upgrade_e2e_v1_test.go | 2 +- 6 files changed, 102 insertions(+), 39 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 600a6c7d8..95f4a75b9 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -77,6 +77,9 @@ type BtcRewardsDistribution struct { // bech32 address of the delegators del1Addr string del2Addr string + // bech32 address of the finality providers + fp1Addr string + fp2Addr string // covenant helpers covenantSKs []*btcec.PrivateKey @@ -134,11 +137,19 @@ func (s *BtcRewardsDistribution) Test1CreateFinalityProviders() { n2, err := chainA.GetNodeAtIndex(2) s.NoError(err) + s.fp1Addr = n1.KeysAdd(wFp1) + s.fp2Addr = n2.KeysAdd(wFp2) + + n2.BankMultiSendFromNode([]string{s.fp1Addr, s.fp2Addr}, "100000ubbn") + + n2.WaitForNextBlock() + s.fp1 = CreateNodeFP( s.T(), s.r, s.fp1BTCSK, n1, + s.fp1Addr, ) s.NotNil(s.fp1) @@ -147,6 +158,7 @@ func (s *BtcRewardsDistribution) Test1CreateFinalityProviders() { s.r, s.fp2BTCSK, n2, + s.fp2Addr, ) s.NotNil(s.fp2) @@ -165,14 +177,14 @@ func (s *BtcRewardsDistribution) Test2CreateFirstBtcDelegations() { n2.BankMultiSendFromNode([]string{s.del1Addr, s.del2Addr}, "100000ubbn") + n2.WaitForNextBlock() + // fp1Del1 s.CreateBTCDelegationAndCheck(n2, wDel1, s.fp1, s.del1BTCSK, s.del1Addr, s.fp1Del1StakingAmt) // fp1Del2 s.CreateBTCDelegationAndCheck(n2, wDel2, s.fp1, s.del2BTCSK, s.del2Addr, s.fp1Del2StakingAmt) // fp2Del1 s.CreateBTCDelegationAndCheck(n2, wDel1, s.fp2, s.del1BTCSK, s.del1Addr, s.fp2Del1StakingAmt) - - n2.WaitForNextBlock() } // Test3SubmitCovenantSignature covenant approves all the 3 BTC delegation @@ -273,6 +285,7 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { s.fp1RandListInfo.SRList[s.finalityIdx], &s.fp1RandListInfo.PRList[s.finalityIdx], *s.fp1RandListInfo.ProofList[s.finalityIdx].ToProto(), + fmt.Sprintf("--from=%s", wFp1), ) n2.AddFinalitySignatureToBlock( @@ -282,10 +295,11 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { s.fp2RandListInfo.SRList[s.finalityIdx], &s.fp2RandListInfo.PRList[s.finalityIdx], *s.fp2RandListInfo.ProofList[s.finalityIdx].ToProto(), + fmt.Sprintf("--from=%s", wFp2), ) - n2.WaitForNextBlocks(2) - s.AddFinalityVote([]string{}, []string{}) + s.AddFinalityVoteUntilCurrentHeight() + n2.WaitForNextBlock() // ensure vote is eventually cast var finalizedBlocks []*ftypes.IndexedBlock @@ -397,34 +411,34 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { } // Test7FinalityVoteBlock votes in one more block from both finality providers -func (s *BtcRewardsDistribution) Test7FinalityVoteBlock() { - chainA := s.configurer.GetChainConfig(0) - // n2, err := chainA.GetNodeAtIndex(2) - // s.NoError(err) - // covenants are at n1 - n1, err := chainA.GetNodeAtIndex(1) - s.NoError(err) - - // lastFinalizedEpoch, err := n1.QueryLastFinalizedEpoch() - // s.NoError(err) - // lastFinalizedEpoch++ - // n1.WaitUntilCurrentEpochIsSealedAndFinalized(lastFinalizedEpoch) - - appHash := s.AddFinalityVote([]string{}, []string{}) - n1.WaitForNextBlock() - - // ensure vote is eventually cast - var finalizedBlocks []*ftypes.IndexedBlock - s.Eventually(func() bool { - finalizedBlocks = n1.QueryListBlocks(ftypes.QueriedBlockStatus_FINALIZED) - return len(finalizedBlocks) > 1 - }, time.Minute, time.Millisecond*50) - - lastFinalizedBlock := finalizedBlocks[len(finalizedBlocks)-1] - s.Equal(s.finalityBlockHeightVoted, lastFinalizedBlock.Height) - s.Equal(appHash.Bytes(), lastFinalizedBlock.AppHash) - s.T().Logf("the block %d is finalized", s.finalityBlockHeightVoted) -} +// func (s *BtcRewardsDistribution) Test7FinalityVoteBlock() { +// chainA := s.configurer.GetChainConfig(0) +// // n2, err := chainA.GetNodeAtIndex(2) +// // s.NoError(err) +// // covenants are at n1 +// n1, err := chainA.GetNodeAtIndex(1) +// s.NoError(err) + +// // lastFinalizedEpoch, err := n1.QueryLastFinalizedEpoch() +// // s.NoError(err) +// // lastFinalizedEpoch++ +// // n1.WaitUntilCurrentEpochIsSealedAndFinalized(lastFinalizedEpoch) + +// appHash := s.AddFinalityVote([]string{}, []string{}) +// n1.WaitForNextBlock() + +// // ensure vote is eventually cast +// var finalizedBlocks []*ftypes.IndexedBlock +// s.Eventually(func() bool { +// finalizedBlocks = n1.QueryListBlocks(ftypes.QueriedBlockStatus_FINALIZED) +// return len(finalizedBlocks) > 1 +// }, time.Minute, time.Millisecond*50) + +// lastFinalizedBlock := finalizedBlocks[len(finalizedBlocks)-1] +// s.Equal(s.finalityBlockHeightVoted, lastFinalizedBlock.Height) +// s.Equal(appHash.Bytes(), lastFinalizedBlock.AppHash) +// s.T().Logf("the block %d is finalized", s.finalityBlockHeightVoted) +// } // Test8CheckRewards verifies the rewards of all the delegations // and finality provider @@ -432,6 +446,8 @@ func (s *BtcRewardsDistribution) Test8CheckRewards() { n2, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(2) s.NoError(err) + n2.WaitForNextBlock() + s.AddFinalityVoteUntilCurrentHeight() // updates the cache of the suite // s.UpdateRewardGauges(n2) @@ -454,7 +470,12 @@ func (s *BtcRewardsDistribution) Test8CheckRewards() { // del2 ~16989ubbn fp1RewardGaugePrev, fp2RewardGaugePrev, btcDel1RewardGaugePrev, btcDel2RewardGaugePrev := s.QueryRewardGauges(n2) // wait a few block of rewards - n2.WaitForNextBlocks(10) + n2.WaitForNextBlocks(3) + s.AddFinalityVoteUntilCurrentHeight() + n2.WaitForNextBlocks(3) + s.AddFinalityVoteUntilCurrentHeight() + n2.WaitForNextBlocks(3) + fp1RewardGauge, fp2RewardGauge, btcDel1RewardGauge, btcDel2RewardGauge := s.QueryRewardGauges(n2) // since varius block were created, it is needed to get the difference @@ -519,11 +540,13 @@ func (s *BtcRewardsDistribution) AddFinalityVoteUntilCurrentHeight() { "--offline", fmt.Sprintf("--account-number=%d", accNumberN1), fmt.Sprintf("--sequence=%d", accSequenceN1), + fmt.Sprintf("--from=%s", wFp1), } n2Flags := []string{ "--offline", fmt.Sprintf("--account-number=%d", accNumberN2), fmt.Sprintf("--sequence=%d", accSequenceN2), + fmt.Sprintf("--from=%s", wFp2), } s.AddFinalityVote(n1Flags, n2Flags) diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index c074997e9..9e30e42f1 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -80,7 +80,7 @@ func (s *BTCStakingTestSuite) Test1CreateFinalityProviderAndDelegation() { nonValidatorNode, err := chainA.GetNodeAtIndex(2) s.NoError(err) - s.cacheFP = CreateNodeFP( + s.cacheFP = CreateNodeFPFromNodeAddr( s.T(), s.r, s.fptBTCSK, @@ -829,15 +829,55 @@ func equalFinalityProviderResp(t *testing.T, fp *bstypes.FinalityProvider, fpRes require.Equal(t, fp.SlashedBtcHeight, fpResp.SlashedBtcHeight) } +// CreateNodeFPFromNodeAddr creates a random finality provider. +func CreateNodeFPFromNodeAddr( + t *testing.T, + r *rand.Rand, + fpSk *btcec.PrivateKey, + node *chain.NodeConfig, +) (newFP *bstypes.FinalityProvider) { + // the node is the new FP + nodeAddr, err := sdk.AccAddressFromBech32(node.PublicAddress) + require.NoError(t, err) + + newFP, err = datagen.GenRandomFinalityProviderWithBTCBabylonSKs(r, fpSk, nodeAddr) + require.NoError(t, err) + + previousFps := node.QueryFinalityProviders() + + // use a higher commission to ensure the reward is more than tx fee of a finality sig + commission := sdkmath.LegacyNewDecWithPrec(20, 2) + newFP.Commission = &commission + node.CreateFinalityProvider(newFP.Addr, newFP.BtcPk, newFP.Pop, newFP.Description.Moniker, newFP.Description.Identity, newFP.Description.Website, newFP.Description.SecurityContact, newFP.Description.Details, newFP.Commission) + + // wait for a block so that above txs take effect + node.WaitForNextBlock() + + // query the existence of finality provider and assert equivalence + actualFps := node.QueryFinalityProviders() + require.Len(t, actualFps, len(previousFps)+1) + + for _, fpResp := range actualFps { + if !strings.EqualFold(fpResp.Addr, newFP.Addr) { + continue + } + equalFinalityProviderResp(t, newFP, fpResp) + return newFP + } + + return nil +} + // CreateNodeFP creates a random finality provider. func CreateNodeFP( t *testing.T, r *rand.Rand, fpSk *btcec.PrivateKey, node *chain.NodeConfig, + fpAddr string, ) (newFP *bstypes.FinalityProvider) { // the node is the new FP - nodeAddr, err := sdk.AccAddressFromBech32(node.PublicAddress) + nodeAddr, err := sdk.AccAddressFromBech32(fpAddr) require.NoError(t, err) newFP, err = datagen.GenRandomFinalityProviderWithBTCBabylonSKs(r, fpSk, nodeAddr) diff --git a/test/e2e/btc_staking_pre_approval_e2e_test.go b/test/e2e/btc_staking_pre_approval_e2e_test.go index 77651f8b7..76fc7b7b1 100644 --- a/test/e2e/btc_staking_pre_approval_e2e_test.go +++ b/test/e2e/btc_staking_pre_approval_e2e_test.go @@ -78,7 +78,7 @@ func (s *BTCStakingPreApprovalTestSuite) Test1CreateFinalityProviderAndDelegatio nonValidatorNode, err := chainA.GetNodeAtIndex(2) s.NoError(err) - s.cacheFP = CreateNodeFP( + s.cacheFP = CreateNodeFPFromNodeAddr( s.T(), s.r, s.fptBTCSK, diff --git a/test/e2e/configurer/chain/commands_btcstaking.go b/test/e2e/configurer/chain/commands_btcstaking.go index bd7963eb9..07e378422 100644 --- a/test/e2e/configurer/chain/commands_btcstaking.go +++ b/test/e2e/configurer/chain/commands_btcstaking.go @@ -469,7 +469,7 @@ func (n *NodeConfig) AddFinalitySignatureToBlock( finalitySig := bbn.NewSchnorrEOTSSigFromModNScalar(fp1Sig) // submit finality signature - n.AddFinalitySigFromVal( + n.AddFinalitySig( fpBTCPK, blockHeight, pubRand, diff --git a/test/e2e/initialization/config.go b/test/e2e/initialization/config.go index 53be9e6b7..c46f8ef69 100644 --- a/test/e2e/initialization/config.go +++ b/test/e2e/initialization/config.go @@ -358,7 +358,7 @@ func updateBtccheckpointGenesis(btccheckpointGenState *btccheckpointtypes.Genesi func updateFinalityGenesis(finalityGenState *finalitytypes.GenesisState) { finalityGenState.Params = finalitytypes.DefaultParams() finalityGenState.Params.FinalityActivationHeight = 0 - finalityGenState.Params.FinalitySigTimeout = 3 + finalityGenState.Params.FinalitySigTimeout = 4 finalityGenState.Params.SignedBlocksWindow = 300 finalityGenState.Params.MinSignedPerWindow = sdkmath.LegacyMustNewDecFromStr("0.000005000000000000") } diff --git a/test/e2e/software_upgrade_e2e_v1_test.go b/test/e2e/software_upgrade_e2e_v1_test.go index e28934a4d..cc1a4309e 100644 --- a/test/e2e/software_upgrade_e2e_v1_test.go +++ b/test/e2e/software_upgrade_e2e_v1_test.go @@ -111,7 +111,7 @@ func (s *SoftwareUpgradeV1TestnetTestSuite) TestUpgradeV1() { r := rand.New(rand.NewSource(time.Now().Unix())) fptBTCSK, _, _ := datagen.GenRandomBTCKeyPair(r) - fp := CreateNodeFP( + fp := CreateNodeFPFromNodeAddr( s.T(), r, fptBTCSK, From 531b4065e84c29bf56172d1b86deb61ea7e8bf21 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 01:19:17 -0300 Subject: [PATCH 101/132] fix: e2e test with checking rewards --- test/e2e/btc_rewards_distribution_e2e_test.go | 96 +++++-------------- test/e2e/initialization/node.go | 2 +- 2 files changed, 24 insertions(+), 74 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 95f4a75b9..cc48515dd 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -91,12 +91,6 @@ type BtcRewardsDistribution struct { fp1RandListInfo *datagen.RandListInfo fp2RandListInfo *datagen.RandListInfo - // reward helpers - fp1LastRewardGauge *itypes.RewardGaugesResponse - fp2LastRewardGauge *itypes.RewardGaugesResponse - btcDel2LastRewardGauge *itypes.RewardGaugesResponse - btcDel1LastRewardGauge *itypes.RewardGaugesResponse - configurer configurer.Configurer } @@ -330,19 +324,19 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { // (del2) => 4_00000000 // The rewards distributed for the finality providers should be fp1 => 3x, fp2 => 1x - s.UpdateRewardGauges(n2) + fp1LastRewardGauge, fp2LastRewardGauge, btcDel1LastRewardGauge, btcDel2LastRewardGauge := s.QueryRewardGauges(n2) // fp1 ~2674ubbn // fp2 ~891ubbn coins.RequireCoinsDiffInPointOnePercentMargin( s.T(), - s.fp2LastRewardGauge.Coins.MulInt(sdkmath.NewIntFromUint64(3)), // ~2673ubbn - s.fp1LastRewardGauge.Coins, + fp2LastRewardGauge.Coins.MulInt(sdkmath.NewIntFromUint64(3)), // ~2673ubbn + fp1LastRewardGauge.Coins, ) // The rewards distributed to the delegators should be the same for each delegator // del1 ~7130ubbn // del2 ~7130ubbn - s.Equal(s.btcDel1LastRewardGauge.Coins.String(), s.btcDel2LastRewardGauge.Coins.String()) + s.Equal(btcDel1LastRewardGauge.Coins.String(), btcDel2LastRewardGauge.Coins.String()) // note that the rewards will not be precise as more or less blocks were produced and given out rewards. // Withdraw the reward just for del2 to check it is possible @@ -355,7 +349,7 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { del2BalanceAfterWithdraw, err := n2.QueryBalances(s.del2Addr) s.NoError(err) - s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(s.btcDel2LastRewardGauge.Coins...).String()) + s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(btcDel2LastRewardGauge.Coins...).String()) } // Test6ActiveLastDelegation creates a new btc delegation @@ -402,44 +396,8 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { for _, activeDel := range allDelegations { s.True(activeDel.Active) } - - // cache the reward gauges prior to the BTC delegation is active, so it - // can calculate the rewards properly based on the difference - // even then it could be that a block is mined between the query of this - // 4 address, but the difference would be very small - // s.UpdateRewardGauges() } -// Test7FinalityVoteBlock votes in one more block from both finality providers -// func (s *BtcRewardsDistribution) Test7FinalityVoteBlock() { -// chainA := s.configurer.GetChainConfig(0) -// // n2, err := chainA.GetNodeAtIndex(2) -// // s.NoError(err) -// // covenants are at n1 -// n1, err := chainA.GetNodeAtIndex(1) -// s.NoError(err) - -// // lastFinalizedEpoch, err := n1.QueryLastFinalizedEpoch() -// // s.NoError(err) -// // lastFinalizedEpoch++ -// // n1.WaitUntilCurrentEpochIsSealedAndFinalized(lastFinalizedEpoch) - -// appHash := s.AddFinalityVote([]string{}, []string{}) -// n1.WaitForNextBlock() - -// // ensure vote is eventually cast -// var finalizedBlocks []*ftypes.IndexedBlock -// s.Eventually(func() bool { -// finalizedBlocks = n1.QueryListBlocks(ftypes.QueriedBlockStatus_FINALIZED) -// return len(finalizedBlocks) > 1 -// }, time.Minute, time.Millisecond*50) - -// lastFinalizedBlock := finalizedBlocks[len(finalizedBlocks)-1] -// s.Equal(s.finalityBlockHeightVoted, lastFinalizedBlock.Height) -// s.Equal(appHash.Bytes(), lastFinalizedBlock.AppHash) -// s.T().Logf("the block %d is finalized", s.finalityBlockHeightVoted) -// } - // Test8CheckRewards verifies the rewards of all the delegations // and finality provider func (s *BtcRewardsDistribution) Test8CheckRewards() { @@ -448,8 +406,6 @@ func (s *BtcRewardsDistribution) Test8CheckRewards() { n2.WaitForNextBlock() s.AddFinalityVoteUntilCurrentHeight() - // updates the cache of the suite - // s.UpdateRewardGauges(n2) // Current setup of voting power // (fp1, del1) => 2_00000000 @@ -463,18 +419,20 @@ func (s *BtcRewardsDistribution) Test8CheckRewards() { // (del1) => 4_00000000 // (del2) => 10_00000000 - // Current rewards for each FP + // Current rewards for each addr // fp1 ~5364ubbn // fp2 ~1787ubbn // del1 ~11625ubbn // del2 ~16989ubbn fp1RewardGaugePrev, fp2RewardGaugePrev, btcDel1RewardGaugePrev, btcDel2RewardGaugePrev := s.QueryRewardGauges(n2) - // wait a few block of rewards - n2.WaitForNextBlocks(3) + // wait a few block of rewards to calculate the difference + n2.WaitForNextBlocks(2) + s.AddFinalityVoteUntilCurrentHeight() + n2.WaitForNextBlocks(2) s.AddFinalityVoteUntilCurrentHeight() - n2.WaitForNextBlocks(3) + n2.WaitForNextBlocks(2) s.AddFinalityVoteUntilCurrentHeight() - n2.WaitForNextBlocks(3) + n2.WaitForNextBlocks(2) fp1RewardGauge, fp2RewardGauge, btcDel1RewardGauge, btcDel2RewardGauge := s.QueryRewardGauges(n2) @@ -488,6 +446,16 @@ func (s *BtcRewardsDistribution) Test8CheckRewards() { del1DiffRewards := btcDel1RewardGauge.Coins.Sub(btcDel1RewardGaugePrev.Coins...) del2DiffRewards := btcDel2RewardGauge.Coins.Sub(btcDel2RewardGaugePrev.Coins...) + // Check the difference in the finality providers + // fp1 should receive ~75% of the rewards received by fp2 + expectedRwdFp1 := coins.CalculatePercentageOfCoins(fp2DiffRewards, 75) + coins.RequireCoinsDiffInPointOnePercentMargin(s.T(), fp1DiffRewards, expectedRwdFp1) + + // Check the difference in the delegators + // the del1 should receive ~40% of the rewards received by del2 + expectedRwdDel1 := coins.CalculatePercentageOfCoins(del2DiffRewards, 40) + coins.RequireCoinsDiffInPointOnePercentMargin(s.T(), del1DiffRewards, expectedRwdDel1) + fp1DiffRewardsStr := fp1DiffRewards.String() fp2DiffRewardsStr := fp2DiffRewards.String() del1DiffRewardsStr := del1DiffRewards.String() @@ -497,20 +465,6 @@ func (s *BtcRewardsDistribution) Test8CheckRewards() { s.NotEmpty(fp2DiffRewardsStr) s.NotEmpty(del1DiffRewardsStr) s.NotEmpty(del2DiffRewardsStr) - - // s.Equal(btcDel1RewardGauge.Coins.String(), btcDel2RewardGauge.Coins.String()) - - // // Withdraw the reward just for del2 - // del2BalanceBeforeWithdraw, err := n2.QueryBalances(s.del2Addr) - // s.NoError(err) - - // n2.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) - // n2.WaitForNextBlock() - - // del2BalanceAfterWithdraw, err := n2.QueryBalances(s.del2Addr) - // s.NoError(err) - - // s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(btcDel2RewardGauge.Coins...).String()) } // TODO(rafilx): Slash a FP and expect rewards to be withdraw. @@ -588,11 +542,7 @@ func (s *BtcRewardsDistribution) AddFinalityVote(flagsN1, flagsN2 []string) (app return appHash } -// UpdateRewardGauges update the current reward gauges on the test suite -func (s *BtcRewardsDistribution) UpdateRewardGauges(n *chain.NodeConfig) { - s.fp1LastRewardGauge, s.fp2LastRewardGauge, s.btcDel1LastRewardGauge, s.btcDel2LastRewardGauge = s.QueryRewardGauges(n) -} - +// QueryRewardGauges returns the rewards available for fp1, fp2, del1, del2 func (s *BtcRewardsDistribution) QueryRewardGauges(n *chain.NodeConfig) ( fp1, fp2, del1, del2 *itypes.RewardGaugesResponse, ) { diff --git a/test/e2e/initialization/node.go b/test/e2e/initialization/node.go index 703ea6211..7452bdd58 100644 --- a/test/e2e/initialization/node.go +++ b/test/e2e/initialization/node.go @@ -355,7 +355,7 @@ func (n *internalNode) initNodeConfigs(persistentPeers []string) error { valConfig.P2P.ExternalAddress = fmt.Sprintf("%s:%d", n.moniker, 26656) valConfig.RPC.ListenAddress = "tcp://0.0.0.0:26657" valConfig.StateSync.Enable = false - valConfig.LogLevel = "info" + valConfig.LogLevel = "debug" valConfig.P2P.PersistentPeers = strings.Join(persistentPeers, ",") valConfig.Storage.DiscardABCIResponses = false From c58ecf03ef30afec8fe537702853bb56730bc4f4 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 01:22:23 -0300 Subject: [PATCH 102/132] chore: update comments --- test/e2e/btc_rewards_distribution_e2e_test.go | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index cc48515dd..897aa67d2 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -49,29 +49,22 @@ type BtcRewardsDistribution struct { fp1 *bstypes.FinalityProvider fp2 *bstypes.FinalityProvider - // Staking amount of each delegation // 3 Delegations will start closely and possibly in the same block // (fp1, del1), (fp1, del2), (fp2, del1) // (fp1, del1) fp1Del1StakingAmt => 2_00000000 // (fp1, del2) fp1Del2StakingAmt => 4_00000000 // (fp2, del1) fp2Del2StakingAmt => 2_00000000 - // for this top configure the reward distribution should - // be 25%, 50%, 25% respectively (if they will be processed in the same block) - // since the rewards distribution is by their bech32 address the delegations - // are combined the voting power and each delegator should receive the same - // amount of rewards, finality providers on the other hand will have different amounts - // fp2 with 2_00000000 and fp1 with 6_00000000. This means the fp1 will - // receive 3x the amount of rewards then fp2. fp1Del1StakingAmt int64 fp1Del2StakingAmt int64 fp2Del1StakingAmt int64 - // The lastet delegation will come right after (del2) had withdraw his rewards - // and stake 6_00000000 to (fp2, del2). Since the rewards are combined by - // their bech32 address, del2 will have 10_00000000 and del1 will have 4_00000000 - // as voting power, meaning that del1 will receive only 40% of the amount of rewards - // that del2 will receive once every delegation is active + // The lastet delegation will stake 6_00000000 to (fp2, del2). + // Since the rewards are combined by their bech32 address, del2 + // will have 10_00000000 and del1 will have 4_00000000 as voting power, + // meaning that del1 will receive only 40% of the amount of rewards + // that del2 will receive once every delegation is active and blocks + // are being rewarded. fp2Del2StakingAmt int64 // bech32 address of the delegators From 802c0660a37f4002240130c226a9fdbfa245de9d Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 01:23:20 -0300 Subject: [PATCH 103/132] fix: test name --- test/e2e/btc_rewards_distribution_e2e_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 897aa67d2..0db698989 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -391,9 +391,9 @@ func (s *BtcRewardsDistribution) Test6ActiveLastDelegation() { } } -// Test8CheckRewards verifies the rewards of all the delegations +// Test7CheckRewards verifies the rewards of all the delegations // and finality provider -func (s *BtcRewardsDistribution) Test8CheckRewards() { +func (s *BtcRewardsDistribution) Test7CheckRewards() { n2, err := s.configurer.GetChainConfig(0).GetNodeAtIndex(2) s.NoError(err) From e666be6acbf4dfeef0c60155cd1e6668a758d89b Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 01:40:41 -0300 Subject: [PATCH 104/132] chore: rollback to 3 fi sig timeout --- test/e2e/initialization/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/initialization/config.go b/test/e2e/initialization/config.go index c46f8ef69..53be9e6b7 100644 --- a/test/e2e/initialization/config.go +++ b/test/e2e/initialization/config.go @@ -358,7 +358,7 @@ func updateBtccheckpointGenesis(btccheckpointGenState *btccheckpointtypes.Genesi func updateFinalityGenesis(finalityGenState *finalitytypes.GenesisState) { finalityGenState.Params = finalitytypes.DefaultParams() finalityGenState.Params.FinalityActivationHeight = 0 - finalityGenState.Params.FinalitySigTimeout = 4 + finalityGenState.Params.FinalitySigTimeout = 3 finalityGenState.Params.SignedBlocksWindow = 300 finalityGenState.Params.MinSignedPerWindow = sdkmath.LegacyMustNewDecFromStr("0.000005000000000000") } From f99d86e4ac1adbf7209c79d14dba55bd5ca2b1e5 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 08:06:46 -0300 Subject: [PATCH 105/132] fix: coins check --- test/e2e/btc_rewards_distribution_e2e_test.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 0db698989..179158bd2 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -329,14 +329,15 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { // The rewards distributed to the delegators should be the same for each delegator // del1 ~7130ubbn // del2 ~7130ubbn - s.Equal(btcDel1LastRewardGauge.Coins.String(), btcDel2LastRewardGauge.Coins.String()) - // note that the rewards will not be precise as more or less blocks were produced and given out rewards. + coins.RequireCoinsDiffInPointOnePercentMargin(s.T(), btcDel1LastRewardGauge.Coins, btcDel2LastRewardGauge.Coins) + // note that the rewards will not be precise as more or less blocks were produced and given out rewards. // Withdraw the reward just for del2 to check it is possible - del2BalanceBeforeWithdraw, err := n2.QueryBalances(s.del2Addr) - s.NoError(err) - + n2.WaitForNextBlockWithSleep50ms() + del2BalanceBeforeWithdraw, errQueryB := n2.QueryBalances(s.del2Addr) n2.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) + + s.NoError(errQueryB) n2.WaitForNextBlock() del2BalanceAfterWithdraw, err := n2.QueryBalances(s.del2Addr) From f5b8bfc00b136ff2fb41510fe0dbde86122feb1e Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 08:22:14 -0300 Subject: [PATCH 106/132] tryfix: reward check on withdraw --- test/e2e/btc_rewards_distribution_e2e_test.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 179158bd2..d04430d5a 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -318,6 +318,12 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { // The rewards distributed for the finality providers should be fp1 => 3x, fp2 => 1x fp1LastRewardGauge, fp2LastRewardGauge, btcDel1LastRewardGauge, btcDel2LastRewardGauge := s.QueryRewardGauges(n2) + + // does the withdraw right after the query to avoid new blocks rewarded + del2BalanceBeforeWithdraw, errQueryB := n2.QueryBalances(s.del2Addr) + n2.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) + s.NoError(errQueryB) + // fp1 ~2674ubbn // fp2 ~891ubbn coins.RequireCoinsDiffInPointOnePercentMargin( @@ -331,13 +337,8 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { // del2 ~7130ubbn coins.RequireCoinsDiffInPointOnePercentMargin(s.T(), btcDel1LastRewardGauge.Coins, btcDel2LastRewardGauge.Coins) - // note that the rewards will not be precise as more or less blocks were produced and given out rewards. + // note that the rewards might not be precise as more or less blocks were produced and given out rewards. // Withdraw the reward just for del2 to check it is possible - n2.WaitForNextBlockWithSleep50ms() - del2BalanceBeforeWithdraw, errQueryB := n2.QueryBalances(s.del2Addr) - n2.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) - - s.NoError(errQueryB) n2.WaitForNextBlock() del2BalanceAfterWithdraw, err := n2.QueryBalances(s.del2Addr) From b993b7c54cdc04d68b406e24d9cc18ccbca4d7f4 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 08:31:37 -0300 Subject: [PATCH 107/132] chore: simplify reward check --- test/e2e/btc_rewards_distribution_e2e_test.go | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index d04430d5a..9bb2da338 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -319,11 +319,6 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { // The rewards distributed for the finality providers should be fp1 => 3x, fp2 => 1x fp1LastRewardGauge, fp2LastRewardGauge, btcDel1LastRewardGauge, btcDel2LastRewardGauge := s.QueryRewardGauges(n2) - // does the withdraw right after the query to avoid new blocks rewarded - del2BalanceBeforeWithdraw, errQueryB := n2.QueryBalances(s.del2Addr) - n2.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) - s.NoError(errQueryB) - // fp1 ~2674ubbn // fp2 ~891ubbn coins.RequireCoinsDiffInPointOnePercentMargin( @@ -337,14 +332,7 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { // del2 ~7130ubbn coins.RequireCoinsDiffInPointOnePercentMargin(s.T(), btcDel1LastRewardGauge.Coins, btcDel2LastRewardGauge.Coins) - // note that the rewards might not be precise as more or less blocks were produced and given out rewards. - // Withdraw the reward just for del2 to check it is possible - n2.WaitForNextBlock() - - del2BalanceAfterWithdraw, err := n2.QueryBalances(s.del2Addr) - s.NoError(err) - - s.Equal(del2BalanceAfterWithdraw.String(), del2BalanceBeforeWithdraw.Add(btcDel2LastRewardGauge.Coins...).String()) + CheckWithdrawReward(s.T(), n2, wDel2, s.del2Addr) } // Test6ActiveLastDelegation creates a new btc delegation @@ -583,6 +571,37 @@ func (s *BtcRewardsDistribution) CreateBTCDelegationAndCheck( n.CreateBTCDelegationAndCheck(s.r, s.T(), s.net, wDel, fp, btcStakerSK, delAddr, stakingTimeBlocks, stakingSatAmt) } +// CheckWithdrawReward withdraw rewards for one delegation and check the balance +func CheckWithdrawReward( + t testing.TB, + n *chain.NodeConfig, + delWallet, delAddr string, +) { + accDelAddr := sdk.MustAccAddressFromBech32(delAddr) + n.WaitForNextBlockWithSleep50ms() + + // does the withdraw right after the query to avoid new blocks rewarded + delRwdGauge, err := n.QueryRewardGauge(accDelAddr) + n.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) + delBalanceBeforeWithdraw, errQueryB := n.QueryBalances(delAddr) + + require.NoError(t, err) + require.NoError(t, errQueryB) + + n.WaitForNextBlock() + + delBalanceAfterWithdraw, err := n.QueryBalances(delAddr) + require.NoError(t, err) + + // note that the rewards might not be precise as more or less blocks were produced and given out rewards. + // Withdraw the reward just for del2 to check it is possible + delRewardGauge, ok := delRwdGauge[itypes.BTCDelegationType.String()] + require.True(t, ok) + require.True(t, delRewardGauge.Coins.IsAllPositive()) + + require.Equal(t, delBalanceAfterWithdraw.String(), delBalanceBeforeWithdraw.Add(delRewardGauge.Coins...).String()) +} + func SendCovenantSigsToPendingDel( r *rand.Rand, t testing.TB, From 7ff75de253c9f34e2b900b78511032d998b4e76c Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 08:54:09 -0300 Subject: [PATCH 108/132] tryfix: reward withdraw check --- test/e2e/btc_rewards_distribution_e2e_test.go | 6 +- x/finality/keeper/power_dist_change.go | 83 +++++++++---------- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 9bb2da338..3e202ab6f 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -581,8 +581,8 @@ func CheckWithdrawReward( n.WaitForNextBlockWithSleep50ms() // does the withdraw right after the query to avoid new blocks rewarded - delRwdGauge, err := n.QueryRewardGauge(accDelAddr) n.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) + delRwdGauge, err := n.QueryRewardGauge(accDelAddr) delBalanceBeforeWithdraw, errQueryB := n.QueryBalances(delAddr) require.NoError(t, err) @@ -593,8 +593,8 @@ func CheckWithdrawReward( delBalanceAfterWithdraw, err := n.QueryBalances(delAddr) require.NoError(t, err) - // note that the rewards might not be precise as more or less blocks were produced and given out rewards. - // Withdraw the reward just for del2 to check it is possible + // note that the rewards might not be precise as more or less blocks were produced and given out rewards + // while the query balance / withdraw / query gauge was running delRewardGauge, ok := delRwdGauge[itypes.BTCDelegationType.String()] require.True(t, ok) require.True(t, delRewardGauge.Coins.IsAllPositive()) diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 94d0d3ac2..6166b0d07 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -183,8 +183,9 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( jailedFPs := map[string]struct{}{} // a map where key is unjailed finality providers' BTC PK unjailedFPs := map[string]struct{}{} - newActiveBtcDels := make([]*btcDelWithStkTxHash, 0) - newUnbondedBtcDels := make([]*btcDelWithStkTxHash, 0) + + // simple cache to load fp by his btc pk hex + cacheFpByBtcPkHex := map[string]*types.FinalityProvider{} /* filter and classify all events into new/expired BTC delegations and jailed/slashed FPs @@ -201,11 +202,6 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( panic(err) // only programming error } - btcDelWithStkTxHash := &btcDelWithStkTxHash{ - StakingTxHash: delStkTxHash, - BTCDelegation: btcDel, - } - switch delEvent.NewState { case types.BTCDelegationStatus_ACTIVE: // newly active BTC delegation @@ -214,19 +210,26 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( fpBTCPKHex := fpBTCPK.MarshalHex() activeBTCDels[fpBTCPKHex] = append(activeBTCDels[fpBTCPKHex], btcDel) } - newActiveBtcDels = append(newActiveBtcDels, btcDelWithStkTxHash) + + k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { + k.MustProcessBtcDelegationActivated(ctx, fp, del, sats) + }) case types.BTCDelegationStatus_UNBONDED: - newUnbondedBtcDels = append(newUnbondedBtcDels, btcDelWithStkTxHash) // add the unbonded BTC delegation to the map unbondedBTCDels[delStkTxHash] = struct{}{} + k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { + k.MustProcessBtcDelegationUnbonded(ctx, fp, del, sats) + }) case types.BTCDelegationStatus_EXPIRED: types.EmitExpiredDelegationEvent(sdkCtx, delStkTxHash) if !btcDel.IsUnbondedEarly() { // only adds to the new unbonded list if it hasn't // previously unbonded with types.BTCDelegationStatus_UNBONDED - newUnbondedBtcDels = append(newUnbondedBtcDels, btcDelWithStkTxHash) unbondedBTCDels[delStkTxHash] = struct{}{} + k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { + k.MustProcessBtcDelegationUnbonded(ctx, fp, del, sats) + }) } } case *types.EventPowerDistUpdate_SlashedFp: @@ -328,9 +331,6 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( return fpActiveBtcPkHexList[i] < fpActiveBtcPkHexList[j] }) - // simple cache to load fp by his btc pk hex - cacheFpByBtcPkHex := map[string]*types.FinalityProvider{} - // for each new finality provider, apply the new BTC delegations to the new dist cache for _, fpBTCPKHex := range fpActiveBtcPkHexList { // get the finality provider and initialise its dist info @@ -349,20 +349,6 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( } } - k.processBtcDelegations(ctx, cacheFpByBtcPkHex, newActiveBtcDels, func(fp, del sdk.AccAddress, sats uint64) { - err := k.IncentiveKeeper.BtcDelegationActivated(ctx, fp, del, sats) - if err != nil { - panic(err) - } - }) - - k.processBtcDelegations(ctx, cacheFpByBtcPkHex, newUnbondedBtcDels, func(fp, del sdk.AccAddress, sats uint64) { - err := k.IncentiveKeeper.BtcDelegationUnbonded(ctx, fp, del, sats) - if err != nil { - panic(err) - } - }) - return newDc } @@ -396,28 +382,39 @@ func (k Keeper) votingPowerDistCacheStore(ctx context.Context) prefix.Store { return prefix.NewStore(storeAdapter, ftypes.VotingPowerDistCacheKey) } -// processBtcDelegations sorts the btc delegations and -// executed the function by passing the fp, delegator address -// and the total amount of satoshi in that delegation. -func (k Keeper) processBtcDelegations( +// processRewardTracker loads the fps from inside the btc delegation +// with cache and executes the function by passing the fp, delegator address +// and satoshi amounts. +func (k Keeper) processRewardTracker( ctx context.Context, cacheFpByBtcPkHex map[string]*types.FinalityProvider, - btcDels []*btcDelWithStkTxHash, + btcDel *types.BTCDelegation, f func(fp, del sdk.AccAddress, sats uint64), ) { - sort.SliceStable(btcDels, func(i, j int) bool { - return btcDels[i].StakingTxHash < btcDels[j].StakingTxHash - }) + delAddr := sdk.MustAccAddressFromBech32(btcDel.StakerAddr) + for _, fpBTCPK := range btcDel.FpBtcPkList { + fp := k.loadFP(ctx, cacheFpByBtcPkHex, fpBTCPK.MarshalHex()) + fpAddr := sdk.MustAccAddressFromBech32(fp.Addr) - for _, btcDel := range btcDels { - delAddr := sdk.MustAccAddressFromBech32(btcDel.StakerAddr) - for _, fpBTCPK := range btcDel.FpBtcPkList { - fpBTCPKHex := fpBTCPK.MarshalHex() - fp := k.loadFP(ctx, cacheFpByBtcPkHex, fpBTCPKHex) - fpAddr := sdk.MustAccAddressFromBech32(fp.Addr) + f(fpAddr, delAddr, btcDel.TotalSat) + } +} - f(fpAddr, delAddr, btcDel.TotalSat) - } +// MustProcessBtcDelegationActivated calls the IncentiveKeeper.BtcDelegationActivated +// and panics if it errors +func (k Keeper) MustProcessBtcDelegationActivated(ctx context.Context, fp, del sdk.AccAddress, sats uint64) { + err := k.IncentiveKeeper.BtcDelegationActivated(ctx, fp, del, sats) + if err != nil { + panic(err) + } +} + +// MustProcessBtcDelegationUnbonded calls the IncentiveKeeper.BtcDelegationUnbonded +// and panics if it errors +func (k Keeper) MustProcessBtcDelegationUnbonded(ctx context.Context, fp, del sdk.AccAddress, sats uint64) { + err := k.IncentiveKeeper.BtcDelegationUnbonded(ctx, fp, del, sats) + if err != nil { + panic(err) } } From 21fc6062fe7a7981823f82292a07f2681687b7e1 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 08:57:28 -0300 Subject: [PATCH 109/132] fix: lint remove unused struct --- x/finality/keeper/power_dist_change.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 6166b0d07..88d3f6ba2 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -438,8 +438,3 @@ func (k Keeper) loadFP( return fp } - -type btcDelWithStkTxHash struct { - StakingTxHash string - *types.BTCDelegation -} From 3810f90562913a711fc574a96ac86de24d243155 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 09:12:21 -0300 Subject: [PATCH 110/132] tryfix: add more time for activation --- test/e2e/configurer/chain/queries.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/configurer/chain/queries.go b/test/e2e/configurer/chain/queries.go index 50406341e..892bac78b 100644 --- a/test/e2e/configurer/chain/queries.go +++ b/test/e2e/configurer/chain/queries.go @@ -462,7 +462,7 @@ func (n *NodeConfig) WaitFinalityIsActivated() (activatedHeight uint64) { return false } return activatedHeight > 0 - }, time.Minute*2, time.Millisecond*50) + }, time.Minute*4, time.Millisecond*50) n.t.Logf("the activated height is %d", activatedHeight) return activatedHeight } From 951a24c2ee9c1b563e5e6e46397e42ac171e4022 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 09:38:44 -0300 Subject: [PATCH 111/132] tryfix: change order, query first --- test/e2e/btc_rewards_distribution_e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 3e202ab6f..b5c5dc646 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -581,9 +581,9 @@ func CheckWithdrawReward( n.WaitForNextBlockWithSleep50ms() // does the withdraw right after the query to avoid new blocks rewarded - n.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) delRwdGauge, err := n.QueryRewardGauge(accDelAddr) delBalanceBeforeWithdraw, errQueryB := n.QueryBalances(delAddr) + n.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) require.NoError(t, err) require.NoError(t, errQueryB) From 46a5156d6d04329dd415168a2a37d96245ce2217 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 09:52:15 -0300 Subject: [PATCH 112/132] tryfix: moved to check withdraw after block and withdraw --- test/e2e/btc_rewards_distribution_e2e_test.go | 7 ++++--- x/finality/keeper/power_table_test.go | 3 ++- x/finality/types/power_table.go | 4 ++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index b5c5dc646..bf419350f 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -581,15 +581,16 @@ func CheckWithdrawReward( n.WaitForNextBlockWithSleep50ms() // does the withdraw right after the query to avoid new blocks rewarded - delRwdGauge, err := n.QueryRewardGauge(accDelAddr) delBalanceBeforeWithdraw, errQueryB := n.QueryBalances(delAddr) n.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) - require.NoError(t, err) require.NoError(t, errQueryB) n.WaitForNextBlock() + delRwdGauge, err := n.QueryRewardGauge(accDelAddr) + require.NoError(t, err) + delBalanceAfterWithdraw, err := n.QueryBalances(delAddr) require.NoError(t, err) @@ -599,7 +600,7 @@ func CheckWithdrawReward( require.True(t, ok) require.True(t, delRewardGauge.Coins.IsAllPositive()) - require.Equal(t, delBalanceAfterWithdraw.String(), delBalanceBeforeWithdraw.Add(delRewardGauge.Coins...).String()) + require.Equal(t, delBalanceAfterWithdraw.String(), delBalanceBeforeWithdraw.Add(delRewardGauge.WithdrawnCoins...).String()) } func SendCovenantSigsToPendingDel( diff --git a/x/finality/keeper/power_table_test.go b/x/finality/keeper/power_table_test.go index f3a67b352..1da55453f 100644 --- a/x/finality/keeper/power_table_test.go +++ b/x/finality/keeper/power_table_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "fmt" "math/rand" "sort" "testing" @@ -535,7 +536,7 @@ func FuzzVotingPowerTable_ActiveFinalityProviderRotation(f *testing.F) { }) for i := 0; i < numActiveFPs; i++ { votingPower := h.FinalityKeeper.GetVotingPower(h.Ctx, *fpsWithMeta[i].BtcPk, babylonHeight) - require.Equal(t, fpsWithMeta[i].VotingPower, votingPower) + require.Equal(t, fmt.Sprintf("%d", fpsWithMeta[i].VotingPower), fmt.Sprintf("%d", votingPower)) } for i := numActiveFPs; i < int(numFps); i++ { votingPower := h.FinalityKeeper.GetVotingPower(h.Ctx, *fpsWithMeta[i].BtcPk, babylonHeight) diff --git a/x/finality/types/power_table.go b/x/finality/types/power_table.go index c25aebe72..7dc357065 100644 --- a/x/finality/types/power_table.go +++ b/x/finality/types/power_table.go @@ -165,6 +165,10 @@ func (v *FinalityProviderDistInfo) AddBTCDel(btcDel *bstypes.BTCDelegation) { v.TotalBondedSat += btcDelDistInfo.TotalSat } +func (v *FinalityProviderDistInfo) UnbondBTCDel(btcDel *bstypes.BTCDelegation) { + v.TotalBondedSat = v.TotalBondedSat - btcDel.TotalSat +} + func (v *FinalityProviderDistInfo) AddBTCDelDistInfo(d *BTCDelDistInfo) { v.BtcDels = append(v.BtcDels, d) v.TotalBondedSat += d.TotalSat From c0417f0e5ed1923f3198ad9bcaf4f3e1d11131ed Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 11:19:51 -0300 Subject: [PATCH 113/132] chore: removed BTC del distribution info structure --- proto/babylon/finality/v1/finality.proto | 21 +- testutil/datagen/incentive.go | 52 +- x/finality/keeper/power_dist_change.go | 50 +- x/finality/keeper/power_table_test.go | 4 - x/finality/types/finality.pb.go | 525 +++---------------- x/finality/types/power_table.go | 25 +- x/incentive/keeper/btc_staking_gauge_test.go | 17 +- 7 files changed, 148 insertions(+), 546 deletions(-) diff --git a/proto/babylon/finality/v1/finality.proto b/proto/babylon/finality/v1/finality.proto index 21f67f837..90623e099 100644 --- a/proto/babylon/finality/v1/finality.proto +++ b/proto/babylon/finality/v1/finality.proto @@ -36,31 +36,16 @@ message FinalityProviderDistInfo { ]; // total_bonded_sat is the total amount of bonded BTC stake (in Satoshi) of the finality provider uint64 total_bonded_sat = 4; - // btc_dels is a list of BTC delegations' voting power information under this finality provider - repeated BTCDelDistInfo btc_dels = 5; // is_timestamped indicates whether the finality provider // has timestamped public randomness committed // if no, it should not be assigned voting power - bool is_timestamped = 6; + bool is_timestamped = 5; // is_jailed indicates whether the finality provider // is jailed, if so, it should not be assigned voting power - bool is_jailed = 7; + bool is_jailed = 6; // is_slashed indicates whether the finality provider // is slashed, if so, it should not be assigned voting power - bool is_slashed = 8; -} - -// BTCDelDistInfo contains the information related to voting power distribution for a BTC delegation -message BTCDelDistInfo { - // btc_pk is the Bitcoin secp256k1 PK of this BTC delegation - // the PK follows encoding in BIP-340 spec - bytes btc_pk = 1 [ (gogoproto.customtype) = "github.com/babylonlabs-io/babylon/types.BIP340PubKey" ]; - // staker_addr is the address to receive rewards from BTC delegation. - string staker_addr = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - // staking_tx_hash is the staking tx hash of the BTC delegation - string staking_tx_hash = 3; - // total_sat is the amount of BTC stake (in Satoshi) of the BTC delegation - uint64 total_sat = 4; + bool is_slashed = 7; } // IndexedBlock is the necessary metadata and finalization status of a block diff --git a/testutil/datagen/incentive.go b/testutil/datagen/incentive.go index a952f53fc..19c2da45e 100644 --- a/testutil/datagen/incentive.go +++ b/testutil/datagen/incentive.go @@ -78,53 +78,55 @@ func GenRandomGauge(r *rand.Rand) *itypes.Gauge { return itypes.NewGauge(coins...) } -func GenRandomBTCDelDistInfo(r *rand.Rand) (*ftypes.BTCDelDistInfo, error) { - btcPK, err := GenRandomBIP340PubKey(r) - if err != nil { - return nil, err - } - return &ftypes.BTCDelDistInfo{ - BtcPk: btcPK, - StakerAddr: GenRandomAccount().Address, - TotalSat: RandomInt(r, 1000) + 1, - }, nil +func GenRandomAddrAndSat(r *rand.Rand) (string, uint64) { + return GenRandomAccount().Address, RandomInt(r, 1000) + 1 } -func GenRandomFinalityProviderDistInfo(r *rand.Rand) (*ftypes.FinalityProviderDistInfo, error) { +func GenRandomFinalityProviderDistInfo(r *rand.Rand) ( + fpDistInfo *ftypes.FinalityProviderDistInfo, + btcTotalSatByAddress map[string]uint64, + err error, +) { // create finality provider with random commission fp, err := GenRandomFinalityProvider(r) if err != nil { - return nil, err + return nil, nil, err } // create finality provider distribution info - fpDistInfo := ftypes.NewFinalityProviderDistInfo(fp) + fpDistInfo = ftypes.NewFinalityProviderDistInfo(fp) // add a random number of BTC delegation distribution info numBTCDels := RandomInt(r, 100) + 1 + btcTotalSatByAddress = make(map[string]uint64, numBTCDels) for i := uint64(0); i < numBTCDels; i++ { - btcDelDistInfo, err := GenRandomBTCDelDistInfo(r) - if err != nil { - return nil, err - } - fpDistInfo.BtcDels = append(fpDistInfo.BtcDels, btcDelDistInfo) - fpDistInfo.TotalBondedSat += btcDelDistInfo.TotalSat + btcAddr, totalSat := GenRandomAddrAndSat(r) + btcTotalSatByAddress[btcAddr] += totalSat + fpDistInfo.TotalBondedSat += totalSat fpDistInfo.IsTimestamped = true } - return fpDistInfo, nil + return fpDistInfo, btcTotalSatByAddress, nil } -func GenRandomVotingPowerDistCache(r *rand.Rand, maxFPs uint32) (*ftypes.VotingPowerDistCache, error) { - dc := ftypes.NewVotingPowerDistCache() +func GenRandomVotingPowerDistCache(r *rand.Rand, maxFPs uint32) ( + dc *ftypes.VotingPowerDistCache, + // fpAddr => delAddr => totalSat + btcTotalSatByDelAddressByFpAddress map[string]map[string]uint64, + err error, +) { + dc = ftypes.NewVotingPowerDistCache() // a random number of finality providers numFps := RandomInt(r, 10) + 1 + + btcTotalSatByDelAddressByFpAddress = make(map[string]map[string]uint64, numFps) for i := uint64(0); i < numFps; i++ { - v, err := GenRandomFinalityProviderDistInfo(r) + v, btcTotalSatByAddress, err := GenRandomFinalityProviderDistInfo(r) if err != nil { - return nil, err + return nil, nil, err } + btcTotalSatByDelAddressByFpAddress[v.GetAddress().String()] = btcTotalSatByAddress dc.AddFinalityProviderDistInfo(v) } dc.ApplyActiveFinalityProviders(maxFPs) - return dc, nil + return dc, btcTotalSatByDelAddressByFpAddress, nil } func GenRandomCheckpointAddressPair(r *rand.Rand) *btcctypes.CheckpointAddressPair { diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 88d3f6ba2..1a669e772 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -175,8 +175,10 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // a map where key is finality provider's BTC PK hex and value is a list // of BTC delegations that newly become active under this provider activeBTCDels := map[string][]*types.BTCDelegation{} - // a map where key is unbonded BTC delegation's staking tx hash - unbondedBTCDels := map[string]struct{}{} + // a map where key is finality provider's BTC PK hex and value is a list + // of BTC delegations that were unbonded or expired without previously + // being unbonded + unbondedBTCDels := map[string][]*types.BTCDelegation{} // a map where key is slashed finality providers' BTC PK slashedFPs := map[string]struct{}{} // a map where key is jailed finality providers' BTC PK @@ -216,7 +218,11 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( }) case types.BTCDelegationStatus_UNBONDED: // add the unbonded BTC delegation to the map - unbondedBTCDels[delStkTxHash] = struct{}{} + // unbondedBTCDels[delStkTxHash] = struct{}{} + for _, fpBTCPK := range btcDel.FpBtcPkList { + fpBTCPKHex := fpBTCPK.MarshalHex() + unbondedBTCDels[fpBTCPKHex] = append(unbondedBTCDels[fpBTCPKHex], btcDel) + } k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { k.MustProcessBtcDelegationUnbonded(ctx, fp, del, sats) }) @@ -226,7 +232,11 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( if !btcDel.IsUnbondedEarly() { // only adds to the new unbonded list if it hasn't // previously unbonded with types.BTCDelegationStatus_UNBONDED - unbondedBTCDels[delStkTxHash] = struct{}{} + // unbondedBTCDels[delStkTxHash] = struct{}{} + for _, fpBTCPK := range btcDel.FpBtcPkList { + fpBTCPKHex := fpBTCPK.MarshalHex() + unbondedBTCDels[fpBTCPKHex] = append(unbondedBTCDels[fpBTCPKHex], btcDel) + } k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { k.MustProcessBtcDelegationUnbonded(ctx, fp, del, sats) }) @@ -261,9 +271,6 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( for i := range dc.FinalityProviders { // create a copy of the finality provider fp := *dc.FinalityProviders[i] - fp.TotalBondedSat = 0 - fp.BtcDels = []*ftypes.BTCDelDistInfo{} - fpBTCPKHex := fp.BtcPk.MarshalHex() // if this finality provider is slashed, continue to avoid @@ -289,16 +296,17 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( fp.IsJailed = false } - // add all BTC delegations that are not unbonded to the new finality provider - for j := range dc.FinalityProviders[i].BtcDels { - btcDel := *dc.FinalityProviders[i].BtcDels[j] - - _, isUnbondedBtcDelegation := unbondedBTCDels[btcDel.StakingTxHash] - if isUnbondedBtcDelegation { - continue + // process all new BTC delegations under this finality provider + if fpUnbondedBTCDels, ok := unbondedBTCDels[fpBTCPKHex]; ok { + // handle unbonded delegations for this finality provider + for _, d := range fpUnbondedBTCDels { + fp.UnbondBTCDel(d) } - // if it is not unbonded add to the del dist info - fp.AddBTCDelDistInfo(&btcDel) + // remove the finality provider entry in unbondedBTCDels map, so that + // after the for loop the rest entries in unbondedBTCDels belongs to new + // finality providers that might have btc delegations entries + // that activated and unbonded in the same slice of events + delete(unbondedBTCDels, fpBTCPKHex) } // process all new BTC delegations under this finality provider @@ -343,6 +351,16 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( fpDistInfo.AddBTCDel(d) } + // edge case where we might be processing an unbonded event + // from a newly active finality provider in the same slice + // of events received. + fpUnbondedBTCDels, ok := unbondedBTCDels[fpBTCPKHex] + if ok { + for _, d := range fpUnbondedBTCDels { + fpDistInfo.UnbondBTCDel(d) + } + } + // add this finality provider to the new cache if it has voting power if fpDistInfo.TotalBondedSat > 0 { newDc.AddFinalityProviderDistInfo(fpDistInfo) diff --git a/x/finality/keeper/power_table_test.go b/x/finality/keeper/power_table_test.go index 1da55453f..2b2d14520 100644 --- a/x/finality/keeper/power_table_test.go +++ b/x/finality/keeper/power_table_test.go @@ -246,10 +246,6 @@ func FuzzRecordVotingPowerDistCache(f *testing.F) { fp, ok := fpsWithVotingPowerMap[sdk.AccAddress(fpDistInfo.Addr).String()] require.True(t, ok) require.Equal(t, fpDistInfo.Commission, fp.Commission) - require.Len(t, fpDistInfo.BtcDels, int(numBTCDels)) - for _, delDistInfo := range fpDistInfo.BtcDels { - require.Equal(t, delDistInfo.TotalSat, stakingValue) - } } }) } diff --git a/x/finality/types/finality.pb.go b/x/finality/types/finality.pb.go index 1f7c74471..f8daf23d4 100644 --- a/x/finality/types/finality.pb.go +++ b/x/finality/types/finality.pb.go @@ -88,18 +88,16 @@ type FinalityProviderDistInfo struct { Commission *cosmossdk_io_math.LegacyDec `protobuf:"bytes,3,opt,name=commission,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"commission,omitempty"` // total_bonded_sat is the total amount of bonded BTC stake (in Satoshi) of the finality provider TotalBondedSat uint64 `protobuf:"varint,4,opt,name=total_bonded_sat,json=totalBondedSat,proto3" json:"total_bonded_sat,omitempty"` - // btc_dels is a list of BTC delegations' voting power information under this finality provider - BtcDels []*BTCDelDistInfo `protobuf:"bytes,5,rep,name=btc_dels,json=btcDels,proto3" json:"btc_dels,omitempty"` // is_timestamped indicates whether the finality provider // has timestamped public randomness committed // if no, it should not be assigned voting power - IsTimestamped bool `protobuf:"varint,6,opt,name=is_timestamped,json=isTimestamped,proto3" json:"is_timestamped,omitempty"` + IsTimestamped bool `protobuf:"varint,5,opt,name=is_timestamped,json=isTimestamped,proto3" json:"is_timestamped,omitempty"` // is_jailed indicates whether the finality provider // is jailed, if so, it should not be assigned voting power - IsJailed bool `protobuf:"varint,7,opt,name=is_jailed,json=isJailed,proto3" json:"is_jailed,omitempty"` + IsJailed bool `protobuf:"varint,6,opt,name=is_jailed,json=isJailed,proto3" json:"is_jailed,omitempty"` // is_slashed indicates whether the finality provider // is slashed, if so, it should not be assigned voting power - IsSlashed bool `protobuf:"varint,8,opt,name=is_slashed,json=isSlashed,proto3" json:"is_slashed,omitempty"` + IsSlashed bool `protobuf:"varint,7,opt,name=is_slashed,json=isSlashed,proto3" json:"is_slashed,omitempty"` } func (m *FinalityProviderDistInfo) Reset() { *m = FinalityProviderDistInfo{} } @@ -149,13 +147,6 @@ func (m *FinalityProviderDistInfo) GetTotalBondedSat() uint64 { return 0 } -func (m *FinalityProviderDistInfo) GetBtcDels() []*BTCDelDistInfo { - if m != nil { - return m.BtcDels - } - return nil -} - func (m *FinalityProviderDistInfo) GetIsTimestamped() bool { if m != nil { return m.IsTimestamped @@ -177,73 +168,6 @@ func (m *FinalityProviderDistInfo) GetIsSlashed() bool { return false } -// BTCDelDistInfo contains the information related to voting power distribution for a BTC delegation -type BTCDelDistInfo struct { - // btc_pk is the Bitcoin secp256k1 PK of this BTC delegation - // the PK follows encoding in BIP-340 spec - BtcPk *github_com_babylonlabs_io_babylon_types.BIP340PubKey `protobuf:"bytes,1,opt,name=btc_pk,json=btcPk,proto3,customtype=github.com/babylonlabs-io/babylon/types.BIP340PubKey" json:"btc_pk,omitempty"` - // staker_addr is the address to receive rewards from BTC delegation. - StakerAddr string `protobuf:"bytes,2,opt,name=staker_addr,json=stakerAddr,proto3" json:"staker_addr,omitempty"` - // staking_tx_hash is the staking tx hash of the BTC delegation - StakingTxHash string `protobuf:"bytes,3,opt,name=staking_tx_hash,json=stakingTxHash,proto3" json:"staking_tx_hash,omitempty"` - // total_sat is the amount of BTC stake (in Satoshi) of the BTC delegation - TotalSat uint64 `protobuf:"varint,4,opt,name=total_sat,json=totalSat,proto3" json:"total_sat,omitempty"` -} - -func (m *BTCDelDistInfo) Reset() { *m = BTCDelDistInfo{} } -func (m *BTCDelDistInfo) String() string { return proto.CompactTextString(m) } -func (*BTCDelDistInfo) ProtoMessage() {} -func (*BTCDelDistInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ca5b87e52e3e6d02, []int{2} -} -func (m *BTCDelDistInfo) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *BTCDelDistInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_BTCDelDistInfo.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *BTCDelDistInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_BTCDelDistInfo.Merge(m, src) -} -func (m *BTCDelDistInfo) XXX_Size() int { - return m.Size() -} -func (m *BTCDelDistInfo) XXX_DiscardUnknown() { - xxx_messageInfo_BTCDelDistInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_BTCDelDistInfo proto.InternalMessageInfo - -func (m *BTCDelDistInfo) GetStakerAddr() string { - if m != nil { - return m.StakerAddr - } - return "" -} - -func (m *BTCDelDistInfo) GetStakingTxHash() string { - if m != nil { - return m.StakingTxHash - } - return "" -} - -func (m *BTCDelDistInfo) GetTotalSat() uint64 { - if m != nil { - return m.TotalSat - } - return 0 -} - // IndexedBlock is the necessary metadata and finalization status of a block type IndexedBlock struct { // height is the height of the block @@ -259,7 +183,7 @@ func (m *IndexedBlock) Reset() { *m = IndexedBlock{} } func (m *IndexedBlock) String() string { return proto.CompactTextString(m) } func (*IndexedBlock) ProtoMessage() {} func (*IndexedBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_ca5b87e52e3e6d02, []int{3} + return fileDescriptor_ca5b87e52e3e6d02, []int{2} } func (m *IndexedBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -328,7 +252,7 @@ func (m *PubRandCommit) Reset() { *m = PubRandCommit{} } func (m *PubRandCommit) String() string { return proto.CompactTextString(m) } func (*PubRandCommit) ProtoMessage() {} func (*PubRandCommit) Descriptor() ([]byte, []int) { - return fileDescriptor_ca5b87e52e3e6d02, []int{4} + return fileDescriptor_ca5b87e52e3e6d02, []int{3} } func (m *PubRandCommit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -412,7 +336,7 @@ func (m *Evidence) Reset() { *m = Evidence{} } func (m *Evidence) String() string { return proto.CompactTextString(m) } func (*Evidence) ProtoMessage() {} func (*Evidence) Descriptor() ([]byte, []int) { - return fileDescriptor_ca5b87e52e3e6d02, []int{5} + return fileDescriptor_ca5b87e52e3e6d02, []int{4} } func (m *Evidence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -480,7 +404,7 @@ func (m *FinalityProviderSigningInfo) Reset() { *m = FinalityProviderSig func (m *FinalityProviderSigningInfo) String() string { return proto.CompactTextString(m) } func (*FinalityProviderSigningInfo) ProtoMessage() {} func (*FinalityProviderSigningInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_ca5b87e52e3e6d02, []int{6} + return fileDescriptor_ca5b87e52e3e6d02, []int{5} } func (m *FinalityProviderSigningInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -533,7 +457,6 @@ func (m *FinalityProviderSigningInfo) GetJailedUntil() time.Time { func init() { proto.RegisterType((*VotingPowerDistCache)(nil), "babylon.finality.v1.VotingPowerDistCache") proto.RegisterType((*FinalityProviderDistInfo)(nil), "babylon.finality.v1.FinalityProviderDistInfo") - proto.RegisterType((*BTCDelDistInfo)(nil), "babylon.finality.v1.BTCDelDistInfo") proto.RegisterType((*IndexedBlock)(nil), "babylon.finality.v1.IndexedBlock") proto.RegisterType((*PubRandCommit)(nil), "babylon.finality.v1.PubRandCommit") proto.RegisterType((*Evidence)(nil), "babylon.finality.v1.Evidence") @@ -545,71 +468,65 @@ func init() { } var fileDescriptor_ca5b87e52e3e6d02 = []byte{ - // 1019 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0x26, 0x4e, 0x6c, 0x8f, 0xed, 0xb4, 0x99, 0x86, 0x6a, 0x9b, 0x80, 0x9d, 0x9a, 0x3f, - 0x8a, 0x50, 0xb3, 0xa6, 0x69, 0x85, 0xa0, 0x07, 0xa4, 0x6c, 0xd2, 0xaa, 0x81, 0x40, 0xad, 0x75, - 0xca, 0x01, 0x21, 0x8d, 0x66, 0x77, 0xc7, 0xbb, 0x83, 0x77, 0x67, 0x56, 0x3b, 0xb3, 0x21, 0xe6, - 0x03, 0x20, 0x8e, 0xe5, 0x86, 0xc4, 0x85, 0x23, 0x47, 0x0e, 0xfd, 0x10, 0x3d, 0xa1, 0xaa, 0x27, - 0x94, 0x43, 0x80, 0xe4, 0xc0, 0xd7, 0x40, 0x3b, 0xb3, 0x5e, 0xc7, 0x55, 0x11, 0x08, 0xca, 0xc5, - 0x9a, 0xf9, 0xbd, 0x37, 0xef, 0xdf, 0xef, 0xbd, 0xb7, 0x06, 0x5d, 0x17, 0xbb, 0xe3, 0x88, 0xb3, - 0xde, 0x90, 0x32, 0x1c, 0x51, 0x39, 0xee, 0x1d, 0xdd, 0x2c, 0xcf, 0x56, 0x92, 0x72, 0xc9, 0xe1, - 0x95, 0x42, 0xc7, 0x2a, 0xf1, 0xa3, 0x9b, 0x6b, 0xd7, 0x3c, 0x2e, 0x62, 0x2e, 0x90, 0x52, 0xe9, - 0xe9, 0x8b, 0xd6, 0x5f, 0x5b, 0x0d, 0x78, 0xc0, 0x35, 0x9e, 0x9f, 0x0a, 0x74, 0x05, 0xc7, 0x94, - 0xf1, 0x9e, 0xfa, 0x2d, 0xa0, 0x4e, 0xc0, 0x79, 0x10, 0x91, 0x9e, 0xba, 0xb9, 0xd9, 0xb0, 0x27, - 0x69, 0x4c, 0x84, 0xc4, 0x71, 0xa2, 0x15, 0xba, 0x3f, 0x1b, 0x60, 0xf5, 0x53, 0x2e, 0x29, 0x0b, - 0xfa, 0xfc, 0x4b, 0x92, 0xee, 0x51, 0x21, 0x77, 0xb1, 0x17, 0x12, 0x78, 0x03, 0x40, 0xc9, 0x25, - 0x8e, 0xd0, 0x91, 0x92, 0xa2, 0x24, 0x17, 0x9b, 0xc6, 0x86, 0xb1, 0x59, 0x71, 0x2e, 0x2b, 0xc9, - 0x85, 0x67, 0xf0, 0x73, 0x00, 0x27, 0xa1, 0xe7, 0xf1, 0x1e, 0x51, 0x9f, 0xa4, 0xc2, 0x9c, 0xdf, - 0x58, 0xd8, 0x6c, 0x6c, 0x6f, 0x59, 0x2f, 0xc8, 0xce, 0xba, 0x57, 0x9c, 0xfb, 0x85, 0x76, 0xee, - 0x79, 0x9f, 0x0d, 0xb9, 0xb3, 0x32, 0x7c, 0x4e, 0x22, 0xe0, 0x1b, 0x60, 0x99, 0x65, 0x31, 0xc2, - 0x9e, 0xa4, 0x47, 0x04, 0x0d, 0x13, 0x61, 0x2e, 0x6c, 0x18, 0x9b, 0x2d, 0xa7, 0xc9, 0xb2, 0x78, - 0x47, 0x81, 0xf7, 0x12, 0x71, 0xa7, 0xf2, 0xcd, 0x0f, 0x9d, 0xb9, 0xee, 0xf7, 0x0b, 0xc0, 0xfc, - 0x2b, 0xdb, 0xf0, 0x01, 0x58, 0x72, 0xa5, 0x87, 0x92, 0x91, 0x4a, 0xa4, 0x69, 0xbf, 0x77, 0x72, - 0xda, 0xb9, 0x1d, 0x50, 0x19, 0x66, 0xae, 0xe5, 0xf1, 0xb8, 0x57, 0x04, 0x1a, 0x61, 0x57, 0x6c, - 0x51, 0x3e, 0xb9, 0xf6, 0xe4, 0x38, 0x21, 0xc2, 0xb2, 0xf7, 0xfb, 0xb7, 0x6e, 0xbf, 0xd3, 0xcf, - 0xdc, 0x8f, 0xc8, 0xd8, 0x59, 0x74, 0xa5, 0xd7, 0x1f, 0x41, 0x08, 0x2a, 0xd8, 0xf7, 0x53, 0x73, - 0x3e, 0x37, 0xe7, 0xa8, 0x33, 0xfc, 0x18, 0x00, 0x8f, 0xc7, 0x31, 0x15, 0x82, 0x72, 0xa6, 0x22, - 0xad, 0xdb, 0x5b, 0x27, 0xa7, 0x9d, 0x75, 0x4d, 0xa1, 0xf0, 0x47, 0x16, 0xe5, 0xbd, 0x18, 0xcb, - 0xd0, 0x3a, 0x20, 0x01, 0xf6, 0xc6, 0x7b, 0xc4, 0x7b, 0xf6, 0x78, 0x0b, 0x14, 0x0c, 0xef, 0x11, - 0xcf, 0xb9, 0x60, 0x00, 0x6e, 0x02, 0x5d, 0x6e, 0xe4, 0x72, 0xe6, 0x13, 0x1f, 0x09, 0x2c, 0xcd, - 0x8a, 0xa2, 0x61, 0x59, 0xe1, 0xb6, 0x82, 0x07, 0x58, 0xc2, 0x0f, 0x40, 0x2d, 0xcf, 0xce, 0x27, - 0x91, 0x30, 0x17, 0x55, 0xe9, 0x5f, 0x7f, 0x61, 0xe9, 0xed, 0xc3, 0xdd, 0x3d, 0x12, 0x95, 0x05, - 0xaf, 0xba, 0xd2, 0xdb, 0x23, 0x91, 0x80, 0x6f, 0x82, 0x65, 0x2a, 0x50, 0xd9, 0x21, 0xc4, 0x37, - 0x97, 0x36, 0x8c, 0xcd, 0x9a, 0xd3, 0xa2, 0xe2, 0x70, 0x0a, 0xc2, 0x75, 0x50, 0xa7, 0x02, 0x7d, - 0x81, 0x69, 0x44, 0x7c, 0xb3, 0xaa, 0x34, 0x6a, 0x54, 0x7c, 0xa8, 0xee, 0xf0, 0x35, 0x00, 0xa8, - 0x40, 0x22, 0xc2, 0x22, 0x24, 0xbe, 0x59, 0x53, 0xd2, 0x3a, 0x15, 0x03, 0x0d, 0x74, 0x7f, 0x37, - 0xc0, 0xf2, 0xac, 0xfb, 0x97, 0xcf, 0xc9, 0xfb, 0xa0, 0x21, 0x24, 0x1e, 0x91, 0x14, 0x95, 0xd4, - 0xd4, 0x6d, 0xf3, 0xd9, 0xe3, 0xad, 0xd5, 0xa2, 0xc2, 0x3b, 0xbe, 0x9f, 0x12, 0x21, 0x06, 0x32, - 0xa5, 0x2c, 0x70, 0x80, 0x56, 0xce, 0x41, 0xf8, 0x16, 0xb8, 0x94, 0xdf, 0xf2, 0x7e, 0x97, 0xc7, - 0x28, 0xc4, 0x22, 0xd4, 0xfc, 0x39, 0xad, 0x02, 0x3e, 0x3c, 0xbe, 0x8f, 0x45, 0x98, 0x97, 0x40, - 0x73, 0x32, 0x25, 0xa3, 0xa6, 0x80, 0x01, 0x96, 0x5d, 0x04, 0x9a, 0xfb, 0xcc, 0x27, 0xc7, 0xc4, - 0xb7, 0x23, 0xee, 0x8d, 0xe0, 0x55, 0xb0, 0x14, 0x12, 0x1a, 0x84, 0xb2, 0x98, 0x9e, 0xe2, 0x06, - 0xaf, 0x81, 0x1a, 0x4e, 0x12, 0xed, 0x45, 0xf7, 0x4f, 0x15, 0x27, 0x89, 0xb2, 0xff, 0x2a, 0xa8, - 0x6b, 0xc2, 0xbe, 0x22, 0xbe, 0x8a, 0xa0, 0xe6, 0x4c, 0x81, 0xee, 0xb7, 0x06, 0x68, 0xf5, 0x33, - 0xd7, 0xc1, 0xcc, 0xdf, 0xcd, 0xfb, 0x44, 0xc2, 0xeb, 0xa0, 0x29, 0x24, 0x4e, 0x25, 0x9a, 0x71, - 0xd4, 0x50, 0xd8, 0x7d, 0xed, 0x6d, 0x03, 0xe4, 0xd3, 0x82, 0x92, 0xcc, 0x45, 0x29, 0x66, 0xbe, - 0xf2, 0x58, 0x71, 0x00, 0xcb, 0xe2, 0xc2, 0x14, 0x6c, 0x17, 0x7d, 0x2b, 0x63, 0xc2, 0xa4, 0xf2, - 0xda, 0x74, 0x2e, 0x20, 0x79, 0xd2, 0x24, 0xe1, 0x5e, 0x88, 0x58, 0x16, 0x4f, 0x92, 0x56, 0xc0, - 0x27, 0x59, 0xdc, 0xfd, 0xba, 0x02, 0x6a, 0x77, 0xf3, 0x61, 0x63, 0x1e, 0x81, 0x87, 0xa0, 0x3e, - 0x4c, 0xd0, 0x4b, 0x62, 0xb5, 0x3a, 0x4c, 0x6c, 0xc5, 0xeb, 0x75, 0xd0, 0x74, 0xf3, 0x82, 0x4e, - 0x92, 0xd4, 0x19, 0x34, 0x14, 0x56, 0x24, 0xf9, 0x10, 0xd4, 0xca, 0x04, 0x55, 0x02, 0xf6, 0x9d, - 0x93, 0xd3, 0xce, 0xbb, 0xff, 0xd4, 0xef, 0xc0, 0x0b, 0x19, 0x4f, 0xd3, 0xa2, 0x20, 0x4e, 0x35, - 0x29, 0x2a, 0x73, 0x03, 0x40, 0x0f, 0x33, 0xce, 0xa8, 0x87, 0x23, 0x54, 0x72, 0x56, 0x51, 0x15, - 0xba, 0x5c, 0x4a, 0x76, 0x0a, 0xf2, 0xba, 0xa0, 0x35, 0xe4, 0xe9, 0x68, 0xaa, 0xb8, 0xa8, 0x14, - 0x1b, 0x39, 0x38, 0xd1, 0x49, 0xc0, 0xd5, 0xa9, 0xc5, 0x72, 0x73, 0x0a, 0x1a, 0xa8, 0x91, 0xfb, - 0x77, 0x61, 0xdf, 0x7d, 0x70, 0x38, 0x18, 0xd0, 0xc0, 0x59, 0x2d, 0x2d, 0x4f, 0xf6, 0xe0, 0x80, - 0x06, 0x70, 0x08, 0x56, 0x54, 0x54, 0x33, 0xce, 0xaa, 0xff, 0xd9, 0xd9, 0xa5, 0xdc, 0xe8, 0x05, - 0x3f, 0xdd, 0xef, 0xe6, 0xc1, 0xfa, 0xf3, 0xfb, 0x77, 0x40, 0x03, 0x46, 0x59, 0xa0, 0xc6, 0xfd, - 0x7f, 0xeb, 0x8d, 0x99, 0x01, 0xc8, 0x7b, 0x63, 0x61, 0x76, 0x00, 0xb6, 0xc1, 0x2b, 0xf9, 0x4a, - 0x25, 0x3e, 0x52, 0x1d, 0x23, 0x90, 0xc7, 0x33, 0x26, 0x49, 0xaa, 0x1a, 0x65, 0xc1, 0xb9, 0xa2, - 0x85, 0x6a, 0x64, 0xc5, 0xae, 0x16, 0xc1, 0x03, 0xd0, 0xd4, 0x7b, 0x0e, 0x65, 0x4c, 0xd2, 0x48, - 0x51, 0xde, 0xd8, 0x5e, 0xb3, 0xf4, 0x57, 0xd5, 0x9a, 0x7c, 0x55, 0xad, 0x72, 0x3d, 0xda, 0xad, - 0x27, 0xa7, 0x9d, 0xb9, 0x47, 0xbf, 0x76, 0x8c, 0x1f, 0xff, 0xf8, 0xe9, 0x6d, 0xc3, 0x69, 0xe8, - 0xe7, 0x0f, 0xf3, 0xd7, 0xf6, 0xc1, 0x93, 0xb3, 0xb6, 0xf1, 0xf4, 0xac, 0x6d, 0xfc, 0x76, 0xd6, - 0x36, 0x1e, 0x9d, 0xb7, 0xe7, 0x9e, 0x9e, 0xb7, 0xe7, 0x7e, 0x39, 0x6f, 0xcf, 0x7d, 0xb6, 0xfd, - 0xf7, 0xd9, 0x1f, 0x4f, 0xff, 0x3f, 0xa8, 0x42, 0xb8, 0x4b, 0xca, 0xfb, 0xad, 0x3f, 0x03, 0x00, - 0x00, 0xff, 0xff, 0xe6, 0xb7, 0x70, 0x5d, 0x60, 0x08, 0x00, 0x00, + // 916 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x4f, 0x6f, 0xdc, 0x44, + 0x14, 0x5f, 0x27, 0x9b, 0xec, 0xee, 0xec, 0x6e, 0x68, 0xa6, 0xa1, 0x72, 0x13, 0xd8, 0xdd, 0xae, + 0x40, 0x5a, 0xa1, 0xc6, 0xa6, 0x69, 0x85, 0x50, 0x6f, 0x75, 0xd2, 0xaa, 0x81, 0x40, 0x57, 0xde, + 0x94, 0x03, 0x42, 0x1a, 0x8d, 0xed, 0xb1, 0x3d, 0xac, 0x3d, 0x63, 0x79, 0xc6, 0x4b, 0x97, 0x0f, + 0x80, 0x38, 0x96, 0x1b, 0x47, 0x8e, 0x1c, 0x39, 0xf0, 0x21, 0x7a, 0x42, 0x15, 0x27, 0x14, 0xa4, + 0x80, 0x92, 0x03, 0x5f, 0x03, 0x79, 0xec, 0xf5, 0x26, 0x11, 0x08, 0xc4, 0x9f, 0x8b, 0x35, 0xef, + 0xf7, 0x9e, 0xdf, 0x9f, 0xdf, 0x7b, 0xf3, 0x06, 0x0c, 0x1d, 0xec, 0xcc, 0x23, 0xce, 0x4c, 0x9f, + 0x32, 0x1c, 0x51, 0x39, 0x37, 0x67, 0x77, 0xaa, 0xb3, 0x91, 0xa4, 0x5c, 0x72, 0x78, 0xbd, 0xb4, + 0x31, 0x2a, 0x7c, 0x76, 0x67, 0xfb, 0xa6, 0xcb, 0x45, 0xcc, 0x05, 0x52, 0x26, 0x66, 0x21, 0x14, + 0xf6, 0xdb, 0x5b, 0x01, 0x0f, 0x78, 0x81, 0xe7, 0xa7, 0x12, 0xdd, 0xc4, 0x31, 0x65, 0xdc, 0x54, + 0xdf, 0x12, 0xea, 0x07, 0x9c, 0x07, 0x11, 0x31, 0x95, 0xe4, 0x64, 0xbe, 0x29, 0x69, 0x4c, 0x84, + 0xc4, 0x71, 0x52, 0x18, 0x0c, 0x7f, 0xd0, 0xc0, 0xd6, 0x47, 0x5c, 0x52, 0x16, 0x8c, 0xf9, 0x67, + 0x24, 0x3d, 0xa0, 0x42, 0xee, 0x63, 0x37, 0x24, 0xf0, 0x36, 0x80, 0x92, 0x4b, 0x1c, 0xa1, 0x99, + 0xd2, 0xa2, 0x24, 0x57, 0xeb, 0xda, 0x40, 0x1b, 0xd5, 0xed, 0x6b, 0x4a, 0x73, 0xe1, 0x37, 0xf8, + 0x09, 0x80, 0x8b, 0xd4, 0xf3, 0x7c, 0x67, 0xd4, 0x23, 0xa9, 0xd0, 0x57, 0x06, 0xab, 0xa3, 0xf6, + 0xde, 0xae, 0xf1, 0x07, 0xd5, 0x19, 0x8f, 0xca, 0xf3, 0xb8, 0xb4, 0xce, 0x23, 0x1f, 0x32, 0x9f, + 0xdb, 0x9b, 0xfe, 0x15, 0x8d, 0x80, 0x6f, 0x80, 0x0d, 0x96, 0xc5, 0x08, 0xbb, 0x92, 0xce, 0x08, + 0xf2, 0x13, 0xa1, 0xaf, 0x0e, 0xb4, 0x51, 0xd7, 0xee, 0xb0, 0x2c, 0x7e, 0xa0, 0xc0, 0x47, 0x89, + 0xb8, 0x5f, 0xff, 0xf2, 0x9b, 0x7e, 0x6d, 0xf8, 0xf3, 0x0a, 0xd0, 0xff, 0xcc, 0x37, 0x7c, 0x02, + 0xd6, 0x1d, 0xe9, 0xa2, 0x64, 0xaa, 0x0a, 0xe9, 0x58, 0xef, 0x9e, 0x9c, 0xf6, 0xef, 0x05, 0x54, + 0x86, 0x99, 0x63, 0xb8, 0x3c, 0x36, 0xcb, 0x44, 0x23, 0xec, 0x88, 0x5d, 0xca, 0x17, 0xa2, 0x29, + 0xe7, 0x09, 0x11, 0x86, 0x75, 0x38, 0xbe, 0x7b, 0xef, 0xed, 0x71, 0xe6, 0xbc, 0x4f, 0xe6, 0xf6, + 0x9a, 0x23, 0xdd, 0xf1, 0x14, 0x42, 0x50, 0xc7, 0x9e, 0x97, 0xea, 0x2b, 0xb9, 0x3b, 0x5b, 0x9d, + 0xe1, 0x07, 0x00, 0xb8, 0x3c, 0x8e, 0xa9, 0x10, 0x94, 0x33, 0x95, 0x69, 0xcb, 0xda, 0x3d, 0x39, + 0xed, 0xef, 0x14, 0x2d, 0x14, 0xde, 0xd4, 0xa0, 0xdc, 0x8c, 0xb1, 0x0c, 0x8d, 0x23, 0x12, 0x60, + 0x77, 0x7e, 0x40, 0xdc, 0x1f, 0xbf, 0xdf, 0x05, 0x65, 0x87, 0x0f, 0x88, 0x6b, 0x5f, 0x70, 0x00, + 0x47, 0xa0, 0xa0, 0x1b, 0x39, 0x9c, 0x79, 0xc4, 0x43, 0x02, 0x4b, 0xbd, 0xae, 0xda, 0xb0, 0xa1, + 0x70, 0x4b, 0xc1, 0x13, 0x2c, 0xe1, 0x9b, 0x60, 0x83, 0x0a, 0x54, 0x75, 0x98, 0x78, 0xfa, 0xda, + 0x40, 0x1b, 0x35, 0xed, 0x2e, 0x15, 0xc7, 0x4b, 0x10, 0xee, 0x80, 0x16, 0x15, 0xe8, 0x53, 0x4c, + 0x23, 0xe2, 0xe9, 0xeb, 0xca, 0xa2, 0x49, 0xc5, 0x7b, 0x4a, 0x86, 0xaf, 0x03, 0x40, 0x05, 0x12, + 0x11, 0x16, 0x21, 0xf1, 0xf4, 0x86, 0xd2, 0xb6, 0xa8, 0x98, 0x14, 0xc0, 0x10, 0x81, 0xce, 0x21, + 0xf3, 0xc8, 0x33, 0xe2, 0x59, 0x11, 0x77, 0xa7, 0xf0, 0x06, 0x58, 0x0f, 0x09, 0x0d, 0x42, 0x59, + 0x4e, 0x46, 0x29, 0xc1, 0x9b, 0xa0, 0x89, 0x93, 0x04, 0x85, 0x58, 0x84, 0x25, 0x37, 0x0d, 0x9c, + 0x24, 0x8f, 0xb1, 0x08, 0xe1, 0x6b, 0xa0, 0x55, 0x74, 0xf8, 0x73, 0xe2, 0x29, 0x76, 0x9a, 0xf6, + 0x12, 0x18, 0x7e, 0xa5, 0x81, 0xee, 0x38, 0x73, 0x6c, 0xcc, 0xbc, 0xfd, 0x9c, 0x03, 0x09, 0x6f, + 0x81, 0x8e, 0x90, 0x38, 0x95, 0xe8, 0x52, 0xa0, 0xb6, 0xc2, 0x1e, 0x17, 0xd1, 0x06, 0x20, 0x9f, + 0x04, 0x94, 0x64, 0x0e, 0x4a, 0x31, 0xf3, 0x54, 0xc4, 0xba, 0x0d, 0x58, 0x16, 0x97, 0xae, 0x60, + 0xaf, 0xec, 0x89, 0x8c, 0x09, 0x93, 0x2a, 0x6a, 0xc7, 0xbe, 0x80, 0xe4, 0x9c, 0x90, 0x84, 0xbb, + 0x21, 0x62, 0x59, 0x5c, 0xb2, 0xdb, 0x54, 0xc0, 0x87, 0x59, 0x3c, 0xfc, 0xa2, 0x0e, 0x9a, 0x0f, + 0xf3, 0x41, 0x62, 0x2e, 0x81, 0xc7, 0xa0, 0xe5, 0x27, 0xe8, 0x3f, 0x9a, 0xa2, 0x86, 0x9f, 0x58, + 0x6a, 0x8e, 0x6e, 0x81, 0x8e, 0x93, 0x13, 0xba, 0x28, 0xb2, 0xa8, 0xa0, 0xad, 0xb0, 0xb2, 0xc8, + 0xa7, 0xa0, 0x59, 0x15, 0xa8, 0x0a, 0xb0, 0xee, 0x9f, 0x9c, 0xf6, 0xdf, 0xf9, 0xbb, 0x71, 0x27, + 0x6e, 0xc8, 0x78, 0x9a, 0x96, 0x84, 0xd8, 0x8d, 0xa4, 0x64, 0xe6, 0x36, 0x80, 0x2e, 0x66, 0x9c, + 0x51, 0x17, 0x47, 0xa8, 0xea, 0x59, 0x5d, 0x31, 0x74, 0xad, 0xd2, 0x3c, 0x28, 0x9b, 0x37, 0x04, + 0x5d, 0x9f, 0xa7, 0xd3, 0xa5, 0xe1, 0x9a, 0x32, 0x6c, 0xe7, 0xe0, 0xc2, 0x26, 0x01, 0x37, 0x96, + 0x1e, 0xab, 0xad, 0x20, 0x68, 0xa0, 0x86, 0xed, 0x9f, 0xa5, 0xfd, 0xf0, 0xc9, 0xf1, 0x64, 0x42, + 0x03, 0x7b, 0xab, 0xf2, 0xbc, 0xb8, 0xe3, 0x13, 0x1a, 0x40, 0x1f, 0x6c, 0xaa, 0xac, 0x2e, 0x05, + 0x6b, 0xfc, 0xeb, 0x60, 0xaf, 0xe4, 0x4e, 0x2f, 0xc4, 0x19, 0x7e, 0xbd, 0x02, 0x76, 0xae, 0xee, + 0x96, 0x09, 0x0d, 0x18, 0x65, 0x81, 0x5a, 0x2f, 0xff, 0xdb, 0x6c, 0x5c, 0xba, 0x00, 0xf9, 0x6c, + 0xac, 0x5e, 0xbe, 0x00, 0x7b, 0xe0, 0xd5, 0x7c, 0x5d, 0x10, 0x0f, 0xa9, 0x89, 0x11, 0xc8, 0xe5, + 0x19, 0x93, 0x24, 0x55, 0x83, 0xb2, 0x6a, 0x5f, 0x2f, 0x94, 0xea, 0xca, 0x8a, 0xfd, 0x42, 0x05, + 0x8f, 0x40, 0xa7, 0xd8, 0x01, 0x28, 0x63, 0x92, 0x46, 0xaa, 0xe5, 0xed, 0xbd, 0x6d, 0xa3, 0x78, + 0x31, 0x8c, 0xc5, 0x8b, 0x61, 0x54, 0xab, 0xc3, 0xea, 0xbe, 0x38, 0xed, 0xd7, 0x9e, 0xff, 0xd2, + 0xd7, 0xbe, 0xfd, 0xed, 0xbb, 0xb7, 0x34, 0xbb, 0x5d, 0xfc, 0xfe, 0x34, 0xff, 0xdb, 0x3a, 0x7a, + 0x71, 0xd6, 0xd3, 0x5e, 0x9e, 0xf5, 0xb4, 0x5f, 0xcf, 0x7a, 0xda, 0xf3, 0xf3, 0x5e, 0xed, 0xe5, + 0x79, 0xaf, 0xf6, 0xd3, 0x79, 0xaf, 0xf6, 0xf1, 0xde, 0x5f, 0x57, 0xff, 0x6c, 0xf9, 0x36, 0x2a, + 0x22, 0x9c, 0x75, 0x15, 0xfd, 0xee, 0xef, 0x01, 0x00, 0x00, 0xff, 0xff, 0x04, 0xb9, 0x65, 0xd0, + 0x3c, 0x07, 0x00, 0x00, } func (m *VotingPowerDistCache) Marshal() (dAtA []byte, err error) { @@ -687,7 +604,7 @@ func (m *FinalityProviderDistInfo) MarshalToSizedBuffer(dAtA []byte) (int, error dAtA[i] = 0 } i-- - dAtA[i] = 0x40 + dAtA[i] = 0x38 } if m.IsJailed { i-- @@ -697,7 +614,7 @@ func (m *FinalityProviderDistInfo) MarshalToSizedBuffer(dAtA []byte) (int, error dAtA[i] = 0 } i-- - dAtA[i] = 0x38 + dAtA[i] = 0x30 } if m.IsTimestamped { i-- @@ -707,21 +624,7 @@ func (m *FinalityProviderDistInfo) MarshalToSizedBuffer(dAtA []byte) (int, error dAtA[i] = 0 } i-- - dAtA[i] = 0x30 - } - if len(m.BtcDels) > 0 { - for iNdEx := len(m.BtcDels) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.BtcDels[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintFinality(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - } + dAtA[i] = 0x28 } if m.TotalBondedSat != 0 { i = encodeVarintFinality(dAtA, i, uint64(m.TotalBondedSat)) @@ -762,60 +665,6 @@ func (m *FinalityProviderDistInfo) MarshalToSizedBuffer(dAtA []byte) (int, error return len(dAtA) - i, nil } -func (m *BTCDelDistInfo) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *BTCDelDistInfo) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BTCDelDistInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.TotalSat != 0 { - i = encodeVarintFinality(dAtA, i, uint64(m.TotalSat)) - i-- - dAtA[i] = 0x20 - } - if len(m.StakingTxHash) > 0 { - i -= len(m.StakingTxHash) - copy(dAtA[i:], m.StakingTxHash) - i = encodeVarintFinality(dAtA, i, uint64(len(m.StakingTxHash))) - i-- - dAtA[i] = 0x1a - } - if len(m.StakerAddr) > 0 { - i -= len(m.StakerAddr) - copy(dAtA[i:], m.StakerAddr) - i = encodeVarintFinality(dAtA, i, uint64(len(m.StakerAddr))) - i-- - dAtA[i] = 0x12 - } - if m.BtcPk != nil { - { - size := m.BtcPk.Size() - i -= size - if _, err := m.BtcPk.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintFinality(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func (m *IndexedBlock) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1102,12 +951,6 @@ func (m *FinalityProviderDistInfo) Size() (n int) { if m.TotalBondedSat != 0 { n += 1 + sovFinality(uint64(m.TotalBondedSat)) } - if len(m.BtcDels) > 0 { - for _, e := range m.BtcDels { - l = e.Size() - n += 1 + l + sovFinality(uint64(l)) - } - } if m.IsTimestamped { n += 2 } @@ -1120,30 +963,6 @@ func (m *FinalityProviderDistInfo) Size() (n int) { return n } -func (m *BTCDelDistInfo) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.BtcPk != nil { - l = m.BtcPk.Size() - n += 1 + l + sovFinality(uint64(l)) - } - l = len(m.StakerAddr) - if l > 0 { - n += 1 + l + sovFinality(uint64(l)) - } - l = len(m.StakingTxHash) - if l > 0 { - n += 1 + l + sovFinality(uint64(l)) - } - if m.TotalSat != 0 { - n += 1 + sovFinality(uint64(m.TotalSat)) - } - return n -} - func (m *IndexedBlock) Size() (n int) { if m == nil { return 0 @@ -1524,40 +1343,6 @@ func (m *FinalityProviderDistInfo) Unmarshal(dAtA []byte) error { } } case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BtcDels", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFinality - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthFinality - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthFinality - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.BtcDels = append(m.BtcDels, &BTCDelDistInfo{}) - if err := m.BtcDels[len(m.BtcDels)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field IsTimestamped", wireType) } @@ -1577,7 +1362,7 @@ func (m *FinalityProviderDistInfo) Unmarshal(dAtA []byte) error { } } m.IsTimestamped = bool(v != 0) - case 7: + case 6: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field IsJailed", wireType) } @@ -1597,7 +1382,7 @@ func (m *FinalityProviderDistInfo) Unmarshal(dAtA []byte) error { } } m.IsJailed = bool(v != 0) - case 8: + case 7: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field IsSlashed", wireType) } @@ -1638,174 +1423,6 @@ func (m *FinalityProviderDistInfo) Unmarshal(dAtA []byte) error { } return nil } -func (m *BTCDelDistInfo) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFinality - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: BTCDelDistInfo: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BTCDelDistInfo: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BtcPk", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFinality - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthFinality - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthFinality - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_babylonlabs_io_babylon_types.BIP340PubKey - m.BtcPk = &v - if err := m.BtcPk.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field StakerAddr", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFinality - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthFinality - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthFinality - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.StakerAddr = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field StakingTxHash", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFinality - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthFinality - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthFinality - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.StakingTxHash = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalSat", wireType) - } - m.TotalSat = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFinality - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalSat |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipFinality(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthFinality - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *IndexedBlock) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/finality/types/power_table.go b/x/finality/types/power_table.go index 7dc357065..1d8a271f3 100644 --- a/x/finality/types/power_table.go +++ b/x/finality/types/power_table.go @@ -146,7 +146,6 @@ func NewFinalityProviderDistInfo(fp *bstypes.FinalityProvider) *FinalityProvider Addr: sdk.MustAccAddressFromBech32(fp.Addr), Commission: fp.Commission, TotalBondedSat: 0, - BtcDels: []*BTCDelDistInfo{}, } } @@ -155,33 +154,17 @@ func (v *FinalityProviderDistInfo) GetAddress() sdk.AccAddress { } func (v *FinalityProviderDistInfo) AddBTCDel(btcDel *bstypes.BTCDelegation) { - btcDelDistInfo := &BTCDelDistInfo{ - BtcPk: btcDel.BtcPk, - StakerAddr: btcDel.StakerAddr, - StakingTxHash: btcDel.MustGetStakingTxHash().String(), - TotalSat: btcDel.TotalSat, - } - v.BtcDels = append(v.BtcDels, btcDelDistInfo) - v.TotalBondedSat += btcDelDistInfo.TotalSat + v.TotalBondedSat += btcDel.TotalSat } func (v *FinalityProviderDistInfo) UnbondBTCDel(btcDel *bstypes.BTCDelegation) { - v.TotalBondedSat = v.TotalBondedSat - btcDel.TotalSat -} - -func (v *FinalityProviderDistInfo) AddBTCDelDistInfo(d *BTCDelDistInfo) { - v.BtcDels = append(v.BtcDels, d) - v.TotalBondedSat += d.TotalSat + v.TotalBondedSat -= btcDel.TotalSat } // GetBTCDelPortion returns the portion of a BTC delegation's voting power out of // the finality provider's total voting power -func (v *FinalityProviderDistInfo) GetBTCDelPortion(d *BTCDelDistInfo) sdkmath.LegacyDec { - return sdkmath.LegacyNewDec(int64(d.TotalSat)).QuoTruncate(sdkmath.LegacyNewDec(int64(v.TotalBondedSat))) -} - -func (d *BTCDelDistInfo) GetAddress() sdk.AccAddress { - return sdk.MustAccAddressFromBech32(d.StakerAddr) +func (v *FinalityProviderDistInfo) GetBTCDelPortion(totalSatDelegation uint64) sdkmath.LegacyDec { + return sdkmath.LegacyNewDec(int64(totalSatDelegation)).QuoTruncate(sdkmath.LegacyNewDec(int64(v.TotalBondedSat))) } // SortFinalityProvidersWithZeroedVotingPower sorts the finality providers slice, diff --git a/x/incentive/keeper/btc_staking_gauge_test.go b/x/incentive/keeper/btc_staking_gauge_test.go index 8939ed4d4..d3aa72494 100644 --- a/x/incentive/keeper/btc_staking_gauge_test.go +++ b/x/incentive/keeper/btc_staking_gauge_test.go @@ -34,7 +34,7 @@ func FuzzRewardBTCStaking(f *testing.F) { k.SetBTCStakingGauge(ctx, height, gauge) // generate a random voting power distribution cache - dc, err := datagen.GenRandomVotingPowerDistCache(r, 100) + dc, btcTotalSatByDelAddressByFpAddress, err := datagen.GenRandomVotingPowerDistCache(r, 100) require.NoError(t, err) // expected values @@ -56,14 +56,15 @@ func FuzzRewardBTCStaking(f *testing.F) { sumCoinsForDels = sumCoinsForDels.Add(coinsForBTCDels...) fpAddr := fp.GetAddress() - for _, btcDel := range fp.BtcDels { - err := k.BtcDelegationActivated(ctx, fpAddr, btcDel.GetAddress(), btcDel.TotalSat) + for delAddrStr, delSat := range btcTotalSatByDelAddressByFpAddress[fpAddr.String()] { + btcDelAddr := sdk.MustAccAddressFromBech32(delAddrStr) + err := k.BtcDelegationActivated(ctx, fpAddr, btcDelAddr, delSat) require.NoError(t, err) - btcDelPortion := fp.GetBTCDelPortion(btcDel) + btcDelPortion := fp.GetBTCDelPortion(delSat) coinsForDel := types.GetCoinsPortion(coinsForBTCDels, btcDelPortion) if coinsForDel.IsAllPositive() { - btcDelRewardMap[btcDel.GetAddress().String()] = coinsForDel + btcDelRewardMap[delAddrStr] = coinsForDel distributedCoins.Add(coinsForDel...) } } @@ -74,11 +75,11 @@ func FuzzRewardBTCStaking(f *testing.F) { for _, fp := range dc.FinalityProviders { fpAddr := fp.GetAddress() - for _, btcDel := range fp.BtcDels { - delAddr := btcDel.GetAddress() + for delAddrStr, delSat := range btcTotalSatByDelAddressByFpAddress[fpAddr.String()] { + delAddr := sdk.MustAccAddressFromBech32(delAddrStr) delRwd, err := k.GetBTCDelegationRewardsTracker(ctx, fpAddr, delAddr) require.NoError(t, err) - require.Equal(t, delRwd.TotalActiveSat.Uint64(), btcDel.TotalSat) + require.Equal(t, delRwd.TotalActiveSat.Uint64(), delSat) // makes sure the rewards added reach the delegation gauge err = k.BtcDelegationActivated(ctx, fpAddr, delAddr, 0) From 4cbdad92ed32063d3b219e6522506b4571306925 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 11:21:43 -0300 Subject: [PATCH 114/132] tryfix: moved reward gauge query --- test/e2e/btc_rewards_distribution_e2e_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index bf419350f..9316ed4e5 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -583,14 +583,13 @@ func CheckWithdrawReward( // does the withdraw right after the query to avoid new blocks rewarded delBalanceBeforeWithdraw, errQueryB := n.QueryBalances(delAddr) n.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) + delRwdGauge, errRwdGauge := n.QueryRewardGauge(accDelAddr) require.NoError(t, errQueryB) + require.NoError(t, errRwdGauge) n.WaitForNextBlock() - delRwdGauge, err := n.QueryRewardGauge(accDelAddr) - require.NoError(t, err) - delBalanceAfterWithdraw, err := n.QueryBalances(delAddr) require.NoError(t, err) From 4e23a9163231a96eb2dbdeb31366ff59317a42ac Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 12:58:52 -0300 Subject: [PATCH 115/132] fix: add gas fee of tx withdraw into calculation of balance --- test/e2e/btc_rewards_distribution_e2e_test.go | 15 ++++++++----- test/e2e/configurer/chain/commands.go | 22 ++++++++++++++++--- test/e2e/configurer/chain/queries.go | 9 ++++++-- test/e2e/containers/containers.go | 5 ++++- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 9316ed4e5..7acfae922 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -333,6 +333,8 @@ func (s *BtcRewardsDistribution) Test5CheckRewardsFirstDelegations() { coins.RequireCoinsDiffInPointOnePercentMargin(s.T(), btcDel1LastRewardGauge.Coins, btcDel2LastRewardGauge.Coins) CheckWithdrawReward(s.T(), n2, wDel2, s.del2Addr) + + s.AddFinalityVoteUntilCurrentHeight() } // Test6ActiveLastDelegation creates a new btc delegation @@ -580,15 +582,16 @@ func CheckWithdrawReward( accDelAddr := sdk.MustAccAddressFromBech32(delAddr) n.WaitForNextBlockWithSleep50ms() - // does the withdraw right after the query to avoid new blocks rewarded + txHash := n.WithdrawReward(itypes.BTCDelegationType.String(), delWallet) delBalanceBeforeWithdraw, errQueryB := n.QueryBalances(delAddr) - n.WithdrawReward(itypes.BTCDelegationType.String(), wDel2) - delRwdGauge, errRwdGauge := n.QueryRewardGauge(accDelAddr) + n.WaitForNextBlock() + + _, txResp := n.QueryTx(txHash) require.NoError(t, errQueryB) - require.NoError(t, errRwdGauge) - n.WaitForNextBlock() + delRwdGauge, errRwdGauge := n.QueryRewardGauge(accDelAddr) + require.NoError(t, errRwdGauge) delBalanceAfterWithdraw, err := n.QueryBalances(delAddr) require.NoError(t, err) @@ -599,7 +602,7 @@ func CheckWithdrawReward( require.True(t, ok) require.True(t, delRewardGauge.Coins.IsAllPositive()) - require.Equal(t, delBalanceAfterWithdraw.String(), delBalanceBeforeWithdraw.Add(delRewardGauge.WithdrawnCoins...).String()) + require.Equal(t, delBalanceAfterWithdraw.Sub(txResp.AuthInfo.Fee.Amount...).String(), delBalanceBeforeWithdraw.Add(delRewardGauge.WithdrawnCoins...).String()) } func SendCovenantSigsToPendingDel( diff --git a/test/e2e/configurer/chain/commands.go b/test/e2e/configurer/chain/commands.go index 16c993a63..592501c35 100644 --- a/test/e2e/configurer/chain/commands.go +++ b/test/e2e/configurer/chain/commands.go @@ -288,13 +288,14 @@ func (n *NodeConfig) WasmExecute(contract, execMsg, from string) { } // WithdrawReward will withdraw the rewards of the address associated with the tx signer `from` -func (n *NodeConfig) WithdrawReward(sType, from string) { +func (n *NodeConfig) WithdrawReward(sType, from string) (txHash string) { n.LogActionF("withdraw rewards of type %s for tx signer %s", sType, from) cmd := []string{"babylond", "tx", "incentive", "withdraw-reward", sType, fmt.Sprintf("--from=%s", from)} n.LogActionF("Executing command: %s", strings.Join(cmd, " ")) - _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainId, n.Name, cmd) + outBuf, _, err := n.containerManager.ExecTxCmd(n.t, n.chainId, n.Name, cmd) require.NoError(n.t, err) - n.LogActionF("successfully withdrawn") + n.LogActionF("successfully withdrawn: %s", outBuf.String()) + return GetTxHashFromOutput(outBuf.String()) } // TxMultisigSign sign a tx in a file with one wallet for a multisig address. @@ -471,3 +472,18 @@ func (n *NodeConfig) SubmitRefundableTxWithAssertion( require.True(n.t, submitterBalanceBefore.IsAllGT(submitterBalanceAfter)) } } + +func GetTxHashFromOutput(txOutput string) (txHash string) { + // Define the regex pattern to match txhash + re := regexp.MustCompile(`txhash:\s*([A-Fa-f0-9]+)`) + + // Find the first match + match := re.FindStringSubmatch(txOutput) + + if len(match) > 1 { + // The first capture group contains the txhash value + txHash := match[1] + return txHash + } + return "" +} diff --git a/test/e2e/configurer/chain/queries.go b/test/e2e/configurer/chain/queries.go index 892bac78b..7cf8e221f 100644 --- a/test/e2e/configurer/chain/queries.go +++ b/test/e2e/configurer/chain/queries.go @@ -18,6 +18,7 @@ import ( cmttypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" + sdktx "github.com/cosmos/cosmos-sdk/types/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" @@ -412,7 +413,7 @@ func (n *NodeConfig) QueryAppliedPlan(planName string) upgradetypes.QueryApplied return resp } -func (n *NodeConfig) QueryTx(txHash string, overallFlags ...string) sdk.TxResponse { +func (n *NodeConfig) QueryTx(txHash string, overallFlags ...string) (sdk.TxResponse, sdktx.Tx) { cmd := []string{ "babylond", "q", "tx", "--type=hash", txHash, "--output=json", n.FlagChainID(), @@ -425,7 +426,11 @@ func (n *NodeConfig) QueryTx(txHash string, overallFlags ...string) sdk.TxRespon err = util.Cdc.UnmarshalJSON(out.Bytes(), &txResp) require.NoError(n.t, err) - return txResp + var txAuth sdktx.Tx + err = util.Cdc.UnpackAny(txResp.Tx, &txAuth) + require.NoError(n.t, err) + + return txResp, txAuth } func (n *NodeConfig) WaitUntilCurrentEpochIsSealedAndFinalized(startEpoch uint64) (lastFinalizedEpoch uint64) { diff --git a/test/e2e/containers/containers.go b/test/e2e/containers/containers.go index 22d6adc5e..b6863d1ef 100644 --- a/test/e2e/containers/containers.go +++ b/test/e2e/containers/containers.go @@ -61,7 +61,10 @@ func NewManager(identifier string, isDebugLogEnabled bool, isCosmosRelayer, isUp } // ExecTxCmd Runs ExecTxCmdWithSuccessString searching for `code: 0` -func (m *Manager) ExecTxCmd(t *testing.T, chainId string, nodeName string, command []string) (bytes.Buffer, bytes.Buffer, error) { +func (m *Manager) ExecTxCmd(t *testing.T, chainId string, nodeName string, command []string) ( + outBuf, errBuf bytes.Buffer, + err error, +) { return m.ExecTxCmdWithSuccessString(t, chainId, nodeName, command, "code: 0") } From 47a822fac3a3022c010a3db4ae8750e9e6105165 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 13:12:28 -0300 Subject: [PATCH 116/132] fix: parse of tx resp auth data --- test/e2e/configurer/chain/queries.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/e2e/configurer/chain/queries.go b/test/e2e/configurer/chain/queries.go index 7cf8e221f..d9046f58f 100644 --- a/test/e2e/configurer/chain/queries.go +++ b/test/e2e/configurer/chain/queries.go @@ -413,7 +413,7 @@ func (n *NodeConfig) QueryAppliedPlan(planName string) upgradetypes.QueryApplied return resp } -func (n *NodeConfig) QueryTx(txHash string, overallFlags ...string) (sdk.TxResponse, sdktx.Tx) { +func (n *NodeConfig) QueryTx(txHash string, overallFlags ...string) (sdk.TxResponse, *sdktx.Tx) { cmd := []string{ "babylond", "q", "tx", "--type=hash", txHash, "--output=json", n.FlagChainID(), @@ -426,10 +426,7 @@ func (n *NodeConfig) QueryTx(txHash string, overallFlags ...string) (sdk.TxRespo err = util.Cdc.UnmarshalJSON(out.Bytes(), &txResp) require.NoError(n.t, err) - var txAuth sdktx.Tx - err = util.Cdc.UnpackAny(txResp.Tx, &txAuth) - require.NoError(n.t, err) - + txAuth := txResp.Tx.GetCachedValue().(*sdktx.Tx) return txResp, txAuth } From bf840dcef05ed3703104a8108a099fe1bae10ee8 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 13:13:46 -0300 Subject: [PATCH 117/132] chore: fix oreder, query first than withdraw --- test/e2e/btc_rewards_distribution_e2e_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 7acfae922..05ffc30e4 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -582,13 +582,13 @@ func CheckWithdrawReward( accDelAddr := sdk.MustAccAddressFromBech32(delAddr) n.WaitForNextBlockWithSleep50ms() + delBalanceBeforeWithdraw, err := n.QueryBalances(delAddr) txHash := n.WithdrawReward(itypes.BTCDelegationType.String(), delWallet) - delBalanceBeforeWithdraw, errQueryB := n.QueryBalances(delAddr) n.WaitForNextBlock() _, txResp := n.QueryTx(txHash) - require.NoError(t, errQueryB) + require.NoError(t, err) delRwdGauge, errRwdGauge := n.QueryRewardGauge(accDelAddr) require.NoError(t, errRwdGauge) From e974b8b3d99888fa4fab3869c33442f1b8cc688c Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 13:24:29 -0300 Subject: [PATCH 118/132] fix: add fee amt to the expected amt --- test/e2e/btc_rewards_distribution_e2e_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 05ffc30e4..9632d318a 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -602,7 +602,9 @@ func CheckWithdrawReward( require.True(t, ok) require.True(t, delRewardGauge.Coins.IsAllPositive()) - require.Equal(t, delBalanceAfterWithdraw.Sub(txResp.AuthInfo.Fee.Amount...).String(), delBalanceBeforeWithdraw.Add(delRewardGauge.WithdrawnCoins...).String()) + actualAmt := delBalanceAfterWithdraw.String() + expectedAmt := delBalanceBeforeWithdraw.Add(delRewardGauge.WithdrawnCoins...).Add(txResp.AuthInfo.Fee.Amount...).String() + require.Equal(t, expectedAmt, actualAmt) } func SendCovenantSigsToPendingDel( From 629daa52b2e8d7084803acc51fe55700a2135da4 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 13:34:49 -0300 Subject: [PATCH 119/132] fix: subtract the fee used in the expected amount of balance after withdraw > getting crazy in amounts calculation .-. --- test/e2e/btc_rewards_distribution_e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 9632d318a..9c3a47107 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -603,7 +603,7 @@ func CheckWithdrawReward( require.True(t, delRewardGauge.Coins.IsAllPositive()) actualAmt := delBalanceAfterWithdraw.String() - expectedAmt := delBalanceBeforeWithdraw.Add(delRewardGauge.WithdrawnCoins...).Add(txResp.AuthInfo.Fee.Amount...).String() + expectedAmt := delBalanceBeforeWithdraw.Add(delRewardGauge.WithdrawnCoins...).Sub(txResp.AuthInfo.Fee.Amount...).String() require.Equal(t, expectedAmt, actualAmt) } From 33f1b7f0ee42b5ffa6867cf04f171743db2a7885 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 13:46:29 -0300 Subject: [PATCH 120/132] chore: reduce structures of btc delegation in maps to amount of satoshi active/unbonded --- x/finality/keeper/power_dist_change.go | 42 +++++++++++++------------- x/finality/types/power_table.go | 8 ++--- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 1a669e772..2ff3035eb 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -174,11 +174,11 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( ) *ftypes.VotingPowerDistCache { // a map where key is finality provider's BTC PK hex and value is a list // of BTC delegations that newly become active under this provider - activeBTCDels := map[string][]*types.BTCDelegation{} + activedSatsByFpBtcPk := map[string][]uint64{} // a map where key is finality provider's BTC PK hex and value is a list // of BTC delegations that were unbonded or expired without previously // being unbonded - unbondedBTCDels := map[string][]*types.BTCDelegation{} + unbondedSatsByFpBtcPk := map[string][]uint64{} // a map where key is slashed finality providers' BTC PK slashedFPs := map[string]struct{}{} // a map where key is jailed finality providers' BTC PK @@ -210,7 +210,7 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // add the BTC delegation to each restaked finality provider for _, fpBTCPK := range btcDel.FpBtcPkList { fpBTCPKHex := fpBTCPK.MarshalHex() - activeBTCDels[fpBTCPKHex] = append(activeBTCDels[fpBTCPKHex], btcDel) + activedSatsByFpBtcPk[fpBTCPKHex] = append(activedSatsByFpBtcPk[fpBTCPKHex], btcDel.TotalSat) } k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { @@ -221,7 +221,7 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // unbondedBTCDels[delStkTxHash] = struct{}{} for _, fpBTCPK := range btcDel.FpBtcPkList { fpBTCPKHex := fpBTCPK.MarshalHex() - unbondedBTCDels[fpBTCPKHex] = append(unbondedBTCDels[fpBTCPKHex], btcDel) + unbondedSatsByFpBtcPk[fpBTCPKHex] = append(unbondedSatsByFpBtcPk[fpBTCPKHex], btcDel.TotalSat) } k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { k.MustProcessBtcDelegationUnbonded(ctx, fp, del, sats) @@ -235,7 +235,7 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // unbondedBTCDels[delStkTxHash] = struct{}{} for _, fpBTCPK := range btcDel.FpBtcPkList { fpBTCPKHex := fpBTCPK.MarshalHex() - unbondedBTCDels[fpBTCPKHex] = append(unbondedBTCDels[fpBTCPKHex], btcDel) + unbondedSatsByFpBtcPk[fpBTCPKHex] = append(unbondedSatsByFpBtcPk[fpBTCPKHex], btcDel.TotalSat) } k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { k.MustProcessBtcDelegationUnbonded(ctx, fp, del, sats) @@ -297,28 +297,28 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( } // process all new BTC delegations under this finality provider - if fpUnbondedBTCDels, ok := unbondedBTCDels[fpBTCPKHex]; ok { + if fpUnbondedBTCDels, ok := unbondedSatsByFpBtcPk[fpBTCPKHex]; ok { // handle unbonded delegations for this finality provider - for _, d := range fpUnbondedBTCDels { - fp.UnbondBTCDel(d) + for _, unbodedSats := range fpUnbondedBTCDels { + fp.RemoveBondedSats(unbodedSats) } // remove the finality provider entry in unbondedBTCDels map, so that // after the for loop the rest entries in unbondedBTCDels belongs to new // finality providers that might have btc delegations entries // that activated and unbonded in the same slice of events - delete(unbondedBTCDels, fpBTCPKHex) + delete(unbondedSatsByFpBtcPk, fpBTCPKHex) } // process all new BTC delegations under this finality provider - if fpActiveBTCDels, ok := activeBTCDels[fpBTCPKHex]; ok { + if fpActiveBTCDels, ok := activedSatsByFpBtcPk[fpBTCPKHex]; ok { // handle new BTC delegations for this finality provider - for _, d := range fpActiveBTCDels { - fp.AddBTCDel(d) + for _, activatedSats := range fpActiveBTCDels { + fp.AddBondedSats(activatedSats) } // remove the finality provider entry in activeBTCDels map, so that // after the for loop the rest entries in activeBTCDels belongs to new // finality providers with new BTC delegations - delete(activeBTCDels, fpBTCPKHex) + delete(activedSatsByFpBtcPk, fpBTCPKHex) } // add this finality provider to the new cache if it has voting power @@ -331,8 +331,8 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( process new BTC delegations under new finality providers in activeBTCDels */ // sort new finality providers in activeBTCDels to ensure determinism - fpActiveBtcPkHexList := make([]string, 0, len(activeBTCDels)) - for fpBTCPKHex := range activeBTCDels { + fpActiveBtcPkHexList := make([]string, 0, len(activedSatsByFpBtcPk)) + for fpBTCPKHex := range activedSatsByFpBtcPk { fpActiveBtcPkHexList = append(fpActiveBtcPkHexList, fpBTCPKHex) } sort.SliceStable(fpActiveBtcPkHexList, func(i, j int) bool { @@ -346,18 +346,18 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( fpDistInfo := ftypes.NewFinalityProviderDistInfo(newFP) // add each BTC delegation - fpActiveBTCDels := activeBTCDels[fpBTCPKHex] - for _, d := range fpActiveBTCDels { - fpDistInfo.AddBTCDel(d) + fpActiveBTCDels := activedSatsByFpBtcPk[fpBTCPKHex] + for _, activatedSats := range fpActiveBTCDels { + fpDistInfo.AddBondedSats(activatedSats) } // edge case where we might be processing an unbonded event // from a newly active finality provider in the same slice // of events received. - fpUnbondedBTCDels, ok := unbondedBTCDels[fpBTCPKHex] + fpUnbondedBTCDels, ok := unbondedSatsByFpBtcPk[fpBTCPKHex] if ok { - for _, d := range fpUnbondedBTCDels { - fpDistInfo.UnbondBTCDel(d) + for _, unbodedSats := range fpUnbondedBTCDels { + fpDistInfo.RemoveBondedSats(unbodedSats) } } diff --git a/x/finality/types/power_table.go b/x/finality/types/power_table.go index 1d8a271f3..c844d358d 100644 --- a/x/finality/types/power_table.go +++ b/x/finality/types/power_table.go @@ -153,12 +153,12 @@ func (v *FinalityProviderDistInfo) GetAddress() sdk.AccAddress { return v.Addr } -func (v *FinalityProviderDistInfo) AddBTCDel(btcDel *bstypes.BTCDelegation) { - v.TotalBondedSat += btcDel.TotalSat +func (v *FinalityProviderDistInfo) AddBondedSats(sats uint64) { + v.TotalBondedSat += sats } -func (v *FinalityProviderDistInfo) UnbondBTCDel(btcDel *bstypes.BTCDelegation) { - v.TotalBondedSat -= btcDel.TotalSat +func (v *FinalityProviderDistInfo) RemoveBondedSats(sats uint64) { + v.TotalBondedSat -= sats } // GetBTCDelPortion returns the portion of a BTC delegation's voting power out of From 050b19190bf2908eb29fbf18a50d39f24046a6d5 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 15:35:31 -0300 Subject: [PATCH 121/132] chore: update TODOs --- x/btcstaking/types/btc_delegation.go | 3 --- x/finality/keeper/power_dist_change.go | 5 ++--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/x/btcstaking/types/btc_delegation.go b/x/btcstaking/types/btc_delegation.go index 690724720..4a71cee90 100644 --- a/x/btcstaking/types/btc_delegation.go +++ b/x/btcstaking/types/btc_delegation.go @@ -360,7 +360,6 @@ func (d *BTCDelegation) GetUnbondingInfo(bsParams *Params, btcNet *chaincfg.Para return unbondingInfo, nil } -// TODO: verify to remove, not used in babylon, only for tests // findFPIdx returns the index of the given finality provider // among all restaked finality providers func (d *BTCDelegation) findFPIdx(fpBTCPK *bbn.BIP340PubKey) (int, error) { @@ -376,7 +375,6 @@ func (d *BTCDelegation) findFPIdx(fpBTCPK *bbn.BIP340PubKey) (int, error) { // the signatures on the slashing tx, such that the slashing tx obtains full // witness and can be submitted to Bitcoin. // This happens after the finality provider is slashed and its SK is extracted. -// TODO: verify not used func (d *BTCDelegation) BuildSlashingTxWithWitness(bsParams *Params, btcNet *chaincfg.Params, fpSK *btcec.PrivateKey) (*wire.MsgTx, error) { stakingMsgTx, err := bbn.NewBTCTxFromBytes(d.StakingTx) if err != nil { @@ -427,7 +425,6 @@ func (d *BTCDelegation) BuildSlashingTxWithWitness(bsParams *Params, btcNet *cha return slashingMsgTxWithWitness, nil } -// TODO: verify to remove, func not used by babylon, used in side car processes. func (d *BTCDelegation) BuildUnbondingSlashingTxWithWitness(bsParams *Params, btcNet *chaincfg.Params, fpSK *btcec.PrivateKey) (*wire.MsgTx, error) { unbondingMsgTx, err := bbn.NewBTCTxFromBytes(d.BtcUndelegation.UnbondingTx) if err != nil { diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 2ff3035eb..3e4af4e7a 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -261,10 +261,9 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( Then, construct a voting power dist cache by reconciling the previous cache and all the new events. */ - // TODO: the algorithm needs to iterate over all BTC delegations so remains + // TODO: the algorithm needs to iterate over all the finality providers so remains // sub-optimal. Ideally we only need to iterate over all events above rather - // than the entire cache. This is made difficulty since BTC delegations are - // not keyed in the cache. Need to find a way to optimise this. + // than the entire cache. newDc := ftypes.NewVotingPowerDistCache() // iterate over all finality providers and apply all events From da1a0f2abe96836c06ad1f4d2a1255696562180f Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 15:35:42 -0300 Subject: [PATCH 122/132] chore: update TODOs --- x/btcstaking/keeper/msg_server.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/x/btcstaking/keeper/msg_server.go b/x/btcstaking/keeper/msg_server.go index 0c9895d43..215e2a0af 100644 --- a/x/btcstaking/keeper/msg_server.go +++ b/x/btcstaking/keeper/msg_server.go @@ -110,8 +110,6 @@ func (ms msgServer) EditFinalityProvider(goCtx context.Context, req *types.MsgEd return nil, types.ErrCommissionGTMaxRate } - // TODO: check to index the finality provider by his address instead of the BTC pk - // find the finality provider with the given BTC PK fp, err := ms.GetFinalityProvider(goCtx, req.BtcPk) if err != nil { return nil, err From 20c1c08f5a4a3014ee3789370a641463f35248f9 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 15:38:10 -0300 Subject: [PATCH 123/132] chore: add test for newly unbond and active BTC staking tx being processed at the same time --- x/finality/keeper/power_dist_change_test.go | 56 +++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/x/finality/keeper/power_dist_change_test.go b/x/finality/keeper/power_dist_change_test.go index 4a2d1a623..fa5a81c40 100644 --- a/x/finality/keeper/power_dist_change_test.go +++ b/x/finality/keeper/power_dist_change_test.go @@ -83,6 +83,62 @@ func FuzzProcessAllPowerDistUpdateEvents_Determinism(f *testing.F) { }) } +func FuzzProcessAllPowerDistUpdateEvents_ActiveAndUnbondTogether(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + r := rand.New(rand.NewSource(seed)) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // mock BTC light client and BTC checkpoint modules + btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) + btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) + h := testutil.NewHelper(t, btclcKeeper, btccKeeper) + + // set all parameters + h.GenAndApplyParams(r) + changeAddress, err := datagen.GenRandomBTCAddress(r, h.Net) + require.NoError(t, err) + + // empty dist cache + dc := ftypes.NewVotingPowerDistCache() + + _, fpPK, _ := h.CreateFinalityProvider(r) + + delSK, _, err := datagen.GenRandomBTCKeyPair(r) + h.NoError(err) + _, _, del, _, _, _, err := h.CreateDelegationWithBtcBlockHeight( + r, + delSK, + fpPK, + changeAddress.EncodeAddress(), + int64(2*10e8), + 1000, + 0, + 0, + false, + false, + 10, + 30, + ) + h.NoError(err) + + eventActive := types.NewEventPowerDistUpdateWithBTCDel(&types.EventBTCDelegationStateUpdate{ + StakingTxHash: del.MustGetStakingTxHash().String(), + NewState: types.BTCDelegationStatus_ACTIVE, + }) + eventUnbond := types.NewEventPowerDistUpdateWithBTCDel(&types.EventBTCDelegationStateUpdate{ + StakingTxHash: del.MustGetStakingTxHash().String(), + NewState: types.BTCDelegationStatus_UNBONDED, + }) + events := []*types.EventPowerDistUpdate{eventActive, eventUnbond} + + newDc := h.FinalityKeeper.ProcessAllPowerDistUpdateEvents(h.Ctx, dc, events) + require.Zero(t, newDc.TotalVotingPower) + }) +} + func FuzzSlashFinalityProviderEvent(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) From 5ed4b1c43d41ac8f149252806dfcb0c7c54a43e6 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 15:50:34 -0300 Subject: [PATCH 124/132] chore: add check for status and expired delegations --- x/btcstaking/keeper/msg_server.go | 4 +- x/btcstaking/keeper/msg_server_test.go | 70 ++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/x/btcstaking/keeper/msg_server.go b/x/btcstaking/keeper/msg_server.go index 215e2a0af..0ef12a442 100644 --- a/x/btcstaking/keeper/msg_server.go +++ b/x/btcstaking/keeper/msg_server.go @@ -455,7 +455,7 @@ func (ms msgServer) AddCovenantSigs(goCtx context.Context, req *types.MsgAddCove // ensure BTC delegation is still pending, i.e., not unbonded btcTipHeight := ms.btclcKeeper.GetTipInfo(ctx).Height status := btcDel.GetStatus(btcTipHeight, params.CovenantQuorum) - if status == types.BTCDelegationStatus_UNBONDED { + if status == types.BTCDelegationStatus_UNBONDED || status == types.BTCDelegationStatus_EXPIRED { ms.Logger(ctx).Debug("Received covenant signature after the BTC delegation is already unbonded", "covenant pk", req.Pk.MarshalHex()) return nil, types.ErrInvalidCovenantSig.Wrap("the BTC delegation is already unbonded") } @@ -606,7 +606,7 @@ func (ms msgServer) BTCUndelegate(goCtx context.Context, req *types.MsgBTCUndele bsParams.CovenantQuorum, ) - if btcDelStatus == types.BTCDelegationStatus_UNBONDED { + if btcDelStatus == types.BTCDelegationStatus_UNBONDED || btcDelStatus == types.BTCDelegationStatus_EXPIRED { return nil, types.ErrInvalidBTCUndelegateReq.Wrap("cannot unbond an unbonded BTC delegation") } diff --git a/x/btcstaking/keeper/msg_server_test.go b/x/btcstaking/keeper/msg_server_test.go index f32bde022..2ce6051a6 100644 --- a/x/btcstaking/keeper/msg_server_test.go +++ b/x/btcstaking/keeper/msg_server_test.go @@ -749,6 +749,76 @@ func FuzzBTCUndelegate(f *testing.F) { }) } +func FuzzBTCUndelegateExpired(f *testing.F) { + datagen.AddRandomSeedsToFuzzer(f, 10) + + f.Fuzz(func(t *testing.T, seed int64) { + r := rand.New(rand.NewSource(seed)) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // mock BTC light client and BTC checkpoint modules + btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) + btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) + h := testutil.NewHelper(t, btclcKeeper, btccKeeper) + + // set all parameters + covenantSKs, _ := h.GenAndApplyParams(r) + + bsParams := h.BTCStakingKeeper.GetParams(h.Ctx) + + changeAddress, err := datagen.GenRandomBTCAddress(r, h.Net) + require.NoError(t, err) + + // generate and insert new finality provider + _, fpPK, _ := h.CreateFinalityProvider(r) + + // generate and insert new BTC delegation + stakingValue := int64(2 * 10e8) + delSK, _, err := datagen.GenRandomBTCKeyPair(r) + h.NoError(err) + stakingTxHash, msgCreateBTCDel, actualDel, btcHeaderInfo, inclusionProof, unbondingInfo, err := h.CreateDelegationWithBtcBlockHeight( + r, + delSK, + fpPK, + changeAddress.EncodeAddress(), + stakingValue, + 1000, + 0, + 0, + true, + false, + 10, + 10, + ) + h.NoError(err) + + // add covenant signatures to this BTC delegation + h.CreateCovenantSigs(r, covenantSKs, msgCreateBTCDel, actualDel, 10) + // activate the BTC delegation + btcTip := uint32(30) + h.AddInclusionProof(stakingTxHash, btcHeaderInfo, inclusionProof, btcTip) + + // ensure the BTC delegation is bonded right now + actualDel, err = h.BTCStakingKeeper.GetBTCDelegation(h.Ctx, stakingTxHash) + h.NoError(err) + status := actualDel.GetStatus(btcTip, bsParams.CovenantQuorum) + require.Equal(t, types.BTCDelegationStatus_ACTIVE, status) + + msg := &types.MsgBTCUndelegate{ + Signer: datagen.GenRandomAccount().Address, + StakingTxHash: stakingTxHash, + StakeSpendingTx: actualDel.BtcUndelegation.UnbondingTx, + StakeSpendingTxInclusionProof: unbondingInfo.UnbondingTxInclusionProof, + } + + // expires the delegation + h.BTCLightClientKeeper.EXPECT().GetTipInfo(gomock.Eq(h.Ctx)).Return(&btclctypes.BTCHeaderInfo{Height: 2000}).AnyTimes() + _, err = h.MsgServer.BTCUndelegate(h.Ctx, msg) + require.EqualError(t, err, types.ErrInvalidBTCUndelegateReq.Wrap("cannot unbond an unbonded BTC delegation").Error()) + }) +} + func FuzzSelectiveSlashing(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) From a0dfc3b8824736ab49ad179667b315a8308dba1c Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 17:08:11 -0300 Subject: [PATCH 125/132] chore: removed signed block window --- test/e2e/configurer/chain/queries.go | 2 +- test/e2e/initialization/config.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/e2e/configurer/chain/queries.go b/test/e2e/configurer/chain/queries.go index d9046f58f..9f7a7b6c7 100644 --- a/test/e2e/configurer/chain/queries.go +++ b/test/e2e/configurer/chain/queries.go @@ -464,7 +464,7 @@ func (n *NodeConfig) WaitFinalityIsActivated() (activatedHeight uint64) { return false } return activatedHeight > 0 - }, time.Minute*4, time.Millisecond*50) + }, time.Minute*4, time.Second*1) n.t.Logf("the activated height is %d", activatedHeight) return activatedHeight } diff --git a/test/e2e/initialization/config.go b/test/e2e/initialization/config.go index 53be9e6b7..c1f4da6f7 100644 --- a/test/e2e/initialization/config.go +++ b/test/e2e/initialization/config.go @@ -360,7 +360,6 @@ func updateFinalityGenesis(finalityGenState *finalitytypes.GenesisState) { finalityGenState.Params.FinalityActivationHeight = 0 finalityGenState.Params.FinalitySigTimeout = 3 finalityGenState.Params.SignedBlocksWindow = 300 - finalityGenState.Params.MinSignedPerWindow = sdkmath.LegacyMustNewDecFromStr("0.000005000000000000") } func updateGenUtilGenesis(c *internalChain) func(*genutiltypes.GenesisState) { From 59488ebf5a8716b43a70b8b376116f6ef3339620 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 17:42:52 -0300 Subject: [PATCH 126/132] chore: reduced duplicated code and update comments --- test/e2e/btc_rewards_distribution_e2e_test.go | 10 ---- test/e2e/configurer/chain/chain.go | 4 -- x/finality/keeper/power_dist_change.go | 57 ++++++++++--------- x/incentive/keeper/btc_staking_gauge_test.go | 1 - x/incentive/keeper/reward_tracker.go | 20 ++++--- x/incentive/keeper/reward_tracker_store.go | 3 +- 6 files changed, 43 insertions(+), 52 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index 9c3a47107..d66388c9f 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -227,9 +227,6 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { n2, err := chainA.GetNodeAtIndex(2) s.NoError(err) - /* - commit a number of public randomness - */ // commit public randomness list commitStartHeight := uint64(1) @@ -259,7 +256,6 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { n1.WaitUntilCurrentEpochIsSealedAndFinalized(1) - // activated height is never returned s.finalityBlockHeightVoted = n1.WaitFinalityIsActivated() // submit finality signature @@ -403,12 +399,6 @@ func (s *BtcRewardsDistribution) Test7CheckRewards() { // (fp2) => 8_00000000 // (del1) => 4_00000000 // (del2) => 10_00000000 - - // Current rewards for each addr - // fp1 ~5364ubbn - // fp2 ~1787ubbn - // del1 ~11625ubbn - // del2 ~16989ubbn fp1RewardGaugePrev, fp2RewardGaugePrev, btcDel1RewardGaugePrev, btcDel2RewardGaugePrev := s.QueryRewardGauges(n2) // wait a few block of rewards to calculate the difference n2.WaitForNextBlocks(2) diff --git a/test/e2e/configurer/chain/chain.go b/test/e2e/configurer/chain/chain.go index d27ce0c76..76ac1f72c 100644 --- a/test/e2e/configurer/chain/chain.go +++ b/test/e2e/configurer/chain/chain.go @@ -3,7 +3,6 @@ package chain import ( "encoding/hex" "fmt" - "sort" "strings" "testing" "time" @@ -77,9 +76,6 @@ func (c *Config) CreateNode(initNode *initialization.Node) *NodeConfig { t: c.t, } c.NodeConfigs = append(c.NodeConfigs, nodeConfig) - sort.Slice(c.NodeConfigs, func(i, j int) bool { - return c.NodeConfigs[i].Name > c.NodeConfigs[j].Name - }) return nodeConfig } diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index 3e4af4e7a..cfed42b5d 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -187,7 +187,7 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( unjailedFPs := map[string]struct{}{} // simple cache to load fp by his btc pk hex - cacheFpByBtcPkHex := map[string]*types.FinalityProvider{} + fpByBtcPkHex := map[string]*types.FinalityProvider{} /* filter and classify all events into new/expired BTC delegations and jailed/slashed FPs @@ -213,39 +213,30 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( activedSatsByFpBtcPk[fpBTCPKHex] = append(activedSatsByFpBtcPk[fpBTCPKHex], btcDel.TotalSat) } - k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { + k.processRewardTracker(ctx, fpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { k.MustProcessBtcDelegationActivated(ctx, fp, del, sats) }) case types.BTCDelegationStatus_UNBONDED: // add the unbonded BTC delegation to the map - // unbondedBTCDels[delStkTxHash] = struct{}{} - for _, fpBTCPK := range btcDel.FpBtcPkList { - fpBTCPKHex := fpBTCPK.MarshalHex() - unbondedSatsByFpBtcPk[fpBTCPKHex] = append(unbondedSatsByFpBtcPk[fpBTCPKHex], btcDel.TotalSat) - } - k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { - k.MustProcessBtcDelegationUnbonded(ctx, fp, del, sats) - }) + k.processPowerDistUpdateEventUnbond(ctx, fpByBtcPkHex, btcDel, unbondedSatsByFpBtcPk) case types.BTCDelegationStatus_EXPIRED: types.EmitExpiredDelegationEvent(sdkCtx, delStkTxHash) if !btcDel.IsUnbondedEarly() { // only adds to the new unbonded list if it hasn't // previously unbonded with types.BTCDelegationStatus_UNBONDED - // unbondedBTCDels[delStkTxHash] = struct{}{} - for _, fpBTCPK := range btcDel.FpBtcPkList { - fpBTCPKHex := fpBTCPK.MarshalHex() - unbondedSatsByFpBtcPk[fpBTCPKHex] = append(unbondedSatsByFpBtcPk[fpBTCPKHex], btcDel.TotalSat) - } - k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { - k.MustProcessBtcDelegationUnbonded(ctx, fp, del, sats) - }) + k.processPowerDistUpdateEventUnbond(ctx, fpByBtcPkHex, btcDel, unbondedSatsByFpBtcPk) } } case *types.EventPowerDistUpdate_SlashedFp: // record slashed fps types.EmitSlashedFPEvent(sdkCtx, typedEvent.SlashedFp.Pk) - slashedFPs[typedEvent.SlashedFp.Pk.MarshalHex()] = struct{}{} + fpBTCPKHex := typedEvent.SlashedFp.Pk.MarshalHex() + slashedFPs[fpBTCPKHex] = struct{}{} + fp := k.loadFP(ctx, fpByBtcPkHex, fpBTCPKHex) + if err := k.IncentiveKeeper.FpSlashed(ctx, fp.Address()); err != nil { + panic(err) + } case *types.EventPowerDistUpdate_JailedFp: // record jailed fps types.EmitJailedFPEvent(sdkCtx, typedEvent.JailedFp.Pk) @@ -276,9 +267,6 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // assigning delegation to it _, isSlashed := slashedFPs[fpBTCPKHex] if isSlashed { - if err := k.IncentiveKeeper.FpSlashed(ctx, fp.GetAddress()); err != nil { - panic(err) - } fp.IsSlashed = true continue } @@ -341,7 +329,7 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // for each new finality provider, apply the new BTC delegations to the new dist cache for _, fpBTCPKHex := range fpActiveBtcPkHexList { // get the finality provider and initialise its dist info - newFP := k.loadFP(ctx, cacheFpByBtcPkHex, fpBTCPKHex) + newFP := k.loadFP(ctx, fpByBtcPkHex, fpBTCPKHex) fpDistInfo := ftypes.NewFinalityProviderDistInfo(newFP) // add each BTC delegation @@ -369,6 +357,21 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( return newDc } +func (k Keeper) processPowerDistUpdateEventUnbond( + ctx context.Context, + cacheFpByBtcPkHex map[string]*types.FinalityProvider, + btcDel *types.BTCDelegation, + unbondedSatsByFpBtcPk map[string][]uint64, +) { + for _, fpBTCPK := range btcDel.FpBtcPkList { + fpBTCPKHex := fpBTCPK.MarshalHex() + unbondedSatsByFpBtcPk[fpBTCPKHex] = append(unbondedSatsByFpBtcPk[fpBTCPKHex], btcDel.TotalSat) + } + k.processRewardTracker(ctx, cacheFpByBtcPkHex, btcDel, func(fp, del sdk.AccAddress, sats uint64) { + k.MustProcessBtcDelegationUnbonded(ctx, fp, del, sats) + }) +} + func (k Keeper) SetVotingPowerDistCache(ctx context.Context, height uint64, dc *ftypes.VotingPowerDistCache) { store := k.votingPowerDistCacheStore(ctx) store.Set(sdk.Uint64ToBigEndian(height), k.cdc.MustMarshal(dc)) @@ -404,16 +407,14 @@ func (k Keeper) votingPowerDistCacheStore(ctx context.Context) prefix.Store { // and satoshi amounts. func (k Keeper) processRewardTracker( ctx context.Context, - cacheFpByBtcPkHex map[string]*types.FinalityProvider, + fpByBtcPkHex map[string]*types.FinalityProvider, btcDel *types.BTCDelegation, f func(fp, del sdk.AccAddress, sats uint64), ) { delAddr := sdk.MustAccAddressFromBech32(btcDel.StakerAddr) for _, fpBTCPK := range btcDel.FpBtcPkList { - fp := k.loadFP(ctx, cacheFpByBtcPkHex, fpBTCPK.MarshalHex()) - fpAddr := sdk.MustAccAddressFromBech32(fp.Addr) - - f(fpAddr, delAddr, btcDel.TotalSat) + fp := k.loadFP(ctx, fpByBtcPkHex, fpBTCPK.MarshalHex()) + f(fp.Address(), delAddr, btcDel.TotalSat) } } diff --git a/x/incentive/keeper/btc_staking_gauge_test.go b/x/incentive/keeper/btc_staking_gauge_test.go index d3aa72494..526e02971 100644 --- a/x/incentive/keeper/btc_staking_gauge_test.go +++ b/x/incentive/keeper/btc_staking_gauge_test.go @@ -24,7 +24,6 @@ func FuzzRewardBTCStaking(f *testing.F) { // mock bank keeper bankKeeper := types.NewMockBankKeeper(ctrl) - // create incentive k k, ctx := testkeeper.IncentiveKeeper(t, bankKeeper, nil, nil) height := datagen.RandomInt(r, 1000) ctx = datagen.WithCtxHeight(ctx, height) diff --git a/x/incentive/keeper/reward_tracker.go b/x/incentive/keeper/reward_tracker.go index 06e8ca305..afee4994b 100644 --- a/x/incentive/keeper/reward_tracker.go +++ b/x/incentive/keeper/reward_tracker.go @@ -247,7 +247,7 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA return 0, err } - // initiates a new period with empty rewards and the same amount of active sat (this value should be updated latter if needed) + // initiates a new period with empty rewards and the same amount of active sat newCurrentRwd := types.NewFinalityProviderCurrentRewards(sdk.NewCoins(), fpCurrentRwd.Period+1, fpCurrentRwd.TotalActiveSat) if err := k.setFinalityProviderCurrentRewards(ctx, fp, newCurrentRwd); err != nil { return 0, err @@ -257,7 +257,7 @@ func (k Keeper) IncrementFinalityProviderPeriod(ctx context.Context, fp sdk.AccA } // initializeFinalityProvider initializes a new finality provider current rewards at period 1, empty rewards and zero sats -// and also a historical rewards at period 0 and zero rewards as well. +// and also creates a new historical rewards at period 0 and zero rewards as well. // It does not verifies if it exists prior to overwrite, who calls it needs to verify. func (k Keeper) initializeFinalityProvider(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { // historical rewards starts at the period 0 @@ -271,14 +271,18 @@ func (k Keeper) initializeFinalityProvider(ctx context.Context, fp sdk.AccAddres return newFp, k.setFinalityProviderCurrentRewards(ctx, fp, newFp) } -// initializeBTCDelegation creates a new BTCDelegationRewardsTracker from the previous acumulative rewards -// period of the finality provider and it should be called right after a BTC delegator withdraw his rewards -// (in our case send the rewards to the reward gauge). Reminder that at every new modification to the amount -// of satoshi staked from this btc delegator to this finality provider (activivation or unbonding) of BTC -// delegations, it should withdraw all rewards (send to gauge) and initialize a new BTCDelegationRewardsTracker. +// initializeBTCDelegation creates a new BTCDelegationRewardsTracker from the +// previous acumulative rewards period of the finality provider. This function +// should be called right after a BTC delegator withdraw his rewards (in our +// case send the rewards to the reward gauge). Reminder that at every new +// modification to the amount of satoshi staked from this btc delegator to +// this finality provider (activivation or unbonding) of BTC delegations, it +// should withdraw all rewards (send to gauge) and initialize a new BTCDelegationRewardsTracker. // TODO: add reference count to keep track of possible prunning state of val rewards func (k Keeper) initializeBTCDelegation(ctx context.Context, fp, del sdk.AccAddress) error { - // period has already been incremented - we want to store the period ended by this delegation action + // period has already been incremented prior to call this function + // it is needed to store the period ended by this delegation action + // as a starting point of the delegation rewards calculation valCurrentRewards, err := k.GetFinalityProviderCurrentRewards(ctx, fp) if err != nil { return err diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index 65de0413b..1414bf46b 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -272,7 +272,8 @@ func (k Keeper) addFinalityProviderStaked(ctx context.Context, fp sdk.AccAddress return err } - // this is needed as the amount of sats for the FP is inside the FpCurrentRewards + // needs to initialize at this point due to the amount of + // sats for the FP is inside the FinalityProviderCurrentRewards fpCurrentRwd, err = k.initializeFinalityProvider(ctx, fp) if err != nil { return err From a2fede3add136633d5c0d21071e7d3296481785c Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 20:05:23 -0300 Subject: [PATCH 127/132] chore: move BTCDelegationRewardTracker to collections --- x/incentive/keeper/keeper.go | 12 +++++ x/incentive/keeper/reward_tracker_store.go | 53 ++++++---------------- x/incentive/types/keys.go | 2 +- 3 files changed, 28 insertions(+), 39 deletions(-) diff --git a/x/incentive/keeper/keeper.go b/x/incentive/keeper/keeper.go index c66d3804f..6feb7d6fd 100644 --- a/x/incentive/keeper/keeper.go +++ b/x/incentive/keeper/keeper.go @@ -29,6 +29,10 @@ type ( authority string // name of the FeeCollector ModuleAccount feeCollectorName string + + // Collections structures + // BTCDelegationRewardsTracker maps (FpAddr, DelAddr) => BTCDelegationRewardsTracker + BTCDelegationRewardsTracker collections.Map[collections.Pair[[]byte, []byte], types.BTCDelegationRewardsTracker] } ) @@ -55,6 +59,14 @@ func NewKeeper( "refundable_msg_key_set", collections.BytesKey, ), + BTCDelegationRewardsTracker: collections.NewMap( + sb, + types.BTCDelegationRewardsTrackerKeyPrefix, + "btc_delegation_rewards_tracker", + // keys: (FpAddr, DelAddr) + collections.PairKeyCodec(collections.BytesKey, collections.BytesKey), + codec.CollValue[types.BTCDelegationRewardsTracker](cdc), + ), authority: authority, feeCollectorName: feeCollectorName, } diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index 1414bf46b..ac4064af1 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "errors" + "cosmossdk.io/collections" sdkmath "cosmossdk.io/math" "cosmossdk.io/store/prefix" "github.com/babylonlabs-io/babylon/x/incentive/types" @@ -26,16 +27,6 @@ func (k Keeper) storeBTCDelegatorToFp(ctx context.Context, del sdk.AccAddress) p return prefix.NewStore(st, del.Bytes()) } -// storeBTCDelegationRewardsTracker returns the KVStore of the FP current rewards -// prefix: BTCDelegationRewardsTrackerKey -// key: (FpAddr, DelAddr) -// value: BTCDelegationRewardsTracker -func (k Keeper) storeBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress) prefix.Store { - storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - st := prefix.NewStore(storeAdaptor, types.BTCDelegationRewardsTrackerKey) - return prefix.NewStore(st, fp.Bytes()) -} - // storeFpCurrentRewards returns the KVStore of the FP current rewards // prefix: FinalityProviderCurrentRewardsKey // key: (finality provider cosmos address) @@ -105,25 +96,24 @@ func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.Ac // IterateBTCDelegationRewardsTracker iterates over all the delegation rewards tracker by the finality provider. // It stops if the function `it` returns an error. func (k Keeper) IterateBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress, it func(fp, del sdk.AccAddress) error) error { - st := k.storeBTCDelegationRewardsTracker(ctx, fp) - - iter := st.Iterator(nil, nil) - defer iter.Close() - for ; iter.Valid(); iter.Next() { - del := sdk.AccAddress(iter.Key()) + rng := collections.NewPrefixedPairRange[[]byte, []byte](fp.Bytes()) + return k.BTCDelegationRewardsTracker.Walk(ctx, rng, func(key collections.Pair[[]byte, []byte], value types.BTCDelegationRewardsTracker) (stop bool, err error) { + del := sdk.AccAddress(key.K2()) if err := it(fp, del); err != nil { - return err + return err != nil, err } - } - - return nil + return false, nil + }) } // deleteKeysFromBTCDelegationRewardsTracker iterates over all the BTC delegation rewards tracker by the finality provider and deletes it. func (k Keeper) deleteKeysFromBTCDelegationRewardsTracker(ctx context.Context, fp sdk.AccAddress, delKeys [][]byte) { - stDelRwdTracker := k.storeBTCDelegationRewardsTracker(ctx, fp) + rng := collections.NewPrefixedPairRange[[]byte, []byte](fp.Bytes()) + err := k.BTCDelegationRewardsTracker.Clear(ctx, rng) + if err != nil { + k.Logger(sdk.UnwrapSDKContext(ctx)).Error("error deleting BTCDelegationRewardsTracker", "error", err) + } for _, delKey := range delKeys { - stDelRwdTracker.Delete(delKey) k.deleteBTCDelegatorToFP(ctx, sdk.AccAddress(delKey), fp) } } @@ -131,30 +121,17 @@ func (k Keeper) deleteKeysFromBTCDelegationRewardsTracker(ctx context.Context, f // GetBTCDelegationRewardsTracker returns the BTCDelegationRewardsTracker based on the delegation key (fp, del) // It returns an error in case the key is not found. func (k Keeper) GetBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk.AccAddress) (types.BTCDelegationRewardsTracker, error) { - key := del.Bytes() - bz := k.storeBTCDelegationRewardsTracker(ctx, fp).Get(key) - if bz == nil { + value, err := k.BTCDelegationRewardsTracker.Get(ctx, collections.Join(fp.Bytes(), del.Bytes())) + if err != nil { return types.BTCDelegationRewardsTracker{}, types.ErrBTCDelegationRewardsTrackerNotFound } - - var value types.BTCDelegationRewardsTracker - if err := k.cdc.Unmarshal(bz, &value); err != nil { - return types.BTCDelegationRewardsTracker{}, err - } return value, nil } // setBTCDelegationRewardsTracker sets a new structure in the store, it fails and returns an error if the rwd fails to marshal. func (k Keeper) setBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk.AccAddress, rwd types.BTCDelegationRewardsTracker) error { - key := del.Bytes() - bz, err := rwd.Marshal() - if err != nil { - return err - } - k.setBTCDelegatorToFP(ctx, del, fp) - k.storeBTCDelegationRewardsTracker(ctx, fp).Set(key, bz) - return nil + return k.BTCDelegationRewardsTracker.Set(ctx, collections.Join(fp.Bytes(), del.Bytes()), rwd) } // setFinalityProviderCurrentRewards sets a new structure in the store, it fails and returns an error if the rwd fails to marshal. diff --git a/x/incentive/types/keys.go b/x/incentive/types/keys.go index 7e01e9099..6ab34ff26 100644 --- a/x/incentive/types/keys.go +++ b/x/incentive/types/keys.go @@ -28,7 +28,7 @@ var ( RefundableMsgKeySetPrefix = collections.NewPrefix(5) // key prefix for refundable msg key set FinalityProviderCurrentRewardsKey = []byte{0x06} // key prefix for storing the Current rewards of finality provider by addr FinalityProviderHistoricalRewardsKey = []byte{0x07} // key prefix for storing the Historical rewards of finality provider by addr and period - BTCDelegationRewardsTrackerKey = []byte{0x8} // key prefix for BTC delegation rewards tracker info (del,fp) => BTCDelegationRewardsTracker + BTCDelegationRewardsTrackerKeyPrefix = collections.NewPrefix(8) // key prefix for BTC delegation rewards tracker info (del,fp) => BTCDelegationRewardsTracker BTCDelegatorToFPKey = []byte{0x9} // key prefix for storing the map reference from delegation to finality provider (del) => fp ) From c9fd71821d1834b51870a64b315d086bb442b3e4 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 21:35:22 -0300 Subject: [PATCH 128/132] chore: move FinalityProviderHistoricalRewards to collections --- x/incentive/keeper/keeper.go | 15 ++++++- x/incentive/keeper/reward_tracker_store.go | 50 +++------------------- x/incentive/types/keys.go | 18 ++++---- 3 files changed, 30 insertions(+), 53 deletions(-) diff --git a/x/incentive/keeper/keeper.go b/x/incentive/keeper/keeper.go index 6feb7d6fd..74be3d893 100644 --- a/x/incentive/keeper/keeper.go +++ b/x/incentive/keeper/keeper.go @@ -30,9 +30,12 @@ type ( // name of the FeeCollector ModuleAccount feeCollectorName string - // Collections structures + // Collections structures for rewards + // BTCDelegationRewardsTracker maps (FpAddr, DelAddr) => BTCDelegationRewardsTracker BTCDelegationRewardsTracker collections.Map[collections.Pair[[]byte, []byte], types.BTCDelegationRewardsTracker] + // FinalityProviderHistoricalRewards maps (FpAddr, period) => FinalityProviderHistoricalRewards + FinalityProviderHistoricalRewards collections.Map[collections.Pair[[]byte, uint64], types.FinalityProviderHistoricalRewards] } ) @@ -59,6 +62,8 @@ func NewKeeper( "refundable_msg_key_set", collections.BytesKey, ), + + // Collections structures for rewards BTCDelegationRewardsTracker: collections.NewMap( sb, types.BTCDelegationRewardsTrackerKeyPrefix, @@ -67,6 +72,14 @@ func NewKeeper( collections.PairKeyCodec(collections.BytesKey, collections.BytesKey), codec.CollValue[types.BTCDelegationRewardsTracker](cdc), ), + FinalityProviderHistoricalRewards: collections.NewMap( + sb, + types.FinalityProviderHistoricalRewardsKeyPrefix, + "fp_historical_rewards", + // keys: (FpAddr, period) + collections.PairKeyCodec(collections.BytesKey, collections.Uint64Key), + codec.CollValue[types.FinalityProviderHistoricalRewards](cdc), + ), authority: authority, feeCollectorName: feeCollectorName, } diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index ac4064af1..f43c5c8bb 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -2,7 +2,6 @@ package keeper import ( "context" - "encoding/binary" "errors" "cosmossdk.io/collections" @@ -36,16 +35,6 @@ func (k Keeper) storeFpCurrentRewards(ctx context.Context) prefix.Store { return prefix.NewStore(storeAdaptor, types.FinalityProviderCurrentRewardsKey) } -// storeFpHistoricalRewards returns the KVStore of the FP historical rewards -// prefix: FinalityProviderHistoricalRewardsKey -// key: (finality provider cosmos address, period) -// value: FinalityProviderHistoricalRewards -func (k Keeper) storeFpHistoricalRewards(ctx context.Context, fp sdk.AccAddress) prefix.Store { - storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - st := prefix.NewStore(storeAdaptor, types.FinalityProviderHistoricalRewardsKey) - return prefix.NewStore(st, fp.Bytes()) -} - // setBTCDelegatorToFP sets a new delegator to finality provider record. func (k Keeper) setBTCDelegatorToFP(ctx context.Context, del, fp sdk.AccAddress) { st := k.storeBTCDelegatorToFp(ctx, del) @@ -149,18 +138,10 @@ func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.Ac // deleteAllFromFinalityProviderRwd deletes all the data related to Finality Provider Rewards // Historical and current from a fp address key. func (k Keeper) deleteAllFromFinalityProviderRwd(ctx context.Context, fp sdk.AccAddress) { - stHistoricalRwd := k.storeFpHistoricalRewards(ctx, fp) - - iter := stHistoricalRwd.Iterator(nil, nil) - defer iter.Close() - - keys := make([][]byte, 0) - for ; iter.Valid(); iter.Next() { - keys = append(keys, iter.Key()) - } - - for _, key := range keys { - stHistoricalRwd.Delete(key) + rng := collections.NewPrefixedPairRange[[]byte, uint64](fp.Bytes()) + err := k.FinalityProviderHistoricalRewards.Clear(ctx, rng) + if err != nil { + k.Logger(sdk.UnwrapSDKContext(ctx)).Error("error deleting FinalityProviderHistoricalRewards", "error", err) } k.deleteFinalityProviderCurrentRewards(ctx, fp) @@ -175,34 +156,17 @@ func (k Keeper) deleteFinalityProviderCurrentRewards(ctx context.Context, fp sdk // GetFinalityProviderHistoricalRewards returns the FinalityProviderHistoricalRewards based on the key (fp, period) // It returns an error if the key is not found inside the store. func (k Keeper) GetFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64) (types.FinalityProviderHistoricalRewards, error) { - key := make([]byte, 8) - binary.LittleEndian.PutUint64(key, period) - - bz := k.storeFpHistoricalRewards(ctx, fp).Get(key) - if bz == nil { + value, err := k.FinalityProviderHistoricalRewards.Get(ctx, collections.Join(fp.Bytes(), period)) + if err != nil { return types.FinalityProviderHistoricalRewards{}, types.ErrFPHistoricalRewardsNotFound } - - var value types.FinalityProviderHistoricalRewards - if err := k.cdc.Unmarshal(bz, &value); err != nil { - return types.FinalityProviderHistoricalRewards{}, err - } return value, nil } // setFinalityProviderHistoricalRewards sets a new value inside the store, it returns an error // if the marshal of the `rwd` fails. func (k Keeper) setFinalityProviderHistoricalRewards(ctx context.Context, fp sdk.AccAddress, period uint64, rwd types.FinalityProviderHistoricalRewards) error { - key := make([]byte, 8) - binary.LittleEndian.PutUint64(key, period) - - bz, err := rwd.Marshal() - if err != nil { - return err - } - - k.storeFpHistoricalRewards(ctx, fp).Set(key, bz) - return nil + return k.FinalityProviderHistoricalRewards.Set(ctx, collections.Join(fp.Bytes(), period), rwd) } // subDelegationSat subtracts an amount of active stake from the BTCDelegationRewardsTracker diff --git a/x/incentive/types/keys.go b/x/incentive/types/keys.go index 6ab34ff26..737af386e 100644 --- a/x/incentive/types/keys.go +++ b/x/incentive/types/keys.go @@ -21,15 +21,15 @@ const ( ) var ( - ParamsKey = []byte{0x01} // key prefix for the parameters - BTCStakingGaugeKey = []byte{0x02} // key prefix for BTC staking gauge at each height - DelegatorWithdrawAddrPrefix = []byte{0x03} // key for delegator withdraw address - RewardGaugeKey = []byte{0x04} // key prefix for reward gauge for a given stakeholder in a given type - RefundableMsgKeySetPrefix = collections.NewPrefix(5) // key prefix for refundable msg key set - FinalityProviderCurrentRewardsKey = []byte{0x06} // key prefix for storing the Current rewards of finality provider by addr - FinalityProviderHistoricalRewardsKey = []byte{0x07} // key prefix for storing the Historical rewards of finality provider by addr and period - BTCDelegationRewardsTrackerKeyPrefix = collections.NewPrefix(8) // key prefix for BTC delegation rewards tracker info (del,fp) => BTCDelegationRewardsTracker - BTCDelegatorToFPKey = []byte{0x9} // key prefix for storing the map reference from delegation to finality provider (del) => fp + ParamsKey = []byte{0x01} // key prefix for the parameters + BTCStakingGaugeKey = []byte{0x02} // key prefix for BTC staking gauge at each height + DelegatorWithdrawAddrPrefix = []byte{0x03} // key for delegator withdraw address + RewardGaugeKey = []byte{0x04} // key prefix for reward gauge for a given stakeholder in a given type + RefundableMsgKeySetPrefix = collections.NewPrefix(5) // key prefix for refundable msg key set + FinalityProviderCurrentRewardsKey = []byte{0x06} // key prefix for storing the Current rewards of finality provider by addr + FinalityProviderHistoricalRewardsKeyPrefix = collections.NewPrefix(7) // key prefix for storing the Historical rewards of finality provider by addr and period + BTCDelegationRewardsTrackerKeyPrefix = collections.NewPrefix(8) // key prefix for BTC delegation rewards tracker info (del,fp) => BTCDelegationRewardsTracker + BTCDelegatorToFPKey = []byte{0x9} // key prefix for storing the map reference from delegation to finality provider (del) => fp ) // GetWithdrawAddrKey creates the key for a delegator's withdraw addr. From a01359f4780986343cfbb0123cb030d7fc062f26 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 22:43:09 -0300 Subject: [PATCH 129/132] chore: move FinalityProviderCurrentRewards to collections --- x/incentive/keeper/keeper.go | 10 +++++++ x/incentive/keeper/reward_tracker_store.go | 33 ++++------------------ x/incentive/types/keys.go | 2 +- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/x/incentive/keeper/keeper.go b/x/incentive/keeper/keeper.go index 74be3d893..7e93ba674 100644 --- a/x/incentive/keeper/keeper.go +++ b/x/incentive/keeper/keeper.go @@ -36,6 +36,8 @@ type ( BTCDelegationRewardsTracker collections.Map[collections.Pair[[]byte, []byte], types.BTCDelegationRewardsTracker] // FinalityProviderHistoricalRewards maps (FpAddr, period) => FinalityProviderHistoricalRewards FinalityProviderHistoricalRewards collections.Map[collections.Pair[[]byte, uint64], types.FinalityProviderHistoricalRewards] + // FinalityProviderCurrentRewards maps (FpAddr) => FinalityProviderCurrentRewards + FinalityProviderCurrentRewards collections.Map[[]byte, types.FinalityProviderCurrentRewards] } ) @@ -80,6 +82,14 @@ func NewKeeper( collections.PairKeyCodec(collections.BytesKey, collections.Uint64Key), codec.CollValue[types.FinalityProviderHistoricalRewards](cdc), ), + FinalityProviderCurrentRewards: collections.NewMap( + sb, + types.FinalityProviderCurrentRewardsKeyPrefix, + "fp_current_rewards", + // key: (FpAddr) + collections.BytesKey, + codec.CollValue[types.FinalityProviderCurrentRewards](cdc), + ), authority: authority, feeCollectorName: feeCollectorName, } diff --git a/x/incentive/keeper/reward_tracker_store.go b/x/incentive/keeper/reward_tracker_store.go index f43c5c8bb..39768b941 100644 --- a/x/incentive/keeper/reward_tracker_store.go +++ b/x/incentive/keeper/reward_tracker_store.go @@ -26,15 +26,6 @@ func (k Keeper) storeBTCDelegatorToFp(ctx context.Context, del sdk.AccAddress) p return prefix.NewStore(st, del.Bytes()) } -// storeFpCurrentRewards returns the KVStore of the FP current rewards -// prefix: FinalityProviderCurrentRewardsKey -// key: (finality provider cosmos address) -// value: FinalityProviderCurrentRewards -func (k Keeper) storeFpCurrentRewards(ctx context.Context) prefix.Store { - storeAdaptor := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - return prefix.NewStore(storeAdaptor, types.FinalityProviderCurrentRewardsKey) -} - // setBTCDelegatorToFP sets a new delegator to finality provider record. func (k Keeper) setBTCDelegatorToFP(ctx context.Context, del, fp sdk.AccAddress) { st := k.storeBTCDelegatorToFp(ctx, del) @@ -69,16 +60,10 @@ func (k Keeper) deleteBTCDelegatorToFP(ctx context.Context, del, fp sdk.AccAddre // GetFinalityProviderCurrentRewards returns the Finality Provider current rewards // based on the FP address key func (k Keeper) GetFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) (types.FinalityProviderCurrentRewards, error) { - key := fp.Bytes() - bz := k.storeFpCurrentRewards(ctx).Get(key) - if bz == nil { + value, err := k.FinalityProviderCurrentRewards.Get(ctx, fp.Bytes()) + if err != nil { return types.FinalityProviderCurrentRewards{}, types.ErrFPCurrentRewardsNotFound } - - var value types.FinalityProviderCurrentRewards - if err := k.cdc.Unmarshal(bz, &value); err != nil { - return types.FinalityProviderCurrentRewards{}, err - } return value, nil } @@ -125,14 +110,7 @@ func (k Keeper) setBTCDelegationRewardsTracker(ctx context.Context, fp, del sdk. // setFinalityProviderCurrentRewards sets a new structure in the store, it fails and returns an error if the rwd fails to marshal. func (k Keeper) setFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress, rwd types.FinalityProviderCurrentRewards) error { - key := fp.Bytes() - bz, err := rwd.Marshal() - if err != nil { - return err - } - - k.storeFpCurrentRewards(ctx).Set(key, bz) - return nil + return k.FinalityProviderCurrentRewards.Set(ctx, fp.Bytes(), rwd) } // deleteAllFromFinalityProviderRwd deletes all the data related to Finality Provider Rewards @@ -149,8 +127,9 @@ func (k Keeper) deleteAllFromFinalityProviderRwd(ctx context.Context, fp sdk.Acc // deleteFinalityProviderCurrentRewards deletes the current FP reward based on the key received func (k Keeper) deleteFinalityProviderCurrentRewards(ctx context.Context, fp sdk.AccAddress) { - key := fp.Bytes() - k.storeFpCurrentRewards(ctx).Delete(key) + if err := k.FinalityProviderCurrentRewards.Remove(ctx, fp.Bytes()); err != nil { + k.Logger(sdk.UnwrapSDKContext(ctx)).Error("error deleting FinalityProviderCurrentRewards", "error", err) + } } // GetFinalityProviderHistoricalRewards returns the FinalityProviderHistoricalRewards based on the key (fp, period) diff --git a/x/incentive/types/keys.go b/x/incentive/types/keys.go index 737af386e..aeb783b96 100644 --- a/x/incentive/types/keys.go +++ b/x/incentive/types/keys.go @@ -26,7 +26,7 @@ var ( DelegatorWithdrawAddrPrefix = []byte{0x03} // key for delegator withdraw address RewardGaugeKey = []byte{0x04} // key prefix for reward gauge for a given stakeholder in a given type RefundableMsgKeySetPrefix = collections.NewPrefix(5) // key prefix for refundable msg key set - FinalityProviderCurrentRewardsKey = []byte{0x06} // key prefix for storing the Current rewards of finality provider by addr + FinalityProviderCurrentRewardsKeyPrefix = collections.NewPrefix(6) // key prefix for storing the Current rewards of finality provider by addr FinalityProviderHistoricalRewardsKeyPrefix = collections.NewPrefix(7) // key prefix for storing the Historical rewards of finality provider by addr and period BTCDelegationRewardsTrackerKeyPrefix = collections.NewPrefix(8) // key prefix for BTC delegation rewards tracker info (del,fp) => BTCDelegationRewardsTracker BTCDelegatorToFPKey = []byte{0x9} // key prefix for storing the map reference from delegation to finality provider (del) => fp From 35374f7bc1172fdc83785806d4c91f821004c926 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Thu, 19 Dec 2024 22:57:41 -0300 Subject: [PATCH 130/132] chore: moved AddFinalityVoteUntilCurrentHeight for after checks --- test/e2e/btc_rewards_distribution_e2e_test.go | 2 +- test/e2e/configurer/chain/queries.go | 6 +++--- x/incentive/keeper/store.go | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/e2e/btc_rewards_distribution_e2e_test.go b/test/e2e/btc_rewards_distribution_e2e_test.go index d66388c9f..df4848a4e 100644 --- a/test/e2e/btc_rewards_distribution_e2e_test.go +++ b/test/e2e/btc_rewards_distribution_e2e_test.go @@ -281,7 +281,6 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { fmt.Sprintf("--from=%s", wFp2), ) - s.AddFinalityVoteUntilCurrentHeight() n2.WaitForNextBlock() // ensure vote is eventually cast @@ -294,6 +293,7 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() { s.Equal(s.finalityBlockHeightVoted, finalizedBlocks[0].Height) s.Equal(appHash.Bytes(), finalizedBlocks[0].AppHash) s.T().Logf("the block %d is finalized", s.finalityBlockHeightVoted) + s.AddFinalityVoteUntilCurrentHeight() } // Test5CheckRewardsFirstDelegations verifies the rewards independent of mint amounts diff --git a/test/e2e/configurer/chain/queries.go b/test/e2e/configurer/chain/queries.go index 9f7a7b6c7..c495e222c 100644 --- a/test/e2e/configurer/chain/queries.go +++ b/test/e2e/configurer/chain/queries.go @@ -442,7 +442,7 @@ func (n *NodeConfig) WaitUntilCurrentEpochIsSealedAndFinalized(startEpoch uint64 return false } return resp.Status == ct.Sealed - }, time.Minute*5, time.Millisecond*50) + }, time.Minute*5, time.Millisecond*200) n.FinalizeSealedEpochs(startEpoch, currentEpoch) // ensure the committed epoch is finalized @@ -452,7 +452,7 @@ func (n *NodeConfig) WaitUntilCurrentEpochIsSealedAndFinalized(startEpoch uint64 return false } return lastFinalizedEpoch >= currentEpoch - }, time.Minute, time.Millisecond*50) + }, time.Minute, time.Millisecond*200) return lastFinalizedEpoch } @@ -464,7 +464,7 @@ func (n *NodeConfig) WaitFinalityIsActivated() (activatedHeight uint64) { return false } return activatedHeight > 0 - }, time.Minute*4, time.Second*1) + }, time.Minute*4, time.Second) n.t.Logf("the activated height is %d", activatedHeight) return activatedHeight } diff --git a/x/incentive/keeper/store.go b/x/incentive/keeper/store.go index e93b1573a..53b148ac7 100644 --- a/x/incentive/keeper/store.go +++ b/x/incentive/keeper/store.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "github.com/babylonlabs-io/babylon/x/incentive/types" sdk "github.com/cosmos/cosmos-sdk/types" ) From 8f83257ed0130d45c0605edb684caae2d599817d Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Fri, 20 Dec 2024 06:26:24 -0300 Subject: [PATCH 131/132] chore: address PR comments --- proto/babylon/btcstaking/v1/btcstaking.proto | 2 +- x/btcstaking/types/btcstaking.pb.go | 2 +- x/finality/keeper/power_dist_change.go | 40 ++++++++++---------- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/proto/babylon/btcstaking/v1/btcstaking.proto b/proto/babylon/btcstaking/v1/btcstaking.proto index 50acad4da..93333670d 100644 --- a/proto/babylon/btcstaking/v1/btcstaking.proto +++ b/proto/babylon/btcstaking/v1/btcstaking.proto @@ -167,7 +167,7 @@ message BTCDelegatorDelegationIndex { // BTCDelegationStatus is the status of a delegation. // There are two possible valid state transition paths for a BTC delegation: -// - PENDING -> ACTIVE -> UNBONDED -> EXPIRED +// - PENDING -> VERIFIED -> ACTIVE -> UNBONDED -> EXPIRED // - PENDING -> VERIFIED -> ACTIVE -> UNBONDED/EXPIRED // and one invalid state transition path: // - PENDING -> VERIFIED -> UNBONDED i.e the staker unbonded before diff --git a/x/btcstaking/types/btcstaking.pb.go b/x/btcstaking/types/btcstaking.pb.go index bef35b3f6..e79ca336b 100644 --- a/x/btcstaking/types/btcstaking.pb.go +++ b/x/btcstaking/types/btcstaking.pb.go @@ -30,7 +30,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // BTCDelegationStatus is the status of a delegation. // There are two possible valid state transition paths for a BTC delegation: -// - PENDING -> ACTIVE -> UNBONDED -> EXPIRED +// - PENDING -> VERIFIED -> ACTIVE -> UNBONDED -> EXPIRED // - PENDING -> VERIFIED -> ACTIVE -> UNBONDED/EXPIRED // and one invalid state transition path: // - PENDING -> VERIFIED -> UNBONDED i.e the staker unbonded before diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index cfed42b5d..b5e488916 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -173,10 +173,10 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( events []*types.EventPowerDistUpdate, ) *ftypes.VotingPowerDistCache { // a map where key is finality provider's BTC PK hex and value is a list - // of BTC delegations that newly become active under this provider + // of BTC delegations satoshis amount that newly become active under this provider activedSatsByFpBtcPk := map[string][]uint64{} // a map where key is finality provider's BTC PK hex and value is a list - // of BTC delegations that were unbonded or expired without previously + // of BTC delegations satoshis that were unbonded or expired without previously // being unbonded unbondedSatsByFpBtcPk := map[string][]uint64{} // a map where key is slashed finality providers' BTC PK @@ -284,6 +284,18 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( } // process all new BTC delegations under this finality provider + if fpActiveBTCDels, ok := activedSatsByFpBtcPk[fpBTCPKHex]; ok { + // handle new BTC delegations for this finality provider + for _, activatedSats := range fpActiveBTCDels { + fp.AddBondedSats(activatedSats) + } + // remove the finality provider entry in activeBTCDels map, so that + // after the for loop the rest entries in activeBTCDels belongs to new + // finality providers with new BTC delegations + delete(activedSatsByFpBtcPk, fpBTCPKHex) + } + + // process all new unbonding BTC delegations under this finality provider if fpUnbondedBTCDels, ok := unbondedSatsByFpBtcPk[fpBTCPKHex]; ok { // handle unbonded delegations for this finality provider for _, unbodedSats := range fpUnbondedBTCDels { @@ -296,18 +308,6 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( delete(unbondedSatsByFpBtcPk, fpBTCPKHex) } - // process all new BTC delegations under this finality provider - if fpActiveBTCDels, ok := activedSatsByFpBtcPk[fpBTCPKHex]; ok { - // handle new BTC delegations for this finality provider - for _, activatedSats := range fpActiveBTCDels { - fp.AddBondedSats(activatedSats) - } - // remove the finality provider entry in activeBTCDels map, so that - // after the for loop the rest entries in activeBTCDels belongs to new - // finality providers with new BTC delegations - delete(activedSatsByFpBtcPk, fpBTCPKHex) - } - // add this finality provider to the new cache if it has voting power if fp.TotalBondedSat > 0 { newDc.AddFinalityProviderDistInfo(&fp) @@ -333,19 +333,17 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( fpDistInfo := ftypes.NewFinalityProviderDistInfo(newFP) // add each BTC delegation - fpActiveBTCDels := activedSatsByFpBtcPk[fpBTCPKHex] - for _, activatedSats := range fpActiveBTCDels { + fpActiveSats := activedSatsByFpBtcPk[fpBTCPKHex] + for _, activatedSats := range fpActiveSats { fpDistInfo.AddBondedSats(activatedSats) } // edge case where we might be processing an unbonded event // from a newly active finality provider in the same slice // of events received. - fpUnbondedBTCDels, ok := unbondedSatsByFpBtcPk[fpBTCPKHex] - if ok { - for _, unbodedSats := range fpUnbondedBTCDels { - fpDistInfo.RemoveBondedSats(unbodedSats) - } + fpUnbondedSats := unbondedSatsByFpBtcPk[fpBTCPKHex] + for _, unbodedSats := range fpUnbondedSats { + fpDistInfo.RemoveBondedSats(unbodedSats) } // add this finality provider to the new cache if it has voting power From 9bb8d5f0e0968f5302319a5cc7d522f6b327fda7 Mon Sep 17 00:00:00 2001 From: RafilxTenfen Date: Fri, 20 Dec 2024 06:27:29 -0300 Subject: [PATCH 132/132] chore: rename btc dels to sats --- x/finality/keeper/power_dist_change.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/x/finality/keeper/power_dist_change.go b/x/finality/keeper/power_dist_change.go index b5e488916..581d415a0 100644 --- a/x/finality/keeper/power_dist_change.go +++ b/x/finality/keeper/power_dist_change.go @@ -284,25 +284,25 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( } // process all new BTC delegations under this finality provider - if fpActiveBTCDels, ok := activedSatsByFpBtcPk[fpBTCPKHex]; ok { + if fpActiveSats, ok := activedSatsByFpBtcPk[fpBTCPKHex]; ok { // handle new BTC delegations for this finality provider - for _, activatedSats := range fpActiveBTCDels { + for _, activatedSats := range fpActiveSats { fp.AddBondedSats(activatedSats) } - // remove the finality provider entry in activeBTCDels map, so that - // after the for loop the rest entries in activeBTCDels belongs to new + // remove the finality provider entry in fpActiveSats map, so that + // after the for loop the rest entries in fpActiveSats belongs to new // finality providers with new BTC delegations delete(activedSatsByFpBtcPk, fpBTCPKHex) } // process all new unbonding BTC delegations under this finality provider - if fpUnbondedBTCDels, ok := unbondedSatsByFpBtcPk[fpBTCPKHex]; ok { + if fpUnbondedSats, ok := unbondedSatsByFpBtcPk[fpBTCPKHex]; ok { // handle unbonded delegations for this finality provider - for _, unbodedSats := range fpUnbondedBTCDels { + for _, unbodedSats := range fpUnbondedSats { fp.RemoveBondedSats(unbodedSats) } - // remove the finality provider entry in unbondedBTCDels map, so that - // after the for loop the rest entries in unbondedBTCDels belongs to new + // remove the finality provider entry in fpUnbondedSats map, so that + // after the for loop the rest entries in fpUnbondedSats belongs to new // finality providers that might have btc delegations entries // that activated and unbonded in the same slice of events delete(unbondedSatsByFpBtcPk, fpBTCPKHex)