lnwallet: add new RegisterFundingIntent method

In this commit, we add a new method `RegisterFundingIntent` that allows
a caller to "inject" a pre-populated chanfunding.Intent into a funding
workflow. As an example, if we've already agreed upon the "shape" of the
funding output _outside_ the protocol, then we can use this to pass down
the details of the output, then leverage the normal wire protocol to
carry out the remainder of the funding flow.
This commit is contained in:
Olaoluwa Osuntokun
2019-10-31 21:47:27 -07:00
parent 6e9cbc19f9
commit 9926259da0

View File

@@ -277,6 +277,11 @@ type LightningWallet struct {
// the currently locked outpoints. // the currently locked outpoints.
lockedOutPoints map[wire.OutPoint]struct{} lockedOutPoints map[wire.OutPoint]struct{}
// fundingIntents houses all the "interception" registered by a caller
// using the RegisterFundingIntent method.
intentMtx sync.RWMutex
fundingIntents map[[32]byte]chanfunding.Intent
quit chan struct{} quit chan struct{}
wg sync.WaitGroup wg sync.WaitGroup
@@ -297,6 +302,7 @@ func NewLightningWallet(Cfg Config) (*LightningWallet, error) {
nextFundingID: 0, nextFundingID: 0,
fundingLimbo: make(map[uint64]*ChannelReservation), fundingLimbo: make(map[uint64]*ChannelReservation),
lockedOutPoints: make(map[wire.OutPoint]struct{}), lockedOutPoints: make(map[wire.OutPoint]struct{}),
fundingIntents: make(map[[32]byte]chanfunding.Intent),
quit: make(chan struct{}), quit: make(chan struct{}),
}, nil }, nil
} }
@@ -435,6 +441,21 @@ func (l *LightningWallet) InitChannelReservation(
return <-req.resp, <-req.err return <-req.resp, <-req.err
} }
// RegisterFundingIntent allows a caller to signal to the wallet that if a
// pending channel ID of expectedID is found, then it can skip constructing a
// new chanfunding.Assembler, and instead use the specified chanfunding.Intent.
// As an example, this lets some of the parameters for funding transaction to
// be negotiated outside the regular funding protocol.
func (l *LightningWallet) RegisterFundingIntent(expectedID [32]byte,
shimIntent chanfunding.Intent) error {
l.intentMtx.Lock()
l.fundingIntents[expectedID] = shimIntent
l.intentMtx.Unlock()
return nil
}
// handleFundingReserveRequest processes a message intending to create, and // handleFundingReserveRequest processes a message intending to create, and
// validate a funding reservation request. // validate a funding reservation request.
func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg) { func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg) {
@@ -478,11 +499,19 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
err error err error
) )
// If we're on the receiving end of a single funder channel then we // If we've just received an inbound funding request that we have a
// don't need to perform any coin selection, and the remote contributes // registered shim intent to, then we'll obtain the backing intent now.
// all funds. Otherwise, attempt to obtain enough coins to meet the // In this case, we're doing a special funding workflow that allows
// required funding amount. // more advanced constructions such as channel factories to be
if req.LocalFundingAmt != 0 { // instantiated.
l.intentMtx.Lock()
fundingIntent, ok := l.fundingIntents[req.PendingChanID]
l.intentMtx.Unlock()
// Otherwise, this is a normal funding flow, so we'll use the chan
// funder in the attached request to provision the inputs/outputs
// that'll ultimately be used to construct the funding transaction.
if !ok {
// Coin selection is done on the basis of sat/kw, so we'll use // Coin selection is done on the basis of sat/kw, so we'll use
// the fee rate passed in to perform coin selection. // the fee rate passed in to perform coin selection.
var err error var err error
@@ -700,6 +729,16 @@ func (l *LightningWallet) handleFundingCancelRequest(req *fundingReserveCancelMs
delete(l.fundingLimbo, req.pendingFundingID) delete(l.fundingLimbo, req.pendingFundingID)
pid := pendingReservation.pendingChanID
l.intentMtx.Lock()
if intent, ok := l.fundingIntents[pid]; ok {
intent.Cancel()
delete(l.fundingIntents, pendingReservation.pendingChanID)
}
l.intentMtx.Unlock()
req.err <- nil req.err <- nil
} }
@@ -1149,6 +1188,10 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs
delete(l.fundingLimbo, res.reservationID) delete(l.fundingLimbo, res.reservationID)
l.limboMtx.Unlock() l.limboMtx.Unlock()
l.intentMtx.Lock()
delete(l.fundingIntents, res.pendingChanID)
l.intentMtx.Unlock()
// As we're about to broadcast the funding transaction, we'll take note // As we're about to broadcast the funding transaction, we'll take note
// of the current height for record keeping purposes. // of the current height for record keeping purposes.
// //
@@ -1347,6 +1390,10 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
l.limboMtx.Lock() l.limboMtx.Lock()
delete(l.fundingLimbo, req.pendingFundingID) delete(l.fundingLimbo, req.pendingFundingID)
l.limboMtx.Unlock() l.limboMtx.Unlock()
l.intentMtx.Lock()
delete(l.fundingIntents, pendingReservation.pendingChanID)
l.intentMtx.Unlock()
} }
// WithCoinSelectLock will execute the passed function closure in a // WithCoinSelectLock will execute the passed function closure in a