discovery: cover requested range in ReplyChannelRange messages

In order to properly adhere to the spec, when handling a
QueryChannelRange message, we must reply with a series of
ReplyChannelRange messages, that when consumed together cover the
entirety of the block range requested.
This commit is contained in:
Wilmer Paulino 2019-12-13 16:08:10 -08:00
parent 1f781ea431
commit c7c0853531
No known key found for this signature in database
GPG Key ID: 6DF57B9F9514972F
2 changed files with 68 additions and 48 deletions

@ -825,13 +825,13 @@ func (g *GossipSyncer) replyChanRangeQuery(query *lnwire.QueryChannelRange) erro
// TODO(roasbeef): means can't send max uint above? // TODO(roasbeef): means can't send max uint above?
// * or make internal 64 // * or make internal 64
// In the base case (no actual response) the first block and the last // In the base case (no actual response) the first block and last block
// block in the query will be the same. In the loop below, we'll update // will match those of the query. In the loop below, we'll update these
// these two variables incrementally with each chunk to properly // two variables incrementally with each chunk to properly compute the
// compute the starting block for each response and the number of // starting block for each response and the number of blocks in a
// blocks in a response. // response.
firstBlockHeight := query.FirstBlockHeight firstBlockHeight := startBlock
lastBlockHeight := query.FirstBlockHeight lastBlockHeight := endBlock
numChannels := int32(len(channelRange)) numChannels := int32(len(channelRange))
numChansSent := int32(0) numChansSent := int32(0)
@ -867,8 +867,25 @@ func (g *GossipSyncer) replyChanRangeQuery(query *lnwire.QueryChannelRange) erro
// update our pointers to the first and last blocks for each // update our pointers to the first and last blocks for each
// response. // response.
if len(channelChunk) > 0 { if len(channelChunk) > 0 {
firstBlockHeight = channelChunk[0].BlockHeight // If this is the first response we'll send, we'll point
lastBlockHeight = channelChunk[len(channelChunk)-1].BlockHeight // the first block to the first block in the query.
// Otherwise, we'll continue from the block we left off
// at.
if numChansSent == 0 {
firstBlockHeight = startBlock
} else {
firstBlockHeight = lastBlockHeight
}
// If this is the last response we'll send, we'll point
// the last block to the last block of the query.
// Otherwise, we'll set it to the height of the last
// channel in the chunk.
if isFinalChunk {
lastBlockHeight = endBlock
} else {
lastBlockHeight = channelChunk[len(channelChunk)-1].BlockHeight
}
} }
// The number of blocks contained in this response (the total // The number of blocks contained in this response (the total

@ -783,52 +783,55 @@ func TestGossipSyncerReplyChanRangeQuery(t *testing.T) {
t.Fatalf("expected ReplyChannelRange instead got %T", msg) t.Fatalf("expected ReplyChannelRange instead got %T", msg)
} }
// Only for the first iteration do we set the offset to // We'll determine the correct values of each field in
// zero as no chunks have been processed yet. For every // each response based on the order that they were sent.
// other iteration, we want to move forward by the var (
// chunkSize (from the staring block height). expectedFirstBlockHeight uint32
offset := 0 expectedNumBlocks uint32
if i != 0 { expectedComplete uint8
offset = 1 )
}
expectedFirstBlockHeight := (i+offset)*2 + startingBlockHeight
switch { switch {
// If this is not the last chunk, then Complete should // The first reply should range from our starting block
// be set to zero. Otherwise, it should be one. // height until it reaches its maximum capacity of
case i < 2 && rangeResp.Complete != 0: // channels.
t.Fatalf("non-final chunk should have "+ case i == 0:
"Complete=0: %v", spew.Sdump(rangeResp)) expectedFirstBlockHeight = startingBlockHeight
expectedNumBlocks = chunkSize + 1
case i < 2 && rangeResp.NumBlocks != chunkSize+1: // The last reply should range starting from the next
t.Fatalf("NumBlocks fields in resp "+ // block of our previous reply up until the ending
"incorrect: expected %v got %v", // height of the query. It should also have the Complete
chunkSize+1, rangeResp.NumBlocks) // bit set.
case i == numExpectedChunks-1:
expectedFirstBlockHeight = respMsgs[len(respMsgs)-1].BlockHeight
expectedNumBlocks = endingBlockHeight - expectedFirstBlockHeight + 1
expectedComplete = 1
case i < 2 && rangeResp.FirstBlockHeight != // Any intermediate replies should range starting from
uint32(expectedFirstBlockHeight): // the next block of our previous reply up until it
// reaches its maximum capacity of channels.
default:
expectedFirstBlockHeight = respMsgs[len(respMsgs)-1].BlockHeight
expectedNumBlocks = 5
}
t.Fatalf("FirstBlockHeight incorrect: "+ switch {
"expected %v got %v", case rangeResp.FirstBlockHeight != expectedFirstBlockHeight:
rangeResp.FirstBlockHeight, t.Fatalf("FirstBlockHeight in resp #%d "+
expectedFirstBlockHeight) "incorrect: expected %v, got %v", i+1,
case i == 2 && rangeResp.Complete != 1: expectedFirstBlockHeight,
t.Fatalf("final chunk should have "+ rangeResp.FirstBlockHeight)
"Complete=1: %v", spew.Sdump(rangeResp))
case i == 2 && rangeResp.NumBlocks != 1: case rangeResp.NumBlocks != expectedNumBlocks:
t.Fatalf("NumBlocks fields in resp "+ t.Fatalf("NumBlocks in resp #%d incorrect: "+
"incorrect: expected %v got %v", 1, "expected %v, got %v", i+1,
rangeResp.NumBlocks) expectedNumBlocks, rangeResp.NumBlocks)
case i == 2 && rangeResp.FirstBlockHeight !=
queryResp[len(queryResp)-1].BlockHeight:
t.Fatalf("FirstBlockHeight incorrect: "+
"expected %v got %v",
rangeResp.FirstBlockHeight,
queryResp[len(queryResp)-1].BlockHeight)
case rangeResp.Complete != expectedComplete:
t.Fatalf("Complete in resp #%d incorrect: "+
"expected %v, got %v", i+1,
expectedNumBlocks, rangeResp.Complete)
} }
respMsgs = append(respMsgs, rangeResp.ShortChanIDs...) respMsgs = append(respMsgs, rangeResp.ShortChanIDs...)