mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-29 11:11:53 +01:00
graph+discovery: calculate funding tx script in gossiper
In preparation for an upcoming commit which will move all channel funding tx validation to the gossiper, we first move the helper method which helps build the expected funding transaction script based on the fields in the channel announcement. We will still want this script later on in the builder for updating the ChainView though, and so we pass this field along with the ChannelEdgeInfo. With this change, we can remove the TapscriptRoot field from the ChannelEdgeInfo since the only reason it was there was so that the builder could reconstruct the full funding script.
This commit is contained in:
parent
8a07bb0950
commit
7853e36488
@ -23,6 +23,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/graph"
|
||||
graphdb "github.com/lightningnetwork/lnd/graph/db"
|
||||
"github.com/lightningnetwork/lnd/graph/db/models"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnpeer"
|
||||
"github.com/lightningnetwork/lnd/lnutils"
|
||||
@ -2619,6 +2620,7 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg,
|
||||
|
||||
// If there were any optional message fields provided, we'll include
|
||||
// them in its serialized disk representation now.
|
||||
var tapscriptRoot fn.Option[chainhash.Hash]
|
||||
if nMsg.optionalMsgFields != nil {
|
||||
if nMsg.optionalMsgFields.capacity != nil {
|
||||
edge.Capacity = *nMsg.optionalMsgFields.capacity
|
||||
@ -2629,7 +2631,24 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(nMsg *networkMsg,
|
||||
}
|
||||
|
||||
// Optional tapscript root for custom channels.
|
||||
edge.TapscriptRoot = nMsg.optionalMsgFields.tapscriptRoot
|
||||
tapscriptRoot = nMsg.optionalMsgFields.tapscriptRoot
|
||||
}
|
||||
|
||||
// We only make use of the funding script later on during funding
|
||||
// transaction validation if AssumeChannelValid is not true.
|
||||
if !(d.cfg.AssumeChannelValid || d.cfg.IsAlias(scid)) {
|
||||
fundingPkScript, err := makeFundingScript(
|
||||
ann.BitcoinKey1[:], ann.BitcoinKey2[:], ann.Features,
|
||||
tapscriptRoot,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to make funding script %v", err)
|
||||
nMsg.err <- err
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
edge.FundingScript = fn.Some(fundingPkScript)
|
||||
}
|
||||
|
||||
log.Debugf("Adding edge for short_chan_id: %v", scid.ToUint64())
|
||||
@ -3598,3 +3617,57 @@ func (d *AuthenticatedGossiper) ShouldDisconnect(pubkey *btcec.PublicKey) (
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// makeFundingScript is used to make the funding script for both segwit v0 and
|
||||
// segwit v1 (taproot) channels.
|
||||
func makeFundingScript(bitcoinKey1, bitcoinKey2 []byte,
|
||||
features *lnwire.RawFeatureVector,
|
||||
tapscriptRoot fn.Option[chainhash.Hash]) ([]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 features.IsEmpty() {
|
||||
return legacyFundingScript()
|
||||
}
|
||||
|
||||
chanFeatureBits := lnwire.NewFeatureVector(features, lnwire.Features)
|
||||
if chanFeatureBits.HasFeature(
|
||||
lnwire.SimpleTaprootChannelsOptionalStaging,
|
||||
) {
|
||||
|
||||
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, tapscriptRoot,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(roasbeef): add tapscript root to gossip v1.5
|
||||
|
||||
return fundingScript, nil
|
||||
}
|
||||
|
||||
return legacyFundingScript()
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -10,15 +9,12 @@ import (
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/lightningnetwork/lnd/batch"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
graphdb "github.com/lightningnetwork/lnd/graph/db"
|
||||
"github.com/lightningnetwork/lnd/graph/db/models"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lnutils"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
@ -1024,72 +1020,6 @@ func (b *Builder) MarkZombieEdge(chanID uint64) error {
|
||||
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,
|
||||
tapscriptRoot fn.Option[chainhash.Hash]) ([]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.SimpleTaprootChannelsOptionalStaging,
|
||||
) {
|
||||
|
||||
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, tapscriptRoot,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(roasbeef): add tapscript root to gossip v1.5
|
||||
|
||||
return fundingScript, nil
|
||||
}
|
||||
|
||||
return legacyFundingScript()
|
||||
}
|
||||
|
||||
// routingMsg couples a routing related routing topology update to the
|
||||
// error channel.
|
||||
type routingMsg struct {
|
||||
@ -1278,6 +1208,16 @@ func (b *Builder) addEdge(edge *models.ChannelEdgeInfo,
|
||||
return nil
|
||||
}
|
||||
|
||||
// If AssumeChannelValid is false, then we expect the funding script to
|
||||
// be present on the edge since it would have been fetched when the
|
||||
// gossiper validated the announcement.
|
||||
fundingPkScript, err := edge.FundingScript.UnwrapOrErr(fmt.Errorf(
|
||||
"expected the funding transaction script to be set",
|
||||
))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Before we can add the channel to the channel graph, we need to obtain
|
||||
// the full funding outpoint that's encoded within the channel ID.
|
||||
channelID := lnwire.NewShortChanIDFromInt(edge.ChannelID)
|
||||
@ -1317,16 +1257,6 @@ func (b *Builder) addEdge(edge *models.ChannelEdgeInfo,
|
||||
return fmt.Errorf("%w: %w", ErrNoFundingTransaction, err)
|
||||
}
|
||||
|
||||
// Recreate witness output to be sure that declared in channel edge
|
||||
// bitcoin keys and channel value corresponds to the reality.
|
||||
fundingPkScript, err := makeFundingScript(
|
||||
edge.BitcoinKey1Bytes[:], edge.BitcoinKey2Bytes[:],
|
||||
edge.Features, edge.TapscriptRoot,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Next we'll validate that this channel is actually well formed. If
|
||||
// this check fails, then this channel either doesn't exist, or isn't
|
||||
// the one that was meant to be created according to the passed channel
|
||||
|
@ -63,10 +63,11 @@ type ChannelEdgeInfo struct {
|
||||
// the value output in the outpoint that created this channel.
|
||||
Capacity btcutil.Amount
|
||||
|
||||
// TapscriptRoot is the optional Merkle root of the tapscript tree if
|
||||
// this channel is a taproot channel that also commits to a tapscript
|
||||
// tree (custom channel).
|
||||
TapscriptRoot fn.Option[chainhash.Hash]
|
||||
// FundingScript holds the script of the channel's funding transaction.
|
||||
//
|
||||
// NOTE: this is not currently persisted and so will not be present if
|
||||
// the edge object is loaded from the database.
|
||||
FundingScript fn.Option[[]byte]
|
||||
|
||||
// ExtraOpaqueData is the set of data that was appended to this
|
||||
// message, some of which we may not actually know how to iterate or
|
||||
|
Loading…
x
Reference in New Issue
Block a user