From bf78122dc736ea1345cf73ddd13713d1b27e7375 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Mon, 6 Feb 2017 14:54:50 -0800 Subject: [PATCH] routing: ensure advertised transaction index is within bounds This commit fixes bug that could result in the panicking or crashing of nodes in the case of an at-funding-time reorganization within the network. In order to avoid such a case, we now ensure that the advertised transaction index is within the bounds of the block before attempting to access it. Note that this is a temporary patch commit until full advertisement validation which is implemented in the discovery PR lands in master. Additionally, better reorg handling during the funding process is being specified within the spec and will properly be implemented within lnd at a later date. --- routing/router.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/routing/router.go b/routing/router.go index bd74c6b42..f6d2234c1 100644 --- a/routing/router.go +++ b/routing/router.go @@ -3,6 +3,7 @@ package routing import ( "bytes" "encoding/hex" + "fmt" "sync" "sync/atomic" "time" @@ -429,7 +430,7 @@ func (r *ChannelRouter) networkHandler() { newBlock.Hash, blockHeight, numClosed) // The retransmission timer has ticked which indicates that we - // should broadcast our personal channel sot the network. This + // should broadcast our personal channel to the network. This // addresses the case of channel advertisements whether being // dropped, or not properly propagated through the network. case <-retransmitTimer.C: @@ -714,7 +715,7 @@ func (r *ChannelRouter) processNetworkAnnouncement(msg lnwire.Message) bool { // the UTXO itself so we can store the proper capacity. chanPoint, err := r.fetchChanPoint(&msg.ChannelID) if err != nil { - log.Errorf("unable to fetch chan point: %v", err) + log.Errorf("unable to fetch chan point for chan_id=%v: %v", chanID, err) return false } utxo, err := r.cfg.Chain.GetUtxo(&chanPoint.Hash, @@ -926,9 +927,18 @@ func (r *ChannelRouter) fetchChanPoint(chanID *lnwire.ChannelID) (*wire.OutPoint return nil, err } - // TODO(roasbeef): skipping validation here as - // the discovery service should handle full - // validate + // As a sanity check, ensure that the advertised transaction index is + // within the bounds of the total number of transactions within a + // block. + numTxns := uint32(len(fundingBlock.Transactions)) + if chanID.TxIndex > numTxns-1 { + return nil, fmt.Errorf("tx_index=#%v is out of range "+ + "(max_index=%v), network_chan_id=%v\n", chanID.TxIndex, + numTxns-1, spew.Sdump(chanID)) + } + + // TODO(roasbeef): skipping validation here as the discovery service + // should handle full validate // Finally once we have the block itself, we seek to the targeted // transaction index to obtain the funding output and txid.