lnwallet: newHtlcResolution now returns both incoming and outgoing HTLC resolutions

In this commit, we’ve added a new HtlcResolutions struct to house both
the incoming and outgoing HTLC resolutions. This struct will now be
coupled with the object that returns when we detect that a commitment
transaction was closed on chain. For incoming HTLC’s, we’ll check the
preimage cache to see if we can claim the HTLC on-chain. If we can,
then we’ll copy of the preimage, and make a proper incoming HTLC
resolution.
This commit is contained in:
Olaoluwa Osuntokun 2018-01-16 18:36:31 -08:00
parent d98026f579
commit b5496c52a2
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21

@ -2098,7 +2098,8 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven
lc.channelState.LocalCommitment.FeePerKw, false, lc.channelState.LocalCommitment.FeePerKw, false,
lc.signer, lc.channelState.LocalCommitment.Htlcs, lc.signer, lc.channelState.LocalCommitment.Htlcs,
keyRing, lc.localChanCfg, lc.remoteChanCfg, keyRing, lc.localChanCfg, lc.remoteChanCfg,
*commitSpend.SpenderTxHash) *commitSpend.SpenderTxHash, lc.pCache,
)
if err != nil { if err != nil {
walletLog.Errorf("unable to create htlc "+ walletLog.Errorf("unable to create htlc "+
"resolutions: %v", err) "resolutions: %v", err)
@ -4416,6 +4417,10 @@ type UnilateralCloseSummary struct {
// then this will be nil. // then this will be nil.
CommitResolution *CommitOutputResolution CommitResolution *CommitOutputResolution
// HtlcResolutions contains a fully populated HtlcResolutions struct
// which contains all the data required to sweep any outgoing HTLC's,
// and also any incoming HTLC's that we know the pre-image to.
HtlcResolutions *HtlcResolutions
// ChanSnapshot is a snapshot of the final state of the channel at the // ChanSnapshot is a snapshot of the final state of the channel at the
// time it was closed. // time it was closed.
@ -4504,10 +4509,20 @@ type OutgoingHtlcResolution struct {
SweepSignDesc SignDescriptor SweepSignDesc SignDescriptor
} }
// newHtlcResolution generates a new HTLC resolution capable of allowing the // HtlcResolutions contains the items necessary to sweep HTLC's on chain
// caller to sweep an outgoing HTLC present on either their, or the remote // directly from a commitment transaction. We'll use this in case either party
// party's commitment transaction. // goes broadcasts a commitment transaction with live HTLC's.
func newHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelConfig, type HtlcResolutions struct {
// IncomingHTLCs contains a set of structs that can be used to sweep
// all the incoming HTL'C that we know the preimage to.
IncomingHTLCs []IncomingHtlcResolution
// OutgoingHTLCs contains a set of structs that contains all the info
// needed to sweep an outgoing HTLC we've sent to the remote party
// after an absolute delay has expired.
OutgoingHTLCs []OutgoingHtlcResolution
}
// newOutgoingHtlcResolution generates a new HTLC resolution capable of // newOutgoingHtlcResolution generates a new HTLC resolution capable of
// allowing the caller to sweep an outgoing HTLC present on either their, or // allowing the caller to sweep an outgoing HTLC present on either their, or
// the remote party's commitment transaction. // the remote party's commitment transaction.
@ -4784,8 +4799,9 @@ func newIncomingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
func extractHtlcResolutions(feePerKw btcutil.Amount, ourCommit bool, func extractHtlcResolutions(feePerKw btcutil.Amount, ourCommit bool,
signer Signer, htlcs []channeldb.HTLC, keyRing *commitmentKeyRing, signer Signer, htlcs []channeldb.HTLC, keyRing *commitmentKeyRing,
localChanCfg, remoteChanCfg *channeldb.ChannelConfig, localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
commitHash chainhash.Hash) ([]OutgoingHtlcResolution, error) { commitHash chainhash.Hash, pCache PreimageCache) (*HtlcResolutions, error) {
// TODO(roasbeef): don't need to swap csv delay?
dustLimit := remoteChanCfg.DustLimit dustLimit := remoteChanCfg.DustLimit
csvDelay := remoteChanCfg.CsvDelay csvDelay := remoteChanCfg.CsvDelay
if ourCommit { if ourCommit {
@ -4793,16 +4809,10 @@ func extractHtlcResolutions(feePerKw btcutil.Amount, ourCommit bool,
csvDelay = localChanCfg.CsvDelay csvDelay = localChanCfg.CsvDelay
} }
htlcResolutions := make([]OutgoingHtlcResolution, 0, len(htlcs)) incomingResolutions := make([]IncomingHtlcResolution, 0, len(htlcs))
outgoingResolutions := make([]OutgoingHtlcResolution, 0, len(htlcs))
for _, htlc := range htlcs { for _, htlc := range htlcs {
// Skip any incoming HTLC's, as unless we have the pre-image to // We'll skip any HTLC's which were dust on the commitment
// spend them, they'll eventually be swept by the party that
// offered the HTLC after the timeout.
if htlc.Incoming {
continue
}
// We'll also skip any HTLC's which were dust on the commitment
// transaction, as these don't have a corresponding output // transaction, as these don't have a corresponding output
// within the commitment transaction. // within the commitment transaction.
if htlcIsDust(htlc.Incoming, ourCommit, feePerKw, if htlcIsDust(htlc.Incoming, ourCommit, feePerKw,
@ -4810,19 +4820,46 @@ func extractHtlcResolutions(feePerKw btcutil.Amount, ourCommit bool,
continue continue
} }
ohr, err := newHtlcResolution( // If the HTLC is incoming, then we'll attempt to see if we
// know the pre-image to the HTLC.
if htlc.Incoming {
// We'll now query the preimage cache for the preimage
// for this HTLC. If it's present then we can fully
// populate this resolution.
preimage, _ := pCache.LookupPreimage(htlc.RHash[:])
// Otherwise, we'll create an incoming HTLC resolution
// as we can satisfy the contract.
var pre [32]byte
copy(pre[:], preimage)
ihr, err := newIncomingHtlcResolution(
signer, localChanCfg, commitHash, &htlc, keyRing,
feePerKw, dustLimit, uint32(csvDelay), ourCommit,
pre,
)
if err != nil {
return nil, err
}
incomingResolutions = append(incomingResolutions, *ihr)
continue
}
ohr, err := newOutgoingHtlcResolution(
signer, localChanCfg, commitHash, &htlc, keyRing, signer, localChanCfg, commitHash, &htlc, keyRing,
feePerKw, dustLimit, uint32(csvDelay), feePerKw, dustLimit, uint32(csvDelay), ourCommit,
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO(roasbeef): needs to point to proper amount including outgoingResolutions = append(outgoingResolutions, *ohr)
htlcResolutions = append(htlcResolutions, *ohr)
} }
return htlcResolutions, nil return &HtlcResolutions{
IncomingHTLCs: incomingResolutions,
OutgoingHTLCs: outgoingResolutions,
}, nil
} }
// ForceCloseSummary describes the final commitment state before the channel is // ForceCloseSummary describes the final commitment state before the channel is