Skip to content
This repository has been archived by the owner on Oct 18, 2023. It is now read-only.

Commit

Permalink
Proper Pos block checker when INVALID/ACCEPTED status is sent (ledger…
Browse files Browse the repository at this point in the history
…watch#4604)

* added proper PoS block checker

* proper invalid lvh

* p

* fixed smol thingy

* fix more

* fixed engine API

* fixed engine API

* better nil hash

* added 0x0 checks

* full support
  • Loading branch information
Giulio2002 committed Jul 3, 2022
1 parent 6e31b56 commit e90e03a
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 13 deletions.
3 changes: 3 additions & 0 deletions cmd/rpcdaemon/commands/engine_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ func convertPayloadStatus(x *remote.EnginePayloadStatus) map[string]interface{}
json := map[string]interface{}{
"status": x.Status.String(),
}
if x.Status == remote.EngineStatus_INVALID || x.Status == remote.EngineStatus_ACCEPTED {
json["latestValidHash"] = common.Hash{}
}
if x.LatestValidHash != nil {
json["latestValidHash"] = common.Hash(gointerfaces.ConvertH256ToHash(x.LatestValidHash))
}
Expand Down
14 changes: 14 additions & 0 deletions core/rawdb/accessors_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1603,3 +1603,17 @@ func Transitioned(db kv.Getter, blockNum uint64, terminalTotalDifficulty *big.In

return headerTd.Cmp(terminalTotalDifficulty) >= 0, nil
}

// IsPosBlock returns true if the block is a PoS block, aka. all blocks with null difficulty.
func IsPosBlock(db kv.Getter, blockHash common.Hash, blockNum uint64) (trans bool, err error) {
if blockNum == 0 {
return false, nil
}

header := ReadHeader(db, blockHash, blockNum)
if header == nil {
return false, nil
}

return header.Difficulty.Cmp(common.Big0) == 0, nil
}
38 changes: 32 additions & 6 deletions eth/stagedsync/stage_headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,11 @@ func handleNewPayload(
}, nil
}

isAncestorPos, err := rawdb.IsPosBlock(tx, header.ParentHash, headerNumber-1)
if err != nil {
return nil, err
}

