Skip to content

Commit

Permalink
tryfix: check rewards seccond time
Browse files Browse the repository at this point in the history
  • Loading branch information
RafilxTenfen committed Dec 18, 2024
1 parent beffe5e commit 3c97ab1
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 50 deletions.
196 changes: 152 additions & 44 deletions test/e2e/btc_rewards_distribution_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
stakingTimeBlocks = uint16(math.MaxUint16)
wDel1 = "del1"
wDel2 = "del2"
numPubRand = uint64(250)
)

type BtcRewardsDistribution struct {
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand All @@ -244,7 +255,7 @@ func (s *BtcRewardsDistribution) Test4CommitPublicRandomnessAndSealed() {
fp2CommitPubRandList.Sig,
)

n1.WaitUntilCurrentEpochIsSealedAndFinalized()
n1.WaitUntilCurrentEpochIsSealedAndFinalized(1)

// activated height is never returned
s.finalityBlockHeightVoted = n1.WaitFinalityIsActivated()
Expand All @@ -270,15 +281,15 @@ 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 {
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)
Expand All @@ -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)

Expand All @@ -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
Expand All @@ -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()
Expand All @@ -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
Expand All @@ -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++
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/btc_staking_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/configurer/chain/commands_btcstaking.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
15 changes: 14 additions & 1 deletion test/e2e/configurer/chain/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions test/e2e/configurer/chain/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -422,17 +422,17 @@ 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 {
return false
}
return lastFinalizedEpoch >= currentEpoch
}, time.Minute, time.Millisecond*50)
return lastFinalizedEpoch
}

func (n *NodeConfig) WaitFinalityIsActivated() (activatedHeight uint64) {
Expand Down
Loading

0 comments on commit 3c97ab1

Please sign in to comment.