core, eth/downloader: fix ancestor lookup for fast sync
This commit is contained in:
parent
51b2f1620c
commit
accc0fab4f
@ -561,6 +561,17 @@ func (bc *BlockChain) HasBlock(hash common.Hash, number uint64) bool {
|
|||||||
return rawdb.HasBody(bc.db, hash, number)
|
return rawdb.HasBody(bc.db, hash, number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasFastBlock checks if a fast block is fully present in the database or not.
|
||||||
|
func (bc *BlockChain) HasFastBlock(hash common.Hash, number uint64) bool {
|
||||||
|
if !bc.HasBlock(hash, number) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if bc.receiptsCache.Contains(hash) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return rawdb.HasReceipts(bc.db, hash, number)
|
||||||
|
}
|
||||||
|
|
||||||
// HasState checks if state trie is fully present in the database or not.
|
// HasState checks if state trie is fully present in the database or not.
|
||||||
func (bc *BlockChain) HasState(hash common.Hash) bool {
|
func (bc *BlockChain) HasState(hash common.Hash) bool {
|
||||||
_, err := bc.stateCache.OpenTrie(hash)
|
_, err := bc.stateCache.OpenTrie(hash)
|
||||||
@ -618,12 +629,10 @@ func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts {
|
|||||||
if receipts, ok := bc.receiptsCache.Get(hash); ok {
|
if receipts, ok := bc.receiptsCache.Get(hash); ok {
|
||||||
return receipts.(types.Receipts)
|
return receipts.(types.Receipts)
|
||||||
}
|
}
|
||||||
|
|
||||||
number := rawdb.ReadHeaderNumber(bc.db, hash)
|
number := rawdb.ReadHeaderNumber(bc.db, hash)
|
||||||
if number == nil {
|
if number == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
receipts := rawdb.ReadReceipts(bc.db, hash, *number)
|
receipts := rawdb.ReadReceipts(bc.db, hash, *number)
|
||||||
bc.receiptsCache.Add(hash, receipts)
|
bc.receiptsCache.Add(hash, receipts)
|
||||||
return receipts
|
return receipts
|
||||||
|
@ -271,6 +271,15 @@ func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasReceipts verifies the existence of all the transaction receipts belonging
|
||||||
|
// to a block.
|
||||||
|
func HasReceipts(db DatabaseReader, hash common.Hash, number uint64) bool {
|
||||||
|
if has, err := db.Has(blockReceiptsKey(number, hash)); !has || err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// ReadReceipts retrieves all the transaction receipts belonging to a block.
|
// ReadReceipts retrieves all the transaction receipts belonging to a block.
|
||||||
func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
|
func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
|
||||||
// Retrieve the flattened receipt slice
|
// Retrieve the flattened receipt slice
|
||||||
|
@ -181,6 +181,9 @@ type BlockChain interface {
|
|||||||
// HasBlock verifies a block's presence in the local chain.
|
// HasBlock verifies a block's presence in the local chain.
|
||||||
HasBlock(common.Hash, uint64) bool
|
HasBlock(common.Hash, uint64) bool
|
||||||
|
|
||||||
|
// HasFastBlock verifies a fast block's presence in the local chain.
|
||||||
|
HasFastBlock(common.Hash, uint64) bool
|
||||||
|
|
||||||
// GetBlockByHash retrieves a block from the local chain.
|
// GetBlockByHash retrieves a block from the local chain.
|
||||||
GetBlockByHash(common.Hash) *types.Block
|
GetBlockByHash(common.Hash) *types.Block
|
||||||
|
|
||||||
@ -663,8 +666,9 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header)
|
|||||||
if localHeight >= MaxForkAncestry {
|
if localHeight >= MaxForkAncestry {
|
||||||
floor = int64(localHeight - MaxForkAncestry)
|
floor = int64(localHeight - MaxForkAncestry)
|
||||||
}
|
}
|
||||||
|
|
||||||
from, count, skip, max := calculateRequestSpan(remoteHeight, localHeight)
|
from, count, skip, max := calculateRequestSpan(remoteHeight, localHeight)
|
||||||
|
|
||||||
|
p.log.Trace("Span searching for common ancestor", "count", count, "from", from, "skip", skip)
|
||||||
go p.peer.RequestHeadersByNumber(uint64(from), count, skip, false)
|
go p.peer.RequestHeadersByNumber(uint64(from), count, skip, false)
|
||||||
|
|
||||||
// Wait for the remote response to the head fetch
|
// Wait for the remote response to the head fetch
|
||||||
@ -708,8 +712,17 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header)
|
|||||||
// Otherwise check if we already know the header or not
|
// Otherwise check if we already know the header or not
|
||||||
h := headers[i].Hash()
|
h := headers[i].Hash()
|
||||||
n := headers[i].Number.Uint64()
|
n := headers[i].Number.Uint64()
|
||||||
if (d.mode == FullSync && d.blockchain.HasBlock(h, n)) ||
|
|
||||||
(d.mode != FullSync && d.lightchain.HasHeader(h, n)) {
|
var known bool
|
||||||
|
switch d.mode {
|
||||||
|
case FullSync:
|
||||||
|
known = d.blockchain.HasBlock(h, n)
|
||||||
|
case FastSync:
|
||||||
|
known = d.blockchain.HasFastBlock(h, n)
|
||||||
|
default:
|
||||||
|
known = d.lightchain.HasHeader(h, n)
|
||||||
|
}
|
||||||
|
if known {
|
||||||
number, hash = n, h
|
number, hash = n, h
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -738,6 +751,8 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header)
|
|||||||
if floor > 0 {
|
if floor > 0 {
|
||||||
start = uint64(floor)
|
start = uint64(floor)
|
||||||
}
|
}
|
||||||
|
p.log.Trace("Binary searching for common ancestor", "start", start, "end", end)
|
||||||
|
|
||||||
for start+1 < end {
|
for start+1 < end {
|
||||||
// Split our chain interval in two, and request the hash to cross check
|
// Split our chain interval in two, and request the hash to cross check
|
||||||
check := (start + end) / 2
|
check := (start + end) / 2
|
||||||
@ -770,7 +785,17 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header)
|
|||||||
// Modify the search interval based on the response
|
// Modify the search interval based on the response
|
||||||
h := headers[0].Hash()
|
h := headers[0].Hash()
|
||||||
n := headers[0].Number.Uint64()
|
n := headers[0].Number.Uint64()
|
||||||
if (d.mode == FullSync && !d.blockchain.HasBlock(h, n)) || (d.mode != FullSync && !d.lightchain.HasHeader(h, n)) {
|
|
||||||
|
var known bool
|
||||||
|
switch d.mode {
|
||||||
|
case FullSync:
|
||||||
|
known = d.blockchain.HasBlock(h, n)
|
||||||
|
case FastSync:
|
||||||
|
known = d.blockchain.HasFastBlock(h, n)
|
||||||
|
default:
|
||||||
|
known = d.lightchain.HasHeader(h, n)
|
||||||
|
}
|
||||||
|
if !known {
|
||||||
end = check
|
end = check
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,15 @@ func (dl *downloadTester) HasBlock(hash common.Hash, number uint64) bool {
|
|||||||
return dl.GetBlockByHash(hash) != nil
|
return dl.GetBlockByHash(hash) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasFastBlock checks if a block is present in the testers canonical chain.
|
||||||
|
func (dl *downloadTester) HasFastBlock(hash common.Hash, number uint64) bool {
|
||||||
|
dl.lock.RLock()
|
||||||
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
|
_, ok := dl.ownReceipts[hash]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
// GetHeader retrieves a header from the testers canonical chain.
|
// GetHeader retrieves a header from the testers canonical chain.
|
||||||
func (dl *downloadTester) GetHeaderByHash(hash common.Hash) *types.Header {
|
func (dl *downloadTester) GetHeaderByHash(hash common.Hash) *types.Header {
|
||||||
dl.lock.RLock()
|
dl.lock.RLock()
|
||||||
@ -235,6 +244,7 @@ func (dl *downloadTester) InsertChain(blocks types.Blocks) (i int, err error) {
|
|||||||
dl.ownHeaders[block.Hash()] = block.Header()
|
dl.ownHeaders[block.Hash()] = block.Header()
|
||||||
}
|
}
|
||||||
dl.ownBlocks[block.Hash()] = block
|
dl.ownBlocks[block.Hash()] = block
|
||||||
|
dl.ownReceipts[block.Hash()] = make(types.Receipts, 0)
|
||||||
dl.stateDb.Put(block.Root().Bytes(), []byte{0x00})
|
dl.stateDb.Put(block.Root().Bytes(), []byte{0x00})
|
||||||
dl.ownChainTd[block.Hash()] = new(big.Int).Add(dl.ownChainTd[block.ParentHash()], block.Difficulty())
|
dl.ownChainTd[block.Hash()] = new(big.Int).Add(dl.ownChainTd[block.ParentHash()], block.Difficulty())
|
||||||
}
|
}
|
||||||
@ -375,28 +385,28 @@ func (dlp *downloadTesterPeer) RequestNodeData(hashes []common.Hash) error {
|
|||||||
// assertOwnChain checks if the local chain contains the correct number of items
|
// assertOwnChain checks if the local chain contains the correct number of items
|
||||||
// of the various chain components.
|
// of the various chain components.
|
||||||
func assertOwnChain(t *testing.T, tester *downloadTester, length int) {
|
func assertOwnChain(t *testing.T, tester *downloadTester, length int) {
|
||||||
|
// Mark this method as a helper to report errors at callsite, not in here
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
assertOwnForkedChain(t, tester, 1, []int{length})
|
assertOwnForkedChain(t, tester, 1, []int{length})
|
||||||
}
|
}
|
||||||
|
|
||||||
// assertOwnForkedChain checks if the local forked chain contains the correct
|
// assertOwnForkedChain checks if the local forked chain contains the correct
|
||||||
// number of items of the various chain components.
|
// number of items of the various chain components.
|
||||||
func assertOwnForkedChain(t *testing.T, tester *downloadTester, common int, lengths []int) {
|
func assertOwnForkedChain(t *testing.T, tester *downloadTester, common int, lengths []int) {
|
||||||
// Initialize the counters for the first fork
|
// Mark this method as a helper to report errors at callsite, not in here
|
||||||
headers, blocks, receipts := lengths[0], lengths[0], lengths[0]-fsMinFullBlocks
|
t.Helper()
|
||||||
|
|
||||||
|
// Initialize the counters for the first fork
|
||||||
|
headers, blocks, receipts := lengths[0], lengths[0], lengths[0]
|
||||||
|
|
||||||
if receipts < 0 {
|
|
||||||
receipts = 1
|
|
||||||
}
|
|
||||||
// Update the counters for each subsequent fork
|
// Update the counters for each subsequent fork
|
||||||
for _, length := range lengths[1:] {
|
for _, length := range lengths[1:] {
|
||||||
headers += length - common
|
headers += length - common
|
||||||
blocks += length - common
|
blocks += length - common
|
||||||
receipts += length - common - fsMinFullBlocks
|
receipts += length - common
|
||||||
}
|
}
|
||||||
switch tester.downloader.mode {
|
if tester.downloader.mode == LightSync {
|
||||||
case FullSync:
|
|
||||||
receipts = 1
|
|
||||||
case LightSync:
|
|
||||||
blocks, receipts = 1, 1
|
blocks, receipts = 1, 1
|
||||||
}
|
}
|
||||||
if hs := len(tester.ownHeaders); hs != headers {
|
if hs := len(tester.ownHeaders); hs != headers {
|
||||||
@ -1150,7 +1160,9 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkProgress(t *testing.T, d *Downloader, stage string, want ethereum.SyncProgress) {
|
func checkProgress(t *testing.T, d *Downloader, stage string, want ethereum.SyncProgress) {
|
||||||
|
// Mark this method as a helper to report errors at callsite, not in here
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
p := d.Progress()
|
p := d.Progress()
|
||||||
p.KnownStates, p.PulledStates = 0, 0
|
p.KnownStates, p.PulledStates = 0, 0
|
||||||
want.KnownStates, want.PulledStates = 0, 0
|
want.KnownStates, want.PulledStates = 0, 0
|
||||||
|
Loading…
Reference in New Issue
Block a user