breacharbiter: split waitForSpendEvent
We split the method waitForSpendEvent into two, such that we can reuse it in case the commitment is spent by various transactions.
This commit is contained in:
parent
bca5839929
commit
a6724c1088
126
breacharbiter.go
126
breacharbiter.go
@ -318,24 +318,22 @@ func convertToSecondLevelRevoke(bo *breachedOutput, breachInfo *retributionInfo,
|
|||||||
bo.outpoint)
|
bo.outpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// spend is used to wrap the index of the retributionInfo output that gets
|
||||||
|
// spent together with the spend details.
|
||||||
|
type spend struct {
|
||||||
|
index int
|
||||||
|
detail *chainntnfs.SpendDetail
|
||||||
|
}
|
||||||
|
|
||||||
// waitForSpendEvent waits for any of the breached outputs to get spent, and
|
// waitForSpendEvent waits for any of the breached outputs to get spent, and
|
||||||
// mutates the breachInfo to be able to sweep it. This method should be used
|
// returns the spend details for those outputs. The spendNtfns map is a cache
|
||||||
// when we fail to publish the justice tx because of a double spend, indicating
|
// used to store registered spend subscriptions, in case we must call this
|
||||||
// that the counter party has taken one of the breached outputs to the second
|
// method multiple times.
|
||||||
// level. The spendNtfns map is a cache used to store registered spend
|
|
||||||
// subscriptions, in case we must call this method multiple times.
|
|
||||||
func (b *breachArbiter) waitForSpendEvent(breachInfo *retributionInfo,
|
func (b *breachArbiter) waitForSpendEvent(breachInfo *retributionInfo,
|
||||||
spendNtfns map[wire.OutPoint]*chainntnfs.SpendEvent) error {
|
spendNtfns map[wire.OutPoint]*chainntnfs.SpendEvent) ([]spend, error) {
|
||||||
|
|
||||||
inputs := breachInfo.breachedOutputs
|
inputs := breachInfo.breachedOutputs
|
||||||
|
|
||||||
// spend is used to wrap the index of the output that gets spent
|
|
||||||
// together with the spend details.
|
|
||||||
type spend struct {
|
|
||||||
index int
|
|
||||||
detail *chainntnfs.SpendDetail
|
|
||||||
}
|
|
||||||
|
|
||||||
// We create a channel the first goroutine that gets a spend event can
|
// We create a channel the first goroutine that gets a spend event can
|
||||||
// signal. We make it buffered in case multiple spend events come in at
|
// signal. We make it buffered in case multiple spend events come in at
|
||||||
// the same time.
|
// the same time.
|
||||||
@ -378,7 +376,7 @@ func (b *breachArbiter) waitForSpendEvent(breachInfo *retributionInfo,
|
|||||||
// to avoid entering an infinite loop.
|
// to avoid entering an infinite loop.
|
||||||
select {
|
select {
|
||||||
case <-b.quit:
|
case <-b.quit:
|
||||||
return errBrarShuttingDown
|
return nil, errBrarShuttingDown
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -438,62 +436,75 @@ func (b *breachArbiter) waitForSpendEvent(breachInfo *retributionInfo,
|
|||||||
// channel before ranging over its content.
|
// channel before ranging over its content.
|
||||||
close(allSpends)
|
close(allSpends)
|
||||||
|
|
||||||
doneOutputs := make(map[int]struct{})
|
// Gather all detected spends and return them.
|
||||||
|
var spends []spend
|
||||||
for s := range allSpends {
|
for s := range allSpends {
|
||||||
breachedOutput := &inputs[s.index]
|
breachedOutput := &inputs[s.index]
|
||||||
delete(spendNtfns, breachedOutput.outpoint)
|
delete(spendNtfns, breachedOutput.outpoint)
|
||||||
|
|
||||||
switch breachedOutput.witnessType {
|
spends = append(spends, s)
|
||||||
case input.HtlcAcceptedRevoke:
|
}
|
||||||
fallthrough
|
|
||||||
case input.HtlcOfferedRevoke:
|
|
||||||
brarLog.Infof("Spend on second-level"+
|
|
||||||
"%s(%v) for ChannelPoint(%v) "+
|
|
||||||
"transitions to second-level output",
|
|
||||||
breachedOutput.witnessType,
|
|
||||||
breachedOutput.outpoint,
|
|
||||||
breachInfo.chanPoint)
|
|
||||||
|
|
||||||
// In this case we'll morph our initial revoke
|
return spends, nil
|
||||||
// spend to instead point to the second level
|
|
||||||
// output, and update the sign descriptor in the
|
|
||||||
// process.
|
|
||||||
convertToSecondLevelRevoke(
|
|
||||||
breachedOutput, breachInfo, s.detail,
|
|
||||||
)
|
|
||||||
|
|
||||||
continue
|
case <-b.quit:
|
||||||
}
|
return nil, errBrarShuttingDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
brarLog.Infof("Spend on %s(%v) for ChannelPoint(%v) "+
|
// updateBreachInfo mutates the passed breachInfo by removing or converting any
|
||||||
"transitions output to terminal state, "+
|
// outputs among the spends.
|
||||||
"removing input from justice transaction",
|
func updateBreachInfo(breachInfo *retributionInfo, spends []spend) {
|
||||||
|
inputs := breachInfo.breachedOutputs
|
||||||
|
doneOutputs := make(map[int]struct{})
|
||||||
|
|
||||||
|
for _, s := range spends {
|
||||||
|
breachedOutput := &inputs[s.index]
|
||||||
|
|
||||||
|
switch breachedOutput.witnessType {
|
||||||
|
case input.HtlcAcceptedRevoke:
|
||||||
|
fallthrough
|
||||||
|
case input.HtlcOfferedRevoke:
|
||||||
|
brarLog.Infof("Spend on second-level "+
|
||||||
|
"%s(%v) for ChannelPoint(%v) "+
|
||||||
|
"transitions to second-level output",
|
||||||
breachedOutput.witnessType,
|
breachedOutput.witnessType,
|
||||||
breachedOutput.outpoint, breachInfo.chanPoint)
|
breachedOutput.outpoint, breachInfo.chanPoint)
|
||||||
|
|
||||||
doneOutputs[s.index] = struct{}{}
|
// In this case we'll morph our initial revoke
|
||||||
|
// spend to instead point to the second level
|
||||||
|
// output, and update the sign descriptor in the
|
||||||
|
// process.
|
||||||
|
convertToSecondLevelRevoke(
|
||||||
|
breachedOutput, breachInfo, s.detail,
|
||||||
|
)
|
||||||
|
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter the inputs for which we can no longer proceed.
|
brarLog.Infof("Spend on %s(%v) for ChannelPoint(%v) "+
|
||||||
var nextIndex int
|
"transitions output to terminal state, "+
|
||||||
for i := range inputs {
|
"removing input from justice transaction",
|
||||||
if _, ok := doneOutputs[i]; ok {
|
breachedOutput.witnessType,
|
||||||
continue
|
breachedOutput.outpoint, breachInfo.chanPoint)
|
||||||
}
|
|
||||||
|
|
||||||
inputs[nextIndex] = inputs[i]
|
doneOutputs[s.index] = struct{}{}
|
||||||
nextIndex++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update our remaining set of outputs before continuing with
|
|
||||||
// another attempt at publication.
|
|
||||||
breachInfo.breachedOutputs = inputs[:nextIndex]
|
|
||||||
|
|
||||||
case <-b.quit:
|
|
||||||
return errBrarShuttingDown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
// Filter the inputs for which we can no longer proceed.
|
||||||
|
var nextIndex int
|
||||||
|
for i := range inputs {
|
||||||
|
if _, ok := doneOutputs[i]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs[nextIndex] = inputs[i]
|
||||||
|
nextIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update our remaining set of outputs before continuing with
|
||||||
|
// another attempt at publication.
|
||||||
|
breachInfo.breachedOutputs = inputs[:nextIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactRetribution is a goroutine which is executed once a contract breach has
|
// exactRetribution is a goroutine which is executed once a contract breach has
|
||||||
@ -587,7 +598,9 @@ justiceTxBroadcast:
|
|||||||
"attempting to craft new justice tx.")
|
"attempting to craft new justice tx.")
|
||||||
finalTx = nil
|
finalTx = nil
|
||||||
|
|
||||||
err := b.waitForSpendEvent(breachInfo, spendNtfns)
|
spends, err := b.waitForSpendEvent(
|
||||||
|
breachInfo, spendNtfns,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != errBrarShuttingDown {
|
if err != errBrarShuttingDown {
|
||||||
brarLog.Errorf("error waiting for "+
|
brarLog.Errorf("error waiting for "+
|
||||||
@ -596,6 +609,7 @@ justiceTxBroadcast:
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateBreachInfo(breachInfo, spends)
|
||||||
if len(breachInfo.breachedOutputs) == 0 {
|
if len(breachInfo.breachedOutputs) == 0 {
|
||||||
brarLog.Debugf("No more outputs to sweep for "+
|
brarLog.Debugf("No more outputs to sweep for "+
|
||||||
"breach, marking ChannelPoint(%v) "+
|
"breach, marking ChannelPoint(%v) "+
|
||||||
|
Loading…
Reference in New Issue
Block a user