mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 07:36:44 +00:00
* initial * update * fix: add validator to NewBlockchain function calls * handle past chain reorg * fix: only check with last checkpoint * rm logs * add: handle future chain import case * fix: handle single block case * add unit tests for past and future chain * modularise forker tests * minor fixes * add: overlapping chain test case, minor fixes * minor fixes * add: isolated unit test for IsValidChain * add more test case for IsValidChain * fix: use index for header time * add: fetch last N checkpoints in first run * fix: change checkpoint count to int64 * fix: handle edge case * fix: handle no checkpoint case separately * fix: consider offset for future chain calculation * re-write test case for split chain * fix: typo * add: split chain properties test * separate reorg checks, validate chain before inserting * fix: handle err incase of invalid chain * fix: use error from whitelist service * split chain property tests * remove duplicate test cases * cleanup * clean up * fix linters * fix: fetch checkpoint count bug, add tests * fix more linters * fix: handle nil chain validator in downloader * fix: mock bor tests Co-authored-by: Evgeny Danienko <6655321@bk.ru>
118 lines
4.1 KiB
Go
118 lines
4.1 KiB
Go
package eth
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"github.com/ethereum/go-ethereum/consensus/bor"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/rpc"
|
|
)
|
|
|
|
var (
|
|
// errCheckpointCount is returned when we are unable to fetch
|
|
// the checkpoint count from local heimdall.
|
|
errCheckpointCount = errors.New("failed to fetch checkpoint count")
|
|
|
|
// errNoCheckpoint is returned when there is not checkpoint proposed
|
|
// by heimdall yet or heimdall is not in sync
|
|
errNoCheckpoint = errors.New("no checkpoint proposed")
|
|
|
|
// errCheckpoint is returned when we are unable to fetch the
|
|
// latest checkpoint from the local heimdall.
|
|
errCheckpoint = errors.New("failed to fetch latest checkpoint")
|
|
|
|
// errMissingCheckpoint is returned when we don't have the
|
|
// checkpoint blocks locally, yet.
|
|
errMissingCheckpoint = errors.New("missing checkpoint blocks")
|
|
|
|
// errRootHash is returned when we aren't able to calculate the root hash
|
|
// locally for a range of blocks.
|
|
errRootHash = errors.New("failed to get local root hash")
|
|
|
|
// errCheckpointRootHashMismatch is returned when the local root hash
|
|
// doesn't match with the root hash in checkpoint.
|
|
errCheckpointRootHashMismatch = errors.New("checkpoint roothash mismatch")
|
|
|
|
// errEndBlock is returned when we're unable to fetch a block locally.
|
|
errEndBlock = errors.New("failed to get end block")
|
|
)
|
|
|
|
// fetchWhitelistCheckpoints fetches the latest checkpoint/s from it's local heimdall
|
|
// and verifies the data against bor data.
|
|
func (h *ethHandler) fetchWhitelistCheckpoints(ctx context.Context, bor *bor.Bor, first bool) ([]uint64, []common.Hash, error) {
|
|
// Create an array for block number and block hashes
|
|
//nolint:prealloc
|
|
var (
|
|
blockNums []uint64 = make([]uint64, 0)
|
|
blockHashes []common.Hash = make([]common.Hash, 0)
|
|
)
|
|
|
|
// Fetch the checkpoint count from heimdall
|
|
count, err := bor.HeimdallClient.FetchCheckpointCount(ctx)
|
|
if err != nil {
|
|
log.Debug("Failed to fetch checkpoint count for whitelisting", "err", err)
|
|
return blockNums, blockHashes, errCheckpointCount
|
|
}
|
|
|
|
if count == 0 {
|
|
return blockNums, blockHashes, errNoCheckpoint
|
|
}
|
|
|
|
// If we're in the first iteration, we'll fetch last 10 checkpoints, else only the latest one
|
|
iterations := 1
|
|
if first {
|
|
iterations = 10
|
|
}
|
|
|
|
for i := 0; i < iterations; i++ {
|
|
// If we don't have any checkpoints in heimdall, break
|
|
if count == 0 {
|
|
break
|
|
}
|
|
|
|
// fetch `count` indexed checkpoint from heimdall
|
|
checkpoint, err := bor.HeimdallClient.FetchCheckpoint(ctx, count)
|
|
if err != nil {
|
|
log.Debug("Failed to fetch latest checkpoint for whitelisting", "err", err)
|
|
return blockNums, blockHashes, errCheckpoint
|
|
}
|
|
|
|
// check if we have the checkpoint blocks
|
|
head := h.ethAPI.BlockNumber()
|
|
if head < hexutil.Uint64(checkpoint.EndBlock.Uint64()) {
|
|
log.Debug("Head block behind checkpoint block", "head", head, "checkpoint end block", checkpoint.EndBlock)
|
|
return blockNums, blockHashes, errMissingCheckpoint
|
|
}
|
|
|
|
// verify the root hash of checkpoint
|
|
roothash, err := h.ethAPI.GetRootHash(ctx, checkpoint.StartBlock.Uint64(), checkpoint.EndBlock.Uint64())
|
|
if err != nil {
|
|
log.Debug("Failed to get root hash of checkpoint while whitelisting", "err", err)
|
|
return blockNums, blockHashes, errRootHash
|
|
}
|
|
|
|
if roothash != checkpoint.RootHash.String()[2:] {
|
|
log.Warn("Checkpoint root hash mismatch while whitelisting", "expected", checkpoint.RootHash.String()[2:], "got", roothash)
|
|
return blockNums, blockHashes, errCheckpointRootHashMismatch
|
|
}
|
|
|
|
// fetch the end checkpoint block hash
|
|
block, err := h.ethAPI.GetBlockByNumber(ctx, rpc.BlockNumber(checkpoint.EndBlock.Uint64()), false)
|
|
if err != nil {
|
|
log.Debug("Failed to get end block hash of checkpoint while whitelisting", "err", err)
|
|
return blockNums, blockHashes, errEndBlock
|
|
}
|
|
|
|
hash := fmt.Sprintf("%v", block["hash"])
|
|
|
|
blockNums = append(blockNums, checkpoint.EndBlock.Uint64())
|
|
blockHashes = append(blockHashes, common.HexToHash(hash))
|
|
count--
|
|
}
|
|
|
|
return blockNums, blockHashes, nil
|
|
}
|