lnwallet+contractcourt: publicly export DeriveCommitmentKeys use in chain watcher

In this commit, we consolidate the number of areas where we derive our
commitment keys. Before this commit, the `isOurCommitment` function in
the chain watcher used a custom routine to derive the expected
scripts/keys for our commitment at that height. With the recent changes,
we now have additional logic in `DeriveCommitmentKeys` that wasn't
copied over to this area. As a result, the prior logic would erroneously
detect if it was our commitment that had hit the chain or not.

In this commit, we remove the old custom code, and use
`DeriveCommitmentKeys` wihtin the chain watcher as well. This ensures
that we only need to maintain the key derivation code in a single place,
preventing future bugs of this nature.
This commit is contained in:
Olaoluwa Osuntokun 2019-09-16 19:06:19 -07:00
parent e497a07d64
commit 6d97bcbacd
No known key found for this signature in database
GPG Key ID: BC13F65E2DC84465
3 changed files with 36 additions and 40 deletions

@ -331,7 +331,7 @@ func (c *chainWatcher) SubscribeChannelEvents() *ChainEventSubscription {
// based off of only the set of outputs included. // based off of only the set of outputs included.
func isOurCommitment(localChanCfg, remoteChanCfg channeldb.ChannelConfig, func isOurCommitment(localChanCfg, remoteChanCfg channeldb.ChannelConfig,
commitSpend *chainntnfs.SpendDetail, broadcastStateNum uint64, commitSpend *chainntnfs.SpendDetail, broadcastStateNum uint64,
revocationProducer shachain.Producer) (bool, error) { revocationProducer shachain.Producer, tweakless bool) (bool, error) {
// First, we'll re-derive our commitment point for this state since // First, we'll re-derive our commitment point for this state since
// this is what we use to randomize each of the keys for this state. // this is what we use to randomize each of the keys for this state.
@ -344,14 +344,15 @@ func isOurCommitment(localChanCfg, remoteChanCfg channeldb.ChannelConfig,
// Now that we have the commit point, we'll derive the tweaked local // Now that we have the commit point, we'll derive the tweaked local
// and remote keys for this state. We use our point as only we can // and remote keys for this state. We use our point as only we can
// revoke our own commitment. // revoke our own commitment.
localDelayBasePoint := localChanCfg.DelayBasePoint.PubKey commitKeyRing := lnwallet.DeriveCommitmentKeys(
localDelayKey := input.TweakPubKey(localDelayBasePoint, commitPoint) commitPoint, true, tweakless, &localChanCfg, &remoteChanCfg,
remoteNonDelayPoint := remoteChanCfg.PaymentBasePoint.PubKey )
remotePayKey := input.TweakPubKey(remoteNonDelayPoint, commitPoint)
// With the keys derived, we'll construct the remote script that'll be // With the keys derived, we'll construct the remote script that'll be
// present if they have a non-dust balance on the commitment. // present if they have a non-dust balance on the commitment.
remotePkScript, err := input.CommitScriptUnencumbered(remotePayKey) remotePkScript, err := input.CommitScriptUnencumbered(
commitKeyRing.NoDelayKey,
)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -359,11 +360,9 @@ func isOurCommitment(localChanCfg, remoteChanCfg channeldb.ChannelConfig,
// Next, we'll derive our script that includes the revocation base for // Next, we'll derive our script that includes the revocation base for
// the remote party allowing them to claim this output before the CSV // the remote party allowing them to claim this output before the CSV
// delay if we breach. // delay if we breach.
revocationKey := input.DeriveRevocationPubkey(
remoteChanCfg.RevocationBasePoint.PubKey, commitPoint,
)
localScript, err := input.CommitScriptToSelf( localScript, err := input.CommitScriptToSelf(
uint32(localChanCfg.CsvDelay), localDelayKey, revocationKey, uint32(localChanCfg.CsvDelay), commitKeyRing.DelayKey,
commitKeyRing.RevocationKey,
) )
if err != nil { if err != nil {
return false, err return false, err
@ -423,6 +422,11 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
// revoked state...!!! // revoked state...!!!
commitTxBroadcast := commitSpend.SpendingTx commitTxBroadcast := commitSpend.SpendingTx
// An additional piece of information we need to properly
// dispatch a close event if is this channel was using the
// tweakless remove key format or not.
tweaklessCommit := c.cfg.chanState.ChanType.IsTweakless()
localCommit, remoteCommit, err := c.cfg.chanState.LatestCommitments() localCommit, remoteCommit, err := c.cfg.chanState.LatestCommitments()
if err != nil { if err != nil {
log.Errorf("Unable to fetch channel state for "+ log.Errorf("Unable to fetch channel state for "+
@ -480,6 +484,7 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
c.cfg.chanState.LocalChanCfg, c.cfg.chanState.LocalChanCfg,
c.cfg.chanState.RemoteChanCfg, commitSpend, c.cfg.chanState.RemoteChanCfg, commitSpend,
broadcastStateNum, c.cfg.chanState.RevocationProducer, broadcastStateNum, c.cfg.chanState.RevocationProducer,
tweaklessCommit,
) )
if err != nil { if err != nil {
log.Errorf("unable to determine self commit for "+ log.Errorf("unable to determine self commit for "+
@ -584,9 +589,6 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
"state #%v!!! Attempting recovery...", "state #%v!!! Attempting recovery...",
broadcastStateNum, remoteStateNum) broadcastStateNum, remoteStateNum)
tweaklessCommit := (c.cfg.chanState.ChanType ==
channeldb.SingleFunderTweakless)
// If this isn't a tweakless commitment, then we'll // If this isn't a tweakless commitment, then we'll
// need to wait for the remote party's latest unrevoked // need to wait for the remote party's latest unrevoked
// commitment point to be presented to us as we need // commitment point to be presented to us as we need

@ -876,13 +876,13 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool,
// haven't yet received a responding commitment from the remote party. // haven't yet received a responding commitment from the remote party.
var localCommitKeys, remoteCommitKeys *CommitmentKeyRing var localCommitKeys, remoteCommitKeys *CommitmentKeyRing
if localCommitPoint != nil { if localCommitPoint != nil {
localCommitKeys = deriveCommitmentKeys( localCommitKeys = DeriveCommitmentKeys(
localCommitPoint, true, tweaklessCommit, localCommitPoint, true, tweaklessCommit,
lc.localChanCfg, lc.remoteChanCfg, lc.localChanCfg, lc.remoteChanCfg,
) )
} }
if remoteCommitPoint != nil { if remoteCommitPoint != nil {
remoteCommitKeys = deriveCommitmentKeys( remoteCommitKeys = DeriveCommitmentKeys(
remoteCommitPoint, false, tweaklessCommit, remoteCommitPoint, false, tweaklessCommit,
lc.localChanCfg, lc.remoteChanCfg, lc.localChanCfg, lc.remoteChanCfg,
) )
@ -981,10 +981,10 @@ type CommitmentKeyRing struct {
RevocationKey *btcec.PublicKey RevocationKey *btcec.PublicKey
} }
// deriveCommitmentKey generates a new commitment key set using the base points // DeriveCommitmentKey generates a new commitment key set using the base points
// and commitment point. The keys are derived differently depending whether the // and commitment point. The keys are derived differently depending whether the
// commitment transaction is ours or the remote peer's. // commitment transaction is ours or the remote peer's.
func deriveCommitmentKeys(commitPoint *btcec.PublicKey, func DeriveCommitmentKeys(commitPoint *btcec.PublicKey,
isOurCommit, tweaklessCommit bool, isOurCommit, tweaklessCommit bool,
localChanCfg, remoteChanCfg *channeldb.ChannelConfig) *CommitmentKeyRing { localChanCfg, remoteChanCfg *channeldb.ChannelConfig) *CommitmentKeyRing {
@ -1711,9 +1711,8 @@ func (lc *LightningChannel) restoreCommitState(
// We'll also re-create the set of commitment keys needed to // We'll also re-create the set of commitment keys needed to
// fully re-derive the state. // fully re-derive the state.
tweaklessCommit := (lc.channelState.ChanType == tweaklessCommit := lc.channelState.ChanType.IsTweakless()
channeldb.SingleFunderTweakless) pendingRemoteKeyChain = DeriveCommitmentKeys(
pendingRemoteKeyChain = deriveCommitmentKeys(
pendingCommitPoint, false, tweaklessCommit, pendingCommitPoint, false, tweaklessCommit,
lc.localChanCfg, lc.remoteChanCfg, lc.localChanCfg, lc.remoteChanCfg,
) )
@ -1999,8 +1998,8 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
// With the commitment point generated, we can now generate the four // With the commitment point generated, we can now generate the four
// keys we'll need to reconstruct the commitment state, // keys we'll need to reconstruct the commitment state,
tweaklessCommit := chanState.ChanType == channeldb.SingleFunderTweakless tweaklessCommit := chanState.ChanType.IsTweakless()
keyRing := deriveCommitmentKeys( keyRing := DeriveCommitmentKeys(
commitmentPoint, false, tweaklessCommit, commitmentPoint, false, tweaklessCommit,
&chanState.LocalChanCfg, &chanState.RemoteChanCfg, &chanState.LocalChanCfg, &chanState.RemoteChanCfg,
) )
@ -3258,11 +3257,9 @@ func (lc *LightningChannel) SignNextCommitment() (lnwire.Sig, []lnwire.Sig, []ch
// Grab the next commitment point for the remote party. This will be // Grab the next commitment point for the remote party. This will be
// used within fetchCommitmentView to derive all the keys necessary to // used within fetchCommitmentView to derive all the keys necessary to
// construct the commitment state. // construct the commitment state.
tweaklessCommit := (lc.channelState.ChanType == keyRing := DeriveCommitmentKeys(
channeldb.SingleFunderTweakless) commitPoint, false, lc.channelState.ChanType.IsTweakless(),
keyRing := deriveCommitmentKeys( lc.localChanCfg, lc.remoteChanCfg,
commitPoint, false, tweaklessCommit, lc.localChanCfg,
lc.remoteChanCfg,
) )
// Create a new commitment view which will calculate the evaluated // Create a new commitment view which will calculate the evaluated
@ -4017,11 +4014,9 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig lnwire.Sig,
return err return err
} }
commitPoint := input.ComputeCommitmentPoint(commitSecret[:]) commitPoint := input.ComputeCommitmentPoint(commitSecret[:])
tweaklessCommit := (lc.channelState.ChanType == keyRing := DeriveCommitmentKeys(
channeldb.SingleFunderTweakless) commitPoint, true, lc.channelState.ChanType.IsTweakless(),
keyRing := deriveCommitmentKeys( lc.localChanCfg, lc.remoteChanCfg,
commitPoint, true, tweaklessCommit, lc.localChanCfg,
lc.remoteChanCfg,
) )
// With the current commitment point re-calculated, construct the new // With the current commitment point re-calculated, construct the new
@ -5050,8 +5045,8 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
// First, we'll generate the commitment point and the revocation point // First, we'll generate the commitment point and the revocation point
// so we can re-construct the HTLC state and also our payment key. // so we can re-construct the HTLC state and also our payment key.
tweaklessCommit := chanState.ChanType == channeldb.SingleFunderTweakless tweaklessCommit := chanState.ChanType.IsTweakless()
keyRing := deriveCommitmentKeys( keyRing := DeriveCommitmentKeys(
commitPoint, false, tweaklessCommit, &chanState.LocalChanCfg, commitPoint, false, tweaklessCommit, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg, &chanState.RemoteChanCfg,
) )
@ -5706,10 +5701,9 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
return nil, err return nil, err
} }
commitPoint := input.ComputeCommitmentPoint(revocation[:]) commitPoint := input.ComputeCommitmentPoint(revocation[:])
tweaklessCommit := chanState.ChanType == channeldb.SingleFunderTweakless keyRing := DeriveCommitmentKeys(
keyRing := deriveCommitmentKeys( commitPoint, true, chanState.ChanType.IsTweakless(),
commitPoint, true, tweaklessCommit, &chanState.LocalChanCfg, &chanState.LocalChanCfg, &chanState.RemoteChanCfg,
&chanState.RemoteChanCfg,
) )
selfScript, err := input.CommitScriptToSelf(csvTimeout, keyRing.DelayKey, selfScript, err := input.CommitScriptToSelf(csvTimeout, keyRing.DelayKey,
keyRing.RevocationKey) keyRing.RevocationKey)

@ -663,11 +663,11 @@ func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount,
fundingTxIn wire.TxIn, fundingTxIn wire.TxIn,
tweaklessCommit bool) (*wire.MsgTx, *wire.MsgTx, error) { tweaklessCommit bool) (*wire.MsgTx, *wire.MsgTx, error) {
localCommitmentKeys := deriveCommitmentKeys( localCommitmentKeys := DeriveCommitmentKeys(
localCommitPoint, true, tweaklessCommit, ourChanCfg, localCommitPoint, true, tweaklessCommit, ourChanCfg,
theirChanCfg, theirChanCfg,
) )
remoteCommitmentKeys := deriveCommitmentKeys( remoteCommitmentKeys := DeriveCommitmentKeys(
remoteCommitPoint, false, tweaklessCommit, ourChanCfg, remoteCommitPoint, false, tweaklessCommit, ourChanCfg,
theirChanCfg, theirChanCfg,
) )