cnct+lnrpc: report anchor resolution

This commit is contained in:
Joost Jager committed 2020-03-18 12:27:03 +01:00
1 parent ea397c9d6e
commit ab451f634e
6 files changed
+826 -708

No files matched your search

+40
View File
@@ -3,8 +3,10 @@ package contractcourt
import ( import (
"errors" "errors"
"io" "io"
"sync"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/sweep" "github.com/lightningnetwork/lnd/sweep"
@@ -30,6 +32,13 @@ type anchorResolver struct {
// chanPoint is the channel point of the original contract. // chanPoint is the channel point of the original contract.
chanPoint wire.OutPoint chanPoint wire.OutPoint
// currentReport stores the current state of the resolver for reporting
// over the rpc interface.
currentReport ContractReport
// reportLock prevents concurrent access to the resolver report.
reportLock sync.Mutex
contractResolverKit contractResolverKit
} }
@@ -38,12 +47,23 @@ func newAnchorResolver(anchorSignDescriptor input.SignDescriptor,
anchor wire.OutPoint, broadcastHeight uint32, anchor wire.OutPoint, broadcastHeight uint32,
chanPoint wire.OutPoint, resCfg ResolverConfig) *anchorResolver { chanPoint wire.OutPoint, resCfg ResolverConfig) *anchorResolver {
amt := btcutil.Amount(anchorSignDescriptor.Output.Value)
report := ContractReport{
Outpoint: anchor,
Type: ReportOutputAnchor,
Amount: amt,
LimboBalance: amt,
RecoveredBalance: 0,
}
r := &anchorResolver{ r := &anchorResolver{
contractResolverKit: *newContractResolverKit(resCfg), contractResolverKit: *newContractResolverKit(resCfg),
anchorSignDescriptor: anchorSignDescriptor, anchorSignDescriptor: anchorSignDescriptor,
anchor: anchor, anchor: anchor,
broadcastHeight: broadcastHeight, broadcastHeight: broadcastHeight,
chanPoint: chanPoint, chanPoint: chanPoint,
currentReport: report,
} }
r.initLogger(r) r.initLogger(r)
@@ -101,6 +121,7 @@ func (c *anchorResolver) Resolve() (ContractResolver, error) {
} }
} }
var anchorRecovered bool
select { select {
case sweepRes := <-resultChan: case sweepRes := <-resultChan:
switch sweepRes.Err { switch sweepRes.Err {
@@ -110,6 +131,8 @@ func (c *anchorResolver) Resolve() (ContractResolver, error) {
c.log.Debugf("anchor swept by tx %v", c.log.Debugf("anchor swept by tx %v",
sweepRes.Tx.TxHash()) sweepRes.Tx.TxHash())
anchorRecovered = true
// Anchor was swept by someone else. This is possible after the // Anchor was swept by someone else. This is possible after the
// 16 block csv lock. // 16 block csv lock.
case sweep.ErrRemoteSpend: case sweep.ErrRemoteSpend:
@@ -136,6 +159,14 @@ func (c *anchorResolver) Resolve() (ContractResolver, error) {
return nil, errResolverShuttingDown return nil, errResolverShuttingDown
} }
// Update report to reflect that funds are no longer in limbo.
c.reportLock.Lock()
if anchorRecovered {
c.currentReport.RecoveredBalance = c.currentReport.LimboBalance
}
c.currentReport.LimboBalance = 0
c.reportLock.Unlock()
c.resolved = true c.resolved = true
return nil, nil return nil, nil
} }
@@ -156,6 +187,15 @@ func (c *anchorResolver) IsResolved() bool {
return c.resolved return c.resolved
} }
// report returns a report on the resolution state of the contract.
func (c *anchorResolver) report() *ContractReport {
c.reportLock.Lock()
defer c.reportLock.Unlock()
reportCopy := c.currentReport
return &reportCopy
}
func (c *anchorResolver) Encode(w io.Writer) error { func (c *anchorResolver) Encode(w io.Writer) error {
return errors.New("serialization not supported") return errors.New("serialization not supported")
} }
+3
View File
@@ -162,6 +162,9 @@ const (
// ReportOutputUnencumbered is an uncontested output on the commitment // ReportOutputUnencumbered is an uncontested output on the commitment
// transaction paying to us directly. // transaction paying to us directly.
ReportOutputUnencumbered ReportOutputUnencumbered
// ReportOutputAnchor is an anchor output on the commitment tx.
ReportOutputAnchor
) )
// ContractReport provides a summary of a commitment tx output. // ContractReport provides a summary of a commitment tx output.
+747 -707
View File
File diff suppressed because it is too large. Load diff
+8
View File
@@ -2016,6 +2016,14 @@ message PendingChannelsResponse {
int64 recovered_balance = 6; int64 recovered_balance = 6;
repeated PendingHTLC pending_htlcs = 8; repeated PendingHTLC pending_htlcs = 8;
enum AnchorState {
LIMBO = 0;
RECOVERED = 1;
LOST = 2;
}
AnchorState anchor = 9;
} }
/// The balance in satoshis encumbered in pending channels /// The balance in satoshis encumbered in pending channels
+12
View File
@@ -1534,6 +1534,15 @@
"default": "RESERVED", "default": "RESERVED",
"description": " - RESERVED: *\nThe numbers assigned in this enumeration match the failure codes as\ndefined in BOLT #4. Because protobuf 3 requires enums to start with 0,\na RESERVED value is added.\n - INTERNAL_FAILURE: *\nAn internal error occurred.\n - UNKNOWN_FAILURE: *\nThe error source is known, but the failure itself couldn't be decoded.\n - UNREADABLE_FAILURE: *\nAn unreadable failure result is returned if the received failure message\ncannot be decrypted. In that case the error source is unknown." "description": " - RESERVED: *\nThe numbers assigned in this enumeration match the failure codes as\ndefined in BOLT #4. Because protobuf 3 requires enums to start with 0,\na RESERVED value is added.\n - INTERNAL_FAILURE: *\nAn internal error occurred.\n - UNKNOWN_FAILURE: *\nThe error source is known, but the failure itself couldn't be decoded.\n - UNREADABLE_FAILURE: *\nAn unreadable failure result is returned if the received failure message\ncannot be decrypted. In that case the error source is unknown."
}, },
"ForceClosedChannelAnchorState": {
"type": "string",
"enum": [
"LIMBO",
"RECOVERED",
"LOST"
],
"default": "LIMBO"
},
"HTLCAttemptHTLCStatus": { "HTLCAttemptHTLCStatus": {
"type": "string", "type": "string",
"enum": [ "enum": [
@@ -1630,6 +1639,9 @@
"items": { "items": {
"$ref": "#/definitions/lnrpcPendingHTLC" "$ref": "#/definitions/lnrpcPendingHTLC"
} }
},
"anchor": {
"$ref": "#/definitions/ForceClosedChannelAnchorState"
} }
} }
}, },
+16 -1
View File
@@ -2839,6 +2839,22 @@ func (r *rpcServer) arbitratorPopulateForceCloseResp(chanPoint *wire.OutPoint,
forceClose.PendingHtlcs = append(forceClose.PendingHtlcs, htlc) forceClose.PendingHtlcs = append(forceClose.PendingHtlcs, htlc)
case contractcourt.ReportOutputAnchor:
// There are three resolution states for the anchor:
// limbo, lost and recovered. Derive the current state
// from the limbo and recovered balances.
switch {
case report.RecoveredBalance != 0:
forceClose.Anchor = lnrpc.PendingChannelsResponse_ForceClosedChannel_RECOVERED
case report.LimboBalance != 0:
forceClose.Anchor = lnrpc.PendingChannelsResponse_ForceClosedChannel_LIMBO
default:
forceClose.Anchor = lnrpc.PendingChannelsResponse_ForceClosedChannel_LOST
}
default: default:
return fmt.Errorf("unknown report output type: %v", return fmt.Errorf("unknown report output type: %v",
report.Type) report.Type)
@@ -2846,7 +2862,6 @@ func (r *rpcServer) arbitratorPopulateForceCloseResp(chanPoint *wire.OutPoint,
forceClose.LimboBalance += int64(report.LimboBalance) forceClose.LimboBalance += int64(report.LimboBalance)
forceClose.RecoveredBalance += int64(report.RecoveredBalance) forceClose.RecoveredBalance += int64(report.RecoveredBalance)
} }
return nil return nil