routing+funding: add new makeFundingScript to support reg and taproot channels

In this commit, we start to set _internally_ a new feature bit in the
channel announcements we generate. As these taproot channels can only be
unadvertised, this will never actually leak to the public network. The
funding manager will then set this field to allow the router to properly
validate these channels.
This commit is contained in:
Olaoluwa Osuntokun 2023-01-19 20:29:50 -08:00
parent 15978a8691
commit 7d7513aa3c
No known key found for this signature in database
GPG Key ID: 3BBD59E99B280306
2 changed files with 76 additions and 10 deletions

View File

@ -4068,6 +4068,18 @@ func (f *Manager) newChanAnnouncement(localPubKey,
ChainHash: chainHash, ChainHash: chainHash,
} }
// If this is a taproot channel, then we'll set a special bit in the
// feature vector to indicate to the routing layer that this needs a
// slightly different type of validation.
//
// TODO(roasbeef): temp, remove after gossip 1.5
if chanType.IsTaproot() {
log.Debugf("Applying taproot feature bit to "+
"ChannelAnnouncement for %v", chanID)
chanAnn.Features.Set(lnwire.SimpleTaprootChannelsRequired)
}
// The chanFlags field indicates which directed edge of the channel is // The chanFlags field indicates which directed edge of the channel is
// being updated within the ChannelUpdateAnnouncement announcement // being updated within the ChannelUpdateAnnouncement announcement
// below. A value of zero means it's the edge of the "first" node and 1 // below. A value of zero means it's the edge of the "first" node and 1

View File

@ -1416,6 +1416,67 @@ func (r *ChannelRouter) addZombieEdge(chanID uint64) error {
return nil return nil
} }
// makeFundingScript is used to make the funding script for both segwit v0 and
// segwit v1 (taproot) channels.
//
// TODO(roasbeef: export and use elsewhere?
func makeFundingScript(bitcoinKey1, bitcoinKey2 []byte,
chanFeatures []byte) ([]byte, error) {
legacyFundingScript := func() ([]byte, error) {
witnessScript, err := input.GenMultiSigScript(
bitcoinKey1, bitcoinKey2,
)
if err != nil {
return nil, err
}
pkScript, err := input.WitnessScriptHash(witnessScript)
if err != nil {
return nil, err
}
return pkScript, nil
}
if len(chanFeatures) == 0 {
return legacyFundingScript()
}
// In order to make the correct funding script, we'll need to parse the
// chanFeatures bytes into a feature vector we can interact with.
rawFeatures := lnwire.NewRawFeatureVector()
err := rawFeatures.Decode(bytes.NewReader(chanFeatures))
if err != nil {
return nil, fmt.Errorf("unable to parse chan feature "+
"bits: %w", err)
}
chanFeatureBits := lnwire.NewFeatureVector(
rawFeatures, lnwire.Features,
)
if chanFeatureBits.HasFeature(lnwire.SimpleTaprootChannelsOptional) {
pubKey1, err := btcec.ParsePubKey(bitcoinKey1)
if err != nil {
return nil, err
}
pubKey2, err := btcec.ParsePubKey(bitcoinKey2)
if err != nil {
return nil, err
}
fundingScript, _, err := input.GenTaprootFundingScript(
pubKey1, pubKey2, 0,
)
if err != nil {
return nil, err
}
return fundingScript, nil
}
return legacyFundingScript()
}
// processUpdate processes a new relate authenticated channel/edge, node or // processUpdate processes a new relate authenticated channel/edge, node or
// channel/edge update network update. If the update didn't affect the internal // channel/edge update network update. If the update didn't affect the internal
// state of the draft due to either being out of date, invalid, or redundant, // state of the draft due to either being out of date, invalid, or redundant,
@ -1525,16 +1586,13 @@ func (r *ChannelRouter) processUpdate(msg interface{},
// Recreate witness output to be sure that declared in channel // Recreate witness output to be sure that declared in channel
// edge bitcoin keys and channel value corresponds to the // edge bitcoin keys and channel value corresponds to the
// reality. // reality.
witnessScript, err := input.GenMultiSigScript( fundingPkScript, err := makeFundingScript(
msg.BitcoinKey1Bytes[:], msg.BitcoinKey2Bytes[:], msg.BitcoinKey1Bytes[:], msg.BitcoinKey2Bytes[:],
msg.Features,
) )
if err != nil { if err != nil {
return err return err
} }
pkScript, err := input.WitnessScriptHash(witnessScript)
if err != nil {
return err
}
// Next we'll validate that this channel is actually well // Next we'll validate that this channel is actually well
// formed. If this check fails, then this channel either // formed. If this check fails, then this channel either
@ -1544,7 +1602,7 @@ func (r *ChannelRouter) processUpdate(msg interface{},
Locator: &chanvalidate.ShortChanIDChanLocator{ Locator: &chanvalidate.ShortChanIDChanLocator{
ID: channelID, ID: channelID,
}, },
MultiSigPkScript: pkScript, MultiSigPkScript: fundingPkScript,
FundingTx: fundingTx, FundingTx: fundingTx,
}) })
if err != nil { if err != nil {
@ -1561,10 +1619,6 @@ func (r *ChannelRouter) processUpdate(msg interface{},
// Now that we have the funding outpoint of the channel, ensure // Now that we have the funding outpoint of the channel, ensure
// that it hasn't yet been spent. If so, then this channel has // that it hasn't yet been spent. If so, then this channel has
// been closed so we'll ignore it. // been closed so we'll ignore it.
fundingPkScript, err := input.WitnessScriptHash(witnessScript)
if err != nil {
return err
}
chanUtxo, err := r.cfg.Chain.GetUtxo( chanUtxo, err := r.cfg.Chain.GetUtxo(
fundingPoint, fundingPkScript, channelID.BlockHeight, fundingPoint, fundingPkScript, channelID.BlockHeight,
r.quit, r.quit,