// Copyright 2017 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package downloader import ( "math/big" "github.com/ledgerwatch/turbo-geth/common" "github.com/ledgerwatch/turbo-geth/core/rawdb" "github.com/ledgerwatch/turbo-geth/core/types" ) type HeaderChain interface { // CurrentHeader retrieves the current header from the local chain. CurrentHeader() *types.Header // GetHeader retrieves a block header from the database by hash and number. GetHeader(hash common.Hash, number uint64) *types.Header // GetHeaderByNumber retrieves a block header from the database by number. GetHeaderByNumber(number uint64) *types.Header // GetHeaderByHash retrieves a block header from the database by its hash. GetHeaderByHash(hash common.Hash) *types.Header GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash GetBlockNumber(dbr rawdb.DatabaseReader, hash common.Hash) *uint64 } // FakePeer is a mock downloader peer that operates on a local database instance // instead of being an actual live node. It's useful for testing and to implement // sync commands from an existing local database. type FakePeer struct { id string db rawdb.DatabaseReader hc HeaderChain dl *Downloader } // NewFakePeer creates a new mock downloader peer with the given data sources. func NewFakePeer(id string, db rawdb.DatabaseReader, hc HeaderChain, dl *Downloader) *FakePeer { return &FakePeer{id: id, db: db, hc: hc, dl: dl} } // Head implements downloader.Peer, returning the current head hash and number // of the best known header. func (p *FakePeer) Head() (common.Hash, *big.Int) { header := p.hc.CurrentHeader() return header.Hash(), header.Number } // RequestHeadersByHash implements downloader.Peer, returning a batch of headers // defined by the origin hash and the associated query parameters. func (p *FakePeer) RequestHeadersByHash(hash common.Hash, amount int, skip int, reverse bool) error { var ( headers []*types.Header unknown bool ) for !unknown && len(headers) < amount { origin := p.hc.GetHeaderByHash(hash) if origin == nil { break } number := origin.Number.Uint64() headers = append(headers, origin) if reverse { for i := 0; i <= skip; i++ { if header := p.hc.GetHeader(hash, number); header != nil { hash = header.ParentHash number-- } else { unknown = true break } } } else { var ( current = origin.Number.Uint64() next = current + uint64(skip) + 1 ) if header := p.hc.GetHeaderByNumber(next); header != nil { if p.hc.GetBlockHashesFromHash(header.Hash(), uint64(skip+1))[skip] == hash { hash = header.Hash() } else { unknown = true } } else { unknown = true } } } p.dl.DeliverHeaders(p.id, headers) return nil } // RequestHeadersByNumber implements downloader.Peer, returning a batch of headers // defined by the origin number and the associated query parameters. func (p *FakePeer) RequestHeadersByNumber(number uint64, amount int, skip int, reverse bool) error { var ( headers []*types.Header unknown bool ) for !unknown && len(headers) < amount { origin := p.hc.GetHeaderByNumber(number) if origin == nil { break } if reverse { if number >= uint64(skip+1) { number -= uint64(skip + 1) } else { unknown = true } } else { number += uint64(skip + 1) } headers = append(headers, origin) } p.dl.DeliverHeaders(p.id, headers) return nil } // RequestBodies implements downloader.Peer, returning a batch of block bodies // corresponding to the specified block hashes. func (p *FakePeer) RequestBodies(hashes []common.Hash) error { var ( txs [][]*types.Transaction uncles [][]*types.Header ) for _, hash := range hashes { block := rawdb.ReadBlock(p.db, hash, *p.hc.GetBlockNumber(p.db, hash)) txs = append(txs, block.Transactions()) uncles = append(uncles, block.Uncles()) } p.dl.DeliverBodies(p.id, txs, uncles) return nil } // RequestReceipts implements downloader.Peer, returning a batch of transaction // receipts corresponding to the specified block hashes. func (p *FakePeer) RequestReceipts(hashes []common.Hash) error { var receipts [][]*types.Receipt for _, hash := range hashes { receipts = append(receipts, rawdb.ReadRawReceipts(p.db, hash, *p.hc.GetBlockNumber(p.db, hash))) } p.dl.DeliverReceipts(p.id, receipts) return nil }