lnd: remove openChanReq, call InitFundingWorkflow with InitFundingMsg

This commit is contained in:
eugene 2020-11-24 12:19:39 -05:00
parent e85baea1b3
commit 936227798a
5 changed files with 312 additions and 283 deletions

@ -120,8 +120,76 @@ func (r *reservationWithCtx) updateTimestamp() {
// embedded within this message giving the funding manager full context w.r.t // embedded within this message giving the funding manager full context w.r.t
// the workflow. // the workflow.
type InitFundingMsg struct { type InitFundingMsg struct {
peer lnpeer.Peer // Peer is the peer that we want to open a channel to.
*openChanReq Peer lnpeer.Peer
// TargetPubkey is the public key of the peer.
TargetPubkey *btcec.PublicKey
// ChainHash is the target genesis hash for this channel.
ChainHash chainhash.Hash
// SubtractFees set to true means that fees will be subtracted
// from the LocalFundingAmt.
SubtractFees bool
// LocalFundingAmt is the size of the channel.
LocalFundingAmt btcutil.Amount
// PushAmt is the amount pushed to the counterparty.
PushAmt lnwire.MilliSatoshi
// FundingFeePerKw is the fee for the funding transaction.
FundingFeePerKw chainfee.SatPerKWeight
// Private determines whether or not this channel will be private.
Private bool
// MinHtlcIn is the minimum incoming HTLC that we accept.
MinHtlcIn lnwire.MilliSatoshi
// RemoteCsvDelay is the CSV delay we require for the remote peer.
RemoteCsvDelay uint16
// MinConfs indicates the minimum number of confirmations that each
// output selected to fund the channel should satisfy.
MinConfs int32
// ShutdownScript is an optional upfront shutdown script for the
// channel. This value is optional, so may be nil.
ShutdownScript lnwire.DeliveryAddress
// MaxValueInFlight is the maximum amount of coins in MilliSatoshi
// that can be pending within the channel. It only applies to the
// remote party.
MaxValueInFlight lnwire.MilliSatoshi
// MaxHtlcs is the maximum number of HTLCs that the remote peer
// can offer us.
MaxHtlcs uint16
// MaxLocalCsv is the maximum local csv delay we will accept from our
// peer.
MaxLocalCsv uint16
// 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
// used.
ChanFunder chanfunding.Assembler
// PendingChanID is not all zeroes (the default value), then this will
// be the pending channel ID used for the funding flow within the wire
// protocol.
PendingChanID [32]byte
// Updates is a channel which updates to the opening status of the channel
// are sent on.
Updates chan *lnrpc.OpenStatusUpdate
// Err is a channel which errors encountered during the funding flow are
// sent on.
Err chan error
} }
// fundingMsg is sent by the ProcessFundingMsg function and packages a // fundingMsg is sent by the ProcessFundingMsg function and packages a
@ -2919,11 +2987,8 @@ func (f *Manager) announceChannel(localIDKey, remoteIDKey, localFundingKey,
// InitFundingWorkflow sends a message to the funding manager instructing it // InitFundingWorkflow sends a message to the funding manager instructing it
// to initiate a single funder workflow with the source peer. // to initiate a single funder workflow with the source peer.
// TODO(roasbeef): re-visit blocking nature.. // TODO(roasbeef): re-visit blocking nature..
func (f *Manager) InitFundingWorkflow(peer lnpeer.Peer, req *openChanReq) { func (f *Manager) InitFundingWorkflow(msg *InitFundingMsg) {
f.fundingRequests <- &InitFundingMsg{ f.fundingRequests <- msg
peer: peer,
openChanReq: req,
}
} }
// getUpfrontShutdownScript takes a user provided script and a getScript // getUpfrontShutdownScript takes a user provided script and a getScript
@ -2975,13 +3040,13 @@ func getUpfrontShutdownScript(enableUpfrontShutdown bool, peer lnpeer.Peer,
// funding workflow. // funding workflow.
func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
var ( var (
peerKey = msg.peer.IdentityKey() peerKey = msg.Peer.IdentityKey()
localAmt = msg.localFundingAmt localAmt = msg.LocalFundingAmt
minHtlcIn = msg.minHtlcIn minHtlcIn = msg.MinHtlcIn
remoteCsvDelay = msg.remoteCsvDelay remoteCsvDelay = msg.RemoteCsvDelay
maxValue = msg.maxValueInFlight maxValue = msg.MaxValueInFlight
maxHtlcs = msg.maxHtlcs maxHtlcs = msg.MaxHtlcs
maxCSV = msg.maxLocalCsv maxCSV = msg.MaxLocalCsv
) )
// If no maximum CSV delay was set for this channel, we use our default // If no maximum CSV delay was set for this channel, we use our default
@ -3000,14 +3065,14 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
} }
fndgLog.Infof("Initiating fundingRequest(local_amt=%v "+ fndgLog.Infof("Initiating fundingRequest(local_amt=%v "+
"(subtract_fees=%v), push_amt=%v, chain_hash=%v, peer=%x, "+ "(subtract_fees=%v), push_amt=%v, chain_hash=%v, peer=%x, "+
"dust_limit=%v, min_confs=%v)", localAmt, msg.subtractFees, "dust_limit=%v, min_confs=%v)", localAmt, msg.SubtractFees,
msg.pushAmt, msg.chainHash, peerKey.SerializeCompressed(), msg.PushAmt, msg.ChainHash, peerKey.SerializeCompressed(),
ourDustLimit, msg.minConfs) ourDustLimit, msg.MinConfs)
// We set the channel flags to indicate whether we want this channel to // We set the channel flags to indicate whether we want this channel to
// be announced to the network. // be announced to the network.
var channelFlags lnwire.FundingFlag var channelFlags lnwire.FundingFlag
if !msg.openChanReq.private { if !msg.Private {
// This channel will be announced. // This channel will be announced.
channelFlags = lnwire.FFAnnounceChannel channelFlags = lnwire.FFAnnounceChannel
} }
@ -3016,15 +3081,15 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
// Otherwise we'll generate a fresh one as normal. This will be used // Otherwise we'll generate a fresh one as normal. This will be used
// to track this reservation throughout its lifetime. // to track this reservation throughout its lifetime.
var chanID [32]byte var chanID [32]byte
if msg.pendingChanID == zeroID { if msg.PendingChanID == zeroID {
chanID = f.nextPendingChanID() chanID = f.nextPendingChanID()
} else { } else {
// If the user specified their own pending channel ID, then // If the user specified their own pending channel ID, then
// we'll ensure it doesn't collide with any existing pending // we'll ensure it doesn't collide with any existing pending
// channel ID. // channel ID.
chanID = msg.pendingChanID chanID = msg.PendingChanID
if _, err := f.getReservationCtx(peerKey, chanID); err == nil { if _, err := f.getReservationCtx(peerKey, chanID); err == nil {
msg.err <- fmt.Errorf("pendingChannelID(%x) "+ msg.Err <- fmt.Errorf("pendingChannelID(%x) "+
"already present", chanID[:]) "already present", chanID[:])
return return
} }
@ -3035,8 +3100,8 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
// address from the wallet if our node is configured to set shutdown // address from the wallet if our node is configured to set shutdown
// address by default). // address by default).
shutdown, err := getUpfrontShutdownScript( shutdown, err := getUpfrontShutdownScript(
f.cfg.EnableUpfrontShutdown, msg.peer, f.cfg.EnableUpfrontShutdown, msg.Peer,
msg.openChanReq.shutdownScript, msg.ShutdownScript,
func() (lnwire.DeliveryAddress, error) { func() (lnwire.DeliveryAddress, error) {
addr, err := f.cfg.Wallet.NewAddress( addr, err := f.cfg.Wallet.NewAddress(
lnwallet.WitnessPubKey, false, lnwallet.WitnessPubKey, false,
@ -3048,7 +3113,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
}, },
) )
if err != nil { if err != nil {
msg.err <- err msg.Err <- err
return return
} }
@ -3060,7 +3125,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
// format we can use with this peer. This is dependent on *both* us and // format we can use with this peer. This is dependent on *both* us and
// the remote peer are signaling the proper feature bit. // the remote peer are signaling the proper feature bit.
commitType := commitmentType( commitType := commitmentType(
msg.peer.LocalFeatures(), msg.peer.RemoteFeatures(), msg.Peer.LocalFeatures(), msg.Peer.RemoteFeatures(),
) )
// First, we'll query the fee estimator for a fee that should get the // First, we'll query the fee estimator for a fee that should get the
@ -3069,7 +3134,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
// to execute a timely unilateral channel closure if needed. // to execute a timely unilateral channel closure if needed.
commitFeePerKw, err := f.cfg.FeeEstimator.EstimateFeePerKW(3) commitFeePerKw, err := f.cfg.FeeEstimator.EstimateFeePerKW(3)
if err != nil { if err != nil {
msg.err <- err msg.Err <- err
return return
} }
@ -3082,25 +3147,25 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
} }
req := &lnwallet.InitFundingReserveMsg{ req := &lnwallet.InitFundingReserveMsg{
ChainHash: &msg.chainHash, ChainHash: &msg.ChainHash,
PendingChanID: chanID, PendingChanID: chanID,
NodeID: peerKey, NodeID: peerKey,
NodeAddr: msg.peer.Address(), NodeAddr: msg.Peer.Address(),
SubtractFees: msg.subtractFees, SubtractFees: msg.SubtractFees,
LocalFundingAmt: localAmt, LocalFundingAmt: localAmt,
RemoteFundingAmt: 0, RemoteFundingAmt: 0,
CommitFeePerKw: commitFeePerKw, CommitFeePerKw: commitFeePerKw,
FundingFeePerKw: msg.fundingFeePerKw, FundingFeePerKw: msg.FundingFeePerKw,
PushMSat: msg.pushAmt, PushMSat: msg.PushAmt,
Flags: channelFlags, Flags: channelFlags,
MinConfs: msg.minConfs, MinConfs: msg.MinConfs,
CommitType: commitType, CommitType: commitType,
ChanFunder: msg.chanFunder, ChanFunder: msg.ChanFunder,
} }
reservation, err := f.cfg.Wallet.InitChannelReservation(req) reservation, err := f.cfg.Wallet.InitChannelReservation(req)
if err != nil { if err != nil {
msg.err <- err msg.Err <- err
return return
} }
@ -3154,9 +3219,9 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
remoteMaxHtlcs: maxHtlcs, remoteMaxHtlcs: maxHtlcs,
maxLocalCsv: maxCSV, maxLocalCsv: maxCSV,
reservation: reservation, reservation: reservation,
peer: msg.peer, peer: msg.Peer,
updates: msg.updates, updates: msg.Updates,
err: msg.err, err: msg.Err,
} }
f.activeReservations[peerIDKey][chanID] = resCtx f.activeReservations[peerIDKey][chanID] = resCtx
f.resMtx.Unlock() f.resMtx.Unlock()
@ -3174,13 +3239,13 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
chanReserve := f.cfg.RequiredRemoteChanReserve(capacity, ourDustLimit) chanReserve := f.cfg.RequiredRemoteChanReserve(capacity, ourDustLimit)
fndgLog.Infof("Starting funding workflow with %v for pending_id(%x), "+ fndgLog.Infof("Starting funding workflow with %v for pending_id(%x), "+
"committype=%v", msg.peer.Address(), chanID, commitType) "committype=%v", msg.Peer.Address(), chanID, commitType)
fundingOpen := lnwire.OpenChannel{ fundingOpen := lnwire.OpenChannel{
ChainHash: *f.cfg.Wallet.Cfg.NetParams.GenesisHash, ChainHash: *f.cfg.Wallet.Cfg.NetParams.GenesisHash,
PendingChannelID: chanID, PendingChannelID: chanID,
FundingAmount: capacity, FundingAmount: capacity,
PushAmount: msg.pushAmt, PushAmount: msg.PushAmt,
DustLimit: ourContribution.DustLimit, DustLimit: ourContribution.DustLimit,
MaxValueInFlight: maxValue, MaxValueInFlight: maxValue,
ChannelReserve: chanReserve, ChannelReserve: chanReserve,
@ -3197,7 +3262,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
ChannelFlags: channelFlags, ChannelFlags: channelFlags,
UpfrontShutdownScript: shutdown, UpfrontShutdownScript: shutdown,
} }
if err := msg.peer.SendMessage(true, &fundingOpen); err != nil { if err := msg.Peer.SendMessage(true, &fundingOpen); err != nil {
e := fmt.Errorf("unable to send funding request message: %v", e := fmt.Errorf("unable to send funding request message: %v",
err) err)
fndgLog.Errorf(e.Error()) fndgLog.Errorf(e.Error())
@ -3209,7 +3274,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
fndgLog.Errorf("unable to cancel reservation: %v", err) fndgLog.Errorf("unable to cancel reservation: %v", err)
} }
msg.err <- e msg.Err <- e
return return
} }
} }

