Skip to content

Commit

Permalink
Merge pull request #108 from halseth/query-sync-misaligned-intervals
Browse files Browse the repository at this point in the history
Handle misaligned intervals on sync
  • Loading branch information
Roasbeef authored Oct 26, 2018
2 parents 23d294f + bd61bc3 commit 9a42f7d
Show file tree
Hide file tree
Showing 2 changed files with 524 additions and 209 deletions.
47 changes: 37 additions & 10 deletions blockmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ type blockManager struct {
// headers that we've verified in the past 10 seconds.
fltrHeaderProgessLogger *headerProgressLogger

// genesisHeader is the filter header of the genesis block.
genesisHeader chainhash.Hash

// headerTip will be set to the current block header tip at all times.
// Callers MUST hold the lock below each time they read/write from
// this field.
Expand Down Expand Up @@ -207,6 +210,14 @@ func newBlockManager(s *ChainService) (*blockManager, error) {
bm.newHeadersSignal = sync.NewCond(&bm.newHeadersMtx)
bm.newFilterHeadersSignal = sync.NewCond(&bm.newFilterHeadersMtx)

// We fetch the genesis header to use for verifying the first received
// interval.
genesisHeader, err := s.RegFilterHeaders.FetchHeaderByHeight(0)
if err != nil {
return nil, err
}
bm.genesisHeader = *genesisHeader

// Initialize the next checkpoint based on the current height.
header, height, err := s.BlockHeaders.ChainTip()
if err != nil {
Expand Down Expand Up @@ -874,8 +885,19 @@ func (b *blockManager) getCheckpointedCFHeaders(checkpoints []*chainhash.Hash,
return false
}

// Use either the genesis header or the previous
// checkpoint index as the previous checkpoint when
// verifying that the filter headers in the response
// match up.
prevCheckpoint := &b.genesisHeader
if checkPointIndex > 0 {
prevCheckpoint = checkpoints[checkPointIndex-1]

}
nextCheckpoint := checkpoints[checkPointIndex]

// The response doesn't match the checkpoint.
if !verifyCheckpoint(checkpoints[checkPointIndex], r) {
if !verifyCheckpoint(prevCheckpoint, nextCheckpoint, r) {
log.Warnf("Checkpoints at index %v don't match " +
"response!!!")
return false
Expand All @@ -893,7 +915,7 @@ func (b *blockManager) getCheckpointedCFHeaders(checkpoints []*chainhash.Hash,
// Find the first and last height for the blocks
// represented by this message.
startHeight := checkPointIndex*wire.CFCheckptInterval + 1
lastHeight := startHeight + wire.CFCheckptInterval
lastHeight := (checkPointIndex + 1) * wire.CFCheckptInterval

log.Debugf("Got cfheaders from height=%v to "+
"height=%v, prev_hash=%v", startHeight,
Expand Down Expand Up @@ -1003,14 +1025,14 @@ func (b *blockManager) writeCFHeadersMsg(msg *wire.MsgCFHeaders,

// Check that the PrevFilterHeader is the same as the last stored so we
// can prevent misalignment.
tip, _, err := store.ChainTip()
tip, tipHeight, err := store.ChainTip()
if err != nil {
return nil, err
}
if *tip != msg.PrevFilterHeader {
return nil, fmt.Errorf("attempt to write cfheaders out of "+
"order! Tip=%v, prev_hash=%v.", *tip,
msg.PrevFilterHeader)
"order! Tip=%v (height=%v), prev_hash=%v.", *tip,
tipHeight, msg.PrevFilterHeader)
}

// Cycle through the headers and compute each header based on the prev
Expand Down Expand Up @@ -1054,8 +1076,8 @@ func (b *blockManager) writeCFHeadersMsg(msg *wire.MsgCFHeaders,
headerBatch[numHeaders-1].HeaderHash = lastHash
headerBatch[numHeaders-1].Height = lastHeight

log.Debugf("Writing filter headers up to height=%v, hash=%v",
lastHeight, lastHash)
log.Debugf("Writing filter headers up to height=%v, hash=%v, "+
"new_tip=%v", lastHeight, lastHash, lastHeader)

// Write the header batch.
err = store.WriteHeaders(headerBatch...)
Expand Down Expand Up @@ -1111,9 +1133,14 @@ func minCheckpointHeight(checkpoints map[string][]*chainhash.Hash) uint32 {
}

// verifyHeaderCheckpoint verifies that a CFHeaders message matches the passed
// checkpoint. It assumes everything else has been checked, including filter
// checkpoints. It assumes everything else has been checked, including filter
// type and stop hash matches, and returns true if matching and false if not.
func verifyCheckpoint(checkpoint *chainhash.Hash, cfheaders *wire.MsgCFHeaders) bool {
func verifyCheckpoint(prevCheckpoint, nextCheckpoint *chainhash.Hash,
cfheaders *wire.MsgCFHeaders) bool {

if *prevCheckpoint != cfheaders.PrevFilterHeader {
return false
}

lastHeader := cfheaders.PrevFilterHeader
for _, hash := range cfheaders.FilterHashes {
Expand All @@ -1122,7 +1149,7 @@ func verifyCheckpoint(checkpoint *chainhash.Hash, cfheaders *wire.MsgCFHeaders)
)
}

return lastHeader == *checkpoint
return lastHeader == *nextCheckpoint
}

// resolveConflict finds the correct checkpoint information, rewinds the header
Expand Down
Loading

0 comments on commit 9a42f7d

Please sign in to comment.