lnwallet: thread through tx conf details in ChannelReservation.DispatchChan()

This commit slightly modifies the channel reservation workflow to
expose the new information conerning the exact confirmation location of
the channel provided by the ChainNotifier. The DispatchChan() method of
the ChannelReservation now also returns the blockHeight and txIndex
where the transaction was ultimately confirmed. This information will
be needed by the fundingManager so it can properly generate the
authenticated channel announcement proofs.
This commit is contained in:
Olaoluwa Osuntokun 2016-12-24 18:47:09 -06:00
parent 702f214972
commit 0313dcfc89
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
3 changed files with 53 additions and 18 deletions

@ -475,9 +475,13 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness, wallet *lnwallet
t.Fatalf("channel state not properly saved") t.Fatalf("channel state not properly saved")
} }
// Assert that tha channel opens after a single block. // Assert that the channel opens after a single block.
lnc := assertChannelOpen(t, miner, uint32(numReqConfs), lnChan := make(chan *lnwallet.LightningChannel, 1)
chanReservation.DispatchChan()) go func() {
channel, _, _ := chanReservation.DispatchChan()
lnChan <- channel
}()
lnc := assertChannelOpen(t, miner, uint32(numReqConfs), lnChan)
// Now that the channel is open, execute a cooperative closure of the // Now that the channel is open, execute a cooperative closure of the
// now open channel. // now open channel.
@ -611,7 +615,7 @@ func testCancelNonExistantReservation(miner *rpctest.Harness,
} }
func testSingleFunderReservationWorkflowInitiator(miner *rpctest.Harness, func testSingleFunderReservationWorkflowInitiator(miner *rpctest.Harness,
lnwallet *lnwallet.LightningWallet, t *testing.T) { wallet *lnwallet.LightningWallet, t *testing.T) {
t.Log("Running single funder workflow initiator test") t.Log("Running single funder workflow initiator test")
@ -627,7 +631,7 @@ func testSingleFunderReservationWorkflowInitiator(miner *rpctest.Harness,
// Initialize a reservation for a channel with 4 BTC funded solely by us. // Initialize a reservation for a channel with 4 BTC funded solely by us.
fundingAmt := btcutil.Amount(4 * 1e8) fundingAmt := btcutil.Amount(4 * 1e8)
chanReservation, err := lnwallet.InitChannelReservation(fundingAmt, chanReservation, err := wallet.InitChannelReservation(fundingAmt,
fundingAmt, bobNode.id, bobAddr, numReqConfs, 4, 540) fundingAmt, bobNode.id, bobAddr, numReqConfs, 4, 540)
if err != nil { if err != nil {
t.Fatalf("unable to init channel reservation: %v", err) t.Fatalf("unable to init channel reservation: %v", err)
@ -729,7 +733,7 @@ func testSingleFunderReservationWorkflowInitiator(miner *rpctest.Harness,
// TODO(roasbeef): de-duplicate // TODO(roasbeef): de-duplicate
fundingTx := chanReservation.FinalFundingTx() fundingTx := chanReservation.FinalFundingTx()
fundingSha := fundingTx.TxSha() fundingSha := fundingTx.TxSha()
channels, err := lnwallet.ChannelDB.FetchOpenChannels(bobNode.id) channels, err := wallet.ChannelDB.FetchOpenChannels(bobNode.id)
if err != nil { if err != nil {
t.Fatalf("unable to retrieve channel from DB: %v", err) t.Fatalf("unable to retrieve channel from DB: %v", err)
} }
@ -746,7 +750,12 @@ func testSingleFunderReservationWorkflowInitiator(miner *rpctest.Harness,
channeldb.SingleFunder, channels[0].ChanType) channeldb.SingleFunder, channels[0].ChanType)
} }
assertChannelOpen(t, miner, uint32(numReqConfs), chanReservation.DispatchChan()) lnChan := make(chan *lnwallet.LightningChannel, 1)
go func() {
channel, _, _ := chanReservation.DispatchChan()
lnChan <- channel
}()
assertChannelOpen(t, miner, uint32(numReqConfs), lnChan)
} }
func testSingleFunderReservationWorkflowResponder(miner *rpctest.Harness, func testSingleFunderReservationWorkflowResponder(miner *rpctest.Harness,

@ -121,10 +121,11 @@ type ChannelReservation struct {
// channel should be considered open. // channel should be considered open.
numConfsToOpen uint16 numConfsToOpen uint16
// A channel which will be sent on once the channel is considered // chanOpen houses a struct containing the channel and additional
// 'open'. A channel is open once the funding transaction has reached // confirmation details will be sent on once the channel is considered
// a sufficient number of confirmations. // 'open'. A channel is open once the funding transaction has reached a
chanOpen chan *LightningChannel // sufficient number of confirmations.
chanOpen chan *openChanDetails
wallet *LightningWallet wallet *LightningWallet
} }
@ -208,7 +209,7 @@ func NewChannelReservation(capacity, fundingAmt btcutil.Amount, minFeeRate btcut
}, },
numConfsToOpen: numConfs, numConfsToOpen: numConfs,
reservationID: id, reservationID: id,
chanOpen: make(chan *LightningChannel, 1), chanOpen: make(chan *openChanDetails, 1),
wallet: wallet, wallet: wallet,
} }
} }
@ -437,8 +438,12 @@ func (r *ChannelReservation) Cancel() error {
// //
// NOTE: If this method is called before .CompleteReservation(), it will block // NOTE: If this method is called before .CompleteReservation(), it will block
// indefinitely. // indefinitely.
func (r *ChannelReservation) DispatchChan() <-chan *LightningChannel { func (r *ChannelReservation) DispatchChan() (*LightningChannel, uint32, uint32) {
return r.chanOpen // TODO(roasbeef): goroutine sending in wallet should be lifted up into
// the fundingMgr
openDetails := <-r.chanOpen
return openDetails.channel, openDetails.blockHeight, openDetails.txIndex
} }
// FinalizeReservation completes the pending reservation, returning an active // FinalizeReservation completes the pending reservation, returning an active
@ -455,5 +460,5 @@ func (r *ChannelReservation) FinalizeReservation() (*LightningChannel, error) {
err: errChan, err: errChan,
} }
return <-r.chanOpen, <-errChan return (<-r.chanOpen).channel, <-errChan
} }

