diff --git a/funding/manager.go b/funding/manager.go index 0e58daa61..f243a8037 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -276,6 +276,13 @@ type InitFundingMsg struct { // minimum amount to commit to. MinFundAmt btcutil.Amount + // Outpoints is a list of client-selected outpoints that should be used + // for funding a channel. If LocalFundingAmt is specified then this + // amount is allocated from the sum of outpoints towards funding. If + // the FundUpToMaxAmt is specified the entirety of selected funds is + // allocated towards channel funding. + Outpoints []wire.OutPoint + // ChanFunder is an optional channel funder that allows the caller to // control exactly how the channel funding is carried out. If not // specified, then the default chanfunding.WalletAssembler will be @@ -3973,6 +3980,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { maxHtlcs = msg.MaxHtlcs maxCSV = msg.MaxLocalCsv chanReserve = msg.RemoteChanReserve + outpoints = msg.Outpoints ) // If no maximum CSV delay was set for this channel, we use our default @@ -4101,6 +4109,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { FundUpToMaxAmt: msg.FundUpToMaxAmt, MinFundAmt: msg.MinFundAmt, RemoteChanReserve: chanReserve, + Outpoints: outpoints, CommitFeePerKw: commitFeePerKw, FundingFeePerKw: msg.FundingFeePerKw, PushMSat: msg.PushAmt, diff --git a/rpcserver.go b/rpcserver.go index 05d9fb278..7d6e04d83 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -2145,6 +2145,15 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest, "exceeds %d", in.Memo, len(in.Memo), maxMemoLength) } + // Check, if manually selected outpoints are present to fund a channel. + var outpoints []wire.OutPoint + if len(in.Outpoints) > 0 { + outpoints, err = toWireOutpoints(in.Outpoints) + if err != nil { + return nil, fmt.Errorf("can't create outpoints %w", err) + } + } + // Instruct the server to trigger the necessary events to attempt to // open a new channel. A stream is returned in place, this stream will // be used to consume updates of the state of the pending channel. @@ -2171,9 +2180,29 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest, FundUpToMaxAmt: fundUpToMaxAmt, MinFundAmt: minFundAmt, Memo: []byte(in.Memo), + Outpoints: outpoints, }, nil } +// toWireOutpoints converts a list of outpoints from the rpc format to the wire +// format. +func toWireOutpoints(outpoints []*lnrpc.OutPoint) ([]wire.OutPoint, error) { + var wireOutpoints []wire.OutPoint + for _, outpoint := range outpoints { + hash, err := chainhash.NewHashFromStr(outpoint.TxidStr) + if err != nil { + return nil, fmt.Errorf("cannot create chainhash") + } + + wireOutpoint := wire.NewOutPoint( + hash, outpoint.OutputIndex, + ) + wireOutpoints = append(wireOutpoints, *wireOutpoint) + } + + return wireOutpoints, nil +} + // OpenChannel attempts to open a singly funded channel specified in the // request to a remote peer. func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,