htlcswitch: keep final htlc outcome

This commit is contained in:
Joost Jager 2022-05-10 12:33:44 +02:00
parent b85cda2a1d
commit 28256b7ea8
No known key found for this signature in database
GPG Key ID: B9A26449A5528325
20 changed files with 466 additions and 111 deletions

View File

@ -16,6 +16,7 @@ import (
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
@ -135,6 +136,26 @@ var (
// sent was a revocation and false when it was a commitment signature.
// This is nil in the case of new channels with no updates exchanged.
lastWasRevokeKey = []byte("last-was-revoke")
// finalHtlcsBucket contains the htlcs that have been resolved
// definitively. Within this bucket, there is a sub-bucket for each
// channel. In each channel bucket, the htlc indices are stored along
// with final outcome.
//
// final-htlcs -> chanID -> htlcIndex -> outcome
//
// 'outcome' is a byte value that encodes:
//
// | true false
// ------+------------------
// bit 0 | settled failed
// bit 1 | offchain onchain
//
// This bucket is positioned at the root level, because its contents
// will be kept independent of the channel lifecycle. This is to avoid
// the situation where a channel force-closes autonomously and the user
// not being able to query for htlc outcomes anymore.
finalHtlcsBucket = []byte("final-htlcs")
)
var (
@ -618,6 +639,20 @@ func (c ChannelStatus) String() string {
return statusStr
}
// FinalHtlcByte defines a byte type that encodes information about the final
// htlc resolution.
type FinalHtlcByte byte
const (
// FinalHtlcSettledBit is the bit that encodes whether the htlc was
// settled or failed.
FinalHtlcSettledBit FinalHtlcByte = 1 << 0
// FinalHtlcOffchainBit is the bit that encodes whether the htlc was
// resolved offchain or onchain.
FinalHtlcOffchainBit FinalHtlcByte = 1 << 1
)
// OpenChannel encapsulates the persistent and dynamic state of an open channel
// with a remote node. An open channel supports several options for on-disk
// serialization depending on the exact context. Full (upon channel creation)
@ -1043,6 +1078,26 @@ func fetchChanBucketRw(tx kvdb.RwTx, nodeKey *btcec.PublicKey,
return chanBucket, nil
}
func fetchFinalHtlcsBucketRw(tx kvdb.RwTx,
chanID lnwire.ShortChannelID) (kvdb.RwBucket, error) {
finalHtlcsBucket, err := tx.CreateTopLevelBucket(finalHtlcsBucket)
if err != nil {
return nil, err
}
var chanIDBytes [8]byte
byteOrder.PutUint64(chanIDBytes[:], chanID.ToUint64())
chanBucket, err := finalHtlcsBucket.CreateBucketIfNotExists(
chanIDBytes[:],
)
if err != nil {
return nil, err
}
return chanBucket, nil
}
// fullSync syncs the contents of an OpenChannel while re-using an existing
// database transaction.
func (c *OpenChannel) fullSync(tx kvdb.RwTx) error {
@ -1739,8 +1794,12 @@ func syncNewChannel(tx kvdb.RwTx, c *OpenChannel, addrs []net.Addr) error {
// persisted to be able to produce a valid commit signature if a restart would
// occur. This method its to be called when we revoke our prior commitment
// state.
//
// A map is returned of all the htlc resolutions that were locked in in this
// commitment. Keys correspond to htlc indices and values indicate whether the
// htlc was settled or failed.
func (c *OpenChannel) UpdateCommitment(newCommitment *ChannelCommitment,
unsignedAckedUpdates []LogUpdate) error {
unsignedAckedUpdates []LogUpdate) (map[uint64]bool, error) {
c.Lock()
defer c.Unlock()
@ -1749,9 +1808,11 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *ChannelCommitment,
// state as all, as it's impossible to do so in a protocol compliant
// manner.
if c.hasChanStatus(ChanStatusRestored) {
return ErrNoRestoredChannelMutation
return nil, ErrNoRestoredChannelMutation
}
var finalHtlcs = make(map[uint64]bool)
err := kvdb.Update(c.Db.backend, func(tx kvdb.RwTx) error {
chanBucket, err := fetchChanBucketRw(
tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash,
@ -1822,17 +1883,35 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *ChannelCommitment,
return err
}
var validUpdates []LogUpdate
// Get the bucket where settled htlcs are recorded.
finalHtlcsBucket, err := fetchFinalHtlcsBucketRw(
tx, c.ShortChannelID,
)
if err != nil {
return err
}
var unsignedUpdates []LogUpdate
for _, upd := range updates {
// Filter for updates that are not on our local
// commitment.
// Gather updates that are not on our local commitment.
if upd.LogIndex >= newCommitment.LocalLogIndex {
validUpdates = append(validUpdates, upd)
unsignedUpdates = append(unsignedUpdates, upd)
continue
}
// The update was locked in. If the update was a
// resolution, then store it in the database.
err := processFinalHtlc(
finalHtlcsBucket, upd, finalHtlcs,
)
if err != nil {
return err
}
}
var b3 bytes.Buffer
err = serializeLogUpdates(&b3, validUpdates)
err = serializeLogUpdates(&b3, unsignedUpdates)
if err != nil {
return fmt.Errorf("unable to serialize log updates: %v", err)
}
@ -1843,12 +1922,57 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *ChannelCommitment,
}
return nil
}, func() {})
}, func() {
finalHtlcs = make(map[uint64]bool)
})
if err != nil {
return nil, err
}
c.LocalCommitment = *newCommitment
return finalHtlcs, nil
}
// processFinalHtlc stores a final htlc outcome in the database if signaled via
// the supplied log update. An in-memory htlcs map is updated too.
func processFinalHtlc(finalHtlcsBucket walletdb.ReadWriteBucket, upd LogUpdate,
finalHtlcs map[uint64]bool) error {
var (
settled bool
id uint64
)
switch msg := upd.UpdateMsg.(type) {
case *lnwire.UpdateFulfillHTLC:
settled = true
id = msg.ID
case *lnwire.UpdateFailHTLC:
settled = false
id = msg.ID
case *lnwire.UpdateFailMalformedHTLC:
settled = false
id = msg.ID
default:
return nil
}
err := putFinalHtlc(
finalHtlcsBucket, id,
FinalHtlcInfo{
Settled: settled,
Offchain: true,
},
)
if err != nil {
return err
}
c.LocalCommitment = *newCommitment
finalHtlcs[id] = settled
return nil
}
@ -2681,6 +2805,36 @@ func (c *OpenChannel) AdvanceCommitChainTail(fwdPkg *FwdPkg,
return nil
}
// FinalHtlcInfo contains information about the final outcome of an htlc.
type FinalHtlcInfo struct {
// Settled is true is the htlc was settled. If false, the htlc was
// failed.
Settled bool
// Offchain indicates whether the htlc was resolved off-chain or
// on-chain.
Offchain bool
}
// putFinalHtlc writes the final htlc outcome to the database. Additionally it
// records whether the htlc was resolved off-chain or on-chain.
func putFinalHtlc(finalHtlcsBucket kvdb.RwBucket, id uint64,
info FinalHtlcInfo) error {
var key [8]byte
byteOrder.PutUint64(key[:], id)
var finalHtlcByte FinalHtlcByte
if info.Settled {
finalHtlcByte |= FinalHtlcSettledBit
}
if info.Offchain {
finalHtlcByte |= FinalHtlcOffchainBit
}
return finalHtlcsBucket.Put(key[:], []byte{byte(finalHtlcByte)})
}
// NextLocalHtlcIndex returns the next unallocated local htlc index. To ensure
// this always returns the next index that has been not been allocated, this
// will first try to examine any pending commitments, before falling back to the

View File

@ -641,7 +641,7 @@ func TestChannelStateTransition(t *testing.T) {
},
}
err = channel.UpdateCommitment(&commitment, unsignedAckedUpdates)
_, err = channel.UpdateCommitment(&commitment, unsignedAckedUpdates)
require.NoError(t, err, "unable to update commitment")
// Assert that update is correctly written to the database.
@ -1457,3 +1457,41 @@ func TestKeyLocatorEncoding(t *testing.T) {
// version are equal.
require.Equal(t, keyLoc, decodedKeyLoc)
}
// TestFinalHtlcs tests final htlc storage and retrieval.
func TestFinalHtlcs(t *testing.T) {
t.Parallel()
fullDB, err := MakeTestDB(t)
require.NoError(t, err, "unable to make test database")
cdb := fullDB.ChannelStateDB()
chanID := lnwire.ShortChannelID{
BlockHeight: 1,
TxIndex: 2,
TxPosition: 3,
}
// Test offchain final htlcs.
const offchainHtlcID = 1
err = kvdb.Update(cdb.backend, func(tx kvdb.RwTx) error {
bucket, err := fetchFinalHtlcsBucketRw(
tx, chanID,
)
require.NoError(t, err)
return putFinalHtlc(bucket, offchainHtlcID, FinalHtlcInfo{
Settled: true,
Offchain: true,
})
}, func() {})
require.NoError(t, err)
// Test onchain final htlcs.
const onchainHtlcID = 2
err = cdb.PutOnchainFinalHtlcOutcome(chanID, onchainHtlcID, true)
require.NoError(t, err)
}

