Skip to content

Commit

Permalink
chore(lib/babe): create BlockBuilder type (ChainSafe#1602)
Browse files Browse the repository at this point in the history
  • Loading branch information
danigomez authored and timwu20 committed Dec 6, 2021
1 parent 49a5196 commit f1aa729
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 20 deletions.
83 changes: 68 additions & 15 deletions lib/babe/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,79 @@ package babe

import (
"bytes"
"errors"
"fmt"
"math/big"
"time"

"github.com/ChainSafe/gossamer/lib/crypto/sr25519"

"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/runtime"
"github.com/ChainSafe/gossamer/lib/scale"
"github.com/ChainSafe/gossamer/lib/transaction"
)

// BuildBlock builds a block for the slot with the given parent.
// TODO: separate block builder logic into separate module. The only reason this is exported is so other packages
// can build blocks for testing, but it would be preferred to have the builder functionality separated.
func (b *Service) BuildBlock(parent *types.Header, slot Slot) (*types.Block, error) {
return b.buildBlock(parent, slot)
}

// construct a block for this slot with the given parent
func (b *Service) buildBlock(parent *types.Header, slot Slot) (*types.Block, error) {
builder, err := NewBlockBuilder(
b.rt,
b.keypair,
b.transactionState,
b.blockState,
b.slotToProof,
b.epochData.authorityIndex,
)

if err != nil {
return nil, errors.New("There was an error creating block builder - " + err.Error())
}

block, err := builder.buildBlock(parent, slot)

return block, err

}

// nolint
type BlockBuilder struct {
rt runtime.Instance
keypair *sr25519.Keypair
transactionState TransactionState
blockState BlockState
slotToProof map[uint64]*VrfOutputAndProof
currentAuthorityIndex uint32
}

// nolint
func NewBlockBuilder(rt runtime.Instance, kp *sr25519.Keypair, ts TransactionState, bs BlockState, sp map[uint64]*VrfOutputAndProof, authidx uint32) (*BlockBuilder, error) {
if rt == nil {
return nil, errors.New("cannot create block builder; runtime instance is nil")
}
if ts == nil {
return nil, errors.New("cannot create block builder; transaction state is nil")
}
if bs == nil {
return nil, errors.New("cannot create block builder; block state is nil")
}
if sp == nil {
return nil, errors.New("cannot create block builder; slot to proff is nil")
}

bb := &BlockBuilder{
rt: rt,
keypair: kp,
transactionState: ts,
blockState: bs,
slotToProof: sp,
currentAuthorityIndex: authidx,
}

return bb, nil
}

func (b *BlockBuilder) buildBlock(parent *types.Header, slot Slot) (*types.Block, error) {
logger.Trace("build block", "parent", parent, "slot", slot)

// create pre-digest
Expand Down Expand Up @@ -112,7 +166,7 @@ func (b *Service) buildBlock(parent *types.Header, slot Slot) (*types.Block, err

// buildBlockSeal creates the seal for the block header.
// the seal consists of the ConsensusEngineID and a signature of the encoded block header.
func (b *Service) buildBlockSeal(header *types.Header) (*types.SealDigest, error) {
func (b *BlockBuilder) buildBlockSeal(header *types.Header) (*types.SealDigest, error) {
encHeader, err := header.Encode()
if err != nil {
return nil, err
Expand All @@ -136,7 +190,7 @@ func (b *Service) buildBlockSeal(header *types.Header) (*types.SealDigest, error

// 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 *Service) buildBlockPreDigest(slot Slot) (*types.PreRuntimeDigest, error) {
func (b *BlockBuilder) buildBlockPreDigest(slot Slot) (*types.PreRuntimeDigest, error) {
babeHeader, err := b.buildBlockBABEPrimaryPreDigest(slot)
if err != nil {
return nil, err
Expand All @@ -152,14 +206,14 @@ func (b *Service) buildBlockPreDigest(slot Slot) (*types.PreRuntimeDigest, error

// buildBlockBABEPrimaryPreDigest creates the BABE header for the slot.
// the BABE header includes the proof of authorship right for this slot.
func (b *Service) buildBlockBABEPrimaryPreDigest(slot Slot) (*types.BabePrimaryPreDigest, error) {
func (b *BlockBuilder) buildBlockBABEPrimaryPreDigest(slot Slot) (*types.BabePrimaryPreDigest, error) {
if b.slotToProof[slot.number] == nil {
return nil, ErrNotAuthorized
}

outAndProof := b.slotToProof[slot.number]
return types.NewBabePrimaryPreDigest(
b.epochData.authorityIndex,
b.currentAuthorityIndex,
slot.number,
outAndProof.output,
outAndProof.proof,
Expand All @@ -169,7 +223,7 @@ func (b *Service) buildBlockBABEPrimaryPreDigest(slot Slot) (*types.BabePrimaryP
// 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.
func (b *Service) buildBlockExtrinsics(slot Slot) []*transaction.ValidTransaction {
func (b *BlockBuilder) buildBlockExtrinsics(slot Slot) []*transaction.ValidTransaction {
var included []*transaction.ValidTransaction

for !hasSlotEnded(slot) {
Expand Down Expand Up @@ -211,8 +265,7 @@ func (b *Service) buildBlockExtrinsics(slot Slot) []*transaction.ValidTransactio
return included
}

// buildBlockInherents applies the inherents for a block
func (b *Service) buildBlockInherents(slot Slot) ([][]byte, error) {
func (b *BlockBuilder) buildBlockInherents(slot Slot) ([][]byte, error) {
// Setup inherents: add timstap0
idata := types.NewInherentsData()
err := idata.SetInt64Inherent(types.Timstap0, uint64(time.Now().Unix()))
Expand Down Expand Up @@ -275,7 +328,7 @@ func (b *Service) buildBlockInherents(slot Slot) ([][]byte, error) {
return exts.([][]byte), nil
}

func (b *Service) addToQueue(txs []*transaction.ValidTransaction) {
func (b *BlockBuilder) addToQueue(txs []*transaction.ValidTransaction) {
for _, t := range txs {
hash, err := b.transactionState.Push(t)
if err != nil {
Expand Down
22 changes: 20 additions & 2 deletions lib/babe/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ func TestSeal(t *testing.T) {

babeService := createTestService(t, cfg)

builder, _ := NewBlockBuilder(
babeService.rt,
babeService.keypair,
babeService.transactionState,
babeService.blockState,
babeService.slotToProof,
babeService.epochData.authorityIndex,
)

zeroHash, err := common.HexToHash("0x00")
require.NoError(t, err)

Expand All @@ -57,7 +66,7 @@ func TestSeal(t *testing.T) {
hash, err := common.Blake2bHash(encHeader)
require.NoError(t, err)

seal, err := babeService.buildBlockSeal(header)
seal, err := builder.buildBlockSeal(header)
require.NoError(t, err)

ok, err := kp.Public().Verify(hash[:], seal.Data)
Expand Down Expand Up @@ -115,13 +124,22 @@ func TestBuildBlock_ok(t *testing.T) {
babeService := createTestService(t, cfg)
babeService.epochData.threshold = maxThreshold

builder, _ := NewBlockBuilder(
babeService.rt,
babeService.keypair,
babeService.transactionState,
babeService.blockState,
babeService.slotToProof,
babeService.epochData.authorityIndex,
)

// TODO: re-add extrinsic
exts := [][]byte{}

block, slot := createTestBlock(t, babeService, emptyHeader, exts, 1, testEpochIndex)

// create pre-digest
preDigest, err := babeService.buildBlockPreDigest(slot)
preDigest, err := builder.buildBlockPreDigest(slot)
require.NoError(t, err)

expectedBlockHeader := &types.Header{
Expand Down
22 changes: 20 additions & 2 deletions lib/babe/median_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ func addBlocksToState(t *testing.T, babeService *Service, depth int, blockState
previousHash := blockState.BestBlockHash()
previousAT := startTime
duration, err := time.ParseDuration("1s")
builder, _ := NewBlockBuilder(
babeService.rt,
babeService.keypair,
babeService.transactionState,
babeService.blockState,
babeService.slotToProof,
babeService.epochData.authorityIndex,
)
require.NoError(t, err)

for i := 1; i <= depth; i++ {
Expand All @@ -88,7 +96,7 @@ func addBlocksToState(t *testing.T, babeService *Service, depth int, blockState
number: slotNumber,
}

predigest, err := babeService.buildBlockPreDigest(slot)
predigest, err := builder.buildBlockPreDigest(slot)
require.NoError(t, err)

block := &types.Block{
Expand Down Expand Up @@ -130,6 +138,16 @@ func TestEstimateCurrentSlot(t *testing.T) {
// create proof that we can authorize this block
babeService.epochData.threshold = maxThreshold
babeService.epochData.authorityIndex = 0

builder, _ := NewBlockBuilder(
babeService.rt,
babeService.keypair,
babeService.transactionState,
babeService.blockState,
babeService.slotToProof,
babeService.epochData.authorityIndex,
)

slotNumber := uint64(17)

outAndProof, err := babeService.runLottery(slotNumber, testEpochIndex)
Expand All @@ -145,7 +163,7 @@ func TestEstimateCurrentSlot(t *testing.T) {
number: slotNumber,
}

predigest, err := babeService.buildBlockPreDigest(slot)
predigest, err := builder.buildBlockPreDigest(slot)
require.NoError(t, err)

block := &types.Block{
Expand Down
12 changes: 11 additions & 1 deletion lib/babe/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,16 @@ func TestVerifyPimarySlotWinner(t *testing.T) {
// create proof that we can authorize this block
babeService.epochData.threshold = maxThreshold
babeService.epochData.authorityIndex = 0

builder, _ := NewBlockBuilder(
babeService.rt,
babeService.keypair,
babeService.transactionState,
babeService.blockState,
babeService.slotToProof,
babeService.epochData.authorityIndex,
)

var slotNumber uint64 = 1

addAuthorshipProof(t, babeService, slotNumber, testEpochIndex)
Expand All @@ -315,7 +325,7 @@ func TestVerifyPimarySlotWinner(t *testing.T) {
}

// create babe header
babeHeader, err := babeService.buildBlockBABEPrimaryPreDigest(slot)
babeHeader, err := builder.buildBlockBABEPrimaryPreDigest(slot)
require.NoError(t, err)

Authorities := make([]*types.Authority, 1)
Expand Down

0 comments on commit f1aa729

Please sign in to comment.