Skip to content

Commit

Permalink
fix(lib/babe): fix setting first slot of network, fix loading BABE ep…
Browse files Browse the repository at this point in the history
…och params (ChainSafe#1640)
  • Loading branch information
noot authored and timwu20 committed Dec 6, 2021
1 parent bc1b042 commit 63f73ca
Show file tree
Hide file tree
Showing 29 changed files with 794 additions and 294 deletions.
27 changes: 0 additions & 27 deletions dot/core/mocks/verifier.go

This file was deleted.

4 changes: 3 additions & 1 deletion dot/digest/digest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ func addTestBlocksToStateWithParent(t *testing.T, previousHash common.Hash, dept
Header: &types.Header{
ParentHash: previousHash,
Number: big.NewInt(int64(i)).Add(previousNum, big.NewInt(int64(i))),
Digest: types.Digest{},
Digest: types.Digest{
types.NewBabeSecondaryPlainPreDigest(0, uint64(i)).ToPreRuntimeDigest(),
},
},
Body: &types.Body{},
}
Expand Down
2 changes: 1 addition & 1 deletion dot/network/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ func (q *syncQueue) processBlockRequests() {
}

func (q *syncQueue) trySync(req *syncRequest) {
if q.ctx.Err() != nil {
if q.ctx.Err() != nil || len(q.s.host.peers()) == 0 {
return
}

Expand Down
4 changes: 3 additions & 1 deletion dot/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type Node struct {
Services *services.ServiceRegistry // registry of all node services
StopFunc func() // func to call when node stops, currently used for profiling
wg sync.WaitGroup
started chan struct{}
}

// InitNode initialises a new dot node from the provided dot node configuration
Expand Down Expand Up @@ -323,6 +324,7 @@ func NewNode(cfg *Config, ks *keystore.GlobalKeystore, stopFunc func()) (*Node,
Name: cfg.Global.Name,
StopFunc: stopFunc,
Services: services.NewServiceRegistry(),
started: make(chan struct{}),
}

for _, srvc := range nodeSrvcs {
Expand Down Expand Up @@ -429,8 +431,8 @@ func (n *Node) Start() error {
}()

n.wg.Add(1)
close(n.started)
n.wg.Wait()

return nil
}

Expand Down
5 changes: 1 addition & 4 deletions dot/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"reflect"
"sync"
"testing"
"time"

"github.com/ChainSafe/gossamer/dot/core"
"github.com/ChainSafe/gossamer/dot/state"
Expand Down Expand Up @@ -188,9 +187,7 @@ func TestStartNode(t *testing.T) {
require.NoError(t, err)

go func() {
// TODO: need to wait until all services are started so that wg.Add is called, otherwise
// will call wg.Done before the counter is at 1
time.Sleep(time.Second * 15)
<-node.started
node.Stop()
}()

Expand Down
1 change: 0 additions & 1 deletion dot/rpc/modules/author_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ func TestAuthorModule_SubmitExtrinsic_invalid_input(t *testing.T) {
ext := Extrinsic{fmt.Sprintf("%x", "1")}

res := new(ExtrinsicHashResponse)

err := auth.SubmitExtrinsic(nil, &ext, res)
require.EqualError(t, err, "could not byteify non 0x prefixed string")
}
Expand Down
37 changes: 31 additions & 6 deletions dot/rpc/modules/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,17 @@ func TestChainGetHeader_Genesis(t *testing.T) {
header, err := state.Block.BestBlockHeader()
require.NoError(t, err)

d, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest().Encode()
require.NoError(t, err)

expected := &ChainBlockHeaderResponse{
ParentHash: header.ParentHash.String(),
Number: common.BytesToHex(header.Number.Bytes()),
StateRoot: header.StateRoot.String(),
ExtrinsicsRoot: header.ExtrinsicsRoot.String(),
Digest: ChainBlockHeaderDigest{},
Digest: ChainBlockHeaderDigest{
Logs: []string{common.BytesToHex(d)},
},
}

hash := state.Block.BestBlockHash()
Expand All @@ -64,12 +69,17 @@ func TestChainGetHeader_Latest(t *testing.T) {
header, err := state.Block.BestBlockHeader()
require.NoError(t, err)

d, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest().Encode()
require.NoError(t, err)

expected := &ChainBlockHeaderResponse{
ParentHash: header.ParentHash.String(),
Number: common.BytesToHex(header.Number.Bytes()),
StateRoot: header.StateRoot.String(),
ExtrinsicsRoot: header.ExtrinsicsRoot.String(),
Digest: ChainBlockHeaderDigest{},
Digest: ChainBlockHeaderDigest{
Logs: []string{common.BytesToHex(d)},
},
}

res := &ChainBlockHeaderResponse{}
Expand Down Expand Up @@ -101,12 +111,17 @@ func TestChainGetBlock_Genesis(t *testing.T) {
header, err := state.Block.BestBlockHeader()
require.NoError(t, err)

d, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest().Encode()
require.NoError(t, err)

expectedHeader := &ChainBlockHeaderResponse{
ParentHash: header.ParentHash.String(),
Number: common.BytesToHex(header.Number.Bytes()),
StateRoot: header.StateRoot.String(),
ExtrinsicsRoot: header.ExtrinsicsRoot.String(),
Digest: ChainBlockHeaderDigest{},
Digest: ChainBlockHeaderDigest{
Logs: []string{common.BytesToHex(d)},
},
}

hash := state.Block.BestBlockHash()
Expand Down Expand Up @@ -134,12 +149,17 @@ func TestChainGetBlock_Latest(t *testing.T) {
header, err := state.Block.BestBlockHeader()
require.NoError(t, err)

d, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest().Encode()
require.NoError(t, err)

expectedHeader := &ChainBlockHeaderResponse{
ParentHash: header.ParentHash.String(),
Number: common.BytesToHex(header.Number.Bytes()),
StateRoot: header.StateRoot.String(),
ExtrinsicsRoot: header.ExtrinsicsRoot.String(),
Digest: ChainBlockHeaderDigest{},
Digest: ChainBlockHeaderDigest{
Logs: []string{common.BytesToHex(d)},
},
}

expected := &ChainBlockResponse{
Expand Down Expand Up @@ -267,6 +287,9 @@ func TestChainGetFinalizedHeadByRound(t *testing.T) {

header := &types.Header{
Number: big.NewInt(1),
Digest: types.Digest{
types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest(),
},
}
err = state.Block.SetHeader(header)
require.NoError(t, err)
Expand Down Expand Up @@ -358,8 +381,10 @@ func loadTestBlocks(gh common.Hash, bs *state.BlockState) error {

// Create header & blockData for block 1
header1 := &types.Header{
Number: big.NewInt(1),
Digest: types.Digest{},
Number: big.NewInt(1),
Digest: types.Digest{
types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest(),
},
ParentHash: blockHash0,
StateRoot: trie.EmptyHash,
}
Expand Down
30 changes: 30 additions & 0 deletions dot/state/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,36 @@ func (s *BaseState) loadFirstSlot() (uint64, error) {
return binary.LittleEndian.Uint64(data), nil
}

func (s *BaseState) storeEpochLength(l uint64) error {
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, l)
return s.db.Put(epochLengthKey, buf)
}

func (s *BaseState) loadEpochLength() (uint64, error) {
data, err := s.db.Get(epochLengthKey)
if err != nil {
return 0, err
}

return binary.LittleEndian.Uint64(data), nil
}

func (s *BaseState) storeSlotDuration(duration uint64) error {
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, duration)
return s.db.Put(slotDurationKey, buf)
}

func (s *BaseState) loadSlotDuration() (uint64, error) {
data, err := s.db.Get(slotDurationKey)
if err != nil {
return 0, err
}

return binary.LittleEndian.Uint64(data), nil
}

// storePruningData stores the pruner configuration.
func (s *BaseState) storePruningData(mode pruner.Config) error {
encMode, err := json.Marshal(mode)
Expand Down
26 changes: 26 additions & 0 deletions dot/state/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,29 @@ func TestStoreAndLoadBestBlockHash(t *testing.T) {
require.NoError(t, err)
require.Equal(t, hash, res)
}

func TestLoadStoreEpochLength(t *testing.T) {
db := NewInMemoryDB(t)
base := NewBaseState(db)

length := uint64(2222)
err := base.storeEpochLength(length)
require.NoError(t, err)

ret, err := base.loadEpochLength()
require.NoError(t, err)
require.Equal(t, length, ret)
}

func TestLoadAndStoreSlotDuration(t *testing.T) {
db := NewInMemoryDB(t)
base := NewBaseState(db)

d := uint64(3000)
err := base.storeSlotDuration(d)
require.NoError(t, err)

ret, err := base.loadSlotDuration()
require.NoError(t, err)
require.Equal(t, d, ret)
}
42 changes: 41 additions & 1 deletion dot/state/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ type BlockState struct {
baseState *BaseState
db chaindb.Database
sync.RWMutex
genesisHash common.Hash
genesisHash common.Hash
lastFinalised common.Hash

// block notifiers
imported map[byte]chan<- *types.Block
Expand Down Expand Up @@ -74,6 +75,11 @@ func NewBlockState(db chaindb.Database, bt *blocktree.BlockTree) (*BlockState, e
}

bs.genesisHash = genesisBlock.Header.Hash()
bs.lastFinalised, err = bs.GetFinalizedHash(0, 0)
if err != nil {
return nil, fmt.Errorf("failed to get last finalised hash: %w", err)
}

return bs, nil
}

Expand Down Expand Up @@ -372,6 +378,16 @@ func (bs *BlockState) HasFinalizedBlock(round, setID uint64) (bool, error) {
return bs.db.Has(finalizedHashKey(round, setID))
}

// NumberIsFinalised checks if a block number is finalised or not
func (bs *BlockState) NumberIsFinalised(num *big.Int) (bool, error) {
header, err := bs.GetFinalizedHeader(0, 0)
if err != nil {
return false, err
}

return num.Cmp(header.Number) <= 0, nil
}

// GetFinalizedHeader returns the latest finalised block header
func (bs *BlockState) GetFinalizedHeader(round, setID uint64) (*types.Header, error) {
h, err := bs.GetFinalizedHash(round, setID)
Expand Down Expand Up @@ -407,6 +423,15 @@ func (bs *BlockState) SetFinalizedHash(hash common.Hash, round, setID uint64) er
return fmt.Errorf("cannot finalise unknown block %s", hash)
}

// if nothing was previously finalised, set the first slot of the network to the
// slot number of block 1, which is now being set as final
if bs.lastFinalised.Equal(bs.genesisHash) && !hash.Equal(bs.genesisHash) {
err := bs.setFirstSlotOnFinalisation()
if err != nil {
return err
}
}

go bs.notifyFinalized(hash, round, setID)
if round > 0 {
err := bs.SetRound(round)
Expand All @@ -431,9 +456,24 @@ func (bs *BlockState) SetFinalizedHash(hash common.Hash, round, setID uint64) er
bs.pruneKeyCh <- header
}

bs.lastFinalised = hash
return bs.db.Put(finalizedHashKey(round, setID), hash[:])
}

func (bs *BlockState) setFirstSlotOnFinalisation() error {
header, err := bs.GetHeaderByNumber(big.NewInt(1))
if err != nil {
return err
}

slot, err := types.GetSlotFromHeader(header)
if err != nil {
return err
}

return bs.baseState.storeFirstSlot(slot)
}

// SetRound sets the latest finalised GRANDPA round in the db
// TODO: this needs to use both setID and round
func (bs *BlockState) SetRound(round uint64) error {
Expand Down
Loading

0 comments on commit 63f73ca

Please sign in to comment.