Skip to content

Commit

Permalink
bugfix: SetCurrentHeader bug with not updating the current header
Browse files Browse the repository at this point in the history
CurrentHeader is set based on POEM decision
  • Loading branch information
gameofpointers committed Sep 28, 2023
1 parent 19608af commit d5eef12
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 57 deletions.
8 changes: 4 additions & 4 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func (c *Core) InsertChain(blocks types.Blocks) (int, error) {
log.Info("Already processing block:", "Number:", block.Header().NumberArray(), "Hash:", block.Hash())
return idx, errors.New("Already in process of appending this block")
}
newPendingEtxs, _, err := c.sl.Append(block.Header(), types.EmptyHeader(), common.Hash{}, false, nil)
newPendingEtxs, _, _, err := c.sl.Append(block.Header(), types.EmptyHeader(), common.Hash{}, false, nil)
c.processingCache.Remove(block.Hash())
if err == nil {
// If we have a dom, send the dom any pending ETXs which will become
Expand Down Expand Up @@ -462,8 +462,8 @@ func (c *Core) WriteBlock(block *types.Block) {
}
}

func (c *Core) Append(header *types.Header, manifest types.BlockManifest, domPendingHeader *types.Header, domTerminus common.Hash, domOrigin bool, newInboundEtxs types.Transactions) (types.Transactions, bool, error) {
newPendingEtxs, subReorg, err := c.sl.Append(header, domPendingHeader, domTerminus, domOrigin, newInboundEtxs)
func (c *Core) Append(header *types.Header, manifest types.BlockManifest, domPendingHeader *types.Header, domTerminus common.Hash, domOrigin bool, newInboundEtxs types.Transactions) (types.Transactions, bool, bool, error) {
newPendingEtxs, subReorg, setHead, err := c.sl.Append(header, domPendingHeader, domTerminus, domOrigin, newInboundEtxs)
if err != nil {
if err.Error() == ErrBodyNotFound.Error() || err.Error() == consensus.ErrUnknownAncestor.Error() || err.Error() == ErrSubNotSyncedToDom.Error() {
// Fetch the blocks for each hash in the manifest
Expand All @@ -489,7 +489,7 @@ func (c *Core) Append(header *types.Header, manifest types.BlockManifest, domPen
}
}
}
return newPendingEtxs, subReorg, err
return newPendingEtxs, subReorg, setHead, err
}

func (c *Core) DownloadBlocksInManifest(manifest types.BlockManifest, entropy *big.Int) {
Expand Down
17 changes: 10 additions & 7 deletions core/headerchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,12 +304,10 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) error {
if prevHeader.Hash() == head.Hash() {
return nil
}
//Find a common header
commonHeader := hc.findCommonAncestor(head)
newHeader := head

// write the head block hash to the db
rawdb.WriteHeadBlockHash(hc.headerDb, head.Hash())
log.Info("Setting the current header", "Hash", head.Hash(), "Number", head.NumberArray())
hc.currentHeader.Store(head)

// If head is the normal extension of canonical head, we can return by just wiring the canonical hash.
Expand All @@ -322,6 +320,10 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) error {
return nil
}

//Find a common header
commonHeader := hc.findCommonAncestor(head)
newHeader := head

// Delete each header and rollback state processor until common header
// Accumulate the hash slice stack
var hashStack []*types.Header
Expand Down Expand Up @@ -383,15 +385,16 @@ func (hc *HeaderChain) ReadInboundEtxsAndAppendBlock(header *types.Header) error

// findCommonAncestor
func (hc *HeaderChain) findCommonAncestor(header *types.Header) *types.Header {
current := types.CopyHeader(header)
for {
if header == nil {
if current == nil {
return nil
}
canonicalHash := rawdb.ReadCanonicalHash(hc.headerDb, header.NumberU64())
if canonicalHash == header.Hash() {
canonicalHash := rawdb.ReadCanonicalHash(hc.headerDb, current.NumberU64())
if canonicalHash == current.Hash() {
return hc.GetHeaderByHash(canonicalHash)
}
header = hc.GetHeader(header.ParentHash(), header.NumberU64()-1)
current = hc.GetHeader(current.ParentHash(), current.NumberU64()-1)
}

}
Expand Down
65 changes: 26 additions & 39 deletions core/slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,12 @@ func NewSlice(db ethdb.Database, config *Config, txConfig *TxPoolConfig, txLooku

// Append takes a proposed header and constructs a local block and attempts to hierarchically append it to the block graph.
// If this is called from a dominant context a domTerminus must be provided else a common.Hash{} should be used and domOrigin should be set to true.
func (sl *Slice) Append(header *types.Header, domPendingHeader *types.Header, domTerminus common.Hash, domOrigin bool, newInboundEtxs types.Transactions) (types.Transactions, bool, error) {
// Return of this function is the Etxs generated in the Zone Block, subReorg bool that tells dom if should be mined on, setHead bool that determines if we should set the block as the current head and the error
func (sl *Slice) Append(header *types.Header, domPendingHeader *types.Header, domTerminus common.Hash, domOrigin bool, newInboundEtxs types.Transactions) (types.Transactions, bool, bool, error) {
start := time.Now()

if header.Hash() == sl.config.GenesisHash {
return nil, false, nil
return nil, false, false, nil
}

// Only print in Info level if block is c_startingPrintLimit behind or less
Expand All @@ -145,49 +146,49 @@ func (sl *Slice) Append(header *types.Header, domPendingHeader *types.Header, do
time0_1 := common.PrettyDuration(time.Since(start))
// Check if the header hash exists in the BadHashes list
if sl.IsBlockHashABadHash(header.Hash()) {
return nil, false, ErrBadBlockHash
return nil, false, false, ErrBadBlockHash
}
time0_2 := common.PrettyDuration(time.Since(start))

nodeCtx := common.NodeLocation.Context()
location := header.Location()
_, order, err := sl.engine.CalcOrder(header)
if err != nil {
return nil, false, err
return nil, false, false, err
}
// Don't append the block which already exists in the database.
if sl.hc.HasHeader(header.Hash(), header.NumberU64()) && (sl.hc.GetTerminiByHash(header.Hash()) != nil) {
log.Debug("Block has already been appended: ", "Hash: ", header.Hash())
return nil, false, ErrKnownBlock
return nil, false, false, ErrKnownBlock
}
time1 := common.PrettyDuration(time.Since(start))
// This is to prevent a crash when we try to insert blocks before domClient is on.
// Ideally this check should not exist here and should be fixed before we start the slice.
if sl.domClient == nil && nodeCtx != common.PRIME_CTX {
return nil, false, ErrDomClientNotUp
return nil, false, false, ErrDomClientNotUp
}

batch := sl.sliceDb.NewBatch()

// Run Previous Coincident Reference Check (PCRC)
domTerminus, newTermini, err := sl.pcrc(batch, header, domTerminus, domOrigin)
if err != nil {
return nil, false, err
return nil, false, false, err
}
log.Debug("PCRC done", "hash", header.Hash(), "number", header.NumberArray(), "termini", newTermini)

time2 := common.PrettyDuration(time.Since(start))
// Append the new block
err = sl.hc.AppendHeader(header)
if err != nil {
return nil, false, err
return nil, false, false, err
}

time3 := common.PrettyDuration(time.Since(start))
// Construct the block locally
block, err := sl.ConstructLocalBlock(header)
if err != nil {
return nil, false, err
return nil, false, false, err
}
time4 := common.PrettyDuration(time.Since(start))

Expand All @@ -196,7 +197,7 @@ func (sl *Slice) Append(header *types.Header, domPendingHeader *types.Header, do
// Upate the local pending header
pendingHeaderWithTermini, err = sl.generateSlicePendingHeader(block, newTermini, domPendingHeader, domOrigin, true, false)
if err != nil {
return nil, false, err
return nil, false, false, err
}
}

Expand All @@ -208,24 +209,25 @@ func (sl *Slice) Append(header *types.Header, domPendingHeader *types.Header, do
newInboundEtxs, _, err = sl.CollectNewlyConfirmedEtxs(block, block.Location())
if err != nil {
log.Error("Error collecting newly confirmed etxs: ", "err", err)
return nil, false, ErrSubNotSyncedToDom
return nil, false, false, ErrSubNotSyncedToDom
}
}
time5 := common.PrettyDuration(time.Since(start))

time6 := common.PrettyDuration(time.Since(start))
var subPendingEtxs types.Transactions
var subReorg bool
var setHead bool
var time6_1 common.PrettyDuration
var time6_2 common.PrettyDuration
var time6_3 common.PrettyDuration
// Call my sub to append the block, and collect the rolled up ETXs from that sub
if nodeCtx != common.ZONE_CTX {
// How to get the sub pending etxs if not running the full node?.
if sl.subClients[location.SubIndex()] != nil {
subPendingEtxs, subReorg, err = sl.subClients[location.SubIndex()].Append(context.Background(), header, block.SubManifest(), pendingHeaderWithTermini.Header(), domTerminus, true, newInboundEtxs)
subPendingEtxs, subReorg, setHead, err = sl.subClients[location.SubIndex()].Append(context.Background(), header, block.SubManifest(), pendingHeaderWithTermini.Header(), domTerminus, true, newInboundEtxs)
if err != nil {
return nil, false, err
return nil, false, false, err
}
time6_1 = common.PrettyDuration(time.Since(start))
// Cache the subordinate's pending ETXs
Expand Down Expand Up @@ -264,7 +266,7 @@ func (sl *Slice) Append(header *types.Header, domPendingHeader *types.Header, do

tempPendingHeader, err := sl.generateSlicePendingHeader(block, newTermini, domPendingHeader, domOrigin, false, false)
if err != nil {
return nil, false, err
return nil, false, false, err
}

subReorg = sl.miningStrategy(bestPh, tempPendingHeader)
Expand All @@ -275,17 +277,18 @@ func (sl *Slice) Append(header *types.Header, domPendingHeader *types.Header, do
rawdb.WriteInboundEtxs(sl.sliceDb, block.Hash(), newInboundEtxs.FilterToLocation(common.NodeLocation))
}

if subReorg {
setHead = sl.poem(sl.engine.TotalLogS(block.Header()), sl.engine.TotalLogS(sl.hc.CurrentHeader()))
if setHead {
err := sl.hc.SetCurrentHeader(block.Header())
if err != nil {
log.Error("Error setting current header", "err", err, "Hash", block.Hash())
return nil, false, err
return nil, false, false, err
}
}
// Upate the local pending header
pendingHeaderWithTermini, err = sl.generateSlicePendingHeader(block, newTermini, domPendingHeader, domOrigin, subReorg, false)
if err != nil {
return nil, false, err
return nil, false, false, err
}

time9 = common.PrettyDuration(time.Since(start))
Expand All @@ -305,15 +308,15 @@ func (sl *Slice) Append(header *types.Header, domPendingHeader *types.Header, do

// Append has succeeded write the batch
if err := batch.Write(); err != nil {
return nil, false, err
return nil, false, false, err
}

if subReorg {
if setHead {
if nodeCtx != common.ZONE_CTX {
err := sl.hc.SetCurrentHeader(block.Header())
if err != nil {
log.Error("Error setting current header", "err", err, "Hash", block.Hash())
return nil, false, err
return nil, false, false, err
}
}
sl.hc.chainHeadFeed.Send(ChainHeadEvent{Block: block})
Expand All @@ -340,9 +343,9 @@ func (sl *Slice) Append(header *types.Header, domPendingHeader *types.Header, do
go sl.domClient.UpdateDom(context.Background(), bestPh.Termini().DomTerminus(), pendingHeaderWithTermini, common.NodeLocation)
}
}
return block.ExtTransactions(), subReorg, nil
return block.ExtTransactions(), subReorg, setHead, nil
} else {
return subPendingEtxs, subReorg, nil
return subPendingEtxs, subReorg, setHead, nil
}
}

Expand Down Expand Up @@ -648,7 +651,7 @@ func (sl *Slice) pcrc(batch ethdb.Batch, header *types.Header, domTerminus commo

// POEM compares externS to the currentHead S and returns true if externS is greater
func (sl *Slice) poem(externS *big.Int, currentS *big.Int) bool {
log.Debug("POEM:", "Header hash:", sl.hc.CurrentHeader().Hash(), "currentS:", common.BigBitsToBits(currentS), "externS:", common.BigBitsToBits(externS))
log.Debug("POEM:", "currentS:", common.BigBitsToBits(currentS), "externS:", common.BigBitsToBits(externS))
reorg := currentS.Cmp(externS) <= 0
return reorg
}
Expand Down Expand Up @@ -795,27 +798,14 @@ func (sl *Slice) updatePhCacheFromDom(pendingHeader types.PendingHeader, termini
if (localPendingHeader.Header().Root() != types.EmptyRootHash && nodeCtx == common.ZONE_CTX) || nodeCtx == common.REGION_CTX {
block := sl.hc.GetBlockOrCandidateByHash(localPendingHeader.Header().ParentHash())
if block != nil {
err := sl.hc.SetCurrentHeader(block.Header())
if err != nil {
log.Error("Error setting current header", "err", err, "Hash", block.Hash())
return err
}
log.Info("Choosing phHeader pickPhHead:", "NumberArray:", combinedPendingHeader.NumberArray(), "Number:", combinedPendingHeader.Number(), "ParentHash:", combinedPendingHeader.ParentHash(), "Terminus:", localPendingHeader.Termini().DomTerminus())
sl.WriteBestPhKey(localPendingHeader.Termini().DomTerminus())
if block.Hash() != sl.hc.CurrentHeader().Hash() {
sl.hc.chainHeadFeed.Send(ChainHeadEvent{block})
}
} else {
log.Warn("unable to set the current header after the cord update", "Hash", localPendingHeader.Header().ParentHash())
}
} else {
block := sl.hc.GetBlockOrCandidateByHash(localPendingHeader.Header().ParentHash())
if block != nil {
err := sl.hc.SetCurrentHeader(block.Header())
if err != nil {
log.Error("Error setting current header", "err", err, "Hash", block.Hash())
return err
}
newPendingHeader, err := sl.generateSlicePendingHeader(block, localPendingHeader.Termini(), combinedPendingHeader, true, true, false)
if err != nil {
log.Error("Error generating slice pending header", "err", err)
Expand All @@ -824,9 +814,6 @@ func (sl *Slice) updatePhCacheFromDom(pendingHeader types.PendingHeader, termini
combinedPendingHeader = types.CopyHeader(newPendingHeader.Header())
log.Info("Choosing phHeader pickPhHead:", "NumberArray:", combinedPendingHeader.NumberArray(), "ParentHash:", combinedPendingHeader.ParentHash(), "Terminus:", localPendingHeader.Termini().DomTerminus())
sl.WriteBestPhKey(localPendingHeader.Termini().DomTerminus())
if block.Hash() != sl.hc.CurrentHeader().Hash() {
sl.hc.chainHeadFeed.Send(ChainHeadEvent{block})
}
} else {
log.Warn("unable to set the current header after the cord update", "Hash", localPendingHeader.Header().ParentHash())
}
Expand Down
2 changes: 1 addition & 1 deletion eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ func (b *QuaiAPIBackend) SyncProgress() quai.SyncProgress {
return b.eth.Downloader().Progress()
}

func (b *QuaiAPIBackend) Append(header *types.Header, manifest types.BlockManifest, domPendingHeader *types.Header, domTerminus common.Hash, domOrigin bool, newInboundEtxs types.Transactions) (types.Transactions, bool, error) {
func (b *QuaiAPIBackend) Append(header *types.Header, manifest types.BlockManifest, domPendingHeader *types.Header, domTerminus common.Hash, domOrigin bool, newInboundEtxs types.Transactions) (types.Transactions, bool, bool, error) {
return b.eth.core.Append(header, manifest, domPendingHeader, domTerminus, domOrigin, newInboundEtxs)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/quaiapi/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ type Backend interface {
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
WriteBlock(block *types.Block)
Append(header *types.Header, manifest types.BlockManifest, domPendingHeader *types.Header, domTerminus common.Hash, domOrigin bool, newInboundEtxs types.Transactions) (types.Transactions, bool, error)
Append(header *types.Header, manifest types.BlockManifest, domPendingHeader *types.Header, domTerminus common.Hash, domOrigin bool, newInboundEtxs types.Transactions) (types.Transactions, bool, bool, error)
DownloadBlocksInManifest(manifest types.BlockManifest, entropy *big.Int)
ConstructLocalMinedBlock(header *types.Header) (*types.Block, error)
InsertBlock(ctx context.Context, block *types.Block) (int, error)
Expand Down
3 changes: 2 additions & 1 deletion internal/quaiapi/quai_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -633,14 +633,15 @@ func (s *PublicBlockChainQuaiAPI) Append(ctx context.Context, raw json.RawMessag
return nil, err
}

pendingEtxs, subReorg, err := s.b.Append(body.Header, body.Manifest, body.DomPendingHeader, body.DomTerminus, body.DomOrigin, body.NewInboundEtxs)
pendingEtxs, subReorg, setHead, err := s.b.Append(body.Header, body.Manifest, body.DomPendingHeader, body.DomTerminus, body.DomOrigin, body.NewInboundEtxs)
if err != nil {
return nil, err
}
// Marshal the output for decoding
fields := map[string]interface{}{
"pendingEtxs": pendingEtxs,
"subReorg": subReorg,
"setHead": setHead,
}

return fields, nil
Expand Down
9 changes: 5 additions & 4 deletions quaiclient/quaiclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,10 @@ type Termini struct {
type appendReturns struct {
Etxs types.Transactions `json:"pendingEtxs"`
SubReorg bool `json:"subReorg"`
SetHead bool `json:"setHead"`
}

func (ec *Client) Append(ctx context.Context, header *types.Header, manifest types.BlockManifest, domPendingHeader *types.Header, domTerminus common.Hash, domOrigin bool, newInboundEtxs types.Transactions) (types.Transactions, bool, error) {
func (ec *Client) Append(ctx context.Context, header *types.Header, manifest types.BlockManifest, domPendingHeader *types.Header, domTerminus common.Hash, domOrigin bool, newInboundEtxs types.Transactions) (types.Transactions, bool, bool, error) {
fields := map[string]interface{}{
"header": header.RPCMarshalHeader(),
"manifest": manifest,
Expand All @@ -101,16 +102,16 @@ func (ec *Client) Append(ctx context.Context, header *types.Header, manifest typ
var raw json.RawMessage
err := ec.c.CallContext(ctx, &raw, "quai_append", fields)
if err != nil {
return nil, false, err
return nil, false, false, err
}

// Decode header and transactions.
var aReturns appendReturns
if err := json.Unmarshal(raw, &aReturns); err != nil {
return nil, false, err
return nil, false, false, err
}

return aReturns.Etxs, aReturns.SubReorg, nil
return aReturns.Etxs, aReturns.SubReorg, aReturns.SetHead, nil
}

func (ec *Client) DownloadBlocksInManifest(ctx context.Context, manifest types.BlockManifest, entropy *big.Int) {
Expand Down

0 comments on commit d5eef12

Please sign in to comment.