github.com/decred/dcrlnd@v0.7.6/lnrpc/routerrpc/subscribe_events.go (about)

     1  package routerrpc
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/decred/dcrlnd/htlcswitch"
     8  	"github.com/decred/dcrlnd/invoices"
     9  	"github.com/decred/dcrlnd/lnrpc"
    10  )
    11  
    12  // rpcHtlcEvent returns a rpc htlc event from a htlcswitch event.
    13  func rpcHtlcEvent(htlcEvent interface{}) (*HtlcEvent, error) {
    14  	var (
    15  		key       htlcswitch.HtlcKey
    16  		timestamp time.Time
    17  		eventType htlcswitch.HtlcEventType
    18  		event     isHtlcEvent_Event
    19  	)
    20  
    21  	switch e := htlcEvent.(type) {
    22  	case *htlcswitch.ForwardingEvent:
    23  		event = &HtlcEvent_ForwardEvent{
    24  			ForwardEvent: &ForwardEvent{
    25  				Info: rpcInfo(e.HtlcInfo),
    26  			},
    27  		}
    28  
    29  		key = e.HtlcKey
    30  		eventType = e.HtlcEventType
    31  		timestamp = e.Timestamp
    32  
    33  	case *htlcswitch.ForwardingFailEvent:
    34  		event = &HtlcEvent_ForwardFailEvent{
    35  			ForwardFailEvent: &ForwardFailEvent{},
    36  		}
    37  
    38  		key = e.HtlcKey
    39  		eventType = e.HtlcEventType
    40  		timestamp = e.Timestamp
    41  
    42  	case *htlcswitch.LinkFailEvent:
    43  		failureCode, failReason, err := rpcFailReason(
    44  			e.LinkError,
    45  		)
    46  		if err != nil {
    47  			return nil, err
    48  		}
    49  
    50  		event = &HtlcEvent_LinkFailEvent{
    51  			LinkFailEvent: &LinkFailEvent{
    52  				Info:          rpcInfo(e.HtlcInfo),
    53  				WireFailure:   failureCode,
    54  				FailureDetail: failReason,
    55  				FailureString: e.LinkError.Error(),
    56  			},
    57  		}
    58  
    59  		key = e.HtlcKey
    60  		eventType = e.HtlcEventType
    61  		timestamp = e.Timestamp
    62  
    63  	case *htlcswitch.SettleEvent:
    64  		event = &HtlcEvent_SettleEvent{
    65  			SettleEvent: &SettleEvent{
    66  				Preimage: e.Preimage[:],
    67  			},
    68  		}
    69  
    70  		key = e.HtlcKey
    71  		eventType = e.HtlcEventType
    72  		timestamp = e.Timestamp
    73  
    74  	default:
    75  		return nil, fmt.Errorf("unknown event type: %T", e)
    76  	}
    77  
    78  	rpcEvent := &HtlcEvent{
    79  		IncomingChannelId: key.IncomingCircuit.ChanID.ToUint64(),
    80  		OutgoingChannelId: key.OutgoingCircuit.ChanID.ToUint64(),
    81  		IncomingHtlcId:    key.IncomingCircuit.HtlcID,
    82  		OutgoingHtlcId:    key.OutgoingCircuit.HtlcID,
    83  		TimestampNs:       uint64(timestamp.UnixNano()),
    84  		Event:             event,
    85  	}
    86  
    87  	// Convert the htlc event type to a rpc event.
    88  	switch eventType {
    89  	case htlcswitch.HtlcEventTypeSend:
    90  		rpcEvent.EventType = HtlcEvent_SEND
    91  
    92  	case htlcswitch.HtlcEventTypeReceive:
    93  		rpcEvent.EventType = HtlcEvent_RECEIVE
    94  
    95  	case htlcswitch.HtlcEventTypeForward:
    96  		rpcEvent.EventType = HtlcEvent_FORWARD
    97  
    98  	default:
    99  		return nil, fmt.Errorf("unknown event type: %v", eventType)
   100  	}
   101  
   102  	return rpcEvent, nil
   103  }
   104  
   105  // rpcInfo returns a rpc struct containing the htlc information from the
   106  // switch's htlc info struct.
   107  func rpcInfo(info htlcswitch.HtlcInfo) *HtlcInfo {
   108  	return &HtlcInfo{
   109  		IncomingTimelock:  info.IncomingTimeLock,
   110  		OutgoingTimelock:  info.OutgoingTimeLock,
   111  		IncomingAmtMAtoms: uint64(info.IncomingAmt),
   112  		OutgoingAmtMAtoms: uint64(info.OutgoingAmt),
   113  	}
   114  }
   115  
   116  // rpcFailReason maps a lnwire failure message and failure detail to a rpc
   117  // failure code and detail.
   118  func rpcFailReason(linkErr *htlcswitch.LinkError) (lnrpc.Failure_FailureCode,
   119  	FailureDetail, error) {
   120  
   121  	wireErr, err := marshallError(linkErr)
   122  	if err != nil {
   123  		return 0, 0, err
   124  	}
   125  	wireCode := wireErr.GetCode()
   126  
   127  	// If the link has no failure detail, return with failure detail none.
   128  	if linkErr.FailureDetail == nil {
   129  		return wireCode, FailureDetail_NO_DETAIL, nil
   130  	}
   131  
   132  	switch failureDetail := linkErr.FailureDetail.(type) {
   133  	case invoices.FailResolutionResult:
   134  		fd, err := rpcFailureResolution(failureDetail)
   135  		return wireCode, fd, err
   136  
   137  	case htlcswitch.OutgoingFailure:
   138  		fd, err := rpcOutgoingFailure(failureDetail)
   139  		return wireCode, fd, err
   140  
   141  	default:
   142  		return 0, 0, fmt.Errorf("unknown failure "+
   143  			"detail type: %T", linkErr.FailureDetail)
   144  
   145  	}
   146  
   147  }
   148  
   149  // rpcFailureResolution maps an invoice failure resolution to a rpc failure
   150  // detail. Invoice failures have no zero resolution results (every failure
   151  // is accompanied with a result), so we error if we fail to match the result
   152  // type.
   153  func rpcFailureResolution(invoiceFailure invoices.FailResolutionResult) (
   154  	FailureDetail, error) {
   155  
   156  	switch invoiceFailure {
   157  	case invoices.ResultReplayToCanceled:
   158  		return FailureDetail_INVOICE_CANCELED, nil
   159  
   160  	case invoices.ResultInvoiceAlreadyCanceled:
   161  		return FailureDetail_INVOICE_CANCELED, nil
   162  
   163  	case invoices.ResultAmountTooLow:
   164  		return FailureDetail_INVOICE_UNDERPAID, nil
   165  
   166  	case invoices.ResultExpiryTooSoon:
   167  		return FailureDetail_INVOICE_EXPIRY_TOO_SOON, nil
   168  
   169  	case invoices.ResultCanceled:
   170  		return FailureDetail_INVOICE_CANCELED, nil
   171  
   172  	case invoices.ResultInvoiceNotOpen:
   173  		return FailureDetail_INVOICE_NOT_OPEN, nil
   174  
   175  	case invoices.ResultMppTimeout:
   176  		return FailureDetail_MPP_INVOICE_TIMEOUT, nil
   177  
   178  	case invoices.ResultAddressMismatch:
   179  		return FailureDetail_ADDRESS_MISMATCH, nil
   180  
   181  	case invoices.ResultHtlcSetTotalMismatch:
   182  		return FailureDetail_SET_TOTAL_MISMATCH, nil
   183  
   184  	case invoices.ResultHtlcSetTotalTooLow:
   185  		return FailureDetail_SET_TOTAL_TOO_LOW, nil
   186  
   187  	case invoices.ResultHtlcSetOverpayment:
   188  		return FailureDetail_SET_OVERPAID, nil
   189  
   190  	case invoices.ResultInvoiceNotFound:
   191  		return FailureDetail_UNKNOWN_INVOICE, nil
   192  
   193  	case invoices.ResultKeySendError:
   194  		return FailureDetail_INVALID_KEYSEND, nil
   195  
   196  	case invoices.ResultMppInProgress:
   197  		return FailureDetail_MPP_IN_PROGRESS, nil
   198  
   199  	default:
   200  		return 0, fmt.Errorf("unknown fail resolution: %v",
   201  			invoiceFailure.FailureString())
   202  	}
   203  }
   204  
   205  // rpcOutgoingFailure maps an outgoing failure to a rpc FailureDetail. If the
   206  // failure detail is FailureDetailNone, which indicates that the failure was
   207  // a wire message which required no further failure detail, we return a no
   208  // detail failure detail to indicate that there was no additional information.
   209  func rpcOutgoingFailure(failureDetail htlcswitch.OutgoingFailure) (
   210  	FailureDetail, error) {
   211  
   212  	switch failureDetail {
   213  	case htlcswitch.OutgoingFailureNone:
   214  		return FailureDetail_NO_DETAIL, nil
   215  
   216  	case htlcswitch.OutgoingFailureDecodeError:
   217  		return FailureDetail_ONION_DECODE, nil
   218  
   219  	case htlcswitch.OutgoingFailureLinkNotEligible:
   220  		return FailureDetail_LINK_NOT_ELIGIBLE, nil
   221  
   222  	case htlcswitch.OutgoingFailureOnChainTimeout:
   223  		return FailureDetail_ON_CHAIN_TIMEOUT, nil
   224  
   225  	case htlcswitch.OutgoingFailureHTLCExceedsMax:
   226  		return FailureDetail_HTLC_EXCEEDS_MAX, nil
   227  
   228  	case htlcswitch.OutgoingFailureInsufficientBalance:
   229  		return FailureDetail_INSUFFICIENT_BALANCE, nil
   230  
   231  	case htlcswitch.OutgoingFailureCircularRoute:
   232  		return FailureDetail_CIRCULAR_ROUTE, nil
   233  
   234  	case htlcswitch.OutgoingFailureIncompleteForward:
   235  		return FailureDetail_INCOMPLETE_FORWARD, nil
   236  
   237  	case htlcswitch.OutgoingFailureDownstreamHtlcAdd:
   238  		return FailureDetail_HTLC_ADD_FAILED, nil
   239  
   240  	case htlcswitch.OutgoingFailureForwardsDisabled:
   241  		return FailureDetail_FORWARDS_DISABLED, nil
   242  
   243  	default:
   244  		return 0, fmt.Errorf("unknown outgoing failure "+
   245  			"detail: %v", failureDetail.FailureString())
   246  	}
   247  }