cnct: make original htlc amt available for contract resolvers

Previously, contract resolvers that needed to publish a second level tx,
did not have access to the original htlc amount.

This commit reconstructs this amount from data that is already persisted
in arbitrator log.

Co-authored-by: Joost Jager <joost.jager@gmail.com>
This commit is contained in:
Wilmer Paulino 2019-01-22 20:45:32 -08:00
parent 93754f8d37
commit 974e0f2df5
No known key found for this signature in database
GPG Key ID: 6DF57B9F9514972F
3 changed files with 109 additions and 1 deletions

@ -358,14 +358,109 @@ func (c *ChannelArbitrator) relaunchResolvers() error {
return err
}
// Retrieve the commitment tx hash from the log.
contractResolutions, err := c.log.FetchContractResolutions()
if err != nil {
log.Errorf("unable to fetch contract resolutions: %v",
err)
return err
}
commitHash := contractResolutions.CommitHash
// Reconstruct the htlc outpoints and data from the chain action log.
// The purpose of the constructed htlc map is to supplement to resolvers
// restored from database with extra data. Ideally this data is stored
// as part of the resolver in the log. This is a workaround to prevent a
// db migration.
htlcMap := make(map[wire.OutPoint]*channeldb.HTLC)
chainActions, err := c.log.FetchChainActions()
if err != nil {
log.Errorf("unable to fetch chain actions: %v", err)
return err
}
for _, htlcs := range chainActions {
for _, htlc := range htlcs {
outpoint := wire.OutPoint{
Hash: commitHash,
Index: uint32(htlc.OutputIndex),
}
htlcMap[outpoint] = &htlc
}
}
log.Infof("ChannelArbitrator(%v): relaunching %v contract "+
"resolvers", c.cfg.ChanPoint, len(unresolvedContracts))
for _, resolver := range unresolvedContracts {
supplementResolver(resolver, htlcMap)
}
c.launchResolvers(unresolvedContracts)
return nil
}
// supplementResolver takes a resolver as it is restored from the log and fills
// in missing data from the htlcMap.
func supplementResolver(resolver ContractResolver,
htlcMap map[wire.OutPoint]*channeldb.HTLC) error {
switch r := resolver.(type) {
case *htlcSuccessResolver:
return supplementSuccessResolver(r, htlcMap)
case *htlcIncomingContestResolver:
return supplementSuccessResolver(
&r.htlcSuccessResolver, htlcMap,
)
case *htlcTimeoutResolver:
return supplementTimeoutResolver(r, htlcMap)
case *htlcOutgoingContestResolver:
return supplementTimeoutResolver(
&r.htlcTimeoutResolver, htlcMap,
)
}
return nil
}
// supplementSuccessResolver takes a htlcSuccessResolver as it is restored from
// the log and fills in missing data from the htlcMap.
func supplementSuccessResolver(r *htlcSuccessResolver,
htlcMap map[wire.OutPoint]*channeldb.HTLC) error {
res := r.htlcResolution
htlcPoint := res.HtlcPoint()
htlc, ok := htlcMap[htlcPoint]
if !ok {
return errors.New(
"htlc for success resolver unavailable",
)
}
r.htlcAmt = htlc.Amt
return nil
}
// supplementTimeoutResolver takes a htlcSuccessResolver as it is restored from
// the log and fills in missing data from the htlcMap.
func supplementTimeoutResolver(r *htlcTimeoutResolver,
htlcMap map[wire.OutPoint]*channeldb.HTLC) error {
res := r.htlcResolution
htlcPoint := res.HtlcPoint()
htlc, ok := htlcMap[htlcPoint]
if !ok {
return errors.New(
"htlc for timeout resolver unavailable",
)
}
r.htlcAmt = htlc.Amt
return nil
}
// Stop signals the ChannelArbitrator for a graceful shutdown.
func (c *ChannelArbitrator) Stop() error {
if !atomic.CompareAndSwapInt32(&c.stopped, 0, 1) {
@ -1146,6 +1241,7 @@ func (c *ChannelArbitrator) prepContractResolutions(htlcActions ChainActionMap,
htlcResolution: resolution,
broadcastHeight: height,
payHash: htlc.RHash,
htlcAmt: htlc.Amt,
ResolverKit: resKit,
}
htlcResolvers = append(htlcResolvers, resolver)
@ -1173,6 +1269,7 @@ func (c *ChannelArbitrator) prepContractResolutions(htlcActions ChainActionMap,
htlcResolution: resolution,
broadcastHeight: height,
htlcIndex: htlc.HtlcIndex,
htlcAmt: htlc.Amt,
ResolverKit: resKit,
}
htlcResolvers = append(htlcResolvers, resolver)
@ -1206,6 +1303,7 @@ func (c *ChannelArbitrator) prepContractResolutions(htlcActions ChainActionMap,
htlcResolution: resolution,
broadcastHeight: height,
payHash: htlc.RHash,
htlcAmt: htlc.Amt,
ResolverKit: resKit,
},
}
@ -1232,10 +1330,11 @@ func (c *ChannelArbitrator) prepContractResolutions(htlcActions ChainActionMap,
resKit.Quit = make(chan struct{})
resolver := &htlcOutgoingContestResolver{
htlcTimeoutResolver{
htlcTimeoutResolver: htlcTimeoutResolver{
htlcResolution: resolution,
broadcastHeight: height,
htlcIndex: htlc.HtlcIndex,
htlcAmt: htlc.Amt,
ResolverKit: resKit,
},
}

@ -3,6 +3,7 @@ package contractcourt
import (
"encoding/binary"
"fmt"
"github.com/lightningnetwork/lnd/lnwire"
"io"
"github.com/btcsuite/btcd/wire"
@ -46,6 +47,10 @@ type htlcSuccessResolver struct {
// TODO(roasbeef): send off to utxobundler
sweepTx *wire.MsgTx
// htlcAmt is the original amount of the htlc, not taking into
// account any fees that may have to be paid if it goes on chain.
htlcAmt lnwire.MilliSatoshi
ResolverKit
}

@ -40,6 +40,10 @@ type htlcTimeoutResolver struct {
// additional commitment state machine.
htlcIndex uint64
// htlcAmt is the original amount of the htlc, not taking into
// account any fees that may have to be paid if it goes on chain.
htlcAmt lnwire.MilliSatoshi
ResolverKit
}