Skip to content

Commit c063cb9

Browse files
authored
chore: removed check cov key must be signer of previous stk tx (#128)
* chore: removed check where the covenant key doesn't need to have signed the previous staking tx * chore: add #128 to cl * fix: unit test
1 parent 82191df commit c063cb9

File tree

3 files changed

+137
-12
lines changed

3 files changed

+137
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
4141

4242
* [#125](https://github.com/babylonlabs-io/covenant-emulator/pull/125) Update config defaults for gas adjustment and cov batch sigs.
4343
* [#127](https://github.com/babylonlabs-io/covenant-emulator/pull/127) Add Stake Expansion support
44+
* [#128](https://github.com/babylonlabs-io/covenant-emulator/pull/128) Removed check where the covenant needs to have signed the
45+
previous staking transaction to sign the stake expansion tx.
4446

4547
## v0.15.1
4648

covenant/covenant.go

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ func AcceptDelegationToSign(
612612
}
613613
// 3. For stake expansion, verify if the covenant is in the committee of the previous active delegation
614614
if del.IsStakeExpansion() {
615-
valid, err := validateStakeExpansion(paramCache, covenantSerializedPk, del, prevDel)
615+
valid, err := ValidateStakeExpansion(paramCache, covenantSerializedPk, del, prevDel)
616616
if err != nil {
617617
return false, err
618618
}
@@ -625,9 +625,9 @@ func AcceptDelegationToSign(
625625
return true, nil
626626
}
627627

628-
// validateStakeExpansion validates that a stake expansion delegation is properly configured
628+
// ValidateStakeExpansion validates that a stake expansion delegation is properly configured
629629
// and that the covenant was in the committee for the previous delegation.
630-
func validateStakeExpansion(
630+
func ValidateStakeExpansion(
631631
paramCache ParamsGetter,
632632
covenantSerializedPk []byte,
633633
del *types.Delegation,
@@ -649,8 +649,7 @@ func validateStakeExpansion(
649649
del.StakeExpansion.PreviousStakingTxHashHex, prevStakingTxHash)
650650
}
651651

652-
// Verifications on the previous delegation
653-
// 1. Verify that the current covenant was in the committee for the previous delegation
652+
// Verify that the current covenant was in the committee for the previous delegation
654653
isInCommittee, err := IsKeyInCommittee(paramCache, covenantSerializedPk, prevDel)
655654
if err != nil {
656655
return false, fmt.Errorf("unable to verify if covenant key is in committee: %w", err)
@@ -659,12 +658,6 @@ func validateStakeExpansion(
659658
return false, nil
660659
}
661660

662-
// 2. The previous delegation should already have a covenant signature
663-
if !CovenantAlreadySigned(covenantSerializedPk, prevDel) {
664-
return false, fmt.Errorf("covenant %s did not sign the previous delegation %s of a stake expansion",
665-
hex.EncodeToString(covenantSerializedPk), del.StakeExpansion.PreviousStakingTxHashHex)
666-
}
667-
668661
return true, nil
669662
}
670663

covenant/covenant_test.go

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,6 @@ func TestIsKeyInCommittee(t *testing.T) {
350350
ParamsVersion: pVersionWithCovenant,
351351
}
352352

353-
// simple mock with the parameter versions
354353
paramsGet := NewMockParam(map[uint32]*types.StakingParams{
355354
pVersionWithoutCovenant: paramsWithoutCovenant,
356355
pVersionWithCovenant: paramsWithCovenant,
@@ -411,3 +410,134 @@ func NewMockParamError(err error) *MockParamError {
411410
func (m *MockParamError) Get(version uint32) (*types.StakingParams, error) {
412411
return nil, m.err
413412
}
413+
414+
func TestValidateStakeExpansion(t *testing.T) {
415+
r := rand.New(rand.NewSource(time.Now().Unix()))
416+
417+
covenantConfig := covcfg.DefaultConfig()
418+
covenantConfig.BabylonConfig.KeyDirectory = t.TempDir()
419+
420+
covKeyPairInCommittee, err := keyring.CreateCovenantKey(
421+
covenantConfig.BabylonConfig.KeyDirectory,
422+
covenantConfig.BabylonConfig.ChainID,
423+
covenantConfig.BabylonConfig.Key,
424+
covenantConfig.BabylonConfig.KeyringBackend,
425+
passphrase,
426+
hdPath,
427+
)
428+
require.NoError(t, err)
429+
430+
covKeyInCommittee := schnorr.SerializePubKey(covKeyPairInCommittee.PublicKey)
431+
pubKeyFromSchnorr, err := schnorr.ParsePubKey(covKeyInCommittee)
432+
require.NoError(t, err)
433+
434+
badCovKey, err := keyring.CreateCovenantKey(
435+
covenantConfig.BabylonConfig.KeyDirectory,
436+
covenantConfig.BabylonConfig.ChainID,
437+
"other-covenant-key",
438+
covenantConfig.BabylonConfig.KeyringBackend,
439+
passphrase,
440+
hdPath,
441+
)
442+
require.NoError(t, err)
443+
covKeyNotInCommittee := schnorr.SerializePubKey(badCovKey.PublicKey)
444+
445+
pVersionWithoutCovenant := uint32(datagen.RandomInRange(r, 1, 10))
446+
pVersionWithCovenant := pVersionWithoutCovenant + 1
447+
448+
paramsWithoutCovenant := testutil.GenRandomParams(r, t)
449+
paramsWithCovenant := testutil.GenRandomParams(r, t)
450+
paramsWithCovenant.CovenantPks = append(paramsWithCovenant.CovenantPks, covKeyPairInCommittee.PublicKey)
451+
452+
paramsGet := NewMockParam(map[uint32]*types.StakingParams{
453+
pVersionWithoutCovenant: paramsWithoutCovenant,
454+
pVersionWithCovenant: paramsWithCovenant,
455+
})
456+
457+
stkTxHex := "02000000012c1ca601b81bf5bdd97081d1bf17241d4d688f51ccbe8be3d3f3174d0e4e4aa40100000000ffffffff0250c3000000000000225120d0d55103aa70a12162f733805c3a2f5ff8e857d5fc92381c3d6f22a791165ac115400f00000000002251206f5ec73002ee8b5b2bb942f26e169354821e6ec06f9b3a1d3cf355d6f276c5d800000000"
458+
stakingMsgTx, _, err := bbntypes.NewBTCTxFromHex(stkTxHex)
459+
require.NoError(t, err)
460+
461+
prevStakingTxHashHex := stakingMsgTx.TxHash().String()
462+
prevStk := types.Delegation{
463+
StakingTxHex: stkTxHex,
464+
ParamsVersion: pVersionWithCovenant,
465+
CovenantSigs: []*types.CovenantAdaptorSigInfo{},
466+
}
467+
stkExp := types.Delegation{
468+
StakingTxHex: testutil.GenRandomHexStr(r, 100),
469+
ParamsVersion: pVersionWithCovenant,
470+
CovenantSigs: []*types.CovenantAdaptorSigInfo{},
471+
StakeExpansion: &types.DelegationStakeExpansion{
472+
PreviousStakingTxHashHex: prevStakingTxHashHex,
473+
},
474+
}
475+
476+
t.Run("successful validation - covenant in previous committee and didn't sign", func(t *testing.T) {
477+
valid, err := covenant.ValidateStakeExpansion(paramsGet, covKeyInCommittee, &stkExp, &prevStk)
478+
require.NoError(t, err)
479+
require.True(t, valid, "should be valid when covenant was in previous committee, even if it didn't sign")
480+
})
481+
482+
t.Run("successful validation - covenant in previous committee and signed old del", func(t *testing.T) {
483+
prevDel := prevStk
484+
prevDel.CovenantSigs = append(prevDel.CovenantSigs, &types.CovenantAdaptorSigInfo{
485+
Pk: pubKeyFromSchnorr,
486+
})
487+
488+
valid, err := covenant.ValidateStakeExpansion(paramsGet, covKeyInCommittee, &stkExp, &prevDel)
489+
require.NoError(t, err)
490+
require.True(t, valid, "should be valid when covenant was in previous committee even if it did sign the previous")
491+
})
492+
493+
t.Run("fails when param cache returns error", func(t *testing.T) {
494+
cacheErr := fmt.Errorf("param cache connection error")
495+
errorParamCache := NewMockParamError(cacheErr)
496+
497+
valid, errParamCache := covenant.ValidateStakeExpansion(errorParamCache, covKeyInCommittee, &stkExp, &prevStk)
498+
require.False(t, valid)
499+
require.EqualError(t, errParamCache, fmt.Sprintf("unable to verify if covenant key is in committee: unable to get the param version: %d, reason: %s", prevStk.ParamsVersion, cacheErr.Error()))
500+
})
501+
502+
t.Run("fails when covenant never in previous committee", func(t *testing.T) {
503+
valid, err := covenant.ValidateStakeExpansion(paramsGet, covKeyNotInCommittee, &stkExp, &prevStk)
504+
require.NoError(t, err)
505+
require.False(t, valid, "should fail when covenant was never in previous committee")
506+
})
507+
508+
t.Run("fails when covenant not in previous committee", func(t *testing.T) {
509+
prevDelWithoutCov := prevStk
510+
prevDelWithoutCov.ParamsVersion = pVersionWithoutCovenant
511+
valid, err := covenant.ValidateStakeExpansion(paramsGet, covKeyInCommittee, &stkExp, &prevDelWithoutCov)
512+
require.NoError(t, err)
513+
require.False(t, valid, "should fail when covenant was not in previous committee")
514+
})
515+
516+
t.Run("fails when previous delegation is nil", func(t *testing.T) {
517+
valid, err := covenant.ValidateStakeExpansion(paramsGet, covKeyInCommittee, &stkExp, nil)
518+
require.False(t, valid)
519+
require.EqualError(t, err, fmt.Sprintf("previous delegation is nil for stake expansion delegation: %s", prevStakingTxHashHex))
520+
})
521+
522+
t.Run("fails when transaction hash mismatch", func(t *testing.T) {
523+
wrongHash := datagen.GenRandomHexStr(r, 10)
524+
mismatchedStkExp := stkExp
525+
mismatchedStkExp.StakeExpansion.PreviousStakingTxHashHex = wrongHash
526+
527+
valid, err := covenant.ValidateStakeExpansion(paramsGet, covKeyInCommittee, &mismatchedStkExp, &prevStk)
528+
require.False(t, valid)
529+
require.EqualError(t, err, fmt.Sprintf("previous delegation staking tx hash mismatch: expected %s, got %s", wrongHash, prevStakingTxHashHex))
530+
})
531+
532+
t.Run("fails when previous delegation has invalid staking tx", func(t *testing.T) {
533+
invalidPrevDel := &types.Delegation{
534+
StakingTxHex: "invalid-hex-string",
535+
ParamsVersion: pVersionWithCovenant,
536+
}
537+
538+
valid, err := covenant.ValidateStakeExpansion(paramsGet, covKeyInCommittee, &stkExp, invalidPrevDel)
539+
require.False(t, valid)
540+
require.EqualError(t, err, "failed to decode previous delegation staking tx: encoding/hex: invalid byte: U+0069 'i'")
541+
})
542+
543+
}

0 commit comments

Comments
 (0)