From 34f26054e454e6011b69e58a14ab4a7629e53045 Mon Sep 17 00:00:00 2001 From: Kishan Sagathiya Date: Fri, 25 Feb 2022 17:57:23 +0530 Subject: [PATCH] feat(lib/babe): implement secondary vrf slot block production (#2307) * feat(lib/babe): implement secondary vrf slot - Also merge slot claim logic --- dot/core/messages_integration_test.go | 2 +- dot/core/service_integration_test.go | 2 +- dot/rpc/modules/chain_integration_test.go | 12 ++-- .../modules/childstate_integration_test.go | 2 +- dot/rpc/modules/state_integration_test.go | 2 +- dot/rpc/modules/system_integration_test.go | 2 +- dot/state/block_finalisation_test.go | 6 +- dot/state/block_test.go | 4 +- dot/state/service_test.go | 4 +- dot/state/test_helpers.go | 6 +- dot/sync/chain_processor_test.go | 2 +- dot/sync/message_test.go | 2 +- dot/sync/test_helpers.go | 2 +- dot/types/babe_digest.go | 45 +++++------- lib/babe/build_integration_test.go | 10 +-- lib/babe/crypto.go | 39 +++++++++-- lib/babe/epoch.go | 70 ++++++++++++++----- lib/babe/epoch_handler.go | 43 ++---------- lib/babe/types.go | 2 +- lib/babe/verify_integration_test.go | 2 +- lib/babe/verify_test.go | 20 +++--- lib/grandpa/grandpa_test.go | 4 +- lib/grandpa/message_handler_test.go | 8 +-- lib/grandpa/message_test.go | 2 +- lib/grandpa/message_tracker_test.go | 4 +- lib/grandpa/network_test.go | 2 +- 26 files changed, 158 insertions(+), 141 deletions(-) diff --git a/dot/core/messages_integration_test.go b/dot/core/messages_integration_test.go index 5fca745e56..82f9b77b19 100644 --- a/dot/core/messages_integration_test.go +++ b/dot/core/messages_integration_test.go @@ -82,7 +82,7 @@ func TestService_HandleBlockProduced(t *testing.T) { // simulate block sent from BABE session digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/dot/core/service_integration_test.go b/dot/core/service_integration_test.go index 7ecd5be0a2..01d2104a65 100644 --- a/dot/core/service_integration_test.go +++ b/dot/core/service_integration_test.go @@ -75,7 +75,7 @@ func TestAnnounceBlock(t *testing.T) { // simulate block sent from BABE session digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/dot/rpc/modules/chain_integration_test.go b/dot/rpc/modules/chain_integration_test.go index bc11a6a267..dc8ffaef8f 100644 --- a/dot/rpc/modules/chain_integration_test.go +++ b/dot/rpc/modules/chain_integration_test.go @@ -43,7 +43,7 @@ func TestChainGetHeader_Genesis(t *testing.T) { require.NoError(t, err) di := types.NewDigestItem() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = di.Set(*prd) require.NoError(t, err) @@ -79,7 +79,7 @@ func TestChainGetHeader_Latest(t *testing.T) { require.NoError(t, err) di := types.NewDigestItem() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = di.Set(*prd) require.NoError(t, err) @@ -127,7 +127,7 @@ func TestChainGetBlock_Genesis(t *testing.T) { require.NoError(t, err) di := types.NewDigestItem() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = di.Set(*prd) require.NoError(t, err) @@ -171,7 +171,7 @@ func TestChainGetBlock_Latest(t *testing.T) { require.NoError(t, err) di := types.NewDigestItem() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = di.Set(*prd) require.NoError(t, err) @@ -315,7 +315,7 @@ func TestChainGetFinalizedHeadByRound(t *testing.T) { require.Equal(t, common.BytesToHex(expected[:]), res) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) @@ -388,7 +388,7 @@ func newTestStateService(t *testing.T) *state.Service { func loadTestBlocks(t *testing.T, gh common.Hash, bs *state.BlockState, rt runtime.Instance) { digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/dot/rpc/modules/childstate_integration_test.go b/dot/rpc/modules/childstate_integration_test.go index 6b3cb17de6..0504eda218 100644 --- a/dot/rpc/modules/childstate_integration_test.go +++ b/dot/rpc/modules/childstate_integration_test.go @@ -267,7 +267,7 @@ func setupChildStateStorage(t *testing.T) (*ChildStateModule, common.Hash) { require.NoError(t, err) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/dot/rpc/modules/state_integration_test.go b/dot/rpc/modules/state_integration_test.go index db5834eb2f..efdff75a9d 100644 --- a/dot/rpc/modules/state_integration_test.go +++ b/dot/rpc/modules/state_integration_test.go @@ -531,7 +531,7 @@ func setupStateModule(t *testing.T) (*StateModule, *common.Hash, *common.Hash) { require.NoError(t, err) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/dot/rpc/modules/system_integration_test.go b/dot/rpc/modules/system_integration_test.go index 3d14ea1a1a..9f72c6ae01 100644 --- a/dot/rpc/modules/system_integration_test.go +++ b/dot/rpc/modules/system_integration_test.go @@ -321,7 +321,7 @@ func setupSystemModule(t *testing.T) *SystemModule { require.NoError(t, err) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/dot/state/block_finalisation_test.go b/dot/state/block_finalisation_test.go index b55466c374..7cf2d8848c 100644 --- a/dot/state/block_finalisation_test.go +++ b/dot/state/block_finalisation_test.go @@ -67,7 +67,7 @@ func TestBlockState_SetFinalisedHash(t *testing.T) { require.Equal(t, testGenesisHeader.Hash(), h) digest := types.NewDigest() - di, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + di, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) require.NotNil(t, di) err = digest.Add(*di) @@ -101,13 +101,13 @@ func TestSetFinalisedHash_setFirstSlotOnFinalisation(t *testing.T) { firstSlot := uint64(42069) digest := types.NewDigest() - di, err := types.NewBabeSecondaryPlainPreDigest(0, firstSlot).ToPreRuntimeDigest() + di, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, firstSlot)) require.NoError(t, err) require.NotNil(t, di) err = digest.Add(*di) require.NoError(t, err) digest2 := types.NewDigest() - di, err = types.NewBabeSecondaryPlainPreDigest(0, firstSlot+100).ToPreRuntimeDigest() + di, err = types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, firstSlot+100)) require.NoError(t, err) require.NotNil(t, di) err = digest2.Add(*di) diff --git a/dot/state/block_test.go b/dot/state/block_test.go index 45508e8a53..e2a0e94c0b 100644 --- a/dot/state/block_test.go +++ b/dot/state/block_test.go @@ -483,13 +483,13 @@ func TestNumberIsFinalised(t *testing.T) { require.False(t, fin) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) digest2 := types.NewDigest() - prd, err = types.NewBabeSecondaryPlainPreDigest(0, 100).ToPreRuntimeDigest() + prd, err = types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 100)) require.NoError(t, err) err = digest2.Add(*prd) require.NoError(t, err) diff --git a/dot/state/service_test.go b/dot/state/service_test.go index f8cabd4c08..4cfbb2f836 100644 --- a/dot/state/service_test.go +++ b/dot/state/service_test.go @@ -242,7 +242,7 @@ func TestService_PruneStorage(t *testing.T) { for i := 0; i < 3; i++ { block, trieState := generateBlockWithRandomTrie(t, serv, nil, int64(i+1)) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, uint64(i+1)).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(types.NewBabeSecondaryPlainPreDigest(0, uint64(i+1))) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) @@ -385,7 +385,7 @@ func TestService_Import(t *testing.T) { } digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 177).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 177)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/dot/state/test_helpers.go b/dot/state/test_helpers.go index 62c8def253..46bb0ee5f6 100644 --- a/dot/state/test_helpers.go +++ b/dot/state/test_helpers.go @@ -77,7 +77,7 @@ func AddBlocksToState(t *testing.T, blockState *BlockState, depth int, for i := startNum + 1; i <= depth+startNum; i++ { d := types.NewBabePrimaryPreDigest(0, uint64(i), [32]byte{}, [64]byte{}) digest := types.NewDigest() - prd, err := d.ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*d) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) @@ -166,7 +166,7 @@ func AddBlocksToStateWithFixedBranches(t *testing.T, blockState *BlockState, dep // create base tree startNum := int(head.Number.Int64()) for i := startNum + 1; i <= depth; i++ { - d, err := types.NewBabePrimaryPreDigest(0, uint64(i), [32]byte{}, [64]byte{}).ToPreRuntimeDigest() + d, err := types.ToPreRuntimeDigest(*types.NewBabePrimaryPreDigest(0, uint64(i), [32]byte{}, [64]byte{})) require.NoError(t, err) require.NotNil(t, d) digest := types.NewDigest() @@ -208,7 +208,7 @@ func AddBlocksToStateWithFixedBranches(t *testing.T, blockState *BlockState, dep previousHash = branch.hash for i := branch.depth; i < depth; i++ { - d, err := types.NewBabePrimaryPreDigest(0, uint64(i+j+99), [32]byte{}, [64]byte{}).ToPreRuntimeDigest() + d, err := types.ToPreRuntimeDigest(*types.NewBabePrimaryPreDigest(0, uint64(i+j+99), [32]byte{}, [64]byte{})) require.NoError(t, err) require.NotNil(t, d) digest := types.NewDigest() diff --git a/dot/sync/chain_processor_test.go b/dot/sync/chain_processor_test.go index 78083e6145..56b24b7ba4 100644 --- a/dot/sync/chain_processor_test.go +++ b/dot/sync/chain_processor_test.go @@ -204,7 +204,7 @@ func TestChainProcessor_ExecuteBlock(t *testing.T) { func TestChainProcessor_HandleJustification(t *testing.T) { syncer := newTestSyncer(t) - d, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + d, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) digest := types.NewDigest() err = digest.Add(*d) diff --git a/dot/sync/message_test.go b/dot/sync/message_test.go index c8878b05d0..f5e19ee446 100644 --- a/dot/sync/message_test.go +++ b/dot/sync/message_test.go @@ -22,7 +22,7 @@ func addTestBlocksToState(t *testing.T, depth int, blockState BlockState) { require.Nil(t, err) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/dot/sync/test_helpers.go b/dot/sync/test_helpers.go index 4836e3cf30..8dc1462be0 100644 --- a/dot/sync/test_helpers.go +++ b/dot/sync/test_helpers.go @@ -18,7 +18,7 @@ import ( // BuildBlock ... func BuildBlock(t *testing.T, instance runtime.Instance, parent *types.Header, ext types.Extrinsic) *types.Block { digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/dot/types/babe_digest.go b/dot/types/babe_digest.go index b490d16181..c5fdbc0702 100644 --- a/dot/types/babe_digest.go +++ b/dot/types/babe_digest.go @@ -5,6 +5,7 @@ package types import ( "errors" + "fmt" "github.com/ChainSafe/gossamer/lib/crypto/sr25519" "github.com/ChainSafe/gossamer/pkg/scale" @@ -51,20 +52,6 @@ func NewBabePrimaryPreDigest(authorityIndex uint32, } } -// ToPreRuntimeDigest returns the BabePrimaryPreDigest as a PreRuntimeDigest -func (d *BabePrimaryPreDigest) ToPreRuntimeDigest() (*PreRuntimeDigest, error) { - digest := NewBabeDigest() - err := digest.Set(*d) - if err != nil { - return nil, err - } - enc, err := scale.Marshal(digest) - if err != nil { - return nil, err - } - return NewBABEPreRuntimeDigest(enc), nil -} - // Index Returns VDT index func (d BabePrimaryPreDigest) Index() uint { return 1 } @@ -82,20 +69,6 @@ func NewBabeSecondaryPlainPreDigest(authorityIndex uint32, slotNumber uint64) *B } } -// ToPreRuntimeDigest returns the BabePrimaryPreDigest as a PreRuntimeDigest -func (d *BabeSecondaryPlainPreDigest) ToPreRuntimeDigest() (*PreRuntimeDigest, error) { - digest := NewBabeDigest() - err := digest.Set(*d) - if err != nil { - return nil, err - } - enc, err := scale.Marshal(digest) - if err != nil { - return nil, err - } - return NewBABEPreRuntimeDigest(enc), nil -} - // Index Returns VDT index func (d BabeSecondaryPlainPreDigest) Index() uint { return 2 } @@ -121,3 +94,19 @@ func NewBabeSecondaryVRFPreDigest(authorityIndex uint32, // Index Returns VDT index func (d BabeSecondaryVRFPreDigest) Index() uint { return 3 } + +// ToPreRuntimeDigest returns the VaryingDataTypeValue as a PreRuntimeDigest +func ToPreRuntimeDigest(value scale.VaryingDataTypeValue) (*PreRuntimeDigest, error) { + digest := NewBabeDigest() + err := digest.Set(value) + if err != nil { + return nil, fmt.Errorf("cannot set varying data type value to babe digest: %w", err) + } + + enc, err := scale.Marshal(digest) + if err != nil { + return nil, fmt.Errorf("cannot marshal babe digest: %w", err) + } + + return NewBABEPreRuntimeDigest(enc), nil +} diff --git a/lib/babe/build_integration_test.go b/lib/babe/build_integration_test.go index 507f4833fa..a16e38a033 100644 --- a/lib/babe/build_integration_test.go +++ b/lib/babe/build_integration_test.go @@ -92,7 +92,7 @@ func createTestBlock(t *testing.T, babeService *Service, parent *types.Header, rt, err := babeService.blockState.GetRuntime(nil) require.NoError(t, err) - preRuntimeDigest, err := babeService.runLottery(slotNumber, epoch, epochData) + preRuntimeDigest, err := claimSlot(epoch, slotNumber, epochData, babeService.keypair) require.NoError(t, err) block, err := babeService.buildBlock(parent, slot, rt, epochData.authorityIndex, preRuntimeDigest) @@ -171,11 +171,11 @@ func TestApplyExtrinsic(t *testing.T) { } testVRFOutputAndProof := &VrfOutputAndProof{} - preDigest2, err := types.NewBabePrimaryPreDigest( + preDigest2, err := types.ToPreRuntimeDigest(*types.NewBabePrimaryPreDigest( authorityIndex, slot2.number, testVRFOutputAndProof.output, testVRFOutputAndProof.proof, - ).ToPreRuntimeDigest() + )) require.NoError(t, err) parentHash := babeService.blockState.GenesisHash() @@ -187,11 +187,11 @@ func TestApplyExtrinsic(t *testing.T) { require.NoError(t, err) rt.SetContextStorage(ts) - preDigest, err := types.NewBabePrimaryPreDigest( + preDigest, err := types.ToPreRuntimeDigest(*types.NewBabePrimaryPreDigest( authorityIndex, slot.number, testVRFOutputAndProof.output, testVRFOutputAndProof.proof, - ).ToPreRuntimeDigest() + )) require.NoError(t, err) digest := types.NewDigest() diff --git a/lib/babe/crypto.go b/lib/babe/crypto.go index 3bb10115cc..d2feeb4602 100644 --- a/lib/babe/crypto.go +++ b/lib/babe/crypto.go @@ -84,6 +84,37 @@ func checkPrimaryThreshold(randomness Randomness, return inoutUint.Compare(threshold) < 0, nil } +func claimSecondarySlotVRF(randomness Randomness, + slot, epoch uint64, + authorities []types.Authority, + keypair *sr25519.Keypair, + authorityIndex uint32, +) (*VrfOutputAndProof, error) { + + secondarySlotAuthor, err := getSecondarySlotAuthor(slot, len(authorities), randomness) + if err != nil { + return nil, fmt.Errorf("cannot get secondary slot author: %w", err) + } + + if authorityIndex != secondarySlotAuthor { + return nil, errNotOurTurnToPropose + } + + transcript := makeTranscript(randomness, slot, epoch) + + out, proof, err := keypair.VrfSign(transcript) + if err != nil { + return nil, fmt.Errorf("cannot verify transcript: %w", err) + } + + logger.Debugf("claimed secondary slot, for slot number: %d", slot) + + return &VrfOutputAndProof{ + output: out, + proof: proof, + }, nil +} + func claimSecondarySlotPlain(randomness Randomness, slot uint64, authorities []types.Authority, authorityIndex uint32, ) error { secondarySlotAuthor, err := getSecondarySlotAuthor(slot, len(authorities), randomness) @@ -91,12 +122,12 @@ func claimSecondarySlotPlain(randomness Randomness, slot uint64, authorities []t return fmt.Errorf("cannot get secondary slot author: %w", err) } - if authorityIndex == secondarySlotAuthor { - logger.Debugf("claimed secondary slot, for slot number: %d", slot) - return nil + if authorityIndex != secondarySlotAuthor { + return errNotOurTurnToPropose } - return errNotOurTurnToPropose + logger.Debugf("claimed secondary slot, for slot number: %d", slot) + return nil } // CalculateThreshold calculates the slot lottery threshold diff --git a/lib/babe/epoch.go b/lib/babe/epoch.go index a1caf4a813..5a2f64c00b 100644 --- a/lib/babe/epoch.go +++ b/lib/babe/epoch.go @@ -9,6 +9,7 @@ import ( "math/big" "github.com/ChainSafe/gossamer/dot/types" + "github.com/ChainSafe/gossamer/lib/crypto/sr25519" ) // initiateEpoch sets the epochData for the given epoch, runs the lottery for the slots in the epoch, @@ -138,7 +139,7 @@ func (b *Service) getEpochDataAndStartSlot(epoch uint64) (*epochData, uint64, er authorities: data.Authorities, authorityIndex: idx, threshold: threshold, - secondary: cfgData.SecondarySlots, + secondary: types.AllowedSlots(cfgData.SecondarySlots), } startSlot, err := b.epochState.GetStartSlotForEpoch(epoch) @@ -165,7 +166,7 @@ func (b *Service) getLatestEpochData() (resEpochData *epochData, error error) { return nil, fmt.Errorf("cannot get epoch state latest config data: %w", err) } - resEpochData.secondary = configData.SecondarySlots + resEpochData.secondary = types.AllowedSlots(configData.SecondarySlots) resEpochData.threshold, err = CalculateThreshold(configData.C1, configData.C2, len(resEpochData.authorities)) if err != nil { @@ -187,7 +188,7 @@ func (b *Service) getLatestEpochData() (resEpochData *epochData, error error) { func (b *Service) getFirstAuthoringSlot(epoch uint64, epochData *epochData) (uint64, error) { startSlot := getCurrentSlot(b.constants.slotDuration) for i := startSlot; i < startSlot+b.constants.epochLength; i++ { - _, err := b.runLottery(i, epoch, epochData) + _, err := claimSlot(epoch, i, epochData, b.keypair) if err != nil { if errors.Is(err, errOverPrimarySlotThreshold) { continue @@ -221,37 +222,68 @@ func (b *Service) incrementEpoch() (uint64, error) { return next, nil } -// runLottery runs the lottery for a specific slot number. +// claimSlot claims slot for a specific slot number. // It returns an encoded VrfOutputAndProof if the validator is authorised // to produce a block for that slot. // It returns the wrapped error errOverPrimarySlotThreshold // if it is not authorised. // output = return[0:32]; proof = return[32:96] -func (b *Service) runLottery(slot, epoch uint64, epochData *epochData) (*types.PreRuntimeDigest, error) { +func claimSlot(epochNumber uint64, slotNumber uint64, epochData *epochData, keypair *sr25519.Keypair, +) (*types.PreRuntimeDigest, error) { proof, err := claimPrimarySlot( epochData.randomness, - slot, - epoch, + slotNumber, + epochNumber, epochData.threshold, - b.keypair, + keypair, ) + if err == nil { - return types.NewBabePrimaryPreDigest( - epochData.authorityIndex, slot, proof.output, proof.proof).ToPreRuntimeDigest() + preRuntimeDigest, err := types.ToPreRuntimeDigest(*types.NewBabePrimaryPreDigest( + epochData.authorityIndex, slotNumber, proof.output, proof.proof)) + if err != nil { + return nil, fmt.Errorf("error converting babe primary pre-digest to pre-runtime digest: %w", err) + } + logger.Debugf("epoch %d: claimed primary slot %d", epochNumber, slotNumber) + return preRuntimeDigest, nil + } else if !errors.Is(err, errOverPrimarySlotThreshold) { + return nil, fmt.Errorf("error running slot lottery at slot %d: %w", slotNumber, err) } - if errors.Is(err, errOverPrimarySlotThreshold) { - if epochData.secondary == 0 { - return nil, errSecondarySlotProductionDisabled + switch epochData.secondary { + case types.PrimarySlots: + return nil, errSecondarySlotProductionDisabled + case types.PrimaryAndSecondaryVRFSlots: + proof, err := claimSecondarySlotVRF( + epochData.randomness, slotNumber, epochNumber, epochData.authorities, keypair, epochData.authorityIndex) + if err != nil { + return nil, fmt.Errorf("error claim secondary vrf slot at %d: %w", slotNumber, err) } + preRuntimeDigest, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryVRFPreDigest( + epochData.authorityIndex, slotNumber, proof.output, proof.proof)) - err = claimSecondarySlotPlain(epochData.randomness, slot, - epochData.authorities, epochData.authorityIndex) if err != nil { - return nil, fmt.Errorf("cannot claim secondary slot: %w", err) + return nil, fmt.Errorf("error converting babe secondary vrf pre-digest to pre-runtime digest: %w", err) } - return types.NewBabeSecondaryPlainPreDigest(epochData.authorityIndex, slot).ToPreRuntimeDigest() - } + logger.Debugf("epoch %d: claimed secondary vrf slot %d", epochNumber, slotNumber) + return preRuntimeDigest, nil + case types.PrimaryAndSecondaryPlainSlots: + err = claimSecondarySlotPlain( + epochData.randomness, slotNumber, epochData.authorities, epochData.authorityIndex) + if err != nil { + return nil, fmt.Errorf("error claiming secondary plain slot at %d: %w", slotNumber, err) + } + preRuntimeDigest, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest( + epochData.authorityIndex, slotNumber)) - return nil, err + if err != nil { + return nil, fmt.Errorf( + "failed to get preruntime digest from babe secondary plain predigest for slot %d: %w", slotNumber, err) + } + logger.Debugf("epoch %d: claimed secondary plain slot %d", epochNumber, slotNumber) + return preRuntimeDigest, nil + default: + // this should never occur + return nil, errors.New("invalid slot claiming technique") + } } diff --git a/lib/babe/epoch_handler.go b/lib/babe/epoch_handler.go index 0ff8cb7156..04c8afce34 100644 --- a/lib/babe/epoch_handler.go +++ b/lib/babe/epoch_handler.go @@ -37,52 +37,17 @@ func newEpochHandler(epochNumber, firstSlot uint64, epochData *epochData, consta // determine which slots we'll be authoring in by pre-calculating VRF output slotToPreRuntimeDigest := make(map[uint64]*types.PreRuntimeDigest, constants.epochLength) for i := firstSlot; i < firstSlot+constants.epochLength; i++ { - proof, err := claimPrimarySlot( - epochData.randomness, - i, - epochNumber, - epochData.threshold, - keypair, - ) - - switch err { - case nil: - preRuntimeDigest, err := types.NewBabePrimaryPreDigest( - epochData.authorityIndex, i, proof.output, proof.proof).ToPreRuntimeDigest() - if err != nil { - return nil, fmt.Errorf("error converting babe primary pre-digest to pre-runtime digest: %w", err) - } + preRuntimeDigest, err := claimSlot(epochNumber, i, epochData, keypair) + if err == nil { slotToPreRuntimeDigest[i] = preRuntimeDigest - logger.Debugf("epoch %d: claimed primary slot %d", epochNumber, i) continue - default: - if !errors.Is(err, errOverPrimarySlotThreshold) { - return nil, fmt.Errorf("error running slot lottery at slot %d: %w", i, err) - } } - if epochData.secondary == 0 { + if errors.Is(err, errNotOurTurnToPropose) || errors.Is(err, errSecondarySlotProductionDisabled) { continue } - err = claimSecondarySlotPlain( - epochData.randomness, i, epochData.authorities, epochData.authorityIndex) - if errors.Is(err, errNotOurTurnToPropose) { - continue - } - if err != nil { - return nil, fmt.Errorf("error running slot lottery at slot %d: %w", i, err) - } - - preRuntimeDigest, err := types.NewBabeSecondaryPlainPreDigest( - epochData.authorityIndex, i).ToPreRuntimeDigest() - if err != nil { - return nil, fmt.Errorf( - "failed to get preruntime digest from babe secondary plain predigest for slot %d: %w", i, err) - } - slotToPreRuntimeDigest[i] = preRuntimeDigest - logger.Debugf("epoch %d: claimed secondary slot %d", epochNumber, i) - + return nil, err } return &epochHandler{ diff --git a/lib/babe/types.go b/lib/babe/types.go index 0c475d8cd9..d2981791b4 100644 --- a/lib/babe/types.go +++ b/lib/babe/types.go @@ -60,7 +60,7 @@ type epochData struct { authorityIndex uint32 authorities []types.Authority threshold *scale.Uint128 - secondary byte + secondary types.AllowedSlots } func (ed *epochData) String() string { diff --git a/lib/babe/verify_integration_test.go b/lib/babe/verify_integration_test.go index d52437de7a..a03056abf6 100644 --- a/lib/babe/verify_integration_test.go +++ b/lib/babe/verify_integration_test.go @@ -337,7 +337,7 @@ func TestVerifyPimarySlotWinner(t *testing.T) { const slotNumber uint64 = 1 - preRuntimeDigest, err := babeService.runLottery(slotNumber, testEpochIndex, epochData) + preRuntimeDigest, err := claimSlot(testEpochIndex, slotNumber, epochData, babeService.keypair) require.NoError(t, err) babePreDigest, err := types.DecodeBabePreDigest(preRuntimeDigest.Data) diff --git a/lib/babe/verify_test.go b/lib/babe/verify_test.go index 4d4752ea18..8d1ff5a028 100644 --- a/lib/babe/verify_test.go +++ b/lib/babe/verify_test.go @@ -301,7 +301,7 @@ func Test_verifier_verifyPreRuntimeDigest(t *testing.T) { VRFOutput: output, VRFProof: proof, } - prd1, err := secDigest1.ToPreRuntimeDigest() + prd1, err := types.ToPreRuntimeDigest(secDigest1) assert.NoError(t, err) auth := types.NewAuthority(kp.Public(), uint64(1)) @@ -362,7 +362,7 @@ func Test_verifier_verifyPreRuntimeDigest(t *testing.T) { //BabeSecondaryPlainPreDigest case secDigest := types.BabeSecondaryPlainPreDigest{AuthorityIndex: 0, SlotNumber: uint64(1)} - prd, err := secDigest.ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(secDigest) assert.NoError(t, err) authSec := types.NewAuthority(kp.Public(), uint64(1)) @@ -519,12 +519,12 @@ func Test_verifier_verifyAuthorshipRight(t *testing.T) { testHeaderPrimary.Digest = testDigestPrimary // Secondary Plain Test Header - testParentPrd, err := testBabeSecondaryPlainPreDigest.ToPreRuntimeDigest() + testParentPrd, err := types.ToPreRuntimeDigest(testBabeSecondaryPlainPreDigest) assert.NoError(t, err) testParentHeader := newTestHeader(t, *testParentPrd) testParentHash := encodeAndHashHeader(t, testParentHeader) - testSecondaryPrd, err := testBabeSecondaryPlainPreDigest.ToPreRuntimeDigest() + testSecondaryPrd, err := types.ToPreRuntimeDigest(testBabeSecondaryPlainPreDigest) assert.NoError(t, err) testSecPlainHeader := newTestHeader(t, *testSecondaryPrd) testSecPlainHeader.ParentHash = testParentHash @@ -565,13 +565,13 @@ func Test_verifier_verifyAuthorshipRight(t *testing.T) { header2 := newTestHeader(t, testInvalidPreRuntimeDigest, testInvalidSeal) // Case 3: Invalid Seal Length - babePrd, err := testBabePrimaryPreDigest.ToPreRuntimeDigest() + babePrd, err := types.ToPreRuntimeDigest(testBabePrimaryPreDigest) assert.NoError(t, err) header3 := newTestHeader(t, *babePrd, testInvalidSeal) babeVerifier := newTestVerifier(t, kp, mockBlockState, scale.MaxUint128, false) // Case 4: Invalid signature - BabePrimaryPreDigest - babePrd2, err := testBabePrimaryPreDigest.ToPreRuntimeDigest() + babePrd2, err := types.ToPreRuntimeDigest(testBabePrimaryPreDigest) assert.NoError(t, err) header4 := newTestHeader(t, *babePrd2) @@ -579,7 +579,7 @@ func Test_verifier_verifyAuthorshipRight(t *testing.T) { babeVerifier2 := newTestVerifier(t, kp, mockBlockState, scale.MaxUint128, false) // Case 5: Invalid signature - BabeSecondaryPlainPreDigest - babeSecPlainPrd, err := testBabeSecondaryPlainPreDigest.ToPreRuntimeDigest() + babeSecPlainPrd, err := types.ToPreRuntimeDigest(testBabeSecondaryPlainPreDigest) assert.NoError(t, err) header5 := newTestHeader(t, *babeSecPlainPrd) @@ -595,12 +595,12 @@ func Test_verifier_verifyAuthorshipRight(t *testing.T) { babeVerifier4 := newTestVerifier(t, kp, mockBlockState, scale.MaxUint128, true) // Case 7: GetAuthorityIndex Err - babeParentPrd, err := testBabePrimaryPreDigest.ToPreRuntimeDigest() + babeParentPrd, err := types.ToPreRuntimeDigest(testBabePrimaryPreDigest) assert.NoError(t, err) babeParentHeader := newTestHeader(t, *babeParentPrd) parentHash := encodeAndHashHeader(t, babeParentHeader) - babePrd3, err := testBabePrimaryPreDigest.ToPreRuntimeDigest() + babePrd3, err := types.ToPreRuntimeDigest(testBabePrimaryPreDigest) assert.NoError(t, err) header7 := newTestHeader(t, *babePrd3) @@ -617,7 +617,7 @@ func Test_verifier_verifyAuthorshipRight(t *testing.T) { babeVerifier7 := newTestVerifier(t, kp, mockBlockStateEquiv1, scale.MaxUint128, false) // Case 10: Equivocate case secondary plain - babeSecPlainPrd2, err := testBabeSecondaryPlainPreDigest.ToPreRuntimeDigest() + babeSecPlainPrd2, err := types.ToPreRuntimeDigest(testBabeSecondaryPlainPreDigest) assert.NoError(t, err) header8 := newTestHeader(t, *babeSecPlainPrd2) diff --git a/lib/grandpa/grandpa_test.go b/lib/grandpa/grandpa_test.go index 14a60f0714..c0e4ea252d 100644 --- a/lib/grandpa/grandpa_test.go +++ b/lib/grandpa/grandpa_test.go @@ -1352,7 +1352,7 @@ func addBlocksToState(t *testing.T, blockState *state.BlockState, depth int) { for i := startNum + 1; i <= depth; i++ { arrivalTime := time.Now() - d, err := types.NewBabePrimaryPreDigest(0, uint64(i), [32]byte{}, [64]byte{}).ToPreRuntimeDigest() + d, err := types.ToPreRuntimeDigest(*types.NewBabePrimaryPreDigest(0, uint64(i), [32]byte{}, [64]byte{})) require.NoError(t, err) require.NotNil(t, d) digest := types.NewDigest() @@ -1393,7 +1393,7 @@ func addBlocksAndReturnTheLastOne( bfcNumber := int(previousHead.Number.Int64() + 1) - d, err := types.NewBabePrimaryPreDigest(0, uint64(bfcNumber), [32]byte{}, [64]byte{}).ToPreRuntimeDigest() + d, err := types.ToPreRuntimeDigest(*types.NewBabePrimaryPreDigest(0, uint64(bfcNumber), [32]byte{}, [64]byte{})) require.NoError(t, err) require.NotNil(t, d) digest := types.NewDigest() diff --git a/lib/grandpa/message_handler_test.go b/lib/grandpa/message_handler_test.go index fafb7eb761..f0caef4e98 100644 --- a/lib/grandpa/message_handler_test.go +++ b/lib/grandpa/message_handler_test.go @@ -30,7 +30,7 @@ var testHash = testHeader.Hash() func newTestDigest() scale.VaryingDataTypeSlice { digest := types.NewDigest() - prd, _ := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, _ := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) digest.Add(*prd) return digest } @@ -204,7 +204,7 @@ func TestMessageHandler_NeighbourMessage(t *testing.T) { require.NoError(t, err) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) @@ -262,7 +262,7 @@ func TestMessageHandler_CommitMessage_NoCatchUpRequest_ValidSig(t *testing.T) { fm.Vote = *NewVote(testHash, uint32(round)) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) @@ -377,7 +377,7 @@ func TestMessageHandler_CatchUpRequest_WithResponse(t *testing.T) { gs.state.round = round + 1 digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/lib/grandpa/message_test.go b/lib/grandpa/message_test.go index 737e9ee269..8906d47ed9 100644 --- a/lib/grandpa/message_test.go +++ b/lib/grandpa/message_test.go @@ -143,7 +143,7 @@ func TestNewCatchUpResponse(t *testing.T) { setID := uint64(1) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/lib/grandpa/message_tracker_test.go b/lib/grandpa/message_tracker_test.go index f71c3ef027..b59b4458f8 100644 --- a/lib/grandpa/message_tracker_test.go +++ b/lib/grandpa/message_tracker_test.go @@ -56,7 +56,7 @@ func TestMessageTracker_SendMessage(t *testing.T) { require.NoError(t, err) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) @@ -109,7 +109,7 @@ func TestMessageTracker_ProcessMessage(t *testing.T) { require.NoError(t, err) digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err) diff --git a/lib/grandpa/network_test.go b/lib/grandpa/network_test.go index 036dbb3fd7..ce640fc355 100644 --- a/lib/grandpa/network_test.go +++ b/lib/grandpa/network_test.go @@ -88,7 +88,7 @@ func TestSendNeighbourMessage(t *testing.T) { go gs.sendNeighbourMessage() digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + prd, err := types.ToPreRuntimeDigest(*types.NewBabeSecondaryPlainPreDigest(0, 1)) require.NoError(t, err) err = digest.Add(*prd) require.NoError(t, err)