From b7aebd92cf22ade5cc511dd270bff31bf6dfde28 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 18 Sep 2018 00:22:38 -0700 Subject: [PATCH 1/4] cnct/contract_resolvers: reliably publish commit sweep --- contractcourt/contract_resolvers.go | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/contractcourt/contract_resolvers.go b/contractcourt/contract_resolvers.go index 223220d6..d0d7328e 100644 --- a/contractcourt/contract_resolvers.go +++ b/contractcourt/contract_resolvers.go @@ -1258,18 +1258,33 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) { log.Infof("%T(%v): sweeping commit output with tx=%v", c, c.chanPoint, spew.Sdump(c.sweepTx)) - // Finally, we'll broadcast the sweep transaction to the - // network. - if err := c.PublishTx(c.sweepTx); err != nil { + // With the sweep transaction constructed, we'll now Checkpoint + // our state. + if err := c.Checkpoint(c); err != nil { + log.Errorf("unable to Checkpoint: %v", err) + return nil, err + } + + // With the sweep transaction checkpointed, we'll now publish + // the transaction. Upon restart, the resolver will immediately + // take the case below since the sweep tx is checkpointed. + err := c.PublishTx(c.sweepTx) + if err != nil && err != lnwallet.ErrDoubleSpend { log.Errorf("%T(%v): unable to publish sweep tx: %v", c, c.chanPoint, err) return nil, err } - // With the sweep transaction confirmed, we'll now Checkpoint - // our state. - if err := c.Checkpoint(c); err != nil { - log.Errorf("unable to Checkpoint: %v", err) + // If the sweep transaction has been generated, and the remote party + // broadcast the commit transaction, we'll republish it for reliability + // to ensure it confirms. The resolver will enter this case after + // checkpointing in the case above, ensuring we reliably on restarts. + case c.sweepTx != nil && !isLocalCommitTx: + err := c.PublishTx(c.sweepTx) + if err != nil && err != lnwallet.ErrDoubleSpend { + log.Errorf("%T(%v): unable to publish sweep tx: %v", + c, c.chanPoint, err) + return nil, err } // Otherwise, this is our commitment transaction, So we'll obtain the From 682c4c96c734edb6e151def429e2fb0edd1a70cd Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 18 Sep 2018 00:34:16 -0700 Subject: [PATCH 2/4] cnct/contract_resolvers: reliably publish htlc success sweep --- contractcourt/contract_resolvers.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/contractcourt/contract_resolvers.go b/contractcourt/contract_resolvers.go index d0d7328e..7732c820 100644 --- a/contractcourt/contract_resolvers.go +++ b/contractcourt/contract_resolvers.go @@ -481,21 +481,21 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { log.Infof("%T(%x): crafted sweep tx=%v", h, h.payHash[:], spew.Sdump(h.sweepTx)) - // With the sweep transaction confirmed, we'll now + // With the sweep transaction signed, we'll now // Checkpoint our state. if err := h.Checkpoint(h); err != nil { log.Errorf("unable to Checkpoint: %v", err) } + } - // Finally, we'll broadcast the sweep transaction to - // the network. - // - // TODO(roasbeef): validate first? - if err := h.PublishTx(h.sweepTx); err != nil { - log.Infof("%T(%x): unable to publish tx: %v", - h, h.payHash[:], err) - return nil, err - } + // Regardless of whether an existing transaction was found or newly + // constructed, we'll broadcast the sweep transaction to the + // network. + err := h.PublishTx(h.sweepTx) + if err != nil && err != lnwallet.ErrDoubleSpend { + log.Infof("%T(%x): unable to publish tx: %v", + h, h.payHash[:], err) + return nil, err } // With the sweep transaction broadcast, we'll wait for its From f957b78c0b920534f123e43908762ee54d7d9487 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 18 Sep 2018 00:37:14 -0700 Subject: [PATCH 3/4] cnct/contract_resolvers: ignore duplicate publication error --- contractcourt/contract_resolvers.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contractcourt/contract_resolvers.go b/contractcourt/contract_resolvers.go index 7732c820..4c861e24 100644 --- a/contractcourt/contract_resolvers.go +++ b/contractcourt/contract_resolvers.go @@ -535,7 +535,8 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { // the claiming process. // // TODO(roasbeef): after changing sighashes send to tx bundler - if err := h.PublishTx(h.htlcResolution.SignedSuccessTx); err != nil { + err := h.PublishTx(h.htlcResolution.SignedSuccessTx) + if err != nil && err != lnwallet.ErrDoubleSpend { return nil, err } From f9cec4a67b8bc54252e502e7c24b151355d2a31e Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 18 Sep 2018 04:03:47 -0700 Subject: [PATCH 4/4] cnct/contract_resolvers: propagate checkpoint failures --- contractcourt/contract_resolvers.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contractcourt/contract_resolvers.go b/contractcourt/contract_resolvers.go index 4c861e24..aa743856 100644 --- a/contractcourt/contract_resolvers.go +++ b/contractcourt/contract_resolvers.go @@ -171,6 +171,7 @@ func (h *htlcTimeoutResolver) Resolve() (ContractResolver, error) { if err := h.Checkpoint(h); err != nil { log.Errorf("unable to Checkpoint: %v", err) + return nil, err } } @@ -485,6 +486,7 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { // Checkpoint our state. if err := h.Checkpoint(h); err != nil { log.Errorf("unable to Checkpoint: %v", err) + return nil, err } } @@ -559,6 +561,7 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { if err := h.Checkpoint(h); err != nil { log.Errorf("unable to Checkpoint: %v", err) + return nil, err } } @@ -1323,6 +1326,7 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) { if err := c.Checkpoint(c); err != nil { log.Errorf("unable to Checkpoint: %v", err) + return nil, err } case <-c.Quit: return nil, fmt.Errorf("quitting")