Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lib/babe): implement secondary slot block production #2260

Merged
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e41869d
feat(lib/babe): implement secondary slot block production
kishansagathiya Jan 31, 2022
ea2729c
Initialize the map
kishansagathiya Feb 3, 2022
9d691a7
Merge branch 'development' into kishan/feat/secondary-slot-block-prod…
kishansagathiya Feb 3, 2022
a42b712
adjusting to new babe changes
kishansagathiya Feb 3, 2022
a3d7d4a
adjusting to new babe changes
kishansagathiya Feb 3, 2022
25bddae
fixed some errors and addressed reviews
kishansagathiya Feb 4, 2022
1c09237
Pass pre runtime digest through functions
kishansagathiya Feb 7, 2022
c25d9d6
adjusting some tests
kishansagathiya Feb 7, 2022
a9c0d07
removing unused params
kishansagathiya Feb 7, 2022
454eab2
attempting to stress test
kishansagathiya Feb 7, 2022
151482c
addressed reviews
kishansagathiya Feb 8, 2022
25d7a92
fixing some more errors
kishansagathiya Feb 9, 2022
d771a94
rename
kishansagathiya Feb 9, 2022
1bd089b
Small changes and TODO comments while debugging
kishansagathiya Feb 14, 2022
aea4766
pass lint
kishansagathiya Feb 14, 2022
8e23302
small changes
kishansagathiya Feb 15, 2022
a7e027f
Update lib/babe/epoch_handler.go
kishansagathiya Feb 15, 2022
f2a407f
Merge branch 'kishan/feat/secondary-slot-block-production' of github.…
kishansagathiya Feb 15, 2022
1550205
make sure epochData.secondary gets filled
kishansagathiya Feb 15, 2022
a06c66b
Update lib/babe/verify_integration_test.go
kishansagathiya Feb 17, 2022
b27b37a
Update lib/babe/epoch_handler.go
kishansagathiya Feb 17, 2022
8b6a6d0
Update tests/stress/stress_test.go
kishansagathiya Feb 17, 2022
a9a9d11
addressed reviews
kishansagathiya Feb 17, 2022
f0aab84
more fixes
kishansagathiya Feb 17, 2022
255fdd7
more fixes
kishansagathiya Feb 17, 2022
c7f1730
Merge branch 'development' into kishan/feat/secondary-slot-block-prod…
kishansagathiya Feb 18, 2022
34f2605
feat(lib/babe): implement secondary vrf slot block production (#2307)
kishansagathiya Feb 25, 2022
c9b863a
Update lib/babe/epoch.go
kishansagathiya Feb 28, 2022
d1afc50
addressed reviews, modified tests
kishansagathiya Feb 28, 2022
988395c
Merge branch 'kishan/feat/secondary-slot-block-production' of github.…
kishansagathiya Feb 28, 2022
e9b24a9
fixing lint
kishansagathiya Feb 28, 2022
347a698
Addressed Eclesio's comments
kishansagathiya Mar 2, 2022
11b326b
Update tests/stress/stress_test.go
kishansagathiya Mar 2, 2022
4de8ed5
Using ToPreRuntimeDigest() method now
kishansagathiya Mar 3, 2022
678b2f8
more of quentin's comments
kishansagathiya Mar 3, 2022
c182a0d
Merge branch 'kishan/feat/secondary-slot-block-production' of github.…
kishansagathiya Mar 3, 2022
1291d1b
Merge branch 'development' into kishan/feat/secondary-slot-block-prod…
kishansagathiya Mar 3, 2022
983af6e
Update lib/babe/epoch.go
kishansagathiya Mar 3, 2022
0c8a7b0
Update lib/babe/epoch.go
kishansagathiya Mar 3, 2022
bc775c6
Update lib/babe/epoch.go
kishansagathiya Mar 3, 2022
9d6d62e
removed a comment
kishansagathiya Mar 4, 2022
e71b76d
Merge branch 'development' of github.com:ChainSafe/gossamer into kish…
kishansagathiya Mar 4, 2022
1a44de1
Merge branch 'kishan/feat/secondary-slot-block-production' of github.…
kishansagathiya Mar 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions dot/sync/chain_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,22 @@ func (s *chainProcessor) processReadyBlocks() {
}

// processBlockData processes the BlockData from a BlockResponse and
// eturns the index of the last BlockData it handled on success,
// returns the index of the last BlockData it handled on success,
// or the index of the block data that errored on failure.
func (s *chainProcessor) processBlockData(bd *types.BlockData) error {
if bd == nil {
return ErrNilBlockData
}

hasHeader, _ := s.blockState.HasHeader(bd.Hash)
hasBody, _ := s.blockState.HasBlockBody(bd.Hash)
hasHeader, err := s.blockState.HasHeader(bd.Hash)
if err != nil {
return fmt.Errorf("failed to check if block state has header for hash %s: %w", bd.Hash, err)
}
hasBody, err := s.blockState.HasBlockBody(bd.Hash)
if err != nil {
return fmt.Errorf("failed to check block state has body for hash %s: %w", bd.Hash, err)
}

if hasHeader && hasBody {
// TODO: fix this; sometimes when the node shuts down the "best block" isn't stored properly,
// so when the node restarts it has blocks higher than what it thinks is the best, causing it not to sync
Expand Down
13 changes: 13 additions & 0 deletions dot/types/babe.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ import (
// RandomnessLength is the length of the epoch randomness (32 bytes)
const RandomnessLength = 32

// AllowedSlots tells in what ways a slot can be claimed.
type AllowedSlots byte

// https://github.com/paritytech/substrate/blob/ded44948e2d5a398abcb4e342b0513cb690961bb/primitives/consensus/babe/src/lib.rs#L219-L226
const (
// PrimarySlots only allows primary slots.
PrimarySlots AllowedSlots = iota
// PrimaryAndSecondaryPlainSlots allow primary and secondary plain slots.
PrimaryAndSecondaryPlainSlots
// PrimaryAndSecondaryVRFSlots allows primary and secondary VRF slots.
PrimaryAndSecondaryVRFSlots
)

// BabeConfiguration contains the genesis data for BABE
//nolint:lll
// see: https://github.com/paritytech/substrate/blob/426c26b8bddfcdbaf8d29f45b128e0864b57de1c/core/consensus/babe/primitives/src/lib.rs#L132
Expand Down
46 changes: 25 additions & 21 deletions dot/types/babe_digest.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package types

import (
"errors"
"fmt"

"github.com/ChainSafe/gossamer/lib/crypto/sr25519"
"github.com/ChainSafe/gossamer/pkg/scale"
Expand Down Expand Up @@ -53,16 +54,7 @@ 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
return toPreRuntimeDigest(*d)
}

// Index Returns VDT index
Expand All @@ -82,18 +74,9 @@ func NewBabeSecondaryPlainPreDigest(authorityIndex uint32, slotNumber uint64) *B
}
}

// ToPreRuntimeDigest returns the BabePrimaryPreDigest as a PreRuntimeDigest
// ToPreRuntimeDigest returns the BabeSecondaryPlainPreDigest 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
return toPreRuntimeDigest(*d)
}

// Index Returns VDT index
Expand All @@ -119,5 +102,26 @@ func NewBabeSecondaryVRFPreDigest(authorityIndex uint32,
}
}

