Skip to content

Commit

Permalink
andomnes commit replay test (#344)
Browse files Browse the repository at this point in the history
- Add fuzzing test case for jailing being deterministc
  • Loading branch information
KonradStaniec authored Dec 16, 2024
1 parent a56b247 commit 3cd871c
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 6 deletions.
2 changes: 1 addition & 1 deletion test/replay/btcstaking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func FuzzCreatingAndActivatingDelegations(f *testing.F) {
stakingParams,
)
allDelegationInfos = append(allDelegationInfos, delInfos...)
msgs := DelegationInfosToCreateBTCDelegationMsgs(delInfos)
msgs := ToCreateBTCDelegationMsgs(delInfos)
driver.SendTxWithMsgsFromDriverAccount(t, msgs...)
}

Expand Down
57 changes: 56 additions & 1 deletion test/replay/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
btckckpttypes "github.com/babylonlabs-io/babylon/x/btccheckpoint/types"
ckpttypes "github.com/babylonlabs-io/babylon/x/checkpointing/types"
et "github.com/babylonlabs-io/babylon/x/epoching/types"
ftypes "github.com/babylonlabs-io/babylon/x/finality/types"

"cosmossdk.io/log"
"cosmossdk.io/math"
Expand Down Expand Up @@ -680,6 +681,42 @@ func (d *BabylonAppDriver) GetBTCCkptParams(t *testing.T) btckckpttypes.Params {
return d.App.BtcCheckpointKeeper.GetParams(d.GetContextForLastFinalizedBlock())
}

func (d *BabylonAppDriver) ProgressTillFirstBlockTheNextEpoch(t *testing.T) {
currnetEpochNunber := d.GetEpoch().EpochNumber
nextEpochNumber := currnetEpochNunber + 1

for currnetEpochNunber < nextEpochNumber {
d.GenerateNewBlock(t)
currnetEpochNunber = d.GetEpoch().EpochNumber
}
}

func (d *BabylonAppDriver) GetActiveFpsAtHeight(t *testing.T, height uint64) []*ftypes.ActiveFinalityProvidersAtHeightResponse {
res, err := d.App.FinalityKeeper.ActiveFinalityProvidersAtHeight(
d.GetContextForLastFinalizedBlock(),
&ftypes.QueryActiveFinalityProvidersAtHeightRequest{
Height: height,
Pagination: &query.PageRequest{},
},
)
require.NoError(t, err)
return res.FinalityProviders
}

func (d *BabylonAppDriver) GetActiveFpsAtCurrentHeight(t *testing.T) []*ftypes.ActiveFinalityProvidersAtHeightResponse {
return d.GetActiveFpsAtHeight(t, d.GetLastFinalizedBlock().Height)
}

func (d *BabylonAppDriver) WaitTillAllFpsJailed(t *testing.T) {
for {
activeFps := d.GetActiveFpsAtCurrentHeight(t)
if len(activeFps) == 0 {
break
}
d.GenerateNewBlock(t)
}
}

// SendTxWithMsgsFromDriverAccount sends tx with msgs from driver account and asserts that
// SendTxWithMsgsFromDriverAccount sends tx with msgs from driver account and asserts that
// execution was successful. It assumes that there will only be one tx in the block.
Expand Down Expand Up @@ -838,6 +875,14 @@ func GenerateNFinalityProviders(
return infos
}

func FpInfosToMsgs(fpInfos []*FinalityProviderInfo) []sdk.Msg {
msgs := []sdk.Msg{}
for _, fpInfo := range fpInfos {
msgs = append(msgs, fpInfo.MsgCreateFinalityProvider)
}
return msgs
}

