cnct+lnrpc: report anchor resolution
This commit is contained in:
6 files changed
+826
-708
No files matched your search
@@ -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")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in new issue
Block a user