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

Commit

Permalink
if PoS download block is within reach, determine VALID or INVALID (le…
Browse files Browse the repository at this point in the history
…dgerwatch#4812)

* if PoS download is fast enough, determine VALID or INVALID

* more acceptable absolute value

* solved comments

* remove useless

* moved check in stage_headers

Co-authored-by: giuliorebuffo <giuliorebuffo@system76-pc.localdomain>
  • Loading branch information
Giulio2002 and giuliorebuffo committed Jul 26, 2022
1 parent c1f8487 commit 101e181
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 15 deletions.
8 changes: 8 additions & 0 deletions common/math/integer.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,11 @@ func SafeMul(x, y uint64) (uint64, bool) {
hi, lo := bits.Mul64(x, y)
return lo, hi != 0
}

// GetAbsoluteDifference is a utility method that given 2 int64, it returns the absolute value of their difference in uint64 format.
func AbsoluteDifference(x, y uint64) uint64 {
if x > y {
return x - y
}
return y - x
}
9 changes: 9 additions & 0 deletions common/math/integer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package math

import (
"testing"

"github.com/stretchr/testify/assert"
)

type operation byte
Expand Down Expand Up @@ -114,3 +116,10 @@ func TestMustParseUint64Panic(t *testing.T) {
}()
MustParseUint64("ggg")
}

func TestAbsoluteDifference(t *testing.T) {
x1 := uint64(99)
x2 := uint64(45)
assert.Equal(t, AbsoluteDifference(x1, x2), uint64(x1-x2))
assert.Equal(t, AbsoluteDifference(x2, x1), uint64(x1-x2))
}
30 changes: 25 additions & 5 deletions eth/stagedsync/stage_headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/common/dbutils"
"github.com/ledgerwatch/erigon/common/math"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/ethdb/privateapi"
Expand Down Expand Up @@ -435,11 +436,24 @@ func handleNewPayload(
log.Info(fmt.Sprintf("[%s] New payload missing parent", s.LogPrefix()))
if test {
cfg.hd.BeaconRequestList.Remove(requestId)
return &engineapi.PayloadStatus{Status: remote.EngineStatus_SYNCING}, nil
}
cfg.hd.SetPoSDownloaderTip(headerHash)
schedulePoSDownload(requestId, header.ParentHash, headerNumber-1, s, cfg)
currentHeadNumber := rawdb.ReadCurrentBlockNumber(tx)
if currentHeadNumber != nil && math.AbsoluteDifference(*currentHeadNumber, headerNumber) < 32 {
// We try waiting until we finish downloading the PoS blocks if the distance from the head is enough,
// so that we will perform full validation.
time.Sleep(100 * time.Millisecond)
// If we downloaded the headers in time then save them and if we saved the current header, we return VALID
if cfg.hd.PosStatus() == headerdownload.Synced {
verifyAndSaveDownloadedPoSHeaders(tx, cfg, headerInserter)
} else {
return &engineapi.PayloadStatus{Status: remote.EngineStatus_SYNCING}, nil
}
} else {
cfg.hd.SetPoSDownloaderTip(headerHash)
schedulePoSDownload(requestId, header.ParentHash, headerNumber-1, s, cfg)
return &engineapi.PayloadStatus{Status: remote.EngineStatus_SYNCING}, nil
}
return &engineapi.PayloadStatus{Status: remote.EngineStatus_SYNCING}, nil
}

cfg.hd.BeaconRequestList.Remove(requestId)
Expand Down Expand Up @@ -471,6 +485,12 @@ func verifyAndSaveNewPoSHeader(
headerNumber := header.Number.Uint64()
headerHash := block.Hash()

bad, lastValidHash := cfg.hd.IsBadHeaderPoS(header.ParentHash)
if bad {
cfg.hd.ReportBadHeaderPoS(headerHash, lastValidHash)
return &engineapi.PayloadStatus{Status: remote.EngineStatus_INVALID, LatestValidHash: lastValidHash}, false, nil
}

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)
Expand Down Expand Up @@ -636,7 +656,7 @@ func verifyAndSaveDownloadedPoSHeaders(tx kv.RwTx, cfg HeadersCfg, headerInserte
cfg.hd.BeaconRequestList.Remove(cfg.hd.RequestId())
cfg.hd.ReportBadHeaderPoS(cfg.hd.PoSDownloaderTip(), lastValidHash)
} else {
log.Info("PoS headers verified and saved", "requestId", cfg.hd.RequestId())
log.Info("PoS headers verified and saved", "requestId", cfg.hd.RequestId(), "fork head", lastValidHash)
}

cfg.hd.HeadersCollector().Close()
Expand Down Expand Up @@ -667,7 +687,7 @@ func handleInterrupt(interrupt engineapi.Interrupt, cfg HeadersCfg, tx kv.RwTx,
if interrupt == engineapi.Stopping {
cfg.hd.PayloadStatusCh <- engineapi.PayloadStatus{CriticalError: errors.New("server is stopping")}
}
if interrupt == engineapi.Synced {
if interrupt == engineapi.Synced && cfg.hd.HeadersCollector() != nil {
verifyAndSaveDownloadedPoSHeaders(tx, cfg, headerInserter)
}
if !useExternalTx {
Expand Down
13 changes: 3 additions & 10 deletions turbo/engineapi/fork_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/common/changeset"
"github.com/ledgerwatch/erigon/common/dbutils"
"github.com/ledgerwatch/erigon/common/math"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/types/accounts"
Expand Down Expand Up @@ -60,14 +61,6 @@ type ForkValidator struct {
currentHeight uint64
}

// abs64 is a utility method that given an int64, it returns its absolute value in uint64.
func abs64(n int64) uint64 {
if n < 0 {
return uint64(-n)
}
return uint64(n)
}

func NewForkValidatorMock(currentHeight uint64) *ForkValidator {
return &ForkValidator{
sideForksBlock: make(map[common.Hash]forkSegment),
Expand Down Expand Up @@ -226,7 +219,7 @@ func (fv *ForkValidator) ValidatePayload(tx kv.RwTx, header *types.Header, body
}

// if the block is not in range of maxForkDepth from head then we do not validate it.
if abs64(int64(fv.currentHeight)-header.Number.Int64()) > maxForkDepth {
if math.AbsoluteDifference(fv.currentHeight, header.Number.Uint64()) > maxForkDepth {
status = remote.EngineStatus_ACCEPTED
return
}
Expand Down Expand Up @@ -338,7 +331,7 @@ func (fv *ForkValidator) validateAndStorePayload(tx kv.RwTx, header *types.Heade
// clean wipes out all outdated sideforks whose distance exceed the height of the head.
func (fv *ForkValidator) clean() {
for hash, sb := range fv.sideForksBlock {
if abs64(int64(fv.currentHeight)-sb.header.Number.Int64()) > maxForkDepth {
if math.AbsoluteDifference(fv.currentHeight, sb.header.Number.Uint64()) > maxForkDepth {
delete(fv.sideForksBlock, hash)
}
}
Expand Down

0 comments on commit 101e181

Please sign in to comment.