View File

@ -1652,6 +1652,27 @@ func (c *ChannelStateDB) FetchHistoricalChannel(outPoint *wire.OutPoint) (
return channel, nil
}
// PutOnchainFinalHtlcOutcome stores the final on-chain outcome of an htlc in
// the database.
func (c *ChannelStateDB) PutOnchainFinalHtlcOutcome(
chanID lnwire.ShortChannelID, htlcID uint64, settled bool) error {
return kvdb.Update(c.backend, func(tx kvdb.RwTx) error {
finalHtlcsBucket, err := fetchFinalHtlcsBucketRw(tx, chanID)
if err != nil {
return err
}
return putFinalHtlc(
finalHtlcsBucket, htlcID,
FinalHtlcInfo{
Settled: settled,
Offchain: false,
},
)
}, func() {})
}
// MakeTestDB creates a new instance of the ChannelDB for testing purposes.
// A callback which cleans up the created temporary directories is also
// returned and intended to be executed after the test completes.

View File

@ -355,7 +355,7 @@ func TestRestoreChannelShells(t *testing.T) {
// Ensure that it isn't possible to modify the commitment state machine
// of this restored channel.
channel := nodeChans[0]
err = channel.UpdateCommitment(nil, nil)
_, err = channel.UpdateCommitment(nil, nil)
if err != ErrNoRestoredChannelMutation {
t.Fatalf("able to mutate restored channel")
}

View File

@ -2451,7 +2451,7 @@ func forceStateTransition(chanA, chanB *lnwallet.LightningChannel) error {
return err
}
bobRevocation, _, err := chanB.RevokeCurrentCommitment()
bobRevocation, _, _, err := chanB.RevokeCurrentCommitment()
if err != nil {
return err
}
@ -2468,7 +2468,7 @@ func forceStateTransition(chanA, chanB *lnwallet.LightningChannel) error {
return err
}
aliceRevocation, _, err := chanA.RevokeCurrentCommitment()
aliceRevocation, _, _, err := chanA.RevokeCurrentCommitment()
if err != nil {
return err
}

View File

@ -187,6 +187,11 @@ type ChainArbitratorConfig struct {
// complete.
SubscribeBreachComplete func(op *wire.OutPoint, c chan struct{}) (
bool, error)
// PutFinalHtlcOutcome stores the final outcome of an htlc in the
// database.
PutFinalHtlcOutcome func(chanId lnwire.ShortChannelID,
htlcId uint64, settled bool) error
}
// ChainArbitrator is a sub-system that oversees the on-chain resolution of all

View File

@ -1460,6 +1460,10 @@ const (
// other party time it out, or eventually learn of the pre-image, in
// which case we'll claim on chain.
HtlcIncomingWatchAction = 5
// HtlcIncomingDustFinalAction indicates that we should mark an incoming
// dust htlc as final because it can't be claimed on-chain.
HtlcIncomingDustFinalAction = 6
)
// String returns a human readable string describing a chain action.
@ -1483,6 +1487,9 @@ func (c ChainAction) String() string {
case HtlcIncomingWatchAction:
return "HtlcIncomingWatchAction"
case HtlcIncomingDustFinalAction:
return "HtlcIncomingDustFinalAction"
default:
return "<unknown action>"
}
@ -1698,6 +1705,10 @@ func (c *ChannelArbitrator) checkCommitChainActions(height uint32,
"needed for incoming dust htlc=%x",
c.cfg.ChanPoint, htlc.RHash[:])
actionMap[HtlcIncomingDustFinalAction] = append(
actionMap[HtlcIncomingDustFinalAction], htlc,
)
continue
}
@ -2213,6 +2224,27 @@ func (c *ChannelArbitrator) prepContractResolutions(
htlcResolvers = append(htlcResolvers, resolver)
}
// We've lost an htlc because it isn't manifested on the
// commitment transaction that closed the channel.
case HtlcIncomingDustFinalAction:
for _, htlc := range htlcs {
htlc := htlc
key := channeldb.CircuitKey{
ChanID: c.cfg.ShortChanID,
HtlcID: htlc.HtlcIndex,
}
// Mark this dust htlc as final failed.
chainArbCfg := c.cfg.ChainArbitratorConfig
err := chainArbCfg.PutFinalHtlcOutcome(
key.ChanID, key.HtlcID, false,
)
if err != nil {
return nil, nil, err
}
}
// Finally, if this is an outgoing HTLC we've sent, then we'll
// launch a resolver to watch for the pre-image (and settle
// backwards), or just timeout.

