Skip to content

Commit

Permalink
sew add inclusion proof and tx for undelegate
Browse files Browse the repository at this point in the history
  • Loading branch information
Lazar955 committed Oct 23, 2024
1 parent 8835d63 commit 8775b06
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 16 deletions.
24 changes: 19 additions & 5 deletions btcstaking-tracker/btcslasher/bootstrapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package btcslasher

import (
"fmt"
"github.com/babylonlabs-io/babylon/types"

ftypes "github.com/babylonlabs-io/babylon/x/finality/types"
"github.com/cosmos/cosmos-sdk/types/query"
Expand All @@ -22,16 +23,29 @@ func (bs *BTCSlasher) Bootstrap(startHeight uint64) error {

// handle all evidences since the given start height, i.e., for each evidence,
// extract its SK and try to slash all BTC delegations under it
err := bs.handleAllEvidences(startHeight, func(evidences []*ftypes.Evidence) error {
err := bs.handleAllEvidences(startHeight, func(evidences []*ftypes.EvidenceResponse) error {
var accumulatedErrs error // we use this variable to accumulate errors

for _, evidence := range evidences {
fpBTCPK := evidence.FpBtcPk
fpBTCPKHex := fpBTCPK.MarshalHex()
fpBTCPKHex := evidence.FpBtcPkHex
bs.logger.Infof("found evidence for finality provider %s at height %d after start height %d", fpBTCPKHex, evidence.BlockHeight, startHeight)

btcPK, err := types.NewBIP340PubKeyFromHex(fpBTCPKHex)
if err != nil {
return fmt.Errorf("err parsing fp btc %w", err)
}

e := ftypes.Evidence{
FpBtcPk: btcPK,
BlockHeight: evidence.BlockHeight,
PubRand: evidence.PubRand,
CanonicalAppHash: evidence.CanonicalAppHash,
ForkAppHash: evidence.ForkAppHash,
CanonicalFinalitySig: evidence.CanonicalFinalitySig,
ForkFinalitySig: evidence.ForkFinalitySig,
}
// extract the SK of the slashed finality provider
fpBTCSK, err := evidence.ExtractBTCSK()
fpBTCSK, err := e.ExtractBTCSK()
if err != nil {
bs.logger.Errorf("failed to extract BTC SK of the slashed finality provider %s: %v", fpBTCPKHex, err)
accumulatedErrs = multierror.Append(accumulatedErrs, err)
Expand All @@ -57,7 +71,7 @@ func (bs *BTCSlasher) Bootstrap(startHeight uint64) error {
return nil
}

func (bs *BTCSlasher) handleAllEvidences(startHeight uint64, handleFunc func(evidences []*ftypes.Evidence) error) error {
func (bs *BTCSlasher) handleAllEvidences(startHeight uint64, handleFunc func(evidences []*ftypes.EvidenceResponse) error) error {
pagination := query.PageRequest{Limit: defaultPaginationLimit}
for {
resp, err := bs.BBNQuerier.ListEvidences(startHeight, &pagination)
Expand Down
2 changes: 1 addition & 1 deletion btcstaking-tracker/btcslasher/slasher_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ func (bs *BTCSlasher) getAllActiveAndUnbondedBTCDelegations(
}
if strings.EqualFold(del.StatusDesc, bstypes.BTCDelegationStatus_UNBONDED.String()) &&
len(del.UndelegationResponse.CovenantSlashingSigs) >= int(bsParams.CovenantQuorum) &&
len(del.UndelegationResponse.DelegatorUnbondingSigHex) > 0 {
len(del.UndelegationResponse.DelegatorUnbondingInfoResponse.SpendStakeTxHex) > 0 {
// NOTE: Babylon considers a BTC delegation to be unbonded once it
// receives staker signature for unbonding transaction, no matter
// whether the unbonding tx's timelock has expired. In monitor's view we need to try to slash every
Expand Down
10 changes: 5 additions & 5 deletions btcstaking-tracker/stakingeventwatcher/mock_babylon_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 45 additions & 2 deletions btcstaking-tracker/stakingeventwatcher/stakingeventwatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,14 @@ func (sew *StakingEventWatcher) watchForSpend(spendEvent *notifier.SpendEvent, t
sew.metrics.DetectedUnbondingTransactionsCounter.Inc()
// We found valid unbonding tx. We need to try to report it to babylon.
// We stop reporting if delegation is no longer active or we succeed.
proof, err := sew.waitForStakeSpendInclusionProof(quitCtx, spendingTx)
if err != nil {
// todo(lazar): log and report a metric, push to removalChan
sew.logger.Errorf("unbonding tx %s for staking tx %s proof not built", spendingTxHash, delegationId)
return
}
sew.logger.Debugf("found unbonding tx %s for staking tx %s", spendingTxHash, delegationId)
sew.reportUnbondingToBabylon(quitCtx, delegationId, spendingTx, nil)
sew.reportUnbondingToBabylon(quitCtx, delegationId, spendingTx, proof)
sew.logger.Debugf("unbonding tx %s for staking tx %s reported to babylon", spendingTxHash, delegationId)
}

Expand All @@ -457,7 +463,10 @@ func (sew *StakingEventWatcher) watchForSpend(spendEvent *notifier.SpendEvent, t

func (sew *StakingEventWatcher) buildSpendingTxProof(spendingTx *wire.MsgTx) (*btcstakingtypes.InclusionProof, error) {
txHash := spendingTx.TxHash()
details, status, err := sew.btcClient.TxDetails(&txHash, spendingTx.TxOut[0].PkScript) // todo(lazar):find out which index
if len(spendingTx.TxOut) == 0 {
return nil, fmt.Errorf("stake spending tx has no outputs")
}
details, status, err := sew.btcClient.TxDetails(&txHash, spendingTx.TxOut[0].PkScript)
if err != nil {
return nil, err
}
Expand All @@ -477,6 +486,40 @@ func (sew *StakingEventWatcher) buildSpendingTxProof(spendingTx *wire.MsgTx) (*b
return btcstakingtypes.NewInclusionProofFromSpvProof(proof), nil
}

// waitForStakeSpendInclusionProof polls btc until stake spend tx has inclusion proof built
func (sew *StakingEventWatcher) waitForStakeSpendInclusionProof(
ctx context.Context,
spendingTx *wire.MsgTx,
) (*btcstakingtypes.InclusionProof, error) {
var (
proof *btcstakingtypes.InclusionProof
err error
)
_ = retry.Do(func() error {
proof, err = sew.buildSpendingTxProof(spendingTx)
if err != nil {
return err
}

if proof == nil {
return fmt.Errorf("proof not yet built")
}

return nil
},
retry.Context(ctx),
retryForever,
fixedDelyTypeWithJitter,
retry.MaxDelay(sew.cfg.CheckDelegationActiveInterval),
retry.MaxJitter(sew.cfg.RetryJitter),
retry.OnRetry(func(n uint, err error) {
sew.logger.Debugf("retrying checking if stake spending tx is in chain %s. Attempt: %d. Err: %v", spendingTx.TxHash(), n, err)
}),
)

return proof, nil
}

func (sew *StakingEventWatcher) handleUnbondedDelegations() {
defer sew.wg.Done()
for {
Expand Down
1 change: 1 addition & 0 deletions e2etest/container/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (
func NewImageConfig(t *testing.T) ImageConfig {
babylondVersion, err := testutil.GetBabylonVersion()
require.NoError(t, err)
babylondVersion = "6a0ccacc41435a249316a77fe6e1e06aeb654d13" // todo(lazar): remove this when we have a tag

return ImageConfig{
BitcoindRepository: dockerBitcoindRepository,
Expand Down
11 changes: 8 additions & 3 deletions e2etest/test_manager_btcstaking.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,10 +491,15 @@ func (tm *TestManager) Undelegate(
)
require.NoError(t, err)

var unbondingTxBuf bytes.Buffer
err = unbondingSlashingInfo.UnbondingTx.Serialize(&unbondingTxBuf)
require.NoError(t, err)

msgUndel := &bstypes.MsgBTCUndelegate{
Signer: signerAddr,
StakingTxHash: stakingSlashingInfo.StakingTx.TxHash().String(),
UnbondingTxSig: bbn.NewBIP340SignatureFromBTCSig(unbondingTxSchnorrSig),
Signer: signerAddr,
StakingTxHash: stakingSlashingInfo.StakingTx.TxHash().String(),
StakeSpendingTx: unbondingTxBuf.Bytes(),
StakeSpendingTxInclusionProof: nil,
}
_, err = tm.BabylonClient.ReliablySendMsg(context.Background(), msgUndel, nil, nil)
require.NoError(t, err)
Expand Down
2 changes: 2 additions & 0 deletions e2etest/unbondingwatcher_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ func TestUnbondingWatcher(t *testing.T) {
minedBlock := tm.mineBlock(t)
require.Equal(t, 2, len(minedBlock.Transactions))

tm.CatchUpBTCLightClient(t)

require.Eventually(t, func() bool {
resp, err := tm.BabylonClient.BTCDelegation(stakingSlashingInfo.StakingTx.TxHash().String())
require.NoError(t, err)
Expand Down

0 comments on commit 8775b06

Please sign in to comment.