-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(e2e): e2e test for activating and unbonded in mempool #71
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
package e2etest | ||
|
||
import ( | ||
btcstakingtypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" | ||
"go.uber.org/zap" | ||
"testing" | ||
"time" | ||
|
@@ -157,7 +158,35 @@ func TestActivatingDelegation(t *testing.T) { | |
// set up a finality provider | ||
_, fpSK := tm.CreateFinalityProvider(t) | ||
// set up a BTC delegation | ||
stakingSlashingInfo, _, _ := tm.CreateBTCDelegationWithoutIncl(t, fpSK) | ||
stakingMsgTx, stakingSlashingInfo, _, _ := tm.CreateBTCDelegationWithoutIncl(t, fpSK) | ||
stakingMsgTxHash := stakingMsgTx.TxHash() | ||
|
||
// send staking tx to Bitcoin node's mempool | ||
_, err = tm.BTCClient.SendRawTransaction(stakingMsgTx, true) | ||
require.NoError(t, err) | ||
|
||
require.Eventually(t, func() bool { | ||
return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{&stakingMsgTxHash})) == 1 | ||
}, eventuallyWaitTimeOut, eventuallyPollTime) | ||
|
||
mBlock := tm.mineBlock(t) | ||
require.Equal(t, 2, len(mBlock.Transactions)) | ||
|
||
// wait until staking tx is on Bitcoin | ||
require.Eventually(t, func() bool { | ||
_, err := tm.BTCClient.GetRawTransaction(&stakingMsgTxHash) | ||
return err == nil | ||
}, eventuallyWaitTimeOut, eventuallyPollTime) | ||
|
||
// insert k empty blocks to Bitcoin | ||
btccParamsResp, err := tm.BabylonClient.BTCCheckpointParams() | ||
require.NoError(t, err) | ||
btccParams := btccParamsResp.Params | ||
for i := 0; i < int(btccParams.BtcConfirmationDepth); i++ { | ||
tm.mineBlock(t) | ||
} | ||
|
||
tm.CatchUpBTCLightClient(t) | ||
|
||
// created delegation lacks inclusion proof, once created it will be in | ||
// pending status, once convenant signatures are added it will be in verified status, | ||
|
@@ -170,3 +199,117 @@ func TestActivatingDelegation(t *testing.T) { | |
return resp.BtcDelegation.Active | ||
}, eventuallyWaitTimeOut, eventuallyPollTime) | ||
} | ||
|
||
// TestActivatingAndUnbondingDelegation tests that delegation will eventually become UNBONDED given that | ||
// both staking and unbonding tx are in the same block. | ||
// In this test, we include both staking tx and unbonding tx in the same block. | ||
// The delegation goes through "VERIFIED" → "ACTIVE" → "UNBONDED" status throughout this test. | ||
func TestActivatingAndUnbondingDelegation(t *testing.T) { | ||
//t.Parallel() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for some reason, there might be an unwanted dependancy between e2e test, making it sequential until, will investigate (related to btc frequent headers maybe) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "works on my machine" type of thing 😅 |
||
// segwit is activated at height 300. It's necessary for staking/slashing tx | ||
numMatureOutputs := uint32(300) | ||
|
||
tm := StartManager(t, numMatureOutputs, defaultEpochInterval) | ||
defer tm.Stop(t) | ||
// Insert all existing BTC headers to babylon node | ||
tm.CatchUpBTCLightClient(t) | ||
|
||
btcNotifier, err := btcclient.NewNodeBackend( | ||
btcclient.ToBitcoindConfig(tm.Config.BTC), | ||
&chaincfg.RegressionNetParams, | ||
&btcclient.EmptyHintCache{}, | ||
) | ||
require.NoError(t, err) | ||
|
||
err = btcNotifier.Start() | ||
require.NoError(t, err) | ||
|
||
commonCfg := config.DefaultCommonConfig() | ||
bstCfg := config.DefaultBTCStakingTrackerConfig() | ||
bstCfg.CheckDelegationsInterval = 1 * time.Second | ||
stakingTrackerMetrics := metrics.NewBTCStakingTrackerMetrics() | ||
|
||
bsTracker := bst.NewBTCStakingTracker( | ||
tm.BTCClient, | ||
btcNotifier, | ||
tm.BabylonClient, | ||
&bstCfg, | ||
&commonCfg, | ||
zap.NewNop(), | ||
stakingTrackerMetrics, | ||
) | ||
bsTracker.Start() | ||
defer bsTracker.Stop() | ||
|
||
// set up a finality provider | ||
_, fpSK := tm.CreateFinalityProvider(t) | ||
// set up a BTC delegation | ||
stakingMsgTx, stakingSlashingInfo, unbondingSlashingInfo, delSK := tm.CreateBTCDelegationWithoutIncl(t, fpSK) | ||
stakingMsgTxHash := stakingMsgTx.TxHash() | ||
|
||
// send staking tx to Bitcoin node's mempool | ||
_, err = tm.BTCClient.SendRawTransaction(stakingMsgTx, true) | ||
require.NoError(t, err) | ||
|
||
require.Eventually(t, func() bool { | ||
return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{&stakingMsgTxHash})) == 1 | ||
}, eventuallyWaitTimeOut, eventuallyPollTime) | ||
|
||
// Staker unbonds by directly sending tx to btc network. Watcher should detect it and report to babylon. | ||
unbondingPathSpendInfo, err := stakingSlashingInfo.StakingInfo.UnbondingPathSpendInfo() | ||
require.NoError(t, err) | ||
stakingOutIdx, err := outIdx(unbondingSlashingInfo.UnbondingTx, unbondingSlashingInfo.UnbondingInfo.UnbondingOutput) | ||
require.NoError(t, err) | ||
|
||
unbondingTxSchnorrSig, err := btcstaking.SignTxWithOneScriptSpendInputStrict( | ||
unbondingSlashingInfo.UnbondingTx, | ||
stakingSlashingInfo.StakingTx, | ||
stakingOutIdx, | ||
unbondingPathSpendInfo.GetPkScriptPath(), | ||
delSK, | ||
) | ||
require.NoError(t, err) | ||
|
||
resp, err := tm.BabylonClient.BTCDelegation(stakingSlashingInfo.StakingTx.TxHash().String()) | ||
require.NoError(t, err) | ||
|
||
covenantSigs := resp.BtcDelegation.UndelegationResponse.CovenantUnbondingSigList | ||
witness, err := unbondingPathSpendInfo.CreateUnbondingPathWitness( | ||
[]*schnorr.Signature{covenantSigs[0].Sig.MustToBTCSig()}, | ||
unbondingTxSchnorrSig, | ||
) | ||
require.NoError(t, err) | ||
unbondingSlashingInfo.UnbondingTx.TxIn[0].Witness = witness | ||
|
||
// Send unbonding tx to Bitcoin | ||
_, err = tm.BTCClient.SendRawTransaction(unbondingSlashingInfo.UnbondingTx, true) | ||
require.NoError(t, err) | ||
|
||
unbondingTxHash := unbondingSlashingInfo.UnbondingTx.TxHash() | ||
t.Logf("submitted unbonding tx with hash %s", unbondingTxHash.String()) | ||
require.Eventually(t, func() bool { | ||
return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{&unbondingTxHash})) == 1 | ||
}, eventuallyWaitTimeOut, eventuallyPollTime) | ||
|
||
mBlock := tm.mineBlock(t) | ||
// both staking and unbonding txs are in this block | ||
require.Equal(t, 3, len(mBlock.Transactions)) | ||
|
||
// insert k empty blocks to Bitcoin | ||
btccParamsResp, err := tm.BabylonClient.BTCCheckpointParams() | ||
require.NoError(t, err) | ||
btccParams := btccParamsResp.Params | ||
for i := 0; i < int(btccParams.BtcConfirmationDepth); i++ { | ||
tm.mineBlock(t) | ||
} | ||
|
||
tm.CatchUpBTCLightClient(t) | ||
|
||
// wait until delegation has become unbonded | ||
require.Eventually(t, func() bool { | ||
resp, err := tm.BabylonClient.BTCDelegation(stakingSlashingInfo.StakingTx.TxHash().String()) | ||
require.NoError(t, err) | ||
|
||
return resp.BtcDelegation.StatusDesc == btcstakingtypes.BTCDelegationStatus_UNBONDED.String() | ||
}, eventuallyWaitTimeOut, eventuallyPollTime) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the delegation might have changed from verified to active status, in order to track unbonding, we need the activation height, and data in the tracker might be stale, so let's check this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was a bit confusing the checks
exists && changed
or!exists
If the delegation didn't exists, we still push it as a new delegation to the
unbondingDelegationChan
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we want to track it, but we also want to push it to the channel if it exits and has changed (e.g went from verified -> activated)