parent, err := cfg.blockReader.HeaderByHash(ctx, tx, header.ParentHash)
if err != nil {
return nil, err
Expand All @@ -514,9 +519,14 @@ func handleNewPayload(
}

if header.Number.Uint64() != parent.Number.Uint64()+1 {
latestValidHash := common.Hash{}
if isAncestorPos {
latestValidHash = header.ParentHash
}
cfg.hd.ReportBadHeaderPoS(headerHash, latestValidHash)
return &privateapi.PayloadStatus{
Status: remote.EngineStatus_INVALID,
LatestValidHash: header.ParentHash,
LatestValidHash: latestValidHash,
ValidationError: errors.New("invalid block number"),
}, nil
}
Expand All @@ -525,10 +535,14 @@ func handleNewPayload(

for _, tx := range payloadMessage.Body.Transactions {
if types.TypedTransactionMarshalledAsRlpString(tx) {
cfg.hd.ReportBadHeaderPoS(headerHash, header.ParentHash)
latestValidHash := common.Hash{}
if isAncestorPos {
latestValidHash = header.ParentHash
}
cfg.hd.ReportBadHeaderPoS(headerHash, latestValidHash)
return &privateapi.PayloadStatus{
Status: remote.EngineStatus_INVALID,
LatestValidHash: header.ParentHash,
LatestValidHash: latestValidHash,
ValidationError: errors.New("typed txn marshalled as RLP string"),
}, nil
}
Expand All @@ -537,7 +551,11 @@ func handleNewPayload(
transactions, err := types.DecodeTransactions(payloadMessage.Body.Transactions)
if err != nil {
log.Warn("Error during Beacon transaction decoding", "err", err.Error())
cfg.hd.ReportBadHeaderPoS(headerHash, header.ParentHash)
latestValidHash := common.Hash{}
if isAncestorPos {
latestValidHash = header.ParentHash
}
cfg.hd.ReportBadHeaderPoS(headerHash, latestValidHash)
return &privateapi.PayloadStatus{
Status: remote.EngineStatus_INVALID,
LatestValidHash: header.ParentHash,
Expand Down Expand Up @@ -574,7 +592,15 @@ func verifyAndSaveNewPoSHeader(

if verificationErr := cfg.hd.VerifyHeader(header); verificationErr != nil {
log.Warn("Verification failed for header", "hash", headerHash, "height", headerNumber, "err", verificationErr)
cfg.hd.ReportBadHeaderPoS(headerHash, header.ParentHash)
isAncestorPos, err := rawdb.IsPosBlock(tx, header.ParentHash, headerNumber-1)
if err != nil {
return nil, false, err
}
latestValidHash := common.Hash{}
if isAncestorPos {
latestValidHash = header.ParentHash
}
cfg.hd.ReportBadHeaderPoS(headerHash, latestValidHash)
return &privateapi.PayloadStatus{
Status: remote.EngineStatus_INVALID,
LatestValidHash: header.ParentHash,
Expand Down Expand Up @@ -616,7 +642,7 @@ func verifyAndSaveNewPoSHeader(
}

if cfg.memoryOverlay && (cfg.hd.GetNextForkHash() == (common.Hash{}) || header.ParentHash == cfg.hd.GetNextForkHash()) {
status, latestValidHash, validationError, criticalError := cfg.hd.ValidatePayload(tx, header, body, cfg.chainConfig.TerminalTotalDifficulty, true, cfg.execPayload)
status, latestValidHash, validationError, criticalError := cfg.hd.ValidatePayload(tx, header, body, true, cfg.execPayload)
if criticalError != nil {
return &privateapi.PayloadStatus{CriticalError: criticalError}, false, criticalError
}
Expand Down
4 changes: 1 addition & 3 deletions ethdb/privateapi/ethbackend.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,7 @@ func (s *EthBackendServer) Block(ctx context.Context, req *remote.BlockRequest)

func convertPayloadStatus(payloadStatus *PayloadStatus) *remote.EnginePayloadStatus {
reply := remote.EnginePayloadStatus{Status: payloadStatus.Status}
if payloadStatus.LatestValidHash != (common.Hash{}) {
reply.LatestValidHash = gointerfaces.ConvertHashToH256(payloadStatus.LatestValidHash)
}
reply.LatestValidHash = gointerfaces.ConvertHashToH256(payloadStatus.LatestValidHash)
if payloadStatus.ValidationError != nil {
reply.ValidationError = payloadStatus.ValidationError.Error()
}
Expand Down
12 changes: 8 additions & 4 deletions turbo/stages/headerdownload/header_algos.go
Original file line number Diff line number Diff line change
Expand Up @@ -1117,10 +1117,13 @@ func (hd *HeaderDownload) ValidatePayload(tx kv.RwTx, header *types.Header, body
return
}

isAncestorPosBlock, criticalError := rawdb.Transitioned(tx, header.Number.Uint64()-1, terminalTotalDifficulty)
// If the previous block is the transition block, then the latest valid hash is the 0x0 hash, in case we return INVALID
isAncestorPosBlock, criticalError := rawdb.IsPosBlock(tx, header.ParentHash, header.Number.Uint64()-1)
if criticalError != nil {
return
}
_, isAncestorSideFork := hd.sideForksBlock[header.ParentHash]

if store {
// If it is a continuation of the canonical chain we can stack it up.
if hd.nextForkState == nil {
Expand All @@ -1133,7 +1136,7 @@ func (hd *HeaderDownload) ValidatePayload(tx kv.RwTx, header *types.Header, body
validationError = execPayload(hd.nextForkState, header, body, 0, nil, nil)
if validationError != nil {
status = remote.EngineStatus_INVALID
if isAncestorPosBlock {
if isAncestorPosBlock || isAncestorSideFork {
latestValidHash = header.ParentHash
}
return
Expand Down Expand Up @@ -1183,13 +1186,14 @@ func (hd *HeaderDownload) ValidatePayload(tx kv.RwTx, header *types.Header, body
batch := memdb.NewMemoryBatch(tx)
defer batch.Close()
validationError = execPayload(batch, header, body, unwindPoint, headersChain, bodiesChain)
latestValidHash = header.Hash()
if validationError != nil {
if isAncestorPosBlock {
if isAncestorPosBlock || isAncestorSideFork {
latestValidHash = header.ParentHash
}
status = remote.EngineStatus_INVALID
return
}
latestValidHash = header.Hash()
// After the we finished executing, we clean up old forks
hd.cleanupOutdateSideForks(*currentHeight, maxDepth)
return
Expand Down
9 changes: 9 additions & 0 deletions turbo/stages/stageloop.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,16 @@ func StageLoopStep(
return headBlockHash, err
}
headBlockHash = rawdb.ReadHeadBlockHash(rotx)
headBlockNumber := rawdb.ReadCurrentBlockNumber(rotx)

isAncestorPosBlock, err := rawdb.IsPosBlock(rotx, headBlockHash, *headBlockNumber)
if err != nil {
return headBlockHash, err
}

if !isAncestorPosBlock {
headBlockHash = common.Hash{}
}
if canRunCycleInOneTransaction && snapshotMigratorFinal != nil {
err = snapshotMigratorFinal(rotx)
if err != nil {
Expand Down

0 comments on commit e90e03a

Please sign in to comment.