func GenerateNBTCDelegationsForFinalityProvider(
r *rand.Rand,
t *testing.T,
Expand Down Expand Up @@ -868,7 +913,7 @@ func GenerateNBTCDelegationsForFinalityProvider(
return delInfos
}

func DelegationInfosToCreateBTCDelegationMsgs(
func ToCreateBTCDelegationMsgs(
delInfos []*datagen.CreateDelegationInfo,
) []sdk.Msg {
msgs := []sdk.Msg{}
Expand All @@ -878,6 +923,16 @@ func DelegationInfosToCreateBTCDelegationMsgs(
return msgs
}

func ToCovenantSignaturesMsgs(
delInfos []*datagen.CreateDelegationInfo,
) []sdk.Msg {
msgs := []sdk.Msg{}
for _, delInfo := range delInfos {
msgs = append(msgs, MsgsToSdkMsg(delInfo.MsgAddCovenantSigs)...)
}
return msgs
}

func DelegationInfosToBTCTx(
delInfos []*datagen.CreateDelegationInfo,
) []*wire.MsgTx {
Expand Down
135 changes: 135 additions & 0 deletions test/replay/finality_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package replay

import (
"math/rand"
"testing"

"github.com/babylonlabs-io/babylon/testutil/datagen"
bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"
ftypes "github.com/babylonlabs-io/babylon/x/finality/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)

func FuzzJailing(f *testing.F) {
datagen.AddRandomSeedsToFuzzer(f, 5)

f.Fuzz(func(t *testing.T, seed int64) {
t.Parallel()
r := rand.New(rand.NewSource(seed))
numFinalityProviders := uint32(datagen.RandomInRange(r, 5, 7))
numDelPerFp := uint32(2)
driverTempDir := t.TempDir()
replayerTempDir := t.TempDir()
driver := NewBabylonAppDriver(t, driverTempDir, replayerTempDir)

driver.GenerateNewBlock(t)

stakingParams := driver.GetBTCStakingParams(t)

fpInfos := GenerateNFinalityProviders(
r,
t,
numFinalityProviders,
driver.GetDriverAccountAddress(),
)
registerMsgs := FpInfosToMsgs(fpInfos)
driver.SendTxWithMsgsFromDriverAccount(t, registerMsgs...)

var msgList []*ftypes.MsgCommitPubRandList
for _, fpInfo := range fpInfos {
_, msg, err := datagen.GenRandomMsgCommitPubRandList(r, fpInfo.BTCPrivateKey, 1, 1000)
require.NoError(t, err)
msg.Signer = driver.GetDriverAccountAddress().String()
msgList = append(msgList, msg)
}
// send all commit randomness messages in one block
driver.SendTxWithMsgsFromDriverAccount(t, MsgsToSdkMsg(msgList)...)
currnetEpochNunber := driver.GetEpoch().EpochNumber
driver.ProgressTillFirstBlockTheNextEpoch(t)

driver.FinializeCkptForEpoch(r, t, currnetEpochNunber)

// at this point randomness is finalized.
// - send delegations
// - send covenant signatures
// - send delegation inclusion proofs
var allDelegationInfos []*datagen.CreateDelegationInfo

for _, fpInfo := range fpInfos {
delInfos := GenerateNBTCDelegationsForFinalityProvider(
r,
t,
numDelPerFp,
driver.GetDriverAccountAddress(),
fpInfo,
stakingParams,
)
allDelegationInfos = append(allDelegationInfos, delInfos...)
}

createDelegationMsgs := ToCreateBTCDelegationMsgs(allDelegationInfos)
covenantSignaturesMsgs := ToCovenantSignaturesMsgs(allDelegationInfos)
driver.SendTxWithMsgsFromDriverAccount(t, createDelegationMsgs...)
driver.SendTxWithMsgsFromDriverAccount(t, covenantSignaturesMsgs...)

// all delegations are verified after activation finality provider should
// have voting power
stakingTransactions := DelegationInfosToBTCTx(allDelegationInfos)
blockWithProofs := driver.GenBlockWithTransactions(
r,
t,
stakingTransactions,
)
// make staking txs k-deep
driver.ExtendBTCLcWithNEmptyBlocks(r, t, 10)

activationMsgs := BlockWithProofsToActivationMessages(blockWithProofs, driver.GetDriverAccountAddress())

activeFps := driver.GetActiveFpsAtCurrentHeight(t)
require.Equal(t, 0, len(activeFps))

driver.SendTxWithMsgsFromDriverAccount(t, activationMsgs...)

// on the last block all power events were queued for execution
// after this block execution they should be processed and our fps should
// have voting power
driver.GenerateNewBlock(t)
activeFps = driver.GetActiveFpsAtCurrentHeight(t)
require.Equal(t, numFinalityProviders, uint32(len(activeFps)))

// we do not have voting in this test, so wait until all fps are jailed
driver.WaitTillAllFpsJailed(t)
driver.GenerateNewBlock(t)
activeFps = driver.GetActiveFpsAtCurrentHeight(t)
require.Equal(t, 0, len(activeFps))

// Replay all the blocks from driver and check appHash
replayer := NewBlockReplayer(t, replayerTempDir)
replayer.ReplayBlocks(t, driver.FinalizedBlocks)
// after replay we should have the same apphash
require.Equal(t, driver.LastState.LastBlockHeight, replayer.LastState.LastBlockHeight)
require.Equal(t, driver.LastState.AppHash, replayer.LastState.AppHash)
})
}

func BlockWithProofsToActivationMessages(
blockWithProofs *datagen.BlockWithProofs,
senderAddr sdk.AccAddress,
) []sdk.Msg {
msgs := []sdk.Msg{}

for i, tx := range blockWithProofs.Transactions {
// no coinbase tx
if i == 0 {
continue
}

msgs = append(msgs, &bstypes.MsgAddBTCDelegationInclusionProof{
Signer: senderAddr.String(),
StakingTxHash: tx.TxHash().String(),
StakingTxInclusionProof: bstypes.NewInclusionProofFromSpvProof(blockWithProofs.Proofs[i]),
})
}
return msgs
}
10 changes: 6 additions & 4 deletions testutil/datagen/btc_blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ func GenRandomBtcdBlock(r *rand.Rand, numBabylonTxs int, prevHash *chainhash.Has

// BTC block with proofs of each tx. Index of txs in the block is the same as the index of proofs.
type BlockWithProofs struct {
Block *wire.MsgBlock
Proofs []*btcctypes.BTCSpvProof
Block *wire.MsgBlock
Proofs []*btcctypes.BTCSpvProof
Transactions []*wire.MsgTx
}

func GenRandomBtcdBlockWithTransactions(
Expand Down Expand Up @@ -118,8 +119,9 @@ func GenRandomBtcdBlockWithTransactions(
Transactions: msgTxs,
}
return &BlockWithProofs{
Block: block,
Proofs: proofs,
Block: block,
Proofs: proofs,
Transactions: msgTxs,
}
}

Expand Down

0 comments on commit 3cd871c

Please sign in to comment.