@ -657,25 +657,26 @@ func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
subtractFees: subtractFees, ChainHash: *fundingNetParams.GenesisHash,
localFundingAmt: localFundingAmt, SubtractFees: subtractFees,
pushAmt: lnwire.NewMSatFromSatoshis(pushAmt), LocalFundingAmt: localFundingAmt,
fundingFeePerKw: 1000, PushAmt: lnwire.NewMSatFromSatoshis(pushAmt),
private: !announceChan, FundingFeePerKw: 1000,
updates: updateChan, Private: !announceChan,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -1317,22 +1318,23 @@ func testLocalCSVLimit(t *testing.T, aliceMaxCSV, bobRequiredCSV uint16) {
// First, we will initiate an outgoing channel from Alice -> Bob. // First, we will initiate an outgoing channel from Alice -> Bob.
errChan := make(chan error, 1) errChan := make(chan error, 1)
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 200000, ChainHash: *fundingNetParams.GenesisHash,
fundingFeePerKw: 1000, LocalFundingAmt: 200000,
updates: updateChan, FundingFeePerKw: 1000,
err: errChan, Updates: updateChan,
Err: errChan,
} }
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
@ -1382,23 +1384,24 @@ func testLocalCSVLimit(t *testing.T, aliceMaxCSV, bobRequiredCSV uint16) {
// handle incoming channels, opening a channel from Bob->Alice. // handle incoming channels, opening a channel from Bob->Alice.
errChan = make(chan error, 1) errChan = make(chan error, 1)
updateChan = make(chan *lnrpc.OpenStatusUpdate) updateChan = make(chan *lnrpc.OpenStatusUpdate)
initReq = &openChanReq{ initReq = &InitFundingMsg{
targetPubkey: alice.privKey.PubKey(), Peer: alice,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: alice.privKey.PubKey(),
localFundingAmt: 200000, ChainHash: *fundingNetParams.GenesisHash,
fundingFeePerKw: 1000, LocalFundingAmt: 200000,
updates: updateChan, FundingFeePerKw: 1000,
err: errChan, Updates: updateChan,
Err: errChan,
} }
bob.fundingMgr.InitFundingWorkflow(alice, initReq) bob.fundingMgr.InitFundingWorkflow(initReq)
// Bob should have sent the OpenChannel message to Alice. // Bob should have sent the OpenChannel message to Alice.
var bobMsg lnwire.Message var bobMsg lnwire.Message
select { select {
case bobMsg = <-bob.msgChan: case bobMsg = <-bob.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("bob OpenChannel message failed: %v", err) t.Fatalf("bob OpenChannel message failed: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
@ -1734,23 +1737,24 @@ func TestFundingManagerPeerTimeoutAfterInitFunding(t *testing.T) {
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 500000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: 500000,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -1796,23 +1800,24 @@ func TestFundingManagerPeerTimeoutAfterFundingOpen(t *testing.T) {
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 500000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: 500000,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -1867,23 +1872,24 @@ func TestFundingManagerPeerTimeoutAfterFundingAccept(t *testing.T) {
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 500000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: 500000,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -2591,26 +2597,27 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
// Create a funding request with the custom parameters and start the // Create a funding request with the custom parameters and start the
// workflow. // workflow.
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: localAmt, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(pushAmt), LocalFundingAmt: localAmt,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(pushAmt),
maxValueInFlight: maxValueInFlight, Private: false,
minHtlcIn: minHtlcIn, MaxValueInFlight: maxValueInFlight,
remoteCsvDelay: csvDelay, MinHtlcIn: minHtlcIn,
updates: updateChan, RemoteCsvDelay: csvDelay,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -2871,19 +2878,20 @@ func TestFundingManagerMaxPendingChannels(t *testing.T) {
) )
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// Create openChanReqs for maxPending+1 channels. // Create InitFundingMsg structs for maxPending+1 channels.
var initReqs []*openChanReq var initReqs []*InitFundingMsg
for i := 0; i < maxPending+1; i++ { for i := 0; i < maxPending+1; i++ {
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 5000000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: 5000000,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
initReqs = append(initReqs, initReq) initReqs = append(initReqs, initReq)
} }
@ -2892,13 +2900,13 @@ func TestFundingManagerMaxPendingChannels(t *testing.T) {
var accepts []*lnwire.AcceptChannel var accepts []*lnwire.AcceptChannel
var lastOpen *lnwire.OpenChannel var lastOpen *lnwire.OpenChannel
for i, initReq := range initReqs { for i, initReq := range initReqs {
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -2974,7 +2982,7 @@ func TestFundingManagerMaxPendingChannels(t *testing.T) {
// publish a funding tx to the network. // publish a funding tx to the network.
var pendingUpdate *lnrpc.OpenStatusUpdate var pendingUpdate *lnrpc.OpenStatusUpdate
select { select {
case pendingUpdate = <-initReqs[i].updates: case pendingUpdate = <-initReqs[i].Updates:
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenStatusUpdate_ChanPending") t.Fatalf("alice did not send OpenStatusUpdate_ChanPending")
} }
@ -3046,23 +3054,24 @@ func TestFundingManagerRejectPush(t *testing.T) {
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 500000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(10), LocalFundingAmt: 500000,
private: true, PushAmt: lnwire.NewMSatFromSatoshis(10),
updates: updateChan, Private: true,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -3103,23 +3112,24 @@ func TestFundingManagerMaxConfs(t *testing.T) {
// Create a funding request and start the workflow. // Create a funding request and start the workflow.
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: 500000, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(10), LocalFundingAmt: 500000,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(10),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
// Alice should have sent the OpenChannel message to Bob. // Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message var aliceMsg lnwire.Message
select { select {
case aliceMsg = <-alice.msgChan: case aliceMsg = <-alice.msgChan:
case err := <-initReq.err: case err := <-initReq.Err:
t.Fatalf("error init funding workflow: %v", err) t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message") t.Fatalf("alice did not send OpenChannel message")
@ -3385,19 +3395,20 @@ func TestMaxChannelSizeConfig(t *testing.T) {
// imposed by --maxchansize, which should be rejected. // imposed by --maxchansize, which should be rejected.
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: funding.MaxBtcFundingAmount, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: funding.MaxBtcFundingAmount,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
// After processing the funding open message, bob should respond with // After processing the funding open message, bob should respond with
// an error rejecting the channel that exceeds size limit. // an error rejecting the channel that exceeds size limit.
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg := expectOpenChannelMsg(t, alice.msgChan) openChanMsg := expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertErrorSent(t, bob.msgChan) assertErrorSent(t, bob.msgChan)
@ -3411,8 +3422,11 @@ func TestMaxChannelSizeConfig(t *testing.T) {
cfg.MaxChanSize = funding.MaxBtcFundingAmount + 1 cfg.MaxChanSize = funding.MaxBtcFundingAmount + 1
}) })
// Reset the Peer to the newly created one.
initReq.Peer = bob
// We expect Bob to respond with an Accept channel message. // We expect Bob to respond with an Accept channel message.
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg = expectOpenChannelMsg(t, alice.msgChan) openChanMsg = expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertFundingMsgSent(t, bob.msgChan, "AcceptChannel") assertFundingMsgSent(t, bob.msgChan, "AcceptChannel")
@ -3426,13 +3440,16 @@ func TestMaxChannelSizeConfig(t *testing.T) {
cfg.MaxChanSize = btcutil.Amount(100000000) cfg.MaxChanSize = btcutil.Amount(100000000)
}) })
// Reset the Peer to the newly created one.
initReq.Peer = bob
// Attempt to create a channel above the limit // Attempt to create a channel above the limit
// imposed by --maxchansize, which should be rejected. // imposed by --maxchansize, which should be rejected.
initReq.localFundingAmt = btcutil.SatoshiPerBitcoin + 1 initReq.LocalFundingAmt = btcutil.SatoshiPerBitcoin + 1
// After processing the funding open message, bob should respond with // After processing the funding open message, bob should respond with
// an error rejecting the channel that exceeds size limit. // an error rejecting the channel that exceeds size limit.
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg = expectOpenChannelMsg(t, alice.msgChan) openChanMsg = expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertErrorSent(t, bob.msgChan) assertErrorSent(t, bob.msgChan)
@ -3454,29 +3471,30 @@ func TestWumboChannelConfig(t *testing.T) {
// funding process w/o issue. // funding process w/o issue.
updateChan := make(chan *lnrpc.OpenStatusUpdate) updateChan := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error, 1) errChan := make(chan error, 1)
initReq := &openChanReq{ initReq := &InitFundingMsg{
targetPubkey: bob.privKey.PubKey(), Peer: bob,
chainHash: *fundingNetParams.GenesisHash, TargetPubkey: bob.privKey.PubKey(),
localFundingAmt: funding.MaxBtcFundingAmount, ChainHash: *fundingNetParams.GenesisHash,
pushAmt: lnwire.NewMSatFromSatoshis(0), LocalFundingAmt: funding.MaxBtcFundingAmount,
private: false, PushAmt: lnwire.NewMSatFromSatoshis(0),
updates: updateChan, Private: false,
err: errChan, Updates: updateChan,
Err: errChan,
} }
// We expect Bob to respond with an Accept channel message. // We expect Bob to respond with an Accept channel message.
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg := expectOpenChannelMsg(t, alice.msgChan) openChanMsg := expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertFundingMsgSent(t, bob.msgChan, "AcceptChannel") assertFundingMsgSent(t, bob.msgChan, "AcceptChannel")
// We'll now attempt to create a channel above the wumbo mark, which // We'll now attempt to create a channel above the wumbo mark, which
// should be rejected. // should be rejected.
initReq.localFundingAmt = btcutil.SatoshiPerBitcoin initReq.LocalFundingAmt = btcutil.SatoshiPerBitcoin
// After processing the funding open message, bob should respond with // After processing the funding open message, bob should respond with
// an error rejecting the channel. // an error rejecting the channel.
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg = expectOpenChannelMsg(t, alice.msgChan) openChanMsg = expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertErrorSent(t, bob.msgChan) assertErrorSent(t, bob.msgChan)
@ -3489,9 +3507,12 @@ func TestWumboChannelConfig(t *testing.T) {
cfg.MaxChanSize = funding.MaxBtcFundingAmountWumbo cfg.MaxChanSize = funding.MaxBtcFundingAmountWumbo
}) })
// Reset the Peer to the newly created one.
initReq.Peer = bob
// We should now be able to initiate a wumbo channel funding w/o any // We should now be able to initiate a wumbo channel funding w/o any
// issues. // issues.
alice.fundingMgr.InitFundingWorkflow(bob, initReq) alice.fundingMgr.InitFundingWorkflow(initReq)
openChanMsg = expectOpenChannelMsg(t, alice.msgChan) openChanMsg = expectOpenChannelMsg(t, alice.msgChan)
bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice) bob.fundingMgr.ProcessFundingMsg(openChanMsg, alice)
assertFundingMsgSent(t, bob.msgChan, "AcceptChannel") assertFundingMsgSent(t, bob.msgChan, "AcceptChannel")

@ -97,18 +97,18 @@ func (c *chanController) OpenChannel(target *btcec.PublicKey,
// Construct the open channel request and send it to the server to begin // Construct the open channel request and send it to the server to begin
// the funding workflow. // the funding workflow.
req := &openChanReq{ req := &InitFundingMsg{
targetPubkey: target, TargetPubkey: target,
chainHash: *c.netParams.GenesisHash, ChainHash: *c.netParams.GenesisHash,
subtractFees: true, SubtractFees: true,
localFundingAmt: amt, LocalFundingAmt: amt,
pushAmt: 0, PushAmt: 0,
minHtlcIn: c.chanMinHtlcIn, MinHtlcIn: c.chanMinHtlcIn,
fundingFeePerKw: feePerKw, FundingFeePerKw: feePerKw,
private: c.private, Private: c.private,
remoteCsvDelay: 0, RemoteCsvDelay: 0,
minConfs: c.minConfs, MinConfs: c.minConfs,
maxValueInFlight: 0, MaxValueInFlight: 0,
} }
updateStream, errChan := c.server.OpenChannel(req) updateStream, errChan := c.server.OpenChannel(req)

@ -1761,11 +1761,11 @@ func (r *rpcServer) canOpenChannel() error {
return nil return nil
} }
// praseOpenChannelReq parses an OpenChannelRequest message into the server's // praseOpenChannelReq parses an OpenChannelRequest message into an InitFundingMsg
// native openChanReq struct. The logic is abstracted so that it can be shared // struct. The logic is abstracted so that it can be shared between OpenChannel
// between OpenChannel and OpenChannelSync. // and OpenChannelSync.
func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest, func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
isSync bool) (*openChanReq, error) { isSync bool) (*InitFundingMsg, error) {
rpcsLog.Debugf("[openchannel] request to NodeKey(%x) "+ rpcsLog.Debugf("[openchannel] request to NodeKey(%x) "+
"allocation(us=%v, them=%v)", in.NodePubkey, "allocation(us=%v, them=%v)", in.NodePubkey,
@ -1892,20 +1892,20 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
// Instruct the server to trigger the necessary events to attempt to // Instruct the server to trigger the necessary events to attempt to
// open a new channel. A stream is returned in place, this stream will // 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. // be used to consume updates of the state of the pending channel.
return &openChanReq{ return &InitFundingMsg{
targetPubkey: nodePubKey, TargetPubkey: nodePubKey,
chainHash: *r.cfg.ActiveNetParams.GenesisHash, ChainHash: *r.cfg.ActiveNetParams.GenesisHash,
localFundingAmt: localFundingAmt, LocalFundingAmt: localFundingAmt,
pushAmt: lnwire.NewMSatFromSatoshis(remoteInitialBalance), PushAmt: lnwire.NewMSatFromSatoshis(remoteInitialBalance),
minHtlcIn: minHtlcIn, MinHtlcIn: minHtlcIn,
fundingFeePerKw: feeRate, FundingFeePerKw: feeRate,
private: in.Private, Private: in.Private,
remoteCsvDelay: remoteCsvDelay, RemoteCsvDelay: remoteCsvDelay,
minConfs: minConfs, MinConfs: minConfs,
shutdownScript: script, ShutdownScript: script,
maxValueInFlight: maxValue, MaxValueInFlight: maxValue,
maxHtlcs: maxHtlcs, MaxHtlcs: maxHtlcs,
maxLocalCsv: uint16(in.MaxLocalCsv), MaxLocalCsv: uint16(in.MaxLocalCsv),
}, nil }, nil
} }
@ -1936,8 +1936,8 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
// Map the channel point shim into a new // Map the channel point shim into a new
// chanfunding.CannedAssembler that the wallet will use // chanfunding.CannedAssembler that the wallet will use
// to obtain the channel point details. // to obtain the channel point details.
copy(req.pendingChanID[:], chanPointShim.PendingChanId) copy(req.PendingChanID[:], chanPointShim.PendingChanId)
req.chanFunder, err = newFundingShimAssembler( req.ChanFunder, err = newFundingShimAssembler(
chanPointShim, true, r.server.cc.KeyRing, chanPointShim, true, r.server.cc.KeyRing,
) )
if err != nil { if err != nil {
@ -1954,9 +1954,9 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
// Instruct the wallet to use the new // Instruct the wallet to use the new
// chanfunding.PsbtAssembler to construct the funding // chanfunding.PsbtAssembler to construct the funding
// transaction. // transaction.
copy(req.pendingChanID[:], psbtShim.PendingChanId) copy(req.PendingChanID[:], psbtShim.PendingChanId)
req.chanFunder, err = newPsbtAssembler( req.ChanFunder, err = newPsbtAssembler(
in, req.minConfs, psbtShim, in, req.MinConfs, psbtShim,
&r.server.cc.Wallet.Cfg.NetParams, &r.server.cc.Wallet.Cfg.NetParams,
) )
if err != nil { if err != nil {
@ -1973,7 +1973,7 @@ out:
select { select {
case err := <-errChan: case err := <-errChan:
rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v", rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v",
req.targetPubkey.SerializeCompressed(), err) req.TargetPubkey.SerializeCompressed(), err)
return err return err
case fundingUpdate := <-updateChan: case fundingUpdate := <-updateChan:
rpcsLog.Tracef("[openchannel] sending update: %v", rpcsLog.Tracef("[openchannel] sending update: %v",
@ -2005,7 +2005,7 @@ out:
} }
rpcsLog.Tracef("[openchannel] success NodeKey(%x), ChannelPoint(%v)", rpcsLog.Tracef("[openchannel] success NodeKey(%x), ChannelPoint(%v)",
req.targetPubkey.SerializeCompressed(), outpoint) req.TargetPubkey.SerializeCompressed(), outpoint)
return nil return nil
} }
@ -2030,7 +2030,7 @@ func (r *rpcServer) OpenChannelSync(ctx context.Context,
// If an error occurs them immediately return the error to the client. // If an error occurs them immediately return the error to the client.
case err := <-errChan: case err := <-errChan:
rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v", rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v",
req.targetPubkey.SerializeCompressed(), err) req.TargetPubkey.SerializeCompressed(), err)
return nil, err return nil, err
// Otherwise, wait for the first channel update. The first update sent // Otherwise, wait for the first channel update. The first update sent

@ -52,7 +52,6 @@ import (
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/nat" "github.com/lightningnetwork/lnd/nat"
"github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/netann"
@ -3484,63 +3483,6 @@ func (s *server) removePeer(p *peer.Brontide) {
s.peerNotifier.NotifyPeerOffline(pubKey) s.peerNotifier.NotifyPeerOffline(pubKey)
} }
// openChanReq is a message sent to the server in order to request the
// initiation of a channel funding workflow to the peer with either the
// specified relative peer ID, or a global lightning ID.
type openChanReq struct {
targetPubkey *btcec.PublicKey
chainHash chainhash.Hash
subtractFees bool
localFundingAmt btcutil.Amount
pushAmt lnwire.MilliSatoshi
fundingFeePerKw chainfee.SatPerKWeight
private bool
// minHtlcIn is the minimum incoming htlc that we accept.
minHtlcIn lnwire.MilliSatoshi
remoteCsvDelay uint16
// minConfs indicates the minimum number of confirmations that each
// output selected to fund the channel should satisfy.
minConfs int32
// shutdownScript is an optional upfront shutdown script for the channel.
// This value is optional, so may be nil.
shutdownScript lnwire.DeliveryAddress
// maxValueInFlight is the maximum amount of coins in millisatoshi that can
// be pending within the channel. It only applies to the remote party.
maxValueInFlight lnwire.MilliSatoshi
maxHtlcs uint16
// maxLocalCsv is the maximum local csv delay we will accept from our
// peer.
maxLocalCsv uint16
// TODO(roasbeef): add ability to specify channel constraints as well
// 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
// used.
chanFunder chanfunding.Assembler
// pendingChanID is not all zeroes (the default value), then this will
// be the pending channel ID used for the funding flow within the wire
// protocol.
pendingChanID [32]byte
updates chan *lnrpc.OpenStatusUpdate
err chan error
}
// ConnectToPeer requests that the server connect to a Lightning Network peer // ConnectToPeer requests that the server connect to a Lightning Network peer
// at the specified address. This function will *block* until either a // at the specified address. This function will *block* until either a
// connection is established, or the initial handshake process fails. // connection is established, or the initial handshake process fails.
@ -3685,25 +3627,26 @@ func (s *server) DisconnectPeer(pubKey *btcec.PublicKey) error {
// //
// NOTE: This function is safe for concurrent access. // NOTE: This function is safe for concurrent access.
func (s *server) OpenChannel( func (s *server) OpenChannel(
req *openChanReq) (chan *lnrpc.OpenStatusUpdate, chan error) { req *InitFundingMsg) (chan *lnrpc.OpenStatusUpdate, chan error) {
// The updateChan will have a buffer of 2, since we expect a ChanPending // The updateChan will have a buffer of 2, since we expect a ChanPending
// + a ChanOpen update, and we want to make sure the funding process is // + a ChanOpen update, and we want to make sure the funding process is
// not blocked if the caller is not reading the updates. // not blocked if the caller is not reading the updates.
req.updates = make(chan *lnrpc.OpenStatusUpdate, 2) req.Updates = make(chan *lnrpc.OpenStatusUpdate, 2)
req.err = make(chan error, 1) req.Err = make(chan error, 1)
// First attempt to locate the target peer to open a channel with, if // First attempt to locate the target peer to open a channel with, if
// we're unable to locate the peer then this request will fail. // we're unable to locate the peer then this request will fail.
pubKeyBytes := req.targetPubkey.SerializeCompressed() pubKeyBytes := req.TargetPubkey.SerializeCompressed()
s.mu.RLock() s.mu.RLock()
peer, ok := s.peersByPub[string(pubKeyBytes)] peer, ok := s.peersByPub[string(pubKeyBytes)]
if !ok { if !ok {
s.mu.RUnlock() s.mu.RUnlock()
req.err <- fmt.Errorf("peer %x is not online", pubKeyBytes) req.Err <- fmt.Errorf("peer %x is not online", pubKeyBytes)
return req.updates, req.err return req.Updates, req.Err
} }
req.Peer = peer
s.mu.RUnlock() s.mu.RUnlock()
// We'll wait until the peer is active before beginning the channel // We'll wait until the peer is active before beginning the channel
@ -3711,32 +3654,32 @@ func (s *server) OpenChannel(
select { select {
case <-peer.ActiveSignal(): case <-peer.ActiveSignal():
case <-peer.QuitSignal(): case <-peer.QuitSignal():
req.err <- fmt.Errorf("peer %x disconnected", pubKeyBytes) req.Err <- fmt.Errorf("peer %x disconnected", pubKeyBytes)
return req.updates, req.err return req.Updates, req.Err
case <-s.quit: case <-s.quit:
req.err <- ErrServerShuttingDown req.Err <- ErrServerShuttingDown
return req.updates, req.err return req.Updates, req.Err
} }
// If the fee rate wasn't specified, then we'll use a default // If the fee rate wasn't specified, then we'll use a default
// confirmation target. // confirmation target.
if req.fundingFeePerKw == 0 { if req.FundingFeePerKw == 0 {
estimator := s.cc.FeeEstimator estimator := s.cc.FeeEstimator
feeRate, err := estimator.EstimateFeePerKW(6) feeRate, err := estimator.EstimateFeePerKW(6)
if err != nil { if err != nil {
req.err <- err req.Err <- err
return req.updates, req.err return req.Updates, req.Err
} }
req.fundingFeePerKw = feeRate req.FundingFeePerKw = feeRate
} }
// Spawn a goroutine to send the funding workflow request to the funding // Spawn a goroutine to send the funding workflow request to the funding
// manager. This allows the server to continue handling queries instead // manager. This allows the server to continue handling queries instead
// of blocking on this request which is exported as a synchronous // of blocking on this request which is exported as a synchronous
// request to the outside world. // request to the outside world.
go s.fundingMgr.InitFundingWorkflow(peer, req) go s.fundingMgr.InitFundingWorkflow(req)
return req.updates, req.err return req.Updates, req.Err
} }
// Peers returns a slice of all active peers. // Peers returns a slice of all active peers.