// ToPreRuntimeDigest returns the BabeSecondaryVRFPreDigest as a PreRuntimeDigest
func (d *BabeSecondaryVRFPreDigest) ToPreRuntimeDigest() (*PreRuntimeDigest, error) {
return toPreRuntimeDigest(*d)
}

// 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
}
8 changes: 6 additions & 2 deletions lib/babe/babe.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ func (b *Service) handleEpoch(epoch uint64) (next uint64, err error) {
// stop current epoch handler
cancel()
case err := <-errCh:
// TODO: errEpochPast is sent on this channel, but it doesnot get logged here
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean here, the error is logged below no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have seen below part getting executed

logger.Warnf("attempted to start epoch that has passed: current slot=%d, start slot of epoch=%d",
currSlot, h.firstSlot,
)
errCh <- errEpochPast

Because errEpochPast is being sent on the channel here, I should see error from epochHandler in logs because of following code

gossamer/lib/babe/babe.go

Lines 388 to 390 in 67a9bbb

case err := <-errCh:
cleanup()
logger.Errorf("error from epochHandler: %s", err)

I did not see error from epochHandler in the logs when I was running gossamer

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ok, maybe a deadlock? It would be nice to investigate

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kishansagathiya can you open an issue for this?

cleanup()
logger.Errorf("error from epochHandler: %s", err)
}
Expand All @@ -400,7 +401,10 @@ func (b *Service) handleEpoch(epoch uint64) (next uint64, err error) {
return next, nil
}

