-
Notifications
You must be signed in to change notification settings - Fork 12
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
Initialize the DB with the GenesisState if the node is bootstrapping for the first time #1124
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,10 +13,12 @@ import ( | |
// caught up with the network, before it can start proposing blocks. | ||
// Else it can propose a block at a height that is already finalized | ||
// leading to a fork. | ||
|
||
func (ce *ConsensusEngine) doBlockSync(ctx context.Context) error { | ||
if ce.role.Load() == types.RoleLeader { | ||
if len(ce.validators.GetValidators()) == 1 { | ||
// TODO: which validator set we should use here? whatever we have in the state? | ||
// what if the current validators are not the same as the ones in the state? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think I understand the difference between "current validators" and "the ones in the state". |
||
// and they don't respond to the status request? | ||
if len(ce.validatorSet) == 1 { | ||
return nil // we are the network | ||
} | ||
// figure out the best height to sync with the network | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,8 +50,9 @@ type ConsensusEngine struct { | |
|
||
proposeTimeout time.Duration | ||
|
||
networkHeight atomic.Int64 | ||
validatorSet map[string]ktypes.Validator | ||
networkHeight atomic.Int64 | ||
validatorSet map[string]ktypes.Validator | ||
genesisAppHash types.Hash | ||
|
||
// stores state machine state for the consensus engine | ||
state state | ||
|
@@ -196,6 +197,7 @@ type Config struct { | |
// Leader is the public key of the leader. | ||
Leader crypto.PublicKey | ||
|
||
GenesisHash types.Hash | ||
GenesisParams *GenesisParams // *config.GenesisConfig | ||
|
||
DB *pg.DB | ||
|
@@ -298,13 +300,14 @@ func New(cfg *Config) *ConsensusEngine { | |
resetChan: make(chan int64, 1), | ||
bestHeightCh: make(chan *discoveryMsg, 1), | ||
// interfaces | ||
mempool: cfg.Mempool, | ||
blockStore: cfg.BlockStore, | ||
txapp: cfg.TxApp, | ||
accounts: cfg.Accounts, | ||
validators: cfg.ValidatorStore, | ||
snapshotter: cfg.Snapshots, | ||
log: logger, | ||
mempool: cfg.Mempool, | ||
blockStore: cfg.BlockStore, | ||
txapp: cfg.TxApp, | ||
accounts: cfg.Accounts, | ||
validators: cfg.ValidatorStore, | ||
snapshotter: cfg.Snapshots, | ||
log: logger, | ||
genesisAppHash: cfg.GenesisHash, | ||
} | ||
|
||
ce.role.Store(role) | ||
|
@@ -313,6 +316,8 @@ func New(cfg *Config) *ConsensusEngine { | |
return ce | ||
} | ||
|
||
var initialHeight int64 = 0 // TODO: get it from genesis? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, good point. Yeah we should add this to the genesis config struct. Can do later though. |
||
|
||
func (ce *ConsensusEngine) Start(ctx context.Context, proposerBroadcaster ProposalBroadcaster, | ||
blkAnnouncer BlkAnnouncer, ackBroadcaster AckBroadcaster, blkRequester BlkRequester, stateResetter ResetStateBroadcaster, | ||
discoveryReqBroadcaster DiscoveryReqBroadcaster) error { | ||
|
@@ -337,6 +342,52 @@ func (ce *ConsensusEngine) Start(ctx context.Context, proposerBroadcaster Propos | |
return ce.runConsensusEventLoop(ctx) | ||
} | ||
|
||
// GenesisInit initializes the node with the genesis state. This included initializing the | ||
// votestore with the genesis validators, accounts with the genesis allocations and the | ||
// chain meta store with the genesis network parameters. | ||
// This is called only once when the node is bootstrapping for the first time. | ||
func (ce *ConsensusEngine) GenesisInit(ctx context.Context) error { | ||
genesisTx, err := ce.db.BeginTx(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
defer genesisTx.Rollback(ctx) | ||
|
||
// TODO: genesis allocs | ||
|
||
// genesis validators | ||
genVals := make([]*ktypes.Validator, 0, len(ce.validatorSet)) | ||
for _, v := range ce.validatorSet { | ||
genVals = append(genVals, &ktypes.Validator{ | ||
PubKey: v.PubKey, | ||
Power: v.Power, | ||
}) | ||
} | ||
|
||
startParams := *ce.chainCtx.NetworkParameters | ||
|
||
if err := ce.txapp.GenesisInit(ctx, genesisTx, genVals, nil, initialHeight, ce.chainCtx); err != nil { | ||
return err | ||
} | ||
|
||
if err := meta.SetChainState(ctx, genesisTx, initialHeight, ce.genesisAppHash[:], false); err != nil { | ||
return fmt.Errorf("error storing the genesis state: %w", err) | ||
} | ||
|
||
if err := meta.StoreDiff(ctx, genesisTx, &startParams, ce.chainCtx.NetworkParameters); err != nil { | ||
return fmt.Errorf("error storing the genesis consensus params: %w", err) | ||
} | ||
|
||
// TODO: Genesis hash and what are the mechanics for producing the first block (genesis block)? | ||
ce.txapp.Commit() | ||
|
||
ce.state.lc.appHash = ce.genesisAppHash | ||
ce.state.lc.height = initialHeight | ||
|
||
ce.log.Info("Initialized chain", "height", initialHeight, "appHash", ce.state.lc.appHash.String()) | ||
return genesisTx.Commit(ctx) | ||
} | ||
|
||
// runEventLoop starts the event loop for the consensus engine. | ||
// Below are the event triggers that nodes can receive depending on their role: | ||
// Leader: | ||
|
@@ -497,13 +548,22 @@ func (ce *ConsensusEngine) catchup(ctx context.Context) error { | |
ce.setLastCommitInfo(appHeight, blkHash, types.Hash(appHash)) | ||
} | ||
|
||
if appHeight == -1 { | ||
// This is the first time the node is bootstrapping | ||
// initialize the db with the genesis state | ||
if err := ce.GenesisInit(ctx); err != nil { | ||
return fmt.Errorf("error initializing the genesis state: %w", err) | ||
} | ||
} | ||
|
||
// Replay the blocks from the blockstore if the app hasn't played all the blocks yet. | ||
if appHeight < storeHeight { | ||
// Replay the blocks from the blockstore | ||
if err := ce.replayFromBlockStore(appHeight+1, storeHeight); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
// Sync with the network using the blocksync | ||
if err := ce.doBlockSync(ctx); err != nil { | ||
return err | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One point about these, but not necessarily needing change: these are almost too convenient in that we can casually change the type of these and this code will not break, but the result will change, which is a consensus breaker. It's a lot more cumbersome to use the functions like binary.BigEndian.Append/PutUint64 etc, so let's go ahead with what you have now since we will certainly be changing
gc
a lot before release, but at some point I think we should harden this code.