Merge pull request #10182 from GeorgeTsagk/aux-feature-bits
Aux feature bits
This commit is contained in:
11 files changed
+227
-6
No files matched your search
@@ -213,6 +213,11 @@ type AuxComponents struct {
|
||||
// AuxContractResolver is an optional interface that can be used to
|
||||
// modify the way contracts are resolved.
|
||||
AuxContractResolver fn.Option[lnwallet.AuxContractResolver]
|
||||
|
||||
// AuxChannelNegotiator is an optional interface that allows aux channel
|
||||
// implementations to inject and process custom records over channel
|
||||
// related wire messages.
|
||||
AuxChannelNegotiator fn.Option[lnwallet.AuxChannelNegotiator]
|
||||
}
|
||||
|
||||
// DefaultWalletImpl is the default implementation of our normal, btcwallet
|
||||
|
||||
@@ -76,6 +76,11 @@ a certain amount of msats.
|
||||
[allow](https://github.com/lightningnetwork/lnd/pull/10087)
|
||||
`conf_target=1`. Previously they required `conf_target >= 2`.
|
||||
|
||||
* A new AuxComponent was added named AuxChannelNegotiator. This component aids
|
||||
with custom data communication for aux channels, by injecting and handling
|
||||
data in channel related wire messages. See
|
||||
[PR](https://github.com/lightningnetwork/lnd/pull/10182) for more info.
|
||||
|
||||
## RPC Additions
|
||||
* When querying [`ForwardingEvents`](https://github.com/lightningnetwork/lnd/pull/9813)
|
||||
logs, the response now include the incoming and outgoing htlc indices of the payment
|
||||
|
||||
@@ -568,6 +568,11 @@ type Config struct {
|
||||
// AuxResolver is an optional interface that can be used to modify the
|
||||
// way contracts are resolved.
|
||||
AuxResolver fn.Option[lnwallet.AuxContractResolver]
|
||||
|
||||
// AuxChannelNegotiator is an optional interface that allows aux channel
|
||||
// implementations to inject and process custom records over channel
|
||||
// related wire messages.
|
||||
AuxChannelNegotiator fn.Option[lnwallet.AuxChannelNegotiator]
|
||||
}
|
||||
|
||||
// Manager acts as an orchestrator/bridge between the wallet's
|
||||
@@ -4019,6 +4024,14 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, //nolint:funlen
|
||||
|
||||
defer f.wg.Done()
|
||||
|
||||
// Notify the aux hook that the specified peer just established a
|
||||
// channel with us, identified by the given channel ID.
|
||||
f.cfg.AuxChannelNegotiator.WhenSome(
|
||||
func(acn lnwallet.AuxChannelNegotiator) {
|
||||
acn.ProcessChannelReady(msg.ChanID, peer.PubKey())
|
||||
},
|
||||
)
|
||||
|
||||
// If we are in development mode, we'll wait for specified duration
|
||||
// before processing the channel ready message.
|
||||
if f.cfg.Dev != nil {
|
||||
|
||||
@@ -298,6 +298,11 @@ type ChannelLinkConfig struct {
|
||||
// used to manage the bandwidth of the link.
|
||||
AuxTrafficShaper fn.Option[AuxTrafficShaper]
|
||||
|
||||
// AuxChannelNegotiator is an optional interface that allows aux channel
|
||||
// implementations to inject and process custom records over channel
|
||||
// related wire messages.
|
||||
AuxChannelNegotiator fn.Option[lnwallet.AuxChannelNegotiator]
|
||||
|
||||
// QuiescenceTimeout is the max duration that the channel can be
|
||||
// quiesced. Any dependent protocols (dynamic commitments, splicing,
|
||||
// etc.) must finish their operations under this timeout value,
|
||||
@@ -987,6 +992,22 @@ func (l *channelLink) syncChanStates(ctx context.Context) error {
|
||||
// In any case, we'll then process their ChanSync message.
|
||||
l.log.Info("received re-establishment message from remote side")
|
||||
|
||||
// If we have an AuxChannelNegotiator we notify any external
|
||||
// component for this message. This serves as a notification
|
||||
// that the reestablish message was received.
|
||||
l.cfg.AuxChannelNegotiator.WhenSome(
|
||||
func(acn lnwallet.AuxChannelNegotiator) {
|
||||
fundingPoint := l.channel.ChannelPoint()
|
||||
cid := lnwire.NewChanIDFromOutPoint(
|
||||
fundingPoint,
|
||||
)
|
||||
|
||||
acn.ProcessReestablish(
|
||||
cid, l.cfg.Peer.PubKey(),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
var (
|
||||
openedCircuits []CircuitKey
|
||||
closedCircuits []CircuitKey
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
)
|
||||
|
||||
@@ -97,6 +98,10 @@ type AuxChanState struct {
|
||||
// funding output.
|
||||
TapscriptRoot fn.Option[chainhash.Hash]
|
||||
|
||||
// PeerPubKey is the peer pub key of the peer we've established this
|
||||
// channel with.
|
||||
PeerPubKey route.Vertex
|
||||
|
||||
// CustomBlob is an optional blob that can be used to store information
|
||||
// specific to a custom channel type. This information is only created
|
||||
// at channel funding time, and after wards is to be considered
|
||||
@@ -106,6 +111,8 @@ type AuxChanState struct {
|
||||
|
||||
// NewAuxChanState creates a new AuxChanState from the given channel state.
|
||||
func NewAuxChanState(chanState *channeldb.OpenChannel) AuxChanState {
|
||||
peerPub := chanState.IdentityPub.SerializeCompressed()
|
||||
|
||||
return AuxChanState{
|
||||
ChanType: chanState.ChanType,
|
||||
FundingOutpoint: chanState.FundingOutpoint,
|
||||
@@ -116,6 +123,7 @@ func NewAuxChanState(chanState *channeldb.OpenChannel) AuxChanState {
|
||||
RemoteChanCfg: chanState.RemoteChanCfg,
|
||||
ThawHeight: chanState.ThawHeight,
|
||||
TapscriptRoot: chanState.TapscriptRoot,
|
||||
PeerPubKey: route.Vertex(peerPub),
|
||||
CustomBlob: chanState.CustomBlob,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
)
|
||||
|
||||
// AuxChannelNegotiator is an interface that allows aux channel implementations
|
||||
// to inject or handle custom records in the init message that is used when
|
||||
// establishing a connection with a peer. It may also notify the aux channel
|
||||
// implementation for the channel ready or channel reestablish events, which
|
||||
// mark the channel as ready to use.
|
||||
type AuxChannelNegotiator interface {
|
||||
// GetInitRecords is called when sending an init message to a peer.
|
||||
// It returns custom records to include in the init message TLVs. The
|
||||
// implementation can decide which records to include based on the peer
|
||||
// identity.
|
||||
GetInitRecords(peer route.Vertex) (lnwire.CustomRecords, error)
|
||||
|
||||
// ProcessInitRecords handles received init records from a peer. The
|
||||
// implementation can store state internally to affect future
|
||||
// channel operations with this peer.
|
||||
ProcessInitRecords(peer route.Vertex,
|
||||
customRecords lnwire.CustomRecords) error
|
||||
|
||||
// ProcessChannelReady handles the event of marking a channel identified
|
||||
// by its channel ID as ready to use. We also provide the peer the
|
||||
// channel was established with.
|
||||
ProcessChannelReady(cid lnwire.ChannelID, peer route.Vertex)
|
||||
|
||||
// ProcessReestablish handles the received channel_reestablish message
|
||||
// which marks a channel identified by its cid as ready to use again.
|
||||
ProcessReestablish(cid lnwire.ChannelID, peer route.Vertex)
|
||||
}
|
||||
+29
-4
@@ -24,6 +24,10 @@ type Init struct {
|
||||
// Features field.
|
||||
Features *RawFeatureVector
|
||||
|
||||
// CustomRecords maps TLV types to byte slices, storing arbitrary data
|
||||
// intended for inclusion in the ExtraData field of the init message.
|
||||
CustomRecords CustomRecords
|
||||
|
||||
// ExtraData is the set of data that was appended to this message to
|
||||
// fill out the full maximum transport message size. These fields can
|
||||
// be used to specify optional data such as custom TLV fields.
|
||||
@@ -35,7 +39,6 @@ func NewInitMessage(gf *RawFeatureVector, f *RawFeatureVector) *Init {
|
||||
return &Init{
|
||||
GlobalFeatures: gf,
|
||||
Features: f,
|
||||
ExtraData: make([]byte, 0),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,11 +55,28 @@ var _ SizeableMessage = (*Init)(nil)
|
||||
//
|
||||
// This is part of the lnwire.Message interface.
|
||||
func (msg *Init) Decode(r io.Reader, pver uint32) error {
|
||||
return ReadElements(r,
|
||||
var msgExtraData ExtraOpaqueData
|
||||
|
||||
err := ReadElements(r,
|
||||
&msg.GlobalFeatures,
|
||||
&msg.Features,
|
||||
&msg.ExtraData,
|
||||
&msgExtraData,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
customRecords, _, extraDData, err := ParseAndExtractCustomRecords(
|
||||
msgExtraData,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg.CustomRecords = customRecords
|
||||
msg.ExtraData = extraDData
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encode serializes the target Init into the passed io.Writer observing
|
||||
@@ -72,7 +92,12 @@ func (msg *Init) Encode(w *bytes.Buffer, pver uint32) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return WriteBytes(w, msg.ExtraData)
|
||||
extraData, err := MergeAndEncode(nil, msg.ExtraData, msg.CustomRecords)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return WriteBytes(w, extraData)
|
||||
}
|
||||
|
||||
// MsgType returns the integer uniquely identifying this message type on the
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestInitEncodeDecode checks that we can encode and decode an Init message
|
||||
// to and from a byte stream.
|
||||
func TestInitEncodeDecode(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// These are the raw bytes that we expect to be generated from the
|
||||
// sample Init message.
|
||||
rawBytes := []byte{
|
||||
// GlobalFeatures
|
||||
0x00, 0x01, 0xc0,
|
||||
|
||||
// Features
|
||||
0x00, 0x01, 0xc0,
|
||||
|
||||
// ExtraData - unknown odd-type TLV record.
|
||||
0x6f, // type (111)
|
||||
0x02, // length
|
||||
0x79, 0x79, // value
|
||||
|
||||
// ExtraData - custom TLV record.
|
||||
// TLV record for type 67676
|
||||
0xfe, 0x00, 0x01, 0x08, 0x6c, // type (67676)
|
||||
0x05, // length
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, // value
|
||||
|
||||
// ExtraData - custom TLV record.
|
||||
// TLV record for type 67777
|
||||
0xfe, 0x00, 0x01, 0x08, 0xc1, // type (67777)
|
||||
0x03, // length
|
||||
0x01, 0x02, 0x03, // value
|
||||
}
|
||||
|
||||
// Create a new empty message and decode the raw bytes into it.
|
||||
msg := &Init{}
|
||||
r := bytes.NewReader(rawBytes)
|
||||
err := msg.Decode(r, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, msg.GlobalFeatures)
|
||||
require.NotNil(t, msg.Features)
|
||||
require.NotNil(t, msg.CustomRecords)
|
||||
require.NotNil(t, msg.ExtraData)
|
||||
|
||||
// Next, encode the message back into a new byte buffer.
|
||||
var b bytes.Buffer
|
||||
err = msg.Encode(&b, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
// The re-encoded bytes should be exactly the same as the original raw
|
||||
// bytes.
|
||||
require.Equal(t, rawBytes, b.Bytes())
|
||||
}
|
||||
@@ -1188,6 +1188,10 @@ func (msg *Init) RandTestMessage(t *rapid.T) Message {
|
||||
local.Set(bit)
|
||||
}
|
||||
|
||||
ignoreRecords := fn.NewSet[uint64]()
|
||||
|
||||
msg.ExtraData = RandExtraOpaqueData(t, ignoreRecords)
|
||||
|
||||
return NewInitMessage(global, local)
|
||||
}
|
||||
|
||||
|
||||
+45
-2
@@ -457,6 +457,11 @@ type Config struct {
|
||||
// used to modify the way the co-op close transaction is constructed.
|
||||
AuxChanCloser fn.Option[chancloser.AuxChanCloser]
|
||||
|
||||
// AuxChannelNegotiator is an optional interface that allows aux channel
|
||||
// implementations to inject and process custom records over channel
|
||||
// related wire messages.
|
||||
AuxChannelNegotiator fn.Option[lnwallet.AuxChannelNegotiator]
|
||||
|
||||
// ShouldFwdExpEndorsement is a closure that indicates whether
|
||||
// experimental endorsement signals should be set.
|
||||
ShouldFwdExpEndorsement func() bool
|
||||
@@ -1455,8 +1460,9 @@ func (p *Brontide) addLink(chanPoint *wire.OutPoint,
|
||||
ShouldFwdExpEndorsement: p.cfg.ShouldFwdExpEndorsement,
|
||||
DisallowQuiescence: p.cfg.DisallowQuiescence ||
|
||||
!p.remoteFeatures.HasFeature(lnwire.QuiescenceOptional),
|
||||
AuxTrafficShaper: p.cfg.AuxTrafficShaper,
|
||||
QuiescenceTimeout: p.cfg.QuiescenceTimeout,
|
||||
AuxTrafficShaper: p.cfg.AuxTrafficShaper,
|
||||
AuxChannelNegotiator: p.cfg.AuxChannelNegotiator,
|
||||
QuiescenceTimeout: p.cfg.QuiescenceTimeout,
|
||||
}
|
||||
|
||||
// Before adding our new link, purge the switch of any pending or live
|
||||
@@ -4545,6 +4551,19 @@ func (p *Brontide) handleInitMsg(msg *lnwire.Init) error {
|
||||
return fmt.Errorf("data loss protection required")
|
||||
}
|
||||
|
||||
// If we have an AuxChannelNegotiator and the peer sent aux features,
|
||||
// process them.
|
||||
p.cfg.AuxChannelNegotiator.WhenSome(
|
||||
func(acn lnwallet.AuxChannelNegotiator) {
|
||||
err = acn.ProcessInitRecords(
|
||||
p.cfg.PubKeyBytes, msg.CustomRecords.Copy(),
|
||||
)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not process init records: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4605,6 +4624,30 @@ func (p *Brontide) sendInitMsg(legacyChan bool) error {
|
||||
features.RawFeatureVector,
|
||||
)
|
||||
|
||||
var err error
|
||||
|
||||
// If we have an AuxChannelNegotiator, get custom feature bits to
|
||||
// include in the init message.
|
||||
p.cfg.AuxChannelNegotiator.WhenSome(
|
||||
func(negotiator lnwallet.AuxChannelNegotiator) {
|
||||
var auxRecords lnwire.CustomRecords
|
||||
auxRecords, err = negotiator.GetInitRecords(
|
||||
p.cfg.PubKeyBytes,
|
||||
)
|
||||
if err != nil {
|
||||
p.log.Warnf("Failed to get aux init features: "+
|
||||
"%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mergedRecs := msg.CustomRecords.MergedCopy(auxRecords)
|
||||
msg.CustomRecords = mergedRecs
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.writeMessage(msg)
|
||||
}
|
||||
|
||||
|
||||
@@ -1628,6 +1628,7 @@ func newServer(ctx context.Context, cfg *Config, listenAddrs []net.Addr,
|
||||
AuxFundingController: implCfg.AuxFundingController,
|
||||
AuxSigner: implCfg.AuxSigner,
|
||||
AuxResolver: implCfg.AuxContractResolver,
|
||||
AuxChannelNegotiator: implCfg.AuxChannelNegotiator,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -4431,6 +4432,7 @@ func (s *server) peerConnected(conn net.Conn, connReq *connmgr.ConnReq,
|
||||
AuxChanCloser: s.implCfg.AuxChanCloser,
|
||||
AuxResolver: s.implCfg.AuxContractResolver,
|
||||
AuxTrafficShaper: s.implCfg.TrafficShaper,
|
||||
AuxChannelNegotiator: s.implCfg.AuxChannelNegotiator,
|
||||
ShouldFwdExpEndorsement: func() bool {
|
||||
if s.cfg.ProtocolOptions.NoExperimentalEndorsement() {
|
||||
return false
|
||||
|
||||
Reference in new issue
Block a user