contractcourt: ensure the chainWatcher is able to play all remote commitments
This commit is contained in:
parent
88ff2af931
commit
c8b15719f2
@ -340,40 +340,71 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
|
|||||||
)
|
)
|
||||||
remoteStateNum := remoteCommit.CommitHeight
|
remoteStateNum := remoteCommit.CommitHeight
|
||||||
|
|
||||||
|
remoteChainTip, err := c.cfg.chanState.RemoteCommitChainTip()
|
||||||
|
if err != nil && err != channeldb.ErrNoPendingCommit {
|
||||||
|
log.Errorf("unable to obtain chain tip for "+
|
||||||
|
"ChannelPoint(%v): %v",
|
||||||
|
c.cfg.chanState.FundingOutpoint, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
// If state number spending transaction matches the
|
// If state number spending transaction matches the
|
||||||
// current latest state, then they've initiated a
|
// current latest state, then they've initiated a
|
||||||
// unilateral close. So we'll trigger the unilateral
|
// unilateral close. So we'll trigger the unilateral
|
||||||
// close signal so subscribers can clean up the state
|
// close signal so subscribers can clean up the state
|
||||||
// as necessary.
|
// as necessary.
|
||||||
//
|
case broadcastStateNum == remoteStateNum:
|
||||||
|
err := c.dispatchRemoteForceClose(
|
||||||
|
commitSpend, *remoteCommit, false,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("unable to handle remote "+
|
||||||
|
"close for chan_point=%v: %v",
|
||||||
|
c.cfg.chanState.FundingOutpoint, err)
|
||||||
|
}
|
||||||
|
|
||||||
// We'll also handle the case of the remote party
|
// We'll also handle the case of the remote party
|
||||||
// broadcasting their commitment transaction which is
|
// broadcasting their commitment transaction which is
|
||||||
// one height above ours. This case can arise when we
|
// one height above ours. This case can arise when we
|
||||||
// initiate a state transition, but the remote party
|
// initiate a state transition, but the remote party
|
||||||
// has a fail crash _after_ accepting the new state,
|
// has a fail crash _after_ accepting the new state,
|
||||||
// but _before_ sending their signature to us.
|
// but _before_ sending their signature to us.
|
||||||
case broadcastStateNum >= remoteStateNum:
|
case broadcastStateNum == remoteStateNum+1 &&
|
||||||
if err := c.dispatchRemoteForceClose(
|
remoteChainTip != nil:
|
||||||
commitSpend, *remoteCommit,
|
|
||||||
); err != nil {
|
err := c.dispatchRemoteForceClose(
|
||||||
|
commitSpend, remoteChainTip.Commitment,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
log.Errorf("unable to handle remote "+
|
log.Errorf("unable to handle remote "+
|
||||||
"close for chan_point=%v: %v",
|
"close for chan_point=%v: %v",
|
||||||
c.cfg.chanState.FundingOutpoint, err)
|
c.cfg.chanState.FundingOutpoint, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is the case that somehow the commitment
|
||||||
|
// broadcast is actually greater than even one beyond
|
||||||
|
// our best known state number. This should NEVER
|
||||||
|
// happen, but we'll log it in any case.
|
||||||
|
case broadcastStateNum > remoteStateNum+1:
|
||||||
|
log.Errorf("Remote node broadcast state #%v, "+
|
||||||
|
"which is more than 1 beyond best known "+
|
||||||
|
"state #%v!!!", broadcastStateNum,
|
||||||
|
remoteStateNum)
|
||||||
|
|
||||||
// If the state number broadcast is lower than the
|
// If the state number broadcast is lower than the
|
||||||
// remote node's current un-revoked height, then
|
// remote node's current un-revoked height, then
|
||||||
// THEY'RE ATTEMPTING TO VIOLATE THE CONTRACT LAID OUT
|
// THEY'RE ATTEMPTING TO VIOLATE THE CONTRACT LAID OUT
|
||||||
// WITHIN THE PAYMENT CHANNEL. Therefore we close the
|
// WITHIN THE PAYMENT CHANNEL. Therefore we close the
|
||||||
// signal indicating a revoked broadcast to allow
|
// signal indicating a revoked broadcast to allow
|
||||||
// subscribers to
|
// subscribers to swiftly dispatch justice!!!
|
||||||
// swiftly dispatch justice!!!
|
|
||||||
case broadcastStateNum < remoteStateNum:
|
case broadcastStateNum < remoteStateNum:
|
||||||
if err := c.dispatchContractBreach(
|
err := c.dispatchContractBreach(
|
||||||
commitSpend, remoteCommit,
|
commitSpend, remoteCommit,
|
||||||
broadcastStateNum,
|
broadcastStateNum,
|
||||||
); err != nil {
|
)
|
||||||
|
if err != nil {
|
||||||
log.Errorf("unable to handle channel "+
|
log.Errorf("unable to handle channel "+
|
||||||
"breach for chan_point=%v: %v",
|
"breach for chan_point=%v: %v",
|
||||||
c.cfg.chanState.FundingOutpoint, err)
|
c.cfg.chanState.FundingOutpoint, err)
|
||||||
@ -570,13 +601,16 @@ func (c *chainWatcher) dispatchLocalForceClose(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// dispatchRemoteForceClose processes a detected unilateral channel closure by the
|
// dispatchRemoteForceClose processes a detected unilateral channel closure by
|
||||||
// remote party. This function will prepare a UnilateralCloseSummary which will
|
// the remote party. This function will prepare a UnilateralCloseSummary which
|
||||||
// then be sent to any subscribers allowing them to resolve all our funds in
|
// will then be sent to any subscribers allowing them to resolve all our funds
|
||||||
// the channel on chain. Once this close summary is prepared, all registered
|
// in the channel on chain. Once this close summary is prepared, all registered
|
||||||
// subscribers will receive a notification of this event.
|
// subscribers will receive a notification of this event. The
|
||||||
|
// isRemotePendingCommit argument should be set to true if the remote node
|
||||||
|
// broadcast their pending commitment (w/o revoking their current settled
|
||||||
|
// commitment).
|
||||||
func (c *chainWatcher) dispatchRemoteForceClose(commitSpend *chainntnfs.SpendDetail,
|
func (c *chainWatcher) dispatchRemoteForceClose(commitSpend *chainntnfs.SpendDetail,
|
||||||
remoteCommit channeldb.ChannelCommitment) error {
|
remoteCommit channeldb.ChannelCommitment, isRemotePendingCommit bool) error {
|
||||||
|
|
||||||
log.Infof("Unilateral close of ChannelPoint(%v) "+
|
log.Infof("Unilateral close of ChannelPoint(%v) "+
|
||||||
"detected", c.cfg.chanState.FundingOutpoint)
|
"detected", c.cfg.chanState.FundingOutpoint)
|
||||||
@ -584,8 +618,9 @@ func (c *chainWatcher) dispatchRemoteForceClose(commitSpend *chainntnfs.SpendDet
|
|||||||
// First, we'll create a closure summary that contains all the
|
// First, we'll create a closure summary that contains all the
|
||||||
// materials required to let each subscriber sweep the funds in the
|
// materials required to let each subscriber sweep the funds in the
|
||||||
// channel on-chain.
|
// channel on-chain.
|
||||||
uniClose, err := lnwallet.NewUnilateralCloseSummary(c.cfg.chanState,
|
uniClose, err := lnwallet.NewUnilateralCloseSummary(
|
||||||
c.cfg.signer, c.cfg.pCache, commitSpend, remoteCommit,
|
c.cfg.chanState, c.cfg.signer, c.cfg.pCache, commitSpend,
|
||||||
|
remoteCommit, isRemotePendingCommit,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
Loading…
Reference in New Issue
Block a user