eth, les, light: Refactor downloader to use blockchain interface
This commit is contained in:
parent
dfd076244d
commit
0550957989
|
@ -114,21 +114,11 @@ type Downloader struct {
|
||||||
syncStatsState stateSyncStats
|
syncStatsState stateSyncStats
|
||||||
syncStatsLock sync.RWMutex // Lock protecting the sync stats fields
|
syncStatsLock sync.RWMutex // Lock protecting the sync stats fields
|
||||||
|
|
||||||
|
lightchain LightChain
|
||||||
|
chain BlockChain
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
hasHeader headerCheckFn // Checks if a header is present in the chain
|
dropPeer peerDropFn // Drops a peer for misbehaving
|
||||||
hasBlockAndState blockAndStateCheckFn // Checks if a block and associated state is present in the chain
|
|
||||||
getHeader headerRetrievalFn // Retrieves a header from the chain
|
|
||||||
getBlock blockRetrievalFn // Retrieves a block from the chain
|
|
||||||
headHeader headHeaderRetrievalFn // Retrieves the head header from the chain
|
|
||||||
headBlock headBlockRetrievalFn // Retrieves the head block from the chain
|
|
||||||
headFastBlock headFastBlockRetrievalFn // Retrieves the head fast-sync block from the chain
|
|
||||||
commitHeadBlock headBlockCommitterFn // Commits a manually assembled block as the chain head
|
|
||||||
getTd tdRetrievalFn // Retrieves the TD of a block from the chain
|
|
||||||
insertHeaders headerChainInsertFn // Injects a batch of headers into the chain
|
|
||||||
insertBlocks blockChainInsertFn // Injects a batch of blocks into the chain
|
|
||||||
insertReceipts receiptChainInsertFn // Injects a batch of blocks and their receipts into the chain
|
|
||||||
rollback chainRollbackFn // Removes a batch of recently added chain links
|
|
||||||
dropPeer peerDropFn // Drops a peer for misbehaving
|
|
||||||
|
|
||||||
// Status
|
// Status
|
||||||
synchroniseMock func(id string, hash common.Hash) error // Replacement for synchronise during testing
|
synchroniseMock func(id string, hash common.Hash) error // Replacement for synchronise during testing
|
||||||
|
@ -163,11 +153,56 @@ type Downloader struct {
|
||||||
chainInsertHook func([]*fetchResult) // Method to call upon inserting a chain of blocks (possibly in multiple invocations)
|
chainInsertHook func([]*fetchResult) // Method to call upon inserting a chain of blocks (possibly in multiple invocations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LightChain interface {
|
||||||
|
// HasHeader verifies a header's presence in the local chain.
|
||||||
|
HasHeader(common.Hash) bool
|
||||||
|
|
||||||
|
// GetHeaderByHash retrieves a header from the local chain.
|
||||||
|
GetHeaderByHash(common.Hash) *types.Header
|
||||||
|
|
||||||
|
// CurrentHeader retrieves the head header from the local chain.
|
||||||
|
CurrentHeader() *types.Header
|
||||||
|
|
||||||
|
// GetTdByHash returns the total difficulty of a local block.
|
||||||
|
GetTdByHash(common.Hash) *big.Int
|
||||||
|
|
||||||
|
// InsertHeaderChain inserts a batch of headers into the local chain.
|
||||||
|
InsertHeaderChain([]*types.Header, int) (int, error)
|
||||||
|
|
||||||
|
// Rollback removes a few recently added elements from the local chain.
|
||||||
|
Rollback([]common.Hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlockChain interface {
|
||||||
|
LightChain
|
||||||
|
|
||||||
|
// HasBlockAndState verifies block and associated states' presence in the local chain.
|
||||||
|
HasBlockAndState(common.Hash) bool
|
||||||
|
|
||||||
|
// GetBlockByHash retrieves a block from the local chain.
|
||||||
|
GetBlockByHash(common.Hash) *types.Block
|
||||||
|
|
||||||
|
// CurrentBlock retrieves the head block from the local chain.
|
||||||
|
CurrentBlock() *types.Block
|
||||||
|
|
||||||
|
// CurrentFastBlock retrieves the head fast block from the local chain.
|
||||||
|
CurrentFastBlock() *types.Block
|
||||||
|
|
||||||
|
// FastSyncCommitHead directly commits the head block to a certain entity.
|
||||||
|
FastSyncCommitHead(common.Hash) error
|
||||||
|
|
||||||
|
// InsertChain inserts a batch of blocks into the local chain.
|
||||||
|
InsertChain(types.Blocks) (int, error)
|
||||||
|
|
||||||
|
// InsertReceiptChain inserts a batch of receipts into the local chain.
|
||||||
|
InsertReceiptChain(types.Blocks, []types.Receipts) (int, error)
|
||||||
|
}
|
||||||
|
|
||||||
// New creates a new downloader to fetch hashes and blocks from remote peers.
|
// New creates a new downloader to fetch hashes and blocks from remote peers.
|
||||||
func New(mode SyncMode, stateDb ethdb.Database, mux *event.TypeMux, hasHeader headerCheckFn, hasBlockAndState blockAndStateCheckFn,
|
func New(mode SyncMode, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn) *Downloader {
|
||||||
getHeader headerRetrievalFn, getBlock blockRetrievalFn, headHeader headHeaderRetrievalFn, headBlock headBlockRetrievalFn,
|
if lightchain == nil {
|
||||||
headFastBlock headFastBlockRetrievalFn, commitHeadBlock headBlockCommitterFn, getTd tdRetrievalFn, insertHeaders headerChainInsertFn,
|
lightchain = chain
|
||||||
insertBlocks blockChainInsertFn, insertReceipts receiptChainInsertFn, rollback chainRollbackFn, dropPeer peerDropFn) *Downloader {
|
}
|
||||||
|
|
||||||
dl := &Downloader{
|
dl := &Downloader{
|
||||||
mode: mode,
|
mode: mode,
|
||||||
|
@ -177,19 +212,8 @@ func New(mode SyncMode, stateDb ethdb.Database, mux *event.TypeMux, hasHeader he
|
||||||
stateDB: stateDb,
|
stateDB: stateDb,
|
||||||
rttEstimate: uint64(rttMaxEstimate),
|
rttEstimate: uint64(rttMaxEstimate),
|
||||||
rttConfidence: uint64(1000000),
|
rttConfidence: uint64(1000000),
|
||||||
hasHeader: hasHeader,
|
chain: chain,
|
||||||
hasBlockAndState: hasBlockAndState,
|
lightchain: lightchain,
|
||||||
getHeader: getHeader,
|
|
||||||
getBlock: getBlock,
|
|
||||||
headHeader: headHeader,
|
|
||||||
headBlock: headBlock,
|
|
||||||
headFastBlock: headFastBlock,
|
|
||||||
commitHeadBlock: commitHeadBlock,
|
|
||||||
getTd: getTd,
|
|
||||||
insertHeaders: insertHeaders,
|
|
||||||
insertBlocks: insertBlocks,
|
|
||||||
insertReceipts: insertReceipts,
|
|
||||||
rollback: rollback,
|
|
||||||
dropPeer: dropPeer,
|
dropPeer: dropPeer,
|
||||||
headerCh: make(chan dataPack, 1),
|
headerCh: make(chan dataPack, 1),
|
||||||
bodyCh: make(chan dataPack, 1),
|
bodyCh: make(chan dataPack, 1),
|
||||||
|
@ -223,11 +247,11 @@ func (d *Downloader) Progress() ethereum.SyncProgress {
|
||||||
current := uint64(0)
|
current := uint64(0)
|
||||||
switch d.mode {
|
switch d.mode {
|
||||||
case FullSync:
|
case FullSync:
|
||||||
current = d.headBlock().NumberU64()
|
current = d.chain.CurrentBlock().NumberU64()
|
||||||
case FastSync:
|
case FastSync:
|
||||||
current = d.headFastBlock().NumberU64()
|
current = d.chain.CurrentFastBlock().NumberU64()
|
||||||
case LightSync:
|
case LightSync:
|
||||||
current = d.headHeader().Number.Uint64()
|
current = d.lightchain.CurrentHeader().Number.Uint64()
|
||||||
}
|
}
|
||||||
return ethereum.SyncProgress{
|
return ethereum.SyncProgress{
|
||||||
StartingBlock: d.syncStatsChainOrigin,
|
StartingBlock: d.syncStatsChainOrigin,
|
||||||
|
@ -572,13 +596,13 @@ func (d *Downloader) fetchHeight(p *peer) (*types.Header, error) {
|
||||||
// the head links match), we do a binary search to find the common ancestor.
|
// the head links match), we do a binary search to find the common ancestor.
|
||||||
func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
|
func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
|
||||||
// Figure out the valid ancestor range to prevent rewrite attacks
|
// Figure out the valid ancestor range to prevent rewrite attacks
|
||||||
floor, ceil := int64(-1), d.headHeader().Number.Uint64()
|
floor, ceil := int64(-1), d.lightchain.CurrentHeader().Number.Uint64()
|
||||||
|
|
||||||
p.log.Debug("Looking for common ancestor", "local", ceil, "remote", height)
|
p.log.Debug("Looking for common ancestor", "local", ceil, "remote", height)
|
||||||
if d.mode == FullSync {
|
if d.mode == FullSync {
|
||||||
ceil = d.headBlock().NumberU64()
|
ceil = d.chain.CurrentBlock().NumberU64()
|
||||||
} else if d.mode == FastSync {
|
} else if d.mode == FastSync {
|
||||||
ceil = d.headFastBlock().NumberU64()
|
ceil = d.chain.CurrentFastBlock().NumberU64()
|
||||||
}
|
}
|
||||||
if ceil >= MaxForkAncestry {
|
if ceil >= MaxForkAncestry {
|
||||||
floor = int64(ceil - MaxForkAncestry)
|
floor = int64(ceil - MaxForkAncestry)
|
||||||
|
@ -638,7 +662,7 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Otherwise check if we already know the header or not
|
// Otherwise check if we already know the header or not
|
||||||
if (d.mode == FullSync && d.hasBlockAndState(headers[i].Hash())) || (d.mode != FullSync && d.hasHeader(headers[i].Hash())) {
|
if (d.mode == FullSync && d.chain.HasBlockAndState(headers[i].Hash())) || (d.mode != FullSync && d.lightchain.HasHeader(headers[i].Hash())) {
|
||||||
number, hash = headers[i].Number.Uint64(), headers[i].Hash()
|
number, hash = headers[i].Number.Uint64(), headers[i].Hash()
|
||||||
|
|
||||||
// If every header is known, even future ones, the peer straight out lied about its head
|
// If every header is known, even future ones, the peer straight out lied about its head
|
||||||
|
@ -703,11 +727,11 @@ func (d *Downloader) findAncestor(p *peer, height uint64) (uint64, error) {
|
||||||
arrived = true
|
arrived = true
|
||||||
|
|
||||||
// Modify the search interval based on the response
|
// Modify the search interval based on the response
|
||||||
if (d.mode == FullSync && !d.hasBlockAndState(headers[0].Hash())) || (d.mode != FullSync && !d.hasHeader(headers[0].Hash())) {
|
if (d.mode == FullSync && !d.chain.HasBlockAndState(headers[0].Hash())) || (d.mode != FullSync && !d.lightchain.HasHeader(headers[0].Hash())) {
|
||||||
end = check
|
end = check
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
header := d.getHeader(headers[0].Hash()) // Independent of sync mode, header surely exists
|
header := d.lightchain.GetHeaderByHash(headers[0].Hash()) // Independent of sync mode, header surely exists
|
||||||
if header.Number.Uint64() != check {
|
if header.Number.Uint64() != check {
|
||||||
p.log.Debug("Received non requested header", "number", header.Number, "hash", header.Hash(), "request", check)
|
p.log.Debug("Received non requested header", "number", header.Number, "hash", header.Hash(), "request", check)
|
||||||
return 0, errBadPeer
|
return 0, errBadPeer
|
||||||
|
@ -1124,23 +1148,19 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error {
|
||||||
for i, header := range rollback {
|
for i, header := range rollback {
|
||||||
hashes[i] = header.Hash()
|
hashes[i] = header.Hash()
|
||||||
}
|
}
|
||||||
lastHeader, lastFastBlock, lastBlock := d.headHeader().Number, common.Big0, common.Big0
|
lastHeader, lastFastBlock, lastBlock := d.lightchain.CurrentHeader().Number, common.Big0, common.Big0
|
||||||
if d.headFastBlock != nil {
|
if d.mode != LightSync {
|
||||||
lastFastBlock = d.headFastBlock().Number()
|
lastFastBlock = d.chain.CurrentFastBlock().Number()
|
||||||
|
lastBlock = d.chain.CurrentBlock().Number()
|
||||||
}
|
}
|
||||||
if d.headBlock != nil {
|
d.lightchain.Rollback(hashes)
|
||||||
lastBlock = d.headBlock().Number()
|
|
||||||
}
|
|
||||||
d.rollback(hashes)
|
|
||||||
curFastBlock, curBlock := common.Big0, common.Big0
|
curFastBlock, curBlock := common.Big0, common.Big0
|
||||||
if d.headFastBlock != nil {
|
if d.mode != LightSync {
|
||||||
curFastBlock = d.headFastBlock().Number()
|
curFastBlock = d.chain.CurrentFastBlock().Number()
|
||||||
}
|
curBlock = d.chain.CurrentBlock().Number()
|
||||||
if d.headBlock != nil {
|
|
||||||
curBlock = d.headBlock().Number()
|
|
||||||
}
|
}
|
||||||
log.Warn("Rolled back headers", "count", len(hashes),
|
log.Warn("Rolled back headers", "count", len(hashes),
|
||||||
"header", fmt.Sprintf("%d->%d", lastHeader, d.headHeader().Number),
|
"header", fmt.Sprintf("%d->%d", lastHeader, d.lightchain.CurrentHeader().Number),
|
||||||
"fast", fmt.Sprintf("%d->%d", lastFastBlock, curFastBlock),
|
"fast", fmt.Sprintf("%d->%d", lastFastBlock, curFastBlock),
|
||||||
"block", fmt.Sprintf("%d->%d", lastBlock, curBlock))
|
"block", fmt.Sprintf("%d->%d", lastBlock, curBlock))
|
||||||
|
|
||||||
|
@ -1190,7 +1210,7 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error {
|
||||||
// L: Request new headers up from 11 (R's TD was higher, it must have something)
|
// L: Request new headers up from 11 (R's TD was higher, it must have something)
|
||||||
// R: Nothing to give
|
// R: Nothing to give
|
||||||
if d.mode != LightSync {
|
if d.mode != LightSync {
|
||||||
if !gotHeaders && td.Cmp(d.getTd(d.headBlock().Hash())) > 0 {
|
if !gotHeaders && td.Cmp(d.chain.GetTdByHash(d.chain.CurrentBlock().Hash())) > 0 {
|
||||||
return errStallingPeer
|
return errStallingPeer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1202,7 +1222,7 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error {
|
||||||
// queued for processing when the header download completes. However, as long as the
|
// queued for processing when the header download completes. However, as long as the
|
||||||
// peer gave us something useful, we're already happy/progressed (above check).
|
// peer gave us something useful, we're already happy/progressed (above check).
|
||||||
if d.mode == FastSync || d.mode == LightSync {
|
if d.mode == FastSync || d.mode == LightSync {
|
||||||
if td.Cmp(d.getTd(d.headHeader().Hash())) > 0 {
|
if td.Cmp(d.lightchain.GetTdByHash(d.lightchain.CurrentHeader().Hash())) > 0 {
|
||||||
return errStallingPeer
|
return errStallingPeer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1232,7 +1252,7 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error {
|
||||||
// Collect the yet unknown headers to mark them as uncertain
|
// Collect the yet unknown headers to mark them as uncertain
|
||||||
unknown := make([]*types.Header, 0, len(headers))
|
unknown := make([]*types.Header, 0, len(headers))
|
||||||
for _, header := range chunk {
|
for _, header := range chunk {
|
||||||
if !d.hasHeader(header.Hash()) {
|
if !d.lightchain.HasHeader(header.Hash()) {
|
||||||
unknown = append(unknown, header)
|
unknown = append(unknown, header)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1241,7 +1261,7 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error {
|
||||||
if chunk[len(chunk)-1].Number.Uint64()+uint64(fsHeaderForceVerify) > pivot {
|
if chunk[len(chunk)-1].Number.Uint64()+uint64(fsHeaderForceVerify) > pivot {
|
||||||
frequency = 1
|
frequency = 1
|
||||||
}
|
}
|
||||||
if n, err := d.insertHeaders(chunk, frequency); err != nil {
|
if n, err := d.chain.InsertHeaderChain(chunk, frequency); err != nil {
|
||||||
// If some headers were inserted, add them too to the rollback list
|
// If some headers were inserted, add them too to the rollback list
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
rollback = append(rollback, chunk[:n]...)
|
rollback = append(rollback, chunk[:n]...)
|
||||||
|
@ -1328,7 +1348,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error {
|
||||||
for i, result := range results[:items] {
|
for i, result := range results[:items] {
|
||||||
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles)
|
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles)
|
||||||
}
|
}
|
||||||
if index, err := d.insertBlocks(blocks); err != nil {
|
if index, err := d.chain.InsertChain(blocks); err != nil {
|
||||||
log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err)
|
log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err)
|
||||||
return errInvalidChain
|
return errInvalidChain
|
||||||
}
|
}
|
||||||
|
@ -1368,6 +1388,7 @@ func (d *Downloader) processFastSyncContent(latest *types.Header) error {
|
||||||
stateSync.Cancel()
|
stateSync.Cancel()
|
||||||
if err := d.commitPivotBlock(P); err != nil {
|
if err := d.commitPivotBlock(P); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := d.importBlockResults(afterP); err != nil {
|
if err := d.importBlockResults(afterP); err != nil {
|
||||||
|
@ -1416,7 +1437,7 @@ func (d *Downloader) commitFastSyncData(results []*fetchResult, stateSync *state
|
||||||
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles)
|
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles)
|
||||||
receipts[i] = result.Receipts
|
receipts[i] = result.Receipts
|
||||||
}
|
}
|
||||||
if index, err := d.insertReceipts(blocks, receipts); err != nil {
|
if index, err := d.chain.InsertReceiptChain(blocks, receipts); err != nil {
|
||||||
log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err)
|
log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err)
|
||||||
return errInvalidChain
|
return errInvalidChain
|
||||||
}
|
}
|
||||||
|
@ -1434,10 +1455,10 @@ func (d *Downloader) commitPivotBlock(result *fetchResult) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Debug("Committing fast sync pivot as new head", "number", b.Number(), "hash", b.Hash())
|
log.Debug("Committing fast sync pivot as new head", "number", b.Number(), "hash", b.Hash())
|
||||||
if _, err := d.insertReceipts([]*types.Block{b}, []types.Receipts{result.Receipts}); err != nil {
|
if _, err := d.chain.InsertReceiptChain([]*types.Block{b}, []types.Receipts{result.Receipts}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return d.commitHeadBlock(b.Hash())
|
return d.chain.FastSyncCommitHead(b.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliverHeaders injects a new batch of block headers received from a remote
|
// DeliverHeaders injects a new batch of block headers received from a remote
|
||||||
|
|
|
@ -96,9 +96,7 @@ func newTester() *downloadTester {
|
||||||
tester.stateDb, _ = ethdb.NewMemDatabase()
|
tester.stateDb, _ = ethdb.NewMemDatabase()
|
||||||
tester.stateDb.Put(genesis.Root().Bytes(), []byte{0x00})
|
tester.stateDb.Put(genesis.Root().Bytes(), []byte{0x00})
|
||||||
|
|
||||||
tester.downloader = New(FullSync, tester.stateDb, new(event.TypeMux), tester.hasHeader, tester.hasBlock, tester.getHeader,
|
tester.downloader = New(FullSync, tester.stateDb, new(event.TypeMux), tester, nil, tester.dropPeer)
|
||||||
tester.getBlock, tester.headHeader, tester.headBlock, tester.headFastBlock, tester.commitHeadBlock, tester.getTd,
|
|
||||||
tester.insertHeaders, tester.insertBlocks, tester.insertReceipts, tester.rollback, tester.dropPeer)
|
|
||||||
|
|
||||||
return tester
|
return tester
|
||||||
}
|
}
|
||||||
|
@ -218,14 +216,14 @@ func (dl *downloadTester) sync(id string, td *big.Int, mode SyncMode) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasHeader checks if a header is present in the testers canonical chain.
|
// HasHeader checks if a header is present in the testers canonical chain.
|
||||||
func (dl *downloadTester) hasHeader(hash common.Hash) bool {
|
func (dl *downloadTester) HasHeader(hash common.Hash) bool {
|
||||||
return dl.getHeader(hash) != nil
|
return dl.GetHeaderByHash(hash) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasBlock checks if a block and associated state is present in the testers canonical chain.
|
// HasBlockAndState checks if a block and associated state is present in the testers canonical chain.
|
||||||
func (dl *downloadTester) hasBlock(hash common.Hash) bool {
|
func (dl *downloadTester) HasBlockAndState(hash common.Hash) bool {
|
||||||
block := dl.getBlock(hash)
|
block := dl.GetBlockByHash(hash)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -233,24 +231,24 @@ func (dl *downloadTester) hasBlock(hash common.Hash) bool {
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getHeader retrieves a header from the testers canonical chain.
|
// GetHeader retrieves a header from the testers canonical chain.
|
||||||
func (dl *downloadTester) getHeader(hash common.Hash) *types.Header {
|
func (dl *downloadTester) GetHeaderByHash(hash common.Hash) *types.Header {
|
||||||
dl.lock.RLock()
|
dl.lock.RLock()
|
||||||
defer dl.lock.RUnlock()
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
return dl.ownHeaders[hash]
|
return dl.ownHeaders[hash]
|
||||||
}
|
}
|
||||||
|
|
||||||
// getBlock retrieves a block from the testers canonical chain.
|
// GetBlock retrieves a block from the testers canonical chain.
|
||||||
func (dl *downloadTester) getBlock(hash common.Hash) *types.Block {
|
func (dl *downloadTester) GetBlockByHash(hash common.Hash) *types.Block {
|
||||||
dl.lock.RLock()
|
dl.lock.RLock()
|
||||||
defer dl.lock.RUnlock()
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
return dl.ownBlocks[hash]
|
return dl.ownBlocks[hash]
|
||||||
}
|
}
|
||||||
|
|
||||||
// headHeader retrieves the current head header from the canonical chain.
|
// CurrentHeader retrieves the current head header from the canonical chain.
|
||||||
func (dl *downloadTester) headHeader() *types.Header {
|
func (dl *downloadTester) CurrentHeader() *types.Header {
|
||||||
dl.lock.RLock()
|
dl.lock.RLock()
|
||||||
defer dl.lock.RUnlock()
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
|
@ -262,8 +260,8 @@ func (dl *downloadTester) headHeader() *types.Header {
|
||||||
return dl.genesis.Header()
|
return dl.genesis.Header()
|
||||||
}
|
}
|
||||||
|
|
||||||
// headBlock retrieves the current head block from the canonical chain.
|
// CurrentBlock retrieves the current head block from the canonical chain.
|
||||||
func (dl *downloadTester) headBlock() *types.Block {
|
func (dl *downloadTester) CurrentBlock() *types.Block {
|
||||||
dl.lock.RLock()
|
dl.lock.RLock()
|
||||||
defer dl.lock.RUnlock()
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
|
@ -277,8 +275,8 @@ func (dl *downloadTester) headBlock() *types.Block {
|
||||||
return dl.genesis
|
return dl.genesis
|
||||||
}
|
}
|
||||||
|
|
||||||
// headFastBlock retrieves the current head fast-sync block from the canonical chain.
|
// CurrentFastBlock retrieves the current head fast-sync block from the canonical chain.
|
||||||
func (dl *downloadTester) headFastBlock() *types.Block {
|
func (dl *downloadTester) CurrentFastBlock() *types.Block {
|
||||||
dl.lock.RLock()
|
dl.lock.RLock()
|
||||||
defer dl.lock.RUnlock()
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
|
@ -290,26 +288,26 @@ func (dl *downloadTester) headFastBlock() *types.Block {
|
||||||
return dl.genesis
|
return dl.genesis
|
||||||
}
|
}
|
||||||
|
|
||||||
// commitHeadBlock manually sets the head block to a given hash.
|
// FastSynccommitHead manually sets the head block to a given hash.
|
||||||
func (dl *downloadTester) commitHeadBlock(hash common.Hash) error {
|
func (dl *downloadTester) FastSyncCommitHead(hash common.Hash) error {
|
||||||
// For now only check that the state trie is correct
|
// For now only check that the state trie is correct
|
||||||
if block := dl.getBlock(hash); block != nil {
|
if block := dl.GetBlockByHash(hash); block != nil {
|
||||||
_, err := trie.NewSecure(block.Root(), dl.stateDb, 0)
|
_, err := trie.NewSecure(block.Root(), dl.stateDb, 0)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return fmt.Errorf("non existent block: %x", hash[:4])
|
return fmt.Errorf("non existent block: %x", hash[:4])
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTd retrieves the block's total difficulty from the canonical chain.
|
// GetTdByHash retrieves the block's total difficulty from the canonical chain.
|
||||||
func (dl *downloadTester) getTd(hash common.Hash) *big.Int {
|
func (dl *downloadTester) GetTdByHash(hash common.Hash) *big.Int {
|
||||||
dl.lock.RLock()
|
dl.lock.RLock()
|
||||||
defer dl.lock.RUnlock()
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
return dl.ownChainTd[hash]
|
return dl.ownChainTd[hash]
|
||||||
}
|
}
|
||||||
|
|
||||||
// insertHeaders injects a new batch of headers into the simulated chain.
|
// InsertHeaderChain injects a new batch of headers into the simulated chain.
|
||||||
func (dl *downloadTester) insertHeaders(headers []*types.Header, checkFreq int) (int, error) {
|
func (dl *downloadTester) InsertHeaderChain(headers []*types.Header, checkFreq int) (int, error) {
|
||||||
dl.lock.Lock()
|
dl.lock.Lock()
|
||||||
defer dl.lock.Unlock()
|
defer dl.lock.Unlock()
|
||||||
|
|
||||||
|
@ -337,8 +335,8 @@ func (dl *downloadTester) insertHeaders(headers []*types.Header, checkFreq int)
|
||||||
return len(headers), nil
|
return len(headers), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// insertBlocks injects a new batch of blocks into the simulated chain.
|
// InsertChain injects a new batch of blocks into the simulated chain.
|
||||||
func (dl *downloadTester) insertBlocks(blocks types.Blocks) (int, error) {
|
func (dl *downloadTester) InsertChain(blocks types.Blocks) (int, error) {
|
||||||
dl.lock.Lock()
|
dl.lock.Lock()
|
||||||
defer dl.lock.Unlock()
|
defer dl.lock.Unlock()
|
||||||
|
|
||||||
|
@ -359,8 +357,8 @@ func (dl *downloadTester) insertBlocks(blocks types.Blocks) (int, error) {
|
||||||
return len(blocks), nil
|
return len(blocks), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// insertReceipts injects a new batch of receipts into the simulated chain.
|
// InsertReceiptChain injects a new batch of receipts into the simulated chain.
|
||||||
func (dl *downloadTester) insertReceipts(blocks types.Blocks, receipts []types.Receipts) (int, error) {
|
func (dl *downloadTester) InsertReceiptChain(blocks types.Blocks, receipts []types.Receipts) (int, error) {
|
||||||
dl.lock.Lock()
|
dl.lock.Lock()
|
||||||
defer dl.lock.Unlock()
|
defer dl.lock.Unlock()
|
||||||
|
|
||||||
|
@ -377,8 +375,8 @@ func (dl *downloadTester) insertReceipts(blocks types.Blocks, receipts []types.R
|
||||||
return len(blocks), nil
|
return len(blocks), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// rollback removes some recently added elements from the chain.
|
// Rollback removes some recently added elements from the chain.
|
||||||
func (dl *downloadTester) rollback(hashes []common.Hash) {
|
func (dl *downloadTester) Rollback(hashes []common.Hash) {
|
||||||
dl.lock.Lock()
|
dl.lock.Lock()
|
||||||
defer dl.lock.Unlock()
|
defer dl.lock.Unlock()
|
||||||
|
|
||||||
|
@ -1212,7 +1210,7 @@ func testInvalidHeaderRollback(t *testing.T, protocol int, mode SyncMode) {
|
||||||
if err := tester.sync("fast-attack", nil, mode); err == nil {
|
if err := tester.sync("fast-attack", nil, mode); err == nil {
|
||||||
t.Fatalf("succeeded fast attacker synchronisation")
|
t.Fatalf("succeeded fast attacker synchronisation")
|
||||||
}
|
}
|
||||||
if head := tester.headHeader().Number.Int64(); int(head) > MaxHeaderFetch {
|
if head := tester.CurrentHeader().Number.Int64(); int(head) > MaxHeaderFetch {
|
||||||
t.Errorf("rollback head mismatch: have %v, want at most %v", head, MaxHeaderFetch)
|
t.Errorf("rollback head mismatch: have %v, want at most %v", head, MaxHeaderFetch)
|
||||||
}
|
}
|
||||||
// Attempt to sync with an attacker that feeds junk during the block import phase.
|
// Attempt to sync with an attacker that feeds junk during the block import phase.
|
||||||
|
@ -1226,11 +1224,11 @@ func testInvalidHeaderRollback(t *testing.T, protocol int, mode SyncMode) {
|
||||||
if err := tester.sync("block-attack", nil, mode); err == nil {
|
if err := tester.sync("block-attack", nil, mode); err == nil {
|
||||||
t.Fatalf("succeeded block attacker synchronisation")
|
t.Fatalf("succeeded block attacker synchronisation")
|
||||||
}
|
}
|
||||||
if head := tester.headHeader().Number.Int64(); int(head) > 2*fsHeaderSafetyNet+MaxHeaderFetch {
|
if head := tester.CurrentHeader().Number.Int64(); int(head) > 2*fsHeaderSafetyNet+MaxHeaderFetch {
|
||||||
t.Errorf("rollback head mismatch: have %v, want at most %v", head, 2*fsHeaderSafetyNet+MaxHeaderFetch)
|
t.Errorf("rollback head mismatch: have %v, want at most %v", head, 2*fsHeaderSafetyNet+MaxHeaderFetch)
|
||||||
}
|
}
|
||||||
if mode == FastSync {
|
if mode == FastSync {
|
||||||
if head := tester.headBlock().NumberU64(); head != 0 {
|
if head := tester.CurrentBlock().NumberU64(); head != 0 {
|
||||||
t.Errorf("fast sync pivot block #%d not rolled back", head)
|
t.Errorf("fast sync pivot block #%d not rolled back", head)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1251,11 +1249,11 @@ func testInvalidHeaderRollback(t *testing.T, protocol int, mode SyncMode) {
|
||||||
if err := tester.sync("withhold-attack", nil, mode); err == nil {
|
if err := tester.sync("withhold-attack", nil, mode); err == nil {
|
||||||
t.Fatalf("succeeded withholding attacker synchronisation")
|
t.Fatalf("succeeded withholding attacker synchronisation")
|
||||||
}
|
}
|
||||||
if head := tester.headHeader().Number.Int64(); int(head) > 2*fsHeaderSafetyNet+MaxHeaderFetch {
|
if head := tester.CurrentHeader().Number.Int64(); int(head) > 2*fsHeaderSafetyNet+MaxHeaderFetch {
|
||||||
t.Errorf("rollback head mismatch: have %v, want at most %v", head, 2*fsHeaderSafetyNet+MaxHeaderFetch)
|
t.Errorf("rollback head mismatch: have %v, want at most %v", head, 2*fsHeaderSafetyNet+MaxHeaderFetch)
|
||||||
}
|
}
|
||||||
if mode == FastSync {
|
if mode == FastSync {
|
||||||
if head := tester.headBlock().NumberU64(); head != 0 {
|
if head := tester.CurrentBlock().NumberU64(); head != 0 {
|
||||||
t.Errorf("fast sync pivot block #%d not rolled back", head)
|
t.Errorf("fast sync pivot block #%d not rolled back", head)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,51 +18,10 @@ package downloader
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// headerCheckFn is a callback type for verifying a header's presence in the local chain.
|
|
||||||
type headerCheckFn func(common.Hash) bool
|
|
||||||
|
|
||||||
// blockAndStateCheckFn is a callback type for verifying block and associated states' presence in the local chain.
|
|
||||||
type blockAndStateCheckFn func(common.Hash) bool
|
|
||||||
|
|
||||||
// headerRetrievalFn is a callback type for retrieving a header from the local chain.
|
|
||||||
type headerRetrievalFn func(common.Hash) *types.Header
|
|
||||||
|
|
||||||
// blockRetrievalFn is a callback type for retrieving a block from the local chain.
|
|
||||||
type blockRetrievalFn func(common.Hash) *types.Block
|
|
||||||
|
|
||||||
// headHeaderRetrievalFn is a callback type for retrieving the head header from the local chain.
|
|
||||||
type headHeaderRetrievalFn func() *types.Header
|
|
||||||
|
|
||||||
// headBlockRetrievalFn is a callback type for retrieving the head block from the local chain.
|
|
||||||
type headBlockRetrievalFn func() *types.Block
|
|
||||||
|
|
||||||
// headFastBlockRetrievalFn is a callback type for retrieving the head fast block from the local chain.
|
|
||||||
type headFastBlockRetrievalFn func() *types.Block
|
|
||||||
|
|
||||||
// headBlockCommitterFn is a callback for directly committing the head block to a certain entity.
|
|
||||||
type headBlockCommitterFn func(common.Hash) error
|
|
||||||
|
|
||||||
// tdRetrievalFn is a callback type for retrieving the total difficulty of a local block.
|
|
||||||
type tdRetrievalFn func(common.Hash) *big.Int
|
|
||||||
|
|
||||||
// headerChainInsertFn is a callback type to insert a batch of headers into the local chain.
|
|
||||||
type headerChainInsertFn func([]*types.Header, int) (int, error)
|
|
||||||
|
|
||||||
// blockChainInsertFn is a callback type to insert a batch of blocks into the local chain.
|
|
||||||
type blockChainInsertFn func(types.Blocks) (int, error)
|
|
||||||
|
|
||||||
// receiptChainInsertFn is a callback type to insert a batch of receipts into the local chain.
|
|
||||||
type receiptChainInsertFn func(types.Blocks, []types.Receipts) (int, error)
|
|
||||||
|
|
||||||
// chainRollbackFn is a callback type to remove a few recently added elements from the local chain.
|
|
||||||
type chainRollbackFn func([]common.Hash)
|
|
||||||
|
|
||||||
// peerDropFn is a callback type for dropping a peer detected as malicious.
|
// peerDropFn is a callback type for dropping a peer detected as malicious.
|
||||||
type peerDropFn func(id string)
|
type peerDropFn func(id string)
|
||||||
|
|
||||||
|
|
|
@ -157,10 +157,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
|
||||||
return nil, errIncompatibleConfig
|
return nil, errIncompatibleConfig
|
||||||
}
|
}
|
||||||
// Construct the different synchronisation mechanisms
|
// Construct the different synchronisation mechanisms
|
||||||
manager.downloader = downloader.New(mode, chaindb, manager.eventMux, blockchain.HasHeader, blockchain.HasBlockAndState, blockchain.GetHeaderByHash,
|
manager.downloader = downloader.New(mode, chaindb, manager.eventMux, blockchain, nil, manager.removePeer)
|
||||||
blockchain.GetBlockByHash, blockchain.CurrentHeader, blockchain.CurrentBlock, blockchain.CurrentFastBlock, blockchain.FastSyncCommitHead,
|
|
||||||
blockchain.GetTdByHash, blockchain.InsertHeaderChain, manager.blockchain.InsertChain, blockchain.InsertReceiptChain, blockchain.Rollback,
|
|
||||||
manager.removePeer)
|
|
||||||
|
|
||||||
validator := func(header *types.Header) error {
|
validator := func(header *types.Header) error {
|
||||||
return engine.VerifyHeader(blockchain, header, true)
|
return engine.VerifyHeader(blockchain, header, true)
|
||||||
|
|
|
@ -206,9 +206,7 @@ func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, network
|
||||||
}
|
}
|
||||||
|
|
||||||
if lightSync {
|
if lightSync {
|
||||||
manager.downloader = downloader.New(downloader.LightSync, chainDb, manager.eventMux, blockchain.HasHeader, nil, blockchain.GetHeaderByHash,
|
manager.downloader = downloader.New(downloader.LightSync, chainDb, manager.eventMux, nil, blockchain, removePeer)
|
||||||
nil, blockchain.CurrentHeader, nil, nil, nil, blockchain.GetTdByHash,
|
|
||||||
blockchain.InsertHeaderChain, nil, nil, blockchain.Rollback, removePeer)
|
|
||||||
manager.peers.notify((*downloaderPeerNotify)(manager))
|
manager.peers.notify((*downloaderPeerNotify)(manager))
|
||||||
manager.fetcher = newLightFetcher(manager)
|
manager.fetcher = newLightFetcher(manager)
|
||||||
}
|
}
|
||||||
|
|
|
@ -389,6 +389,21 @@ func (self *LightChain) CurrentHeader() *types.Header {
|
||||||
return self.hc.CurrentHeader()
|
return self.hc.CurrentHeader()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CurrentBlock exists for interface compatibility and always returns nil
|
||||||
|
func (self *LightChain) CurrentBlock() *types.Block {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentFastBlock exists for interface compatibility and always returns nil
|
||||||
|
func (self *LightChain) CurrentFastBlock() *types.Block {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FastSyncCommitHead exists for interface compatibility and does nothing
|
||||||
|
func (self *LightChain) FastSyncCommitHead(h common.Hash) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetTd retrieves a block's total difficulty in the canonical chain from the
|
// GetTd retrieves a block's total difficulty in the canonical chain from the
|
||||||
// database by hash and number, caching it if found.
|
// database by hash and number, caching it if found.
|
||||||
func (self *LightChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
func (self *LightChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
||||||
|
|
Loading…
Reference in New Issue