@ -934,6 +934,17 @@ func (l *LightningWallet) handleSingleContribution(req *addSingleContributionMsg
return return
} }
// openChanDetails contains a "finalized" channel which can be considered
// "open" according to the requested confirmation depth at reservation
// initialization. Additionally, the struct contains additional details
// pertaining to the exact location in the main chain in-which the transaction
// was confirmed.
type openChanDetails struct {
channel *LightningChannel
blockHeight uint32
txIndex uint32
}
// handleFundingCounterPartySigs is the final step in the channel reservation // handleFundingCounterPartySigs is the final step in the channel reservation
// workflow. During this step, we validate *all* the received signatures for // workflow. During this step, we validate *all* the received signatures for
// inputs to the funding transaction. If any of these are invalid, we bail, // inputs to the funding transaction. If any of these are invalid, we bail,
@ -1212,7 +1223,9 @@ func (l *LightningWallet) handleChannelOpen(req *channelOpenMsg) {
channel, _ := NewLightningChannel(l.Signer, l.ChainIO, l.chainNotifier, channel, _ := NewLightningChannel(l.Signer, l.ChainIO, l.chainNotifier,
res.partialState) res.partialState)
res.chanOpen <- channel res.chanOpen <- &openChanDetails{
channel: channel,
}
req.err <- nil req.err <- nil
} }
@ -1231,9 +1244,13 @@ func (l *LightningWallet) openChannelAfterConfirmations(res *ChannelReservation)
// Wait until the specified number of confirmations has been reached, // Wait until the specified number of confirmations has been reached,
// or the wallet signals a shutdown. // or the wallet signals a shutdown.
var (
confDetails *chainntnfs.TxConfirmation
ok bool
)
out: out:
select { select {
case _, ok := <-confNtfn.Confirmed: case confDetails, ok = <-confNtfn.Confirmed:
// Reading a falsey value for the second parameter indicates that // Reading a falsey value for the second parameter indicates that
// the notifier is in the process of shutting down. Therefore, we // the notifier is in the process of shutting down. Therefore, we
// don't count this as the signal that the funding transaction has // don't count this as the signal that the funding transaction has
@ -1253,7 +1270,11 @@ out:
// TODO(roasbeef): CreationTime once tx is 'open' // TODO(roasbeef): CreationTime once tx is 'open'
channel, _ := NewLightningChannel(l.Signer, l.ChainIO, l.chainNotifier, channel, _ := NewLightningChannel(l.Signer, l.ChainIO, l.chainNotifier,
res.partialState) res.partialState)
res.chanOpen <- channel res.chanOpen <- &openChanDetails{
channel: channel,
blockHeight: confDetails.BlockHeight,
txIndex: confDetails.TxIndex,
}
} }
// selectCoinsAndChange performs coin selection in order to obtain witness // selectCoinsAndChange performs coin selection in order to obtain witness