Skip to content

Commit

Permalink
Use only quorum number of covenant signature when building the witness (
Browse files Browse the repository at this point in the history
#53) (#54)

* Use only quorum number of covenant signature when building the witness

* Add change log entry
  • Loading branch information
KonradStaniec authored Oct 14, 2024
1 parent dfe8eec commit 60c2692
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 15 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## Unreleased

### Bug fix

- [#53](https://github.com/babylonlabs-io/btc-staker/pull/53) Use only quorum of
signatures when building unbonding transaction witness

## v0.7.0

### Api breaking
Expand Down
19 changes: 15 additions & 4 deletions babylonclient/babyloncontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -842,14 +842,13 @@ func (bc *BabylonController) IsTxAlreadyPartOfDelegation(stakingTxHash *chainhas

// Test methods for e2e testing
// Different babylon sig methods to support e2e testing
func (bc *BabylonController) SubmitCovenantSig(
func (bc *BabylonController) CreateCovenantMessage(
covPubKey *bbntypes.BIP340PubKey,
stakingTxHash string,
slashStakingAdaptorSigs [][]byte,
unbondindgSig *bbntypes.BIP340Signature,
slashUnbondingAdaptorSigs [][]byte,

) (*pv.RelayerTxResponse, error) {
) *btcstypes.MsgAddCovenantSigs {
msg := &btcstypes.MsgAddCovenantSigs{
Signer: bc.getTxSigner(),
Pk: covPubKey,
Expand All @@ -859,7 +858,19 @@ func (bc *BabylonController) SubmitCovenantSig(
SlashingUnbondingTxSigs: slashUnbondingAdaptorSigs,
}

return bc.reliablySendMsgs([]sdk.Msg{msg})
return msg
}

func (bc *BabylonController) SubmitMultipleCovenantMessages(
covenantMsgs []*btcstypes.MsgAddCovenantSigs,
) (*pv.RelayerTxResponse, error) {
var msgs []sdk.Msg

for _, covenantMsg := range covenantMsgs {
msgs = append(msgs, covenantMsg)
}

return bc.reliablySendMsgs(msgs)
}

func (bc *BabylonController) QueryPendingBTCDelegations() ([]*btcstypes.BTCDelegationResponse, error) {
Expand Down
24 changes: 20 additions & 4 deletions itest/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,13 @@ func retrieveTransactionFromMempool(t *testing.T, client *rpcclient.Client, hash
var txes []*btcutil.Tx
for _, txHash := range hashes {
tx, err := client.GetRawTransaction(txHash)
require.NoError(t, err)

if err != nil {
// this is e2e helper method, so this error most probably some of the
// transactions are still not in the mempool
return []*btcutil.Tx{}
}

txes = append(txes, tx)
}
return txes
Expand Down Expand Up @@ -1026,7 +1032,10 @@ func (tm *TestManager) insertAllMinedBlocksToBabylon(t *testing.T) {
require.NoError(t, err)
}

func (tm *TestManager) insertCovenantSigForDelegation(t *testing.T, btcDel *btcstypes.BTCDelegationResponse) {
func (tm *TestManager) insertCovenantSigForDelegation(
t *testing.T,
btcDel *btcstypes.BTCDelegationResponse,
) {
fpBTCPKs, err := bbntypes.NewBTCPKsFromBIP340PKs(btcDel.FpBtcPkList)
require.NoError(t, err)

Expand Down Expand Up @@ -1101,16 +1110,23 @@ func (tm *TestManager) insertCovenantSigForDelegation(t *testing.T, btcDel *btcs
)
require.NoError(t, err)

var messages []*btcstypes.MsgAddCovenantSigs
for i := 0; i < len(tm.CovenantPrivKeys); i++ {
_, err = tm.BabylonClient.SubmitCovenantSig(
msg := tm.BabylonClient.CreateCovenantMessage(
bbntypes.NewBIP340PubKeyFromBTCPK(tm.CovenantPrivKeys[i].PubKey()),
stakingMsgTx.TxHash().String(),
covenantSlashingTxSigs[i].AdaptorSigs,
bbntypes.NewBIP340SignatureFromBTCSig(covUnbondingSigs[i]),
covenantUnbondingSlashingTxSigs[i].AdaptorSigs,
)
require.NoError(t, err)
messages = append(messages, msg)
}
// we insert are covenant signatures in on message, this way staker
// program must handle the case of all signatures being present in Babylon
// delegation
// it also speeds up the tests
_, err = tm.BabylonClient.SubmitMultipleCovenantMessages(messages)
require.NoError(t, err)
}

func TestStakingFailures(t *testing.T) {
Expand Down
10 changes: 9 additions & 1 deletion staker/stakerapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -1039,11 +1039,19 @@ func (app *StakerApp) sendUnbondingTxToBtcWithWitness(
return fmt.Errorf("failed to receive stakerUnbondingSig.Signature")
}

covenantSigantures := createWitnessSignaturesForPubKeys(
covenantSigantures, err := createWitnessSignaturesForPubKeys(
params.CovenantPks,
params.CovenantQuruomThreshold,
unbondingData.CovenantSignatures,
)

if err != nil {
app.logger.WithFields(logrus.Fields{
"stakingTxHash": stakingTxHash,
"err": err,
}).Fatalf("failed to create witness to send unbonding tx")
}

witness, err := unbondingSpendInfo.CreateUnbondingPathWitness(
covenantSigantures,
stakerUnbondingSig.Signature,
Expand Down
23 changes: 17 additions & 6 deletions staker/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,24 @@ func pubKeyToString(pubKey *btcec.PublicKey) string {

func createWitnessSignaturesForPubKeys(
covenantPubKeys []*btcec.PublicKey,
covenantQuorum uint32,
receivedSignaturePairs []stakerdb.PubKeySigPair,
) []*schnorr.Signature {
) ([]*schnorr.Signature, error) {

if len(receivedSignaturePairs) < int(covenantQuorum) {
return nil, fmt.Errorf("not enough signatures to create witness. Required: %d, received: %d", covenantQuorum, len(receivedSignaturePairs))
}

// create map of received signatures
receivedSignatures := make(map[string]*schnorr.Signature)
receivedSignaturesUpToQuorum := make(map[string]*schnorr.Signature)

for _, pair := range receivedSignaturePairs {
receivedSignatures[pubKeyToString(pair.PubKey)] = pair.Signature
// we are only interested in quorum number of signatures
if len(receivedSignaturesUpToQuorum) >= int(covenantQuorum) {
break
}

receivedSignaturesUpToQuorum[pubKeyToString(pair.PubKey)] = pair.Signature
}

sortedPubKeys := sortPubKeysForWitness(covenantPubKeys)
Expand All @@ -91,12 +102,12 @@ func createWitnessSignaturesForPubKeys(

for i, key := range sortedPubKeys {
k := key
if signature, found := receivedSignatures[pubKeyToString(k)]; found {
if signature, found := receivedSignaturesUpToQuorum[pubKeyToString(k)]; found {
signatures[i] = signature
}
}

return signatures
return signatures, nil
}

func slashingTxForStakingTx(
Expand Down Expand Up @@ -424,7 +435,7 @@ func buildUnbondingSpendInfo(
return nil, fmt.Errorf("cannot create witness for sending unbonding tx. Unbonding data does not contain unbonding transaction")
}

if len(unbondingData.CovenantSignatures) != int(params.CovenantQuruomThreshold) {
if len(unbondingData.CovenantSignatures) < int(params.CovenantQuruomThreshold) {
return nil, fmt.Errorf("cannot create witness for sending unbonding tx. Unbonding data does not contain all necessary signatures. Required: %d, received: %d", params.CovenantQuruomThreshold, len(unbondingData.CovenantSignatures))
}

Expand Down

0 comments on commit 60c2692

Please sign in to comment.