routing: update UTXO verification to use new interface, graph pruning too

This commit is contained in:
Olaoluwa Osuntokun 2018-07-17 19:17:19 -07:00
parent fb98f59407
commit 8c0a151cec
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21
2 changed files with 42 additions and 32 deletions

@ -10,15 +10,15 @@ import (
prand "math/rand"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/chainview"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
var (
@ -176,7 +176,7 @@ func (m *mockChain) addUtxo(op wire.OutPoint, out *wire.TxOut) {
m.utxos[op] = *out
m.Unlock()
}
func (m *mockChain) GetUtxo(op *wire.OutPoint, _ uint32) (*wire.TxOut, error) {
func (m *mockChain) GetUtxo(op *wire.OutPoint, _ []byte, _ uint32) (*wire.TxOut, error) {
m.RLock()
defer m.RUnlock()
@ -242,12 +242,12 @@ func (m *mockChainView) Reset() {
m.staleBlocks = make(chan *chainview.FilteredBlock, 10)
}
func (m *mockChainView) UpdateFilter(ops []wire.OutPoint, updateHeight uint32) error {
func (m *mockChainView) UpdateFilter(ops []channeldb.EdgePoint, updateHeight uint32) error {
m.Lock()
defer m.Unlock()
for _, op := range ops {
m.filter[op] = struct{}{}
m.filter[op.OutPoint] = struct{}{}
}
return nil

@ -967,7 +967,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
// to obtain the full funding outpoint that's encoded within
// the channel ID.
channelID := lnwire.NewShortChanIDFromInt(msg.ChannelID)
fundingPoint, err := r.fetchChanPoint(&channelID)
fundingPoint, _, err := r.fetchChanPoint(&channelID)
if err != nil {
r.rejectMtx.Lock()
r.rejectCache[msg.ChannelID] = struct{}{}
@ -977,11 +977,25 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
"chan_id=%v: %v", msg.ChannelID, err)
}
// Recreate witness output to be sure that declared in channel
// edge bitcoin keys and channel value corresponds to the
// reality.
witnessScript, err := lnwallet.GenMultiSigScript(
msg.BitcoinKey1Bytes[:], msg.BitcoinKey2Bytes[:],
)
if err != nil {
return err
}
fundingPkScript, err := lnwallet.WitnessScriptHash(witnessScript)
if err != nil {
return err
}
// Now that we have the funding outpoint of the channel, ensure
// that it hasn't yet been spent. If so, then this channel has
// been closed so we'll ignore it.
chanUtxo, err := r.cfg.Chain.GetUtxo(
fundingPoint, channelID.BlockHeight,
fundingPoint, fundingPkScript, channelID.BlockHeight,
)
if err != nil {
r.rejectMtx.Lock()
@ -993,26 +1007,14 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
fundingPoint, err)
}
// Recreate witness output to be sure that declared in channel
// edge bitcoin keys and channel value corresponds to the
// reality.
_, witnessOutput, err := lnwallet.GenFundingPkScript(
msg.BitcoinKey1Bytes[:], msg.BitcoinKey2Bytes[:],
chanUtxo.Value,
)
if err != nil {
return errors.Errorf("unable to create funding pk "+
"script: %v", err)
}
// By checking the equality of witness pkscripts we checks that
// funding witness script is multisignature lock which contains
// both local and remote public keys which was declared in
// channel edge and also that the announced channel value is
// right.
if !bytes.Equal(witnessOutput.PkScript, chanUtxo.PkScript) {
if !bytes.Equal(fundingPkScript, chanUtxo.PkScript) {
return errors.Errorf("pkScript mismatch: expected %x, "+
"got %x", witnessOutput.PkScript, chanUtxo.PkScript)
"got %x", fundingPkScript, chanUtxo.PkScript)
}
// TODO(roasbeef): this is a hack, needs to be removed
@ -1034,7 +1036,12 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
// update the current UTXO filter within our active
// FilteredChainView so we are notified if/when this channel is
// closed.
filterUpdate := []wire.OutPoint{*fundingPoint}
filterUpdate := []channeldb.EdgePoint{
{
FundingPkScript: fundingPkScript,
OutPoint: *fundingPoint,
},
}
err = r.cfg.ChainView.UpdateFilter(
filterUpdate, atomic.LoadUint32(&r.bestHeight),
)
@ -1105,7 +1112,9 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
// Before we can update the channel information, we'll
// ensure that the target channel is still open by
// querying the utxo-set for its existence.
chanPoint, err := r.fetchChanPoint(&channelID)
chanPoint, fundingPkScript, err := r.fetchChanPoint(
&channelID,
)
if err != nil {
r.rejectMtx.Lock()
r.rejectCache[msg.ChannelID] = struct{}{}
@ -1116,7 +1125,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
msg.ChannelID, err)
}
_, err = r.cfg.Chain.GetUtxo(
chanPoint, channelID.BlockHeight,
chanPoint, fundingPkScript, channelID.BlockHeight,
)
if err != nil {
r.rejectMtx.Lock()
@ -1157,21 +1166,22 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
}
// fetchChanPoint retrieves the original outpoint which is encoded within the
// channelID.
// channelID. This method also return the public key script for the target
// transaction.
//
// TODO(roasbeef): replace with call to GetBlockTransaction? (would allow to
// later use getblocktxn)
func (r *ChannelRouter) fetchChanPoint(chanID *lnwire.ShortChannelID) (*wire.OutPoint, error) {
func (r *ChannelRouter) fetchChanPoint(chanID *lnwire.ShortChannelID) (*wire.OutPoint, []byte, error) {
// First fetch the block hash by the block number encoded, then use
// that hash to fetch the block itself.
blockNum := int64(chanID.BlockHeight)
blockHash, err := r.cfg.Chain.GetBlockHash(blockNum)
if err != nil {
return nil, err
return nil, nil, err
}
fundingBlock, err := r.cfg.Chain.GetBlock(blockHash)
if err != nil {
return nil, err
return nil, nil, err
}
// As a sanity check, ensure that the advertised transaction index is
@ -1179,7 +1189,7 @@ func (r *ChannelRouter) fetchChanPoint(chanID *lnwire.ShortChannelID) (*wire.Out
// block.
numTxns := uint32(len(fundingBlock.Transactions))
if chanID.TxIndex > numTxns-1 {
return nil, fmt.Errorf("tx_index=#%v is out of range "+
return nil, 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))
}
@ -1190,7 +1200,7 @@ func (r *ChannelRouter) fetchChanPoint(chanID *lnwire.ShortChannelID) (*wire.Out
return &wire.OutPoint{
Hash: fundingTx.TxHash(),
Index: uint32(chanID.TxPosition),
}, nil
}, fundingTx.TxOut[chanID.TxPosition].PkScript, nil
}
// routingMsg couples a routing related routing topology update to the