View File

@ -206,6 +206,8 @@ type chanArbTestCtx struct {
breachSubscribed chan struct{}
breachResolutionChan chan struct{}
finalHtlcs map[uint64]bool
}
func (c *chanArbTestCtx) CleanUp() {
@ -306,6 +308,7 @@ func createTestChannelArbitrator(t *testing.T, log ArbitratorLog,
chanArbCtx := &chanArbTestCtx{
breachSubscribed: make(chan struct{}),
finalHtlcs: make(map[uint64]bool),
}
chanPoint := wire.OutPoint{}
@ -360,6 +363,13 @@ func createTestChannelArbitrator(t *testing.T, log ArbitratorLog,
},
Clock: clock.NewDefaultClock(),
Sweeper: mockSweeper,
PutFinalHtlcOutcome: func(chanId lnwire.ShortChannelID,
htlcId uint64, settled bool) error {
chanArbCtx.finalHtlcs[htlcId] = settled
return nil
},
}
// We'll use the resolvedChan to synchronize on call to
@ -966,6 +976,12 @@ func TestChannelArbitratorLocalForceClosePendingHtlc(t *testing.T) {
t.Fatalf("unable to stop chan arb: %v", err)
}
// Assert that a final resolution was stored for the incoming dust htlc.
expectedFinalHtlcs := map[uint64]bool{
incomingDustHtlc.HtlcIndex: false,
}
require.Equal(t, expectedFinalHtlcs, chanArbCtx.finalHtlcs)
// We'll no re-create the resolver, notice that we use the existing
// arbLog so it carries over the same on-disk state.
chanArbCtxNew, err := chanArbCtx.Restart(nil)

View File

@ -50,6 +50,18 @@ func newIncomingContestResolver(
}
}
func (h *htlcIncomingContestResolver) processFinalHtlcFail() error {
// Mark the htlc as final failed.
err := h.ChainArbitratorConfig.PutFinalHtlcOutcome(
h.ChannelArbitratorConfig.ShortChanID, h.htlc.HtlcIndex, false,
)
if err != nil {
return err
}
return nil
}
// Resolve attempts to resolve this contract. As we don't yet know of the
// preimage for the contract, we'll wait for one of two things to happen:
//
@ -83,6 +95,10 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
// link has ran.
h.resolved = true
if err := h.processFinalHtlcFail(); err != nil {
return nil, err
}
// We write a report to disk that indicates we could not decode
// the htlc.
resReport := h.report().resolverReport(
@ -129,6 +145,10 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
h.htlcExpiry, currentHeight)
h.resolved = true
if err := h.processFinalHtlcFail(); err != nil {
return nil, err
}
// Finally, get our report and checkpoint our resolver with a
// timeout outcome report.
report := h.report().resolverReport(
@ -201,6 +221,10 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
h.resolved = true
if err := h.processFinalHtlcFail(); err != nil {
return nil, err
}
// Checkpoint our resolver with an abandoned outcome
// because we take no further action on this htlc.
report := h.report().resolverReport(
@ -343,6 +367,10 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
h.htlcExpiry, currentHeight)
h.resolved = true
if err := h.processFinalHtlcFail(); err != nil {
return nil, err
}
report := h.report().resolverReport(
nil,
channeldb.ResolverTypeIncomingHtlc,

View File

@ -16,6 +16,7 @@ import (
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require"
)
const (
@ -298,14 +299,15 @@ func (o *mockOnionProcessor) ReconstructHopIterator(r io.Reader, rHash []byte) (
}
type incomingResolverTestContext struct {
registry *mockRegistry
witnessBeacon *mockWitnessBeacon
resolver *htlcIncomingContestResolver
notifier *mock.ChainNotifier
onionProcessor *mockOnionProcessor
resolveErr chan error
nextResolver ContractResolver
t *testing.T
registry *mockRegistry
witnessBeacon *mockWitnessBeacon
resolver *htlcIncomingContestResolver
notifier *mock.ChainNotifier
onionProcessor *mockOnionProcessor
resolveErr chan error
nextResolver ContractResolver
finalHtlcOutcomeStored bool
t *testing.T
}
func newIncomingResolverTestContext(t *testing.T, isExit bool) *incomingResolverTestContext {
@ -323,12 +325,27 @@ func newIncomingResolverTestContext(t *testing.T, isExit bool) *incomingResolver
checkPointChan := make(chan struct{}, 1)
c := &incomingResolverTestContext{
registry: registry,
witnessBeacon: witnessBeacon,
notifier: notifier,
onionProcessor: onionProcessor,
t: t,
}
chainCfg := ChannelArbitratorConfig{
ChainArbitratorConfig: ChainArbitratorConfig{
Notifier: notifier,
PreimageDB: witnessBeacon,
Registry: registry,
OnionProcessor: onionProcessor,
PutFinalHtlcOutcome: func(chanId lnwire.ShortChannelID,
htlcId uint64, settled bool) error {
c.finalHtlcOutcomeStored = true
return nil
},
},
PutResolverReport: func(_ kvdb.RwTx,
_ *channeldb.ResolverReport) error {
@ -346,7 +363,8 @@ func newIncomingResolverTestContext(t *testing.T, isExit bool) *incomingResolver
return nil
},
}
resolver := &htlcIncomingContestResolver{
c.resolver = &htlcIncomingContestResolver{
htlcSuccessResolver: &htlcSuccessResolver{
contractResolverKit: *newContractResolverKit(cfg),
htlcResolution: lnwallet.IncomingHtlcResolution{},
@ -359,14 +377,7 @@ func newIncomingResolverTestContext(t *testing.T, isExit bool) *incomingResolver
htlcExpiry: testHtlcExpiry,
}
return &incomingResolverTestContext{
registry: registry,
witnessBeacon: witnessBeacon,
resolver: resolver,
notifier: notifier,
onionProcessor: onionProcessor,
t: t,
}
return c
}
func (i *incomingResolverTestContext) resolve() {
@ -400,6 +411,10 @@ func (i *incomingResolverTestContext) waitForResult(expectSuccessRes bool) {
if i.nextResolver != nil {
i.t.Fatal("expected no next resolver")
}
require.True(i.t, i.finalHtlcOutcomeStored,
"expected final htlc outcome to be stored")
return
}

View File

@ -469,6 +469,14 @@ func (h *htlcSuccessResolver) resolveRemoteCommitOutput() (
func (h *htlcSuccessResolver) checkpointClaim(spendTx *chainhash.Hash,
outcome channeldb.ResolverOutcome) error {
// Mark the htlc as final settled.
err := h.ChainArbitratorConfig.PutFinalHtlcOutcome(
h.ChannelArbitratorConfig.ShortChanID, h.htlc.HtlcIndex, true,
)
if err != nil {
return err
}
// Create a resolver report for claiming of the htlc itself.
amt := btcutil.Amount(h.htlcResolution.SweepSignDesc.Output.Value)
reports := []*channeldb.ResolverReport{

View File

@ -31,6 +31,8 @@ type htlcResolverTestContext struct {
resolverResultChan chan resolveResult
resolutionChan chan ResolutionMsg
finalHtlcOutcomeStored bool
t *testing.T
}
@ -75,6 +77,13 @@ func newHtlcResolverTestContext(t *testing.T,
testCtx.resolutionChan <- msgs[0]
return nil
},
PutFinalHtlcOutcome: func(chanId lnwire.ShortChannelID,
htlcId uint64, settled bool) error {
testCtx.finalHtlcOutcomeStored = true
return nil
},
},
PutResolverReport: func(_ kvdb.RwTx,
report *channeldb.ResolverReport) error {
@ -186,6 +195,7 @@ func TestHtlcSuccessSingleStage(t *testing.T) {
reports: []*channeldb.ResolverReport{
claim,
},
finalHtlcStored: true,
},
}
@ -269,6 +279,7 @@ func TestHtlcSuccessSecondStageResolution(t *testing.T) {
secondStage,
firstStage,
},
finalHtlcStored: true,
},
}
@ -450,6 +461,7 @@ func TestHtlcSuccessSecondStageResolutionSweeper(t *testing.T) {
secondStage,
firstStage,
},
finalHtlcStored: true,
},
}
@ -465,9 +477,10 @@ type checkpoint struct {
preCheckpoint func(*htlcResolverTestContext, bool) error
// data we expect the resolver to be checkpointed with next.
incubating bool
resolved bool
reports []*channeldb.ResolverReport
incubating bool
resolved bool
reports []*channeldb.ResolverReport
finalHtlcStored bool
}
// testHtlcSuccess tests resolution of a success resolver. It takes a a list of
@ -573,6 +586,11 @@ func runFromCheckpoint(t *testing.T, ctx *htlcResolverTestContext,
}
}
// Check that the final htlc outcome is stored.
if cp.finalHtlcStored != ctx.finalHtlcOutcomeStored {
t.Fatal("final htlc store expectation failed")
}
// Finally encode the resolver, and store it for later use.
b := bytes.Buffer{}
if err := resolver.Encode(&b); err != nil {

View File

@ -1920,7 +1920,8 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) {
// As we've just accepted a new state, we'll now
// immediately send the remote peer a revocation for our prior
// state.
nextRevocation, currentHtlcs, err := l.channel.RevokeCurrentCommitment()
nextRevocation, currentHtlcs, _, err :=
l.channel.RevokeCurrentCommitment()
if err != nil {
l.log.Errorf("unable to revoke commitment: %v", err)
return

View File

@ -179,7 +179,7 @@ func (l *linkTestContext) receiveCommitSigAlice(expHtlcs int) *lnwire.CommitSig
func (l *linkTestContext) sendRevAndAckBobToAlice() {
l.t.Helper()
rev, _, err := l.bobChannel.RevokeCurrentCommitment()
rev, _, _, err := l.bobChannel.RevokeCurrentCommitment()
if err != nil {
l.t.Fatalf("unable to revoke commitment: %v", err)
}

View File

@ -1958,7 +1958,7 @@ func handleStateUpdate(link *channelLink,
return err
}
remoteRev, _, err := remoteChannel.RevokeCurrentCommitment()
remoteRev, _, _, err := remoteChannel.RevokeCurrentCommitment()
if err != nil {
return err
}
@ -2062,7 +2062,7 @@ func updateState(batchTick chan time.Time, link *channelLink,
}
// Lastly, send a revocation back to the link.
remoteRev, _, err := remoteChannel.RevokeCurrentCommitment()
remoteRev, _, _, err := remoteChannel.RevokeCurrentCommitment()
if err != nil {
return err
}
@ -3134,7 +3134,7 @@ func TestChannelLinkTrimCircuitsRemoteCommit(t *testing.T) {
// Next, revoke Bob's current commitment and send it to Alice so that we
// can test that Alice's circuits aren't trimmed.
rev, _, err := bobChan.RevokeCurrentCommitment()
rev, _, _, err := bobChan.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke current commitment")
_, _, _, _, err = alice.channel.ReceiveRevocation(rev)

View File

@ -4779,15 +4779,17 @@ func (lc *LightningChannel) PendingLocalUpdateCount() uint64 {
// chain is advanced by a single commitment. This now lowest unrevoked
// commitment becomes our currently accepted state within the channel. This
// method also returns the set of HTLC's currently active within the commitment
// transaction. This return value allows callers to act once an HTLC has been
// locked into our commitment transaction.
func (lc *LightningChannel) RevokeCurrentCommitment() (*lnwire.RevokeAndAck, []channeldb.HTLC, error) {
// transaction and the htlcs the were resolved. This return value allows callers
// to act once an HTLC has been locked into our commitment transaction.
func (lc *LightningChannel) RevokeCurrentCommitment() (*lnwire.RevokeAndAck,
[]channeldb.HTLC, map[uint64]bool, error) {
lc.Lock()
defer lc.Unlock()
revocationMsg, err := lc.generateRevocation(lc.currentHeight)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
lc.log.Tracef("revoking height=%v, now at height=%v",
@ -4808,11 +4810,11 @@ func (lc *LightningChannel) RevokeCurrentCommitment() (*lnwire.RevokeAndAck, []c
// is committed locally.
unsignedAckedUpdates := lc.getUnsignedAckedUpdates()
err = lc.channelState.UpdateCommitment(
finalHtlcs, err := lc.channelState.UpdateCommitment(
newCommitment, unsignedAckedUpdates,
)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
lc.log.Tracef("state transition accepted: "+
@ -4825,7 +4827,7 @@ func (lc *LightningChannel) RevokeCurrentCommitment() (*lnwire.RevokeAndAck, []c
&lc.channelState.FundingOutpoint,
)
return revocationMsg, newCommitment.Htlcs, nil
return revocationMsg, newCommitment.Htlcs, finalHtlcs, nil
}
// ReceiveRevocation processes a revocation sent by the remote party for the

View File

@ -104,7 +104,7 @@ func testAddSettleWorkflow(t *testing.T, tweakless bool) {
// Bob revokes his prior commitment given to him by Alice, since he now
// has a valid signature for a newer commitment.
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to generate bob revocation")
// Bob finally send a signature for Alice's commitment transaction.
@ -135,7 +135,7 @@ func testAddSettleWorkflow(t *testing.T, tweakless bool) {
require.NoError(t, err, "alice unable to process bob's new commitment")
// Alice then generates a revocation for bob.
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke alice channel")
// Finally Bob processes Alice's revocation, at this point the new HTLC
@ -220,7 +220,7 @@ func testAddSettleWorkflow(t *testing.T, tweakless bool) {
err = aliceChannel.ReceiveNewCommitment(bobSig2, bobHtlcSigs2)
require.NoError(t, err, "alice unable to process bob's new commitment")
aliceRevocation2, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation2, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "alice unable to generate revocation")
aliceSig2, aliceHtlcSigs2, _, err := aliceChannel.SignNextCommitment()
require.NoError(t, err, "alice unable to sign new commitment")
@ -239,8 +239,17 @@ func testAddSettleWorkflow(t *testing.T, tweakless bool) {
err = bobChannel.ReceiveNewCommitment(aliceSig2, aliceHtlcSigs2)
require.NoError(t, err, "bob unable to process alice's new commitment")
bobRevocation2, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation2, _, finalHtlcs, err := bobChannel.
RevokeCurrentCommitment()
require.NoError(t, err, "bob unable to revoke commitment")
// Check finalHtlcs for the expected final resolution.
require.Len(t, finalHtlcs, 1, "final htlc expected")
for _, settled := range finalHtlcs {
require.True(t, settled, "final settle expected")
}
fwdPkg, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation2)
require.NoError(t, err, "alice unable to process bob's revocation")
if len(fwdPkg.Adds) != 0 {
@ -393,7 +402,7 @@ func TestChannelZeroAddLocalHeight(t *testing.T) {
// Alice should reply with a revocation.
// -----rev----->
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
@ -570,7 +579,7 @@ func testCommitHTLCSigTieBreak(t *testing.T, restart bool) {
err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs)
require.NoError(t, err, "unable to receive alice's commitment")
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke bob's commitment")
_, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation)
require.NoError(t, err, "unable to receive bob's revocation")
@ -2312,7 +2321,7 @@ func TestUpdateFeeConcurrentSig(t *testing.T) {
// Bob can revoke the prior commitment he had. This should lock in the
// fee update for him.
_, _, err = bobChannel.RevokeCurrentCommitment()
_, _, _, err = bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to generate bob revocation")
if chainfee.SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee {
@ -2378,7 +2387,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
// Bob can revoke the prior commitment he had. This should lock in the
// fee update for him.
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to generate bob revocation")
if chainfee.SatPerKWeight(
@ -2413,7 +2422,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
// Alice can revoke the old commitment, which will lock in the fee
// update.
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke alice channel")
if chainfee.SatPerKWeight(
@ -2480,7 +2489,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
// Alice can revoke the prior commitment she had, this will ack
// everything received before last commitment signature, but in this
// case that is nothing.
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to generate bob revocation")
// Bob receives the revocation of the old commitment
@ -2508,7 +2517,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
// Bob can revoke the old commitment. This will ack what he has
// received, including the HTLC and fee update. This will lock in the
// fee update for bob.
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke alice channel")
if chainfee.SatPerKWeight(
@ -2542,7 +2551,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
// After Alice now revokes her old commitment, the fee update should
// lock in.
aliceRevocation, _, err = aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err = aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to generate bob revocation")
if chainfee.SatPerKWeight(
@ -2644,7 +2653,7 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
// Bob can revoke the prior commitment he had. This should lock in the
// fee update for him.
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to generate bob revocation")
if chainfee.SatPerKWeight(
@ -2680,7 +2689,7 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
// Alice can revoke the old commitment, which will lock in the fee
// update.
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke alice channel")
if chainfee.SatPerKWeight(
@ -3074,7 +3083,7 @@ func TestChanSyncOweCommitment(t *testing.T) {
// adding one of her own.
err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs)
require.NoError(t, err, "bob unable to process alice's commitment")
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke bob commitment")
bobSig, bobHtlcSigs, _, err := bobChannel.SignNextCommitment()
require.NoError(t, err, "bob unable to sign commitment")
@ -3082,7 +3091,7 @@ func TestChanSyncOweCommitment(t *testing.T) {
require.NoError(t, err, "alice unable to recv revocation")
err = aliceChannel.ReceiveNewCommitment(bobSig, bobHtlcSigs)
require.NoError(t, err, "alice unable to rev bob's commitment")
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "alice unable to revoke commitment")
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err, "bob unable to recv revocation")
@ -3234,7 +3243,7 @@ func TestChanSyncOweCommitmentPendingRemote(t *testing.T) {
// completes, the htlc is settled on the local commitment
// transaction. Bob still owes Alice a signature to also settle
// the htlc on her local commitment transaction.
bobRevoke, _, err := bobChannel.RevokeCurrentCommitment()
bobRevoke, _, _, err := bobChannel.RevokeCurrentCommitment()
if err != nil {
t.Fatalf("unable to revoke commitment: %v", err)
}
@ -3264,7 +3273,7 @@ func TestChanSyncOweCommitmentPendingRemote(t *testing.T) {
if err != nil {
t.Fatal(err)
}
aliceRevoke, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevoke, _, _, err := aliceChannel.RevokeCurrentCommitment()
if err != nil {
t.Fatal(err)
}
@ -3330,7 +3339,7 @@ func TestChanSyncOweRevocation(t *testing.T) {
err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs)
require.NoError(t, err, "bob unable to process alice's commitment")
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke bob commitment")
bobSig, bobHtlcSigs, _, err := bobChannel.SignNextCommitment()
require.NoError(t, err, "bob unable to sign commitment")
@ -3342,7 +3351,7 @@ func TestChanSyncOweRevocation(t *testing.T) {
// At this point, we'll simulate the connection breaking down by Bob's
// lack of knowledge of the revocation message that Alice just sent.
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "alice unable to revoke commitment")
// If we fetch the channel sync messages at this state, then Alice
@ -3482,7 +3491,7 @@ func TestChanSyncOweRevocationAndCommit(t *testing.T) {
// Bob generates the revoke and sig message, but the messages don't
// reach Alice before the connection dies.
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke bob commitment")
bobSig, bobHtlcSigs, _, err := bobChannel.SignNextCommitment()
require.NoError(t, err, "bob unable to sign commitment")
@ -3559,7 +3568,7 @@ func TestChanSyncOweRevocationAndCommit(t *testing.T) {
require.NoError(t, err, "alice unable to recv revocation")
err = aliceChannel.ReceiveNewCommitment(bobSig, bobHtlcSigs)
require.NoError(t, err, "alice unable to rev bob's commitment")
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "alice unable to revoke commitment")
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err, "bob unable to recv revocation")
@ -3630,7 +3639,7 @@ func TestChanSyncOweRevocationAndCommitForceTransition(t *testing.T) {
// signature for Bob's updated state. Instead she will issue a new
// update before sending a new CommitSig. This will lead to Alice's
// local commit chain getting height > remote commit chain.
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "alice unable to revoke commitment")
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err, "bob unable to recv revocation")
@ -3652,7 +3661,7 @@ func TestChanSyncOweRevocationAndCommitForceTransition(t *testing.T) {
// Bob then sends his revocation message, but before Alice can process
// it (and before he scan send his CommitSig message), then connection
// dies.
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke bob commitment")
// Now if we attempt to synchronize states at this point, Alice should
@ -3746,7 +3755,7 @@ func TestChanSyncOweRevocationAndCommitForceTransition(t *testing.T) {
bobSigMsg.CommitSig, bobSigMsg.HtlcSigs,
)
require.NoError(t, err, "alice unable to rev bob's commitment")
aliceRevocation, _, err = aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err = aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "alice unable to revoke commitment")
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err, "bob unable to recv revocation")
@ -4132,7 +4141,7 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) {
err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs)
require.NoError(t, err, "bob unable to process alice's commitment")
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke bob commitment")
bobSig, bobHtlcSigs, _, err := bobChannel.SignNextCommitment()
require.NoError(t, err, "bob unable to sign commitment")
@ -4140,7 +4149,7 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) {
require.NoError(t, err, "alice unable to recv revocation")
err = aliceChannel.ReceiveNewCommitment(bobSig, bobHtlcSigs)
require.NoError(t, err, "alice unable to rev bob's commitment")
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "alice unable to revoke commitment")
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err, "bob unable to recv revocation")
@ -4330,7 +4339,7 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) {
// transition.
err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs)
require.NoError(t, err, "bob unable to process alice's commitment")
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke bob commitment")
bobSig, bobHtlcSigs, _, err := bobChannel.SignNextCommitment()
require.NoError(t, err, "bob unable to sign commitment")
@ -4338,7 +4347,7 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) {
require.NoError(t, err, "alice unable to recv revocation")
err = aliceChannel.ReceiveNewCommitment(bobSig, bobHtlcSigs)
require.NoError(t, err, "alice unable to rev bob's commitment")
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "alice unable to revoke commitment")
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err, "bob unable to recv revocation")
@ -5013,7 +5022,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) {
if err != nil {
t.Fatal(err)
}
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
if err != nil {
t.Fatal(err)
}
@ -5043,7 +5052,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) {
if err != nil {
t.Fatal(err)
}
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
if err != nil {
t.Fatal(err)
}
@ -5087,7 +5096,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) {
if err != nil {
t.Fatal(err)
}
aliceRevocation, _, err = aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err = aliceChannel.RevokeCurrentCommitment()
if err != nil {
t.Fatal(err)
}
@ -5130,11 +5139,18 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) {
err = aliceChannel.ReceiveFailHTLC(htlc2.ID, []byte("bad"))
require.NoError(t, err, "unable to recv htlc cancel")
bobRevocation, _, err = bobChannel.RevokeCurrentCommitment()
bobRevocation, _, finalHtlcs, err := bobChannel.
RevokeCurrentCommitment()
if err != nil {
t.Fatal(err)
}
// Check finalHtlcs for the expected final resolution.
require.Len(t, finalHtlcs, 1, "final htlc expected")
for _, settled := range finalHtlcs {
require.False(t, settled, "final fail expected")
}
// Alice should detect that she doesn't need to forward any Adds's, but
// that the Fail has been locked in an can be forwarded.
_, adds, settleFails, _, err := aliceChannel.ReceiveRevocation(bobRevocation)
@ -5179,7 +5195,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) {
if err != nil {
t.Fatal(err)
}
bobRevocation, _, err = bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err = bobChannel.RevokeCurrentCommitment()
if err != nil {
t.Fatal(err)
}
@ -5210,7 +5226,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) {
t.Fatal(err)
}
aliceRevocation, _, err = aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err = aliceChannel.RevokeCurrentCommitment()
if err != nil {
t.Fatal(err)
}
@ -5240,7 +5256,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) {
if err != nil {
t.Fatal(err)
}
bobRevocation, _, err = bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err = bobChannel.RevokeCurrentCommitment()
if err != nil {
t.Fatal(err)
}
@ -5852,13 +5868,13 @@ func TestMaxAsynchronousHtlcs(t *testing.T) {
require.NoError(t, err, "unable to receive new commitment")
// Both sides exchange revocations as in step 4 & 5.
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke revocation")
_, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation)
require.NoError(t, err, "unable to receive revocation")
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke revocation")
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
@ -6549,7 +6565,7 @@ func TestChannelRestoreUpdateLogs(t *testing.T) {
// Bob receives this commitment signature, and revokes his old state.
err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs)
require.NoError(t, err, "unable to receive commitment")
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke commitment")
// When Alice now receives this revocation, she will advance her remote
@ -6728,7 +6744,7 @@ func TestChannelRestoreUpdateLogsFailedHTLC(t *testing.T) {
assertInLogs(t, aliceChannel, 1, 0, 0, 1)
restoreAndAssert(t, aliceChannel, 1, 0, 0, 0)
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke commitment")
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err, "bob unable to process alice's revocation")
@ -6758,7 +6774,7 @@ func TestChannelRestoreUpdateLogsFailedHTLC(t *testing.T) {
// When Alice receives Bob's revocation, the Fail is irrevocably locked
// in on both sides. She should compact the logs, removing the HTLC and
// the corresponding Fail from the local update log.
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke commitment")
_, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation)
require.NoError(t, err, "unable to receive revocation")
@ -6974,7 +6990,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) {
// Bob receives this commitment signature, and revokes his old state.
err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs)
require.NoError(t, err, "unable to receive commitment")
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke commitment")
// Now the HTLC is locked into Bob's commitment, a restoration should
@ -7004,7 +7020,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) {
err = aliceChannel.ReceiveNewCommitment(bobSig, bobHtlcSigs)
require.NoError(t, err, "unable to receive commitment")
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke commitment")
// Now both the local and remote add heights should be properly set.
@ -7046,7 +7062,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) {
err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs)
require.NoError(t, err, "unable to receive commitment")
bobRevocation, _, err = bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err = bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke commitment")
// Since Bob just revoked another commitment, a restoration should
@ -7082,7 +7098,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) {
// Alice should receive the commitment and send over a revocation.
err = aliceChannel.ReceiveNewCommitment(bobSig, bobHtlcSigs)
require.NoError(t, err, "unable to receive commitment")
aliceRevocation, _, err = aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err = aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke commitment")
// Both heights should be 2 and they are on both commitments.
@ -7119,7 +7135,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) {
// Alice receives commitment, sends revocation.
err = aliceChannel.ReceiveNewCommitment(bobSig, bobHtlcSigs)
require.NoError(t, err, "unable to receive commitment")
_, _, err = aliceChannel.RevokeCurrentCommitment()
_, _, _, err = aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke commitment")
aliceChannel = restoreAndAssertCommitHeights(
@ -7173,7 +7189,7 @@ func TestForceCloseBorkedState(t *testing.T) {
require.NoError(t, err, "unable to sign commit")
err = bobChannel.ReceiveNewCommitment(aliceSigs, aliceHtlcSigs)
require.NoError(t, err, "unable to receive commitment")
revokeMsg, _, err := bobChannel.RevokeCurrentCommitment()
revokeMsg, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err, "unable to revoke bob commitment")
bobSigs, bobHtlcSigs, _, err := bobChannel.SignNextCommitment()
require.NoError(t, err, "unable to sign commit")
@ -7213,7 +7229,7 @@ func TestForceCloseBorkedState(t *testing.T) {
if err != channeldb.ErrChanBorked {
t.Fatalf("sign commitment should have failed: %v", err)
}
_, _, err = aliceChannel.RevokeCurrentCommitment()
_, _, _, err = aliceChannel.RevokeCurrentCommitment()
if err != channeldb.ErrChanBorked {
t.Fatalf("append remove chain tail should have failed")
}
@ -8792,7 +8808,7 @@ func TestChannelUnsignedAckedFailure(t *testing.T) {
// Alice should reply with a revocation.
// -----rev----->
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err)
@ -8817,7 +8833,7 @@ func TestChannelUnsignedAckedFailure(t *testing.T) {
// Bob revokes his current commitment and sends a revocation
// to Alice.
// <----rev------
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = newAliceChannel.ReceiveRevocation(bobRevocation)
require.NoError(t, err)
@ -8903,7 +8919,7 @@ func TestChannelLocalUnsignedUpdatesFailure(t *testing.T) {
// Bob should reply with a revocation and Alice should save the fail as
// an unsigned local update.
// <----rev-----
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation)
require.NoError(t, err)
@ -8987,7 +9003,7 @@ func TestChannelSignedAckRegression(t *testing.T) {
require.NoError(t, err)
// <----rev-----
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation)
require.NoError(t, err)
@ -9014,7 +9030,7 @@ func TestChannelSignedAckRegression(t *testing.T) {
require.NoError(t, err)
// <----rev-----
bobRevocation, _, err = bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err = bobChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation)
require.NoError(t, err)
@ -9027,7 +9043,7 @@ func TestChannelSignedAckRegression(t *testing.T) {
require.NoError(t, err)
// -----rev---->
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err)
fwdPkg, _, _, _, err := newBobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err)
@ -9119,7 +9135,7 @@ func TestIsChannelClean(t *testing.T) {
assertCleanOrDirty(false, aliceChannel, bobChannel, t)
// <---rev---
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation)
require.NoError(t, err)
@ -9133,7 +9149,7 @@ func TestIsChannelClean(t *testing.T) {
assertCleanOrDirty(false, aliceChannel, bobChannel, t)
// ---rev--->
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err)
@ -9154,7 +9170,7 @@ func TestIsChannelClean(t *testing.T) {
assertCleanOrDirty(false, aliceChannel, bobChannel, t)
// ---rev--->
aliceRevocation, _, err = aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err = aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err)
@ -9168,7 +9184,7 @@ func TestIsChannelClean(t *testing.T) {
assertCleanOrDirty(false, aliceChannel, bobChannel, t)
// <---rev---
bobRevocation, _, err = bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err = bobChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation)
require.NoError(t, err)
@ -9192,7 +9208,7 @@ func TestIsChannelClean(t *testing.T) {
assertCleanOrDirty(false, aliceChannel, bobChannel, t)
// <---rev---
bobRevocation, _, err = bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err = bobChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation)
require.NoError(t, err)
@ -9207,7 +9223,7 @@ func TestIsChannelClean(t *testing.T) {
// The state should finally be clean after alice sends her revocation.
// ---rev--->
aliceRevocation, _, err = aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err = aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err)
@ -9346,7 +9362,7 @@ func testGetDustSum(t *testing.T, chantype channeldb.ChannelType) {
// Bob now sends a revocation for his prior commitment, and this should
// change Alice's perspective to no longer include the first HTLC as
// dust.
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation)
require.NoError(t, err)
@ -9359,7 +9375,7 @@ func testGetDustSum(t *testing.T, chantype channeldb.ChannelType) {
require.NoError(t, err)
err = aliceChannel.ReceiveNewCommitment(bobSig, bobHtlcSigs)
require.NoError(t, err)
aliceRevocation, _, err := aliceChannel.RevokeCurrentCommitment()
aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation)
require.NoError(t, err)

View File

@ -502,7 +502,7 @@ func ForceStateTransition(chanA, chanB *LightningChannel) error {
return err
}
bobRevocation, _, err := chanB.RevokeCurrentCommitment()
bobRevocation, _, _, err := chanB.RevokeCurrentCommitment()
if err != nil {
return err
}
@ -518,7 +518,7 @@ func ForceStateTransition(chanA, chanB *LightningChannel) error {
return err
}
aliceRevocation, _, err := chanA.RevokeCurrentCommitment()
aliceRevocation, _, _, err := chanA.RevokeCurrentCommitment()
if err != nil {
return err
}

View File

@ -291,7 +291,7 @@ func testVectors(t *testing.T, chanType channeldb.ChannelType, test testCase) {
err = remoteChannel.ReceiveNewCommitment(localSig, localHtlcSigs)
require.NoError(t, err)
revMsg, _, err := remoteChannel.RevokeCurrentCommitment()
revMsg, _, _, err := remoteChannel.RevokeCurrentCommitment()
require.NoError(t, err)
_, _, _, _, err = localChannel.ReceiveRevocation(revMsg)
@ -309,7 +309,7 @@ func testVectors(t *testing.T, chanType channeldb.ChannelType, test testCase) {
err = localChannel.ReceiveNewCommitment(remoteSig, remoteHtlcSigs)
require.NoError(t, err)
_, _, err = localChannel.RevokeCurrentCommitment()
_, _, _, err = localChannel.RevokeCurrentCommitment()
require.NoError(t, err)
// Now the local node force closes the channel so that we can inspect

View File

@ -1165,6 +1165,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
IsForwardedHTLC: s.htlcSwitch.IsForwardedHTLC,
Clock: clock.NewDefaultClock(),
SubscribeBreachComplete: s.breachArbiter.SubscribeBreachComplete,
PutFinalHtlcOutcome: s.chanStateDB.PutOnchainFinalHtlcOutcome, // nolint: lll
}, dbs.ChanStateDB)
// Select the configuration and furnding parameters for Bitcoin or