rpc: non-existence of a nursery report is no longer an error
This commit fixes a slight logic error that could render the `pendingchannels` RPC unusable if a node was on the reciting end of a channel force close with no time-locked balance. In such a case the channel wouldn’t be sent to the utxoNursery, resulting in an “contract not found error”. To fix this behavior, we’ve created a typed error that can be checked within the RPC, thus we no longer treat this routine case as an error case.
This commit is contained in:
parent
459583ca04
commit
9c685433f3
30
rpcserver.go
30
rpcserver.go
@ -721,13 +721,14 @@ func (r *rpcServer) forceCloseChan(channel *lnwallet.LightningChannel) (*chainha
|
|||||||
chanPoint := channel.ChannelPoint()
|
chanPoint := channel.ChannelPoint()
|
||||||
chanInfo := channel.StateSnapshot()
|
chanInfo := channel.StateSnapshot()
|
||||||
closeInfo := &channeldb.ChannelCloseSummary{
|
closeInfo := &channeldb.ChannelCloseSummary{
|
||||||
ChanPoint: *chanPoint,
|
ChanPoint: *chanPoint,
|
||||||
ClosingTXID: closeTx.TxHash(),
|
ClosingTXID: closeTx.TxHash(),
|
||||||
RemotePub: &chanInfo.RemoteIdentity,
|
RemotePub: &chanInfo.RemoteIdentity,
|
||||||
Capacity: chanInfo.Capacity,
|
Capacity: chanInfo.Capacity,
|
||||||
OurBalance: chanInfo.LocalBalance,
|
SettledBalance: chanInfo.LocalBalance,
|
||||||
CloseType: channeldb.ForceClose,
|
TimeLockedBalance: chanInfo.LocalBalance,
|
||||||
IsPending: true,
|
CloseType: channeldb.ForceClose,
|
||||||
|
IsPending: true,
|
||||||
}
|
}
|
||||||
if err := channel.DeleteState(closeInfo); err != nil {
|
if err := channel.DeleteState(closeInfo); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -767,7 +768,8 @@ func (r *rpcServer) GetInfo(ctx context.Context,
|
|||||||
|
|
||||||
isSynced, err := r.server.lnwallet.IsSynced()
|
isSynced, err := r.server.lnwallet.IsSynced()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to sync PoV of the wallet with current best block in the main chain: %v", err)
|
return nil, fmt.Errorf("unable to sync PoV of the wallet "+
|
||||||
|
"with current best block in the main chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
activeChains := make([]string, registeredChains.NumActiveChains())
|
activeChains := make([]string, registeredChains.NumActiveChains())
|
||||||
@ -933,7 +935,7 @@ func (r *rpcServer) PendingChannels(ctx context.Context,
|
|||||||
RemoteNodePub: hex.EncodeToString(pub),
|
RemoteNodePub: hex.EncodeToString(pub),
|
||||||
ChannelPoint: chanPoint.String(),
|
ChannelPoint: chanPoint.String(),
|
||||||
Capacity: int64(pendingClose.Capacity),
|
Capacity: int64(pendingClose.Capacity),
|
||||||
LocalBalance: int64(pendingClose.OurBalance),
|
LocalBalance: int64(pendingClose.SettledBalance),
|
||||||
}
|
}
|
||||||
|
|
||||||
closeTXID := pendingClose.ClosingTXID.String()
|
closeTXID := pendingClose.ClosingTXID.String()
|
||||||
@ -961,9 +963,14 @@ func (r *rpcServer) PendingChannels(ctx context.Context,
|
|||||||
ClosingTxid: closeTXID,
|
ClosingTxid: closeTXID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Query for the maturity state for this force closed
|
||||||
|
// channel. If we didn't have any time-locked outputs,
|
||||||
|
// then the nursery may not know of the contract.
|
||||||
nurseryInfo, err := r.server.utxoNursery.NurseryReport(&chanPoint)
|
nurseryInfo, err := r.server.utxoNursery.NurseryReport(&chanPoint)
|
||||||
if err != nil {
|
if err != nil && err != ErrContractNotFound {
|
||||||
return nil, err
|
return nil, fmt.Errorf("unable to obtain "+
|
||||||
|
"nursery report for ChannelPoint(%v): %v",
|
||||||
|
chanPoint, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the nursery knows of this channel, then we can
|
// If the nursery knows of this channel, then we can
|
||||||
@ -996,7 +1003,6 @@ func (r *rpcServer) PendingChannels(ctx context.Context,
|
|||||||
|
|
||||||
// ListChannels returns a description of all direct active, open channels the
|
// ListChannels returns a description of all direct active, open channels the
|
||||||
// node knows of.
|
// node knows of.
|
||||||
// TODO(roasbeef): add 'online' bit to response
|
|
||||||
func (r *rpcServer) ListChannels(ctx context.Context,
|
func (r *rpcServer) ListChannels(ctx context.Context,
|
||||||
in *lnrpc.ListChannelsRequest) (*lnrpc.ListChannelsResponse, error) {
|
in *lnrpc.ListChannelsRequest) (*lnrpc.ListChannelsResponse, error) {
|
||||||
|
|
||||||
|
@ -70,6 +70,12 @@ var (
|
|||||||
byteOrder = binary.BigEndian
|
byteOrder = binary.BigEndian
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrContractNotFound is returned when the nursery is unable to
|
||||||
|
// retreive information about a queried contract.
|
||||||
|
ErrContractNotFound = fmt.Errorf("unable to locate contract")
|
||||||
|
)
|
||||||
|
|
||||||
// witnessType determines how an output's witness will be generated. The
|
// witnessType determines how an output's witness will be generated. The
|
||||||
// default commitmentTimeLock type will generate a witness that will allow
|
// default commitmentTimeLock type will generate a witness that will allow
|
||||||
// spending of a time-locked transaction enforced by CheckSequenceVerify.
|
// spending of a time-locked transaction enforced by CheckSequenceVerify.
|
||||||
@ -317,9 +323,9 @@ type incubationRequest struct {
|
|||||||
func (u *utxoNursery) IncubateOutputs(closeSummary *lnwallet.ForceCloseSummary) {
|
func (u *utxoNursery) IncubateOutputs(closeSummary *lnwallet.ForceCloseSummary) {
|
||||||
var incReq incubationRequest
|
var incReq incubationRequest
|
||||||
|
|
||||||
// It could be that our to-self output was below the dust limit. In that
|
// It could be that our to-self output was below the dust limit. In
|
||||||
// case the SignDescriptor would be nil and we would not have that output
|
// that case the SignDescriptor would be nil and we would not have that
|
||||||
// to incubate.
|
// output to incubate.
|
||||||
if closeSummary.SelfOutputSignDesc != nil {
|
if closeSummary.SelfOutputSignDesc != nil {
|
||||||
outputAmt := btcutil.Amount(closeSummary.SelfOutputSignDesc.Output.Value)
|
outputAmt := btcutil.Amount(closeSummary.SelfOutputSignDesc.Output.Value)
|
||||||
selfOutput := &kidOutput{
|
selfOutput := &kidOutput{
|
||||||
@ -510,7 +516,7 @@ func (u *utxoNursery) NurseryReport(chanPoint *wire.OutPoint) (*contractMaturity
|
|||||||
// entry for this particular contract.
|
// entry for this particular contract.
|
||||||
indexInfo := indexBucket.Get(chanPointBytes)
|
indexInfo := indexBucket.Get(chanPointBytes)
|
||||||
if indexInfo == nil {
|
if indexInfo == nil {
|
||||||
return fmt.Errorf("contract not found in index")
|
return ErrContractNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// If an entry is found, then using the height store in
|
// If an entry is found, then using the height store in
|
||||||
@ -519,7 +525,7 @@ func (u *utxoNursery) NurseryReport(chanPoint *wire.OutPoint) (*contractMaturity
|
|||||||
height := indexInfo[:4]
|
height := indexInfo[:4]
|
||||||
heightRow := kgtnBucket.Get(height)
|
heightRow := kgtnBucket.Get(height)
|
||||||
if heightRow == nil {
|
if heightRow == nil {
|
||||||
return fmt.Errorf("contract not found")
|
return ErrContractNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once we have the entry itself, we'll slice of the
|
// Once we have the entry itself, we'll slice of the
|
||||||
|
Loading…
Reference in New Issue
Block a user