func (b *Service) handleSlot(epoch, slotNum uint64, authorityIndex uint32, proof *VrfOutputAndProof) error {
func (b *Service) handleSlot(epoch, slotNum uint64,
authorityIndex uint32,
preRuntimeDigest *types.PreRuntimeDigest,
) error {
parentHeader, err := b.blockState.BestBlockHeader()
if err != nil {
return err
Expand Down Expand Up @@ -442,7 +446,7 @@ func (b *Service) handleSlot(epoch, slotNum uint64, authorityIndex uint32, proof

rt.SetContextStorage(ts)

block, err := b.buildBlock(parent, currentSlot, rt, authorityIndex, proof)
block, err := b.buildBlock(parent, currentSlot, rt, authorityIndex, preRuntimeDigest)
if err != nil {
return err
}
Expand Down
66 changes: 14 additions & 52 deletions lib/babe/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ const (

// construct a block for this slot with the given parent
func (b *Service) buildBlock(parent *types.Header, slot Slot, rt runtime.Instance,
authorityIndex uint32, proof *VrfOutputAndProof) (*types.Block, error) {
authorityIndex uint32, preRuntimeDigest *types.PreRuntimeDigest) (*types.Block, error) {
builder, err := NewBlockBuilder(
b.keypair,
b.transactionState,
b.blockState,
proof,
authorityIndex,
preRuntimeDigest,
)
if err != nil {
return nil, fmt.Errorf("failed to create block builder: %w", err)
Expand All @@ -59,30 +59,31 @@ type BlockBuilder struct {
keypair *sr25519.Keypair
transactionState TransactionState
blockState BlockState
proof *VrfOutputAndProof
currentAuthorityIndex uint32
preRuntimeDigest *types.PreRuntimeDigest
}

// NewBlockBuilder creates a new block builder.
func NewBlockBuilder(kp *sr25519.Keypair, ts TransactionState,
bs BlockState, proof *VrfOutputAndProof,
authidx uint32) (*BlockBuilder, error) {
func NewBlockBuilder(
kp *sr25519.Keypair,
ts TransactionState,
bs BlockState,
authidx uint32,
preRuntimeDigest *types.PreRuntimeDigest,
) (*BlockBuilder, error) {
if ts == nil {
return nil, ErrNilTransactionState
}
if bs == nil {
return nil, ErrNilBlockState
}
if proof == nil {
return nil, ErrNilVRFProof
}

bb := &BlockBuilder{
keypair: kp,
transactionState: ts,
blockState: bs,
proof: proof,
currentAuthorityIndex: authidx,
preRuntimeDigest: preRuntimeDigest,
}

return bb, nil
Expand All @@ -91,18 +92,10 @@ func NewBlockBuilder(kp *sr25519.Keypair, ts TransactionState,
func (b *BlockBuilder) buildBlock(parent *types.Header, slot Slot, rt runtime.Instance) (*types.Block, error) {
logger.Tracef("build block with parent %s and slot: %s", parent, slot)

// create pre-digest
preDigest, err := b.buildBlockPreDigest(slot)
if err != nil {
return nil, err
}

logger.Trace("built pre-digest")

// create new block header
number := big.NewInt(0).Add(parent.Number, big.NewInt(1))
digest := types.NewDigest()
err = digest.Add(*preDigest)
err := digest.Add(*b.preRuntimeDigest)
if err != nil {
return nil, err
}
Expand All @@ -120,7 +113,7 @@ func (b *BlockBuilder) buildBlock(parent *types.Header, slot Slot, rt runtime.In
logger.Trace("initialised block")

// add block inherents
inherents, err := b.buildBlockInherents(slot, rt)
inherents, err := buildBlockInherents(slot, rt)
if err != nil {
return nil, fmt.Errorf("cannot build inherents: %s", err)
}
Expand Down Expand Up @@ -191,37 +184,6 @@ func (b *BlockBuilder) buildBlockSeal(header *types.Header) (*types.SealDigest,
}, nil
}

// buildBlockPreDigest creates the pre-digest for the slot.
// the pre-digest consists of the ConsensusEngineID and the encoded BABE header for the slot.
func (b *BlockBuilder) buildBlockPreDigest(slot Slot) (*types.PreRuntimeDigest, error) {
babeHeader := types.NewBabeDigest()
data := b.buildBlockBABEPrimaryPreDigest(slot)
if err := babeHeader.Set(*data); err != nil {
return nil, fmt.Errorf("cannot set babe header: %w", err)
}

encBABEPrimaryPreDigest, err := scale.Marshal(babeHeader)
if err != nil {
return nil, err
}

return &types.PreRuntimeDigest{
ConsensusEngineID: types.BabeEngineID,
Data: encBABEPrimaryPreDigest,
}, nil
}

// buildBlockBABEPrimaryPreDigest creates the BABE header for the slot.
// the BABE header includes the proof of authorship right for this slot.
func (b *BlockBuilder) buildBlockBABEPrimaryPreDigest(slot Slot) *types.BabePrimaryPreDigest {
return types.NewBabePrimaryPreDigest(
b.currentAuthorityIndex,
slot.number,
b.proof.output,
b.proof.proof,
)
}

// buildBlockExtrinsics applies extrinsics to the block. it returns an array of included extrinsics.
// for each extrinsic in queue, add it to the block, until the slot ends or the block is full.
// if any extrinsic fails, it returns an empty array and an error.
Expand Down Expand Up @@ -276,7 +238,7 @@ func (b *BlockBuilder) buildBlockExtrinsics(slot Slot, rt runtime.Instance) []*t
return included
}

func (b *BlockBuilder) buildBlockInherents(slot Slot, rt runtime.Instance) ([][]byte, error) {
func buildBlockInherents(slot Slot, rt runtime.Instance) ([][]byte, error) {
kishansagathiya marked this conversation as resolved.
Show resolved Hide resolved
kishansagathiya marked this conversation as resolved.
Show resolved Hide resolved
// Setup inherents: add timstap0
idata := types.NewInherentsData()
timestamp := uint64(time.Now().UnixMilli())
Expand Down
35 changes: 18 additions & 17 deletions lib/babe/build_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ func TestSeal(t *testing.T) {
babeService.epochHandler, err = babeService.initiateAndGetEpochHandler(0)
require.NoError(t, err)

authoringSlots := getAuthoringSlots(babeService.epochHandler.slotToProof)
authoringSlots := getAuthoringSlots(babeService.epochHandler.slotToPreRuntimeDigest)
require.NotEmpty(t, authoringSlots)

builder, _ := NewBlockBuilder(
babeService.keypair,
babeService.transactionState,
babeService.blockState,
babeService.epochHandler.slotToProof[authoringSlots[0]],
babeService.epochHandler.epochData.authorityIndex,
babeService.epochHandler.slotToPreRuntimeDigest[authoringSlots[0]],
)

zeroHash, err := common.HexToHash("0x00")
Expand Down Expand Up @@ -92,10 +92,10 @@ func createTestBlock(t *testing.T, babeService *Service, parent *types.Header,
rt, err := babeService.blockState.GetRuntime(nil)
require.NoError(t, err)

outAndProof, 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, outAndProof)
block, err := babeService.buildBlock(parent, slot, rt, epochData.authorityIndex, preRuntimeDigest)
require.NoError(t, err)

babeService.blockState.StoreRuntime(block.Header.Hash(), rt)
Expand Down Expand Up @@ -154,14 +154,6 @@ func TestApplyExtrinsic(t *testing.T) {
babeService := createTestService(t, cfg)
const authorityIndex = 0

builder, _ := NewBlockBuilder(
babeService.keypair,
babeService.transactionState,
babeService.blockState,
&VrfOutputAndProof{},
authorityIndex,
)

duration, err := time.ParseDuration("1s")
require.NoError(t, err)

Expand All @@ -177,8 +169,13 @@ func TestApplyExtrinsic(t *testing.T) {
duration: duration,
number: 2,
}
testVRFOutputAndProof := &VrfOutputAndProof{}

preDigest2, err := builder.buildBlockPreDigest(slot2)
preDigest2, err := types.NewBabePrimaryPreDigest(
authorityIndex, slot2.number,
testVRFOutputAndProof.output,
testVRFOutputAndProof.proof,
).ToPreRuntimeDigest()
require.NoError(t, err)

parentHash := babeService.blockState.GenesisHash()
Expand All @@ -190,7 +187,11 @@ func TestApplyExtrinsic(t *testing.T) {
require.NoError(t, err)
rt.SetContextStorage(ts)

preDigest, err := builder.buildBlockPreDigest(slot)
preDigest, err := types.NewBabePrimaryPreDigest(
authorityIndex, slot.number,
testVRFOutputAndProof.output,
testVRFOutputAndProof.proof,
).ToPreRuntimeDigest()
require.NoError(t, err)

digest := types.NewDigest()
Expand All @@ -204,7 +205,7 @@ func TestApplyExtrinsic(t *testing.T) {
err = rt.InitializeBlock(header)
require.NoError(t, err)

_, err = builder.buildBlockInherents(slot, rt)
_, err = buildBlockInherents(slot, rt)
require.NoError(t, err)

header1, err := rt.FinalizeBlock()
Expand All @@ -223,7 +224,7 @@ func TestApplyExtrinsic(t *testing.T) {
err = rt.InitializeBlock(header2)
require.NoError(t, err)

_, err = builder.buildBlockInherents(slot, rt)
_, err = buildBlockInherents(slot, rt)
require.NoError(t, err)

res, err := rt.ApplyExtrinsic(extBytes)
Expand Down Expand Up @@ -381,7 +382,7 @@ func TestBuildBlock_failing(t *testing.T) {
require.NoError(t, err)

const authorityIndex uint32 = 0
_, err = babeService.buildBlock(parentHeader, slot, rt, authorityIndex, &VrfOutputAndProof{})
_, err = babeService.buildBlock(parentHeader, slot, rt, authorityIndex, &types.PreRuntimeDigest{})
require.NotNil(t, err)
require.Equal(t, "cannot build extrinsics: error applying extrinsic: Apply error, type: Payment",
err.Error(), "Did not receive expected error text")
Expand Down
Loading