diff --git a/dot/types/babe.go b/dot/types/babe.go index 41403aab8d..b707c6b589 100644 --- a/dot/types/babe.go +++ b/dot/types/babe.go @@ -94,7 +94,7 @@ func (d *EpochDataRaw) ToEpochData() (*EpochData, error) { type ConfigData struct { C1 uint64 C2 uint64 - SecondarySlots byte // TODO: this is unused, will need to update BABE verifier to use this (#1863) + SecondarySlots byte } // GetSlotFromHeader returns the BABE slot from the given header diff --git a/lib/babe/verify.go b/lib/babe/verify.go index e60b5cf5eb..a7c4b759d8 100644 --- a/lib/babe/verify.go +++ b/lib/babe/verify.go @@ -31,9 +31,10 @@ import ( // verifierInfo contains the information needed to verify blocks // it remains the same for an epoch type verifierInfo struct { - authorities []types.Authority - randomness Randomness - threshold *common.Uint128 + authorities []types.Authority + randomness Randomness + threshold *common.Uint128 + secondarySlots bool } // onDisabledInfo contains information about an authority that's been disabled at a certain @@ -224,9 +225,10 @@ func (v *VerificationManager) getVerifierInfo(epoch uint64) (*verifierInfo, erro } return &verifierInfo{ - authorities: epochData.Authorities, - randomness: epochData.Randomness, - threshold: threshold, + authorities: epochData.Authorities, + randomness: epochData.Randomness, + threshold: threshold, + secondarySlots: configData.SecondarySlots > 0, }, nil } @@ -247,11 +249,12 @@ func (v *VerificationManager) getConfigData(epoch uint64) (*types.ConfigData, er // verifier is a BABE verifier for a specific authority set, randomness, and threshold type verifier struct { - blockState BlockState - epoch uint64 - authorities []types.Authority - randomness Randomness - threshold *common.Uint128 + blockState BlockState + epoch uint64 + authorities []types.Authority + randomness Randomness + threshold *common.Uint128 + secondarySlots bool } // newVerifier returns a Verifier for the epoch described by the given descriptor @@ -261,11 +264,12 @@ func newVerifier(blockState BlockState, epoch uint64, info *verifierInfo) (*veri } return &verifier{ - blockState: blockState, - epoch: epoch, - authorities: info.authorities, - randomness: info.randomness, - threshold: info.threshold, + blockState: blockState, + epoch: epoch, + authorities: info.authorities, + randomness: info.randomness, + threshold: info.threshold, + secondarySlots: info.secondarySlots, }, nil } @@ -409,15 +413,28 @@ func (b *verifier) verifyPreRuntimeDigest(digest *types.PreRuntimeDigest) (scale case types.BabePrimaryPreDigest: ok, err = b.verifyPrimarySlotWinner(d.AuthorityIndex, d.SlotNumber, d.VRFOutput, d.VRFProof) case types.BabeSecondaryVRFPreDigest: + if !b.secondarySlots { + ok = false + break + } pub := b.authorities[d.AuthorityIndex].Key - var pk *sr25519.PublicKey - pk, err = sr25519.NewPublicKey(pub.Encode()) + + pk, err := sr25519.NewPublicKey(pub.Encode()) if err != nil { return nil, err } ok, err = verifySecondarySlotVRF(&d, pk, b.epoch, len(b.authorities), b.randomness) + if err != nil { + return nil, err + } + case types.BabeSecondaryPlainPreDigest: + if !b.secondarySlots { + ok = false + break + } + ok = true err = verifySecondarySlotPlain(d.AuthorityIndex, d.SlotNumber, len(b.authorities), b.randomness) } diff --git a/lib/babe/verify_test.go b/lib/babe/verify_test.go index 83e065c348..3e1e49a167 100644 --- a/lib/babe/verify_test.go +++ b/lib/babe/verify_test.go @@ -19,18 +19,19 @@ package babe import ( "errors" "io/ioutil" + "math/big" "os" "testing" "time" - "github.com/ChainSafe/gossamer/lib/genesis" - "github.com/stretchr/testify/require" - "github.com/ChainSafe/gossamer/dot/state" "github.com/ChainSafe/gossamer/dot/types" + "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/crypto/sr25519" - + "github.com/ChainSafe/gossamer/lib/genesis" + "github.com/ChainSafe/gossamer/pkg/scale" log "github.com/ChainSafe/log15" + "github.com/stretchr/testify/require" ) func newTestVerificationManager(t *testing.T, genCfg *types.BabeConfiguration) *VerificationManager { @@ -162,6 +163,66 @@ func TestVerificationManager_VerifyBlock_Ok(t *testing.T) { require.NoError(t, err) } +func TestVerificationManager_VerifyBlock_Secondary(t *testing.T) { + babeService := createTestService(t, nil) + rt, err := babeService.blockState.GetRuntime(nil) + require.NoError(t, err) + + cfg, err := rt.BabeConfiguration() + require.NoError(t, err) + + cfg.GenesisAuthorities = types.AuthoritiesToRaw(babeService.epochData.authorities) + cfg.C1 = 1 + cfg.C2 = 1 + cfg.SecondarySlots = 0 + + vm := newTestVerificationManager(t, cfg) + + kp, err := sr25519.GenerateKeypair() + require.NoError(t, err) + + dig := createSecondaryVRFPreDigest(t, kp, 0, uint64(0), uint64(0), Randomness{}) + + bd := types.NewBabeDigest() + err = bd.Set(dig) + require.NoError(t, err) + + bdEnc, err := scale.Marshal(bd) + require.NoError(t, err) + + // create pre-digest + preDigest := &types.PreRuntimeDigest{ + ConsensusEngineID: types.BabeEngineID, + Data: bdEnc, + } + + // create new block header + number := big.NewInt(1) + digest := types.NewDigest() + err = digest.Add(*preDigest) + require.NoError(t, err) + + // create seal and add to digest + seal := &types.SealDigest{ + ConsensusEngineID: types.BabeEngineID, + Data: []byte{0}, + } + require.NoError(t, err) + + err = digest.Add(*seal) + require.NoError(t, err) + + header, err := types.NewHeader(common.Hash{}, common.Hash{}, common.Hash{}, number, digest) + require.NoError(t, err) + + block := types.Block{ + Header: *header, + Body: nil, + } + err = vm.VerifyBlock(&block.Header) + require.EqualError(t, err, "failed to verify pre-runtime digest: could not verify slot claim VRF proof") +} + func TestVerificationManager_VerifyBlock_MultipleEpochs(t *testing.T) { babeService := createTestService(t, nil) rt, err := babeService.blockState.GetRuntime(nil)