mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-13 11:09:23 +01:00
Merge pull request #3972 from joostjager/notify-htlc-arrival
routing: extend trackpayment with htlc events
This commit is contained in:
commit
3ad7ab223e
19 changed files with 1599 additions and 1490 deletions
|
@ -186,38 +186,39 @@ func (p *PaymentControl) InitPayment(paymentHash lntypes.Hash,
|
|||
// RegisterAttempt atomically records the provided HTLCAttemptInfo to the
|
||||
// DB.
|
||||
func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash,
|
||||
attempt *HTLCAttemptInfo) error {
|
||||
attempt *HTLCAttemptInfo) (*MPPayment, error) {
|
||||
|
||||
// Serialize the information before opening the db transaction.
|
||||
var a bytes.Buffer
|
||||
err := serializeHTLCAttemptInfo(&a, attempt)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
htlcInfoBytes := a.Bytes()
|
||||
|
||||
htlcIDBytes := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(htlcIDBytes, attempt.AttemptID)
|
||||
|
||||
return kvdb.Batch(p.db.Backend, func(tx kvdb.RwTx) error {
|
||||
var payment *MPPayment
|
||||
err = kvdb.Batch(p.db.Backend, func(tx kvdb.RwTx) error {
|
||||
bucket, err := fetchPaymentBucketUpdate(tx, paymentHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
payment, err := fetchPayment(bucket)
|
||||
p, err := fetchPayment(bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure the payment is in-flight.
|
||||
if err := ensureInFlight(payment); err != nil {
|
||||
if err := ensureInFlight(p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We cannot register a new attempt if the payment already has
|
||||
// reached a terminal condition:
|
||||
settle, fail := payment.TerminalInfo()
|
||||
settle, fail := p.TerminalInfo()
|
||||
if settle != nil || fail != nil {
|
||||
return ErrPaymentTerminal
|
||||
}
|
||||
|
@ -225,7 +226,7 @@ func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash,
|
|||
// Make sure any existing shards match the new one with regards
|
||||
// to MPP options.
|
||||
mpp := attempt.Route.FinalHop().MPP
|
||||
for _, h := range payment.InFlightHTLCs() {
|
||||
for _, h := range p.InFlightHTLCs() {
|
||||
hMpp := h.Route.FinalHop().MPP
|
||||
|
||||
switch {
|
||||
|
@ -258,13 +259,13 @@ func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash,
|
|||
// If this is a non-MPP attempt, it must match the total amount
|
||||
// exactly.
|
||||
amt := attempt.Route.ReceiverAmt()
|
||||
if mpp == nil && amt != payment.Info.Value {
|
||||
if mpp == nil && amt != p.Info.Value {
|
||||
return ErrValueMismatch
|
||||
}
|
||||
|
||||
// Ensure we aren't sending more than the total payment amount.
|
||||
sentAmt, _ := payment.SentAmt()
|
||||
if sentAmt+amt > payment.Info.Value {
|
||||
sentAmt, _ := p.SentAmt()
|
||||
if sentAmt+amt > p.Info.Value {
|
||||
return ErrValueExceedsAmt
|
||||
}
|
||||
|
||||
|
@ -282,8 +283,20 @@ func (p *PaymentControl) RegisterAttempt(paymentHash lntypes.Hash,
|
|||
return err
|
||||
}
|
||||
|
||||
return htlcBucket.Put(htlcAttemptInfoKey, htlcInfoBytes)
|
||||
err = htlcBucket.Put(htlcAttemptInfoKey, htlcInfoBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Retrieve attempt info for the notification.
|
||||
payment, err = fetchPayment(bucket)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return payment, err
|
||||
}
|
||||
|
||||
// SettleAttempt marks the given attempt settled with the preimage. If this is
|
||||
|
@ -307,16 +320,15 @@ func (p *PaymentControl) SettleAttempt(hash lntypes.Hash,
|
|||
|
||||
// FailAttempt marks the given payment attempt failed.
|
||||
func (p *PaymentControl) FailAttempt(hash lntypes.Hash,
|
||||
attemptID uint64, failInfo *HTLCFailInfo) error {
|
||||
attemptID uint64, failInfo *HTLCFailInfo) (*MPPayment, error) {
|
||||
|
||||
var b bytes.Buffer
|
||||
if err := serializeHTLCFailInfo(&b, failInfo); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
failBytes := b.Bytes()
|
||||
|
||||
_, err := p.updateHtlcKey(hash, attemptID, htlcFailInfoKey, failBytes)
|
||||
return err
|
||||
return p.updateHtlcKey(hash, attemptID, htlcFailInfoKey, failBytes)
|
||||
}
|
||||
|
||||
// updateHtlcKey updates a database key for the specified htlc.
|
||||
|
|
|
@ -117,13 +117,13 @@ func TestPaymentControlSwitchFail(t *testing.T) {
|
|||
// Record a new attempt. In this test scenario, the attempt fails.
|
||||
// However, this is not communicated to control tower in the current
|
||||
// implementation. It only registers the initiation of the attempt.
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to register attempt: %v", err)
|
||||
}
|
||||
|
||||
htlcReason := HTLCFailUnreadable
|
||||
err = pControl.FailAttempt(
|
||||
_, err = pControl.FailAttempt(
|
||||
info.PaymentHash, attempt.AttemptID,
|
||||
&HTLCFailInfo{
|
||||
Reason: htlcReason,
|
||||
|
@ -143,7 +143,7 @@ func TestPaymentControlSwitchFail(t *testing.T) {
|
|||
|
||||
// Record another attempt.
|
||||
attempt.AttemptID = 1
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send htlc message: %v", err)
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ func TestPaymentControlSwitchDoubleSend(t *testing.T) {
|
|||
}
|
||||
|
||||
// Record an attempt.
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send htlc message: %v", err)
|
||||
}
|
||||
|
@ -375,7 +375,7 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unable to send htlc message: %v", err)
|
||||
}
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send htlc message: %v", err)
|
||||
}
|
||||
|
@ -387,7 +387,7 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) {
|
|||
if p.failed {
|
||||
// Fail the payment attempt.
|
||||
htlcFailure := HTLCFailUnreadable
|
||||
err := pControl.FailAttempt(
|
||||
_, err := pControl.FailAttempt(
|
||||
info.PaymentHash, attempt.AttemptID,
|
||||
&HTLCFailInfo{
|
||||
Reason: htlcFailure,
|
||||
|
@ -520,7 +520,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
|
|||
a.AttemptID = i
|
||||
attempts = append(attempts, &a)
|
||||
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, &a)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, &a)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send htlc message: %v", err)
|
||||
}
|
||||
|
@ -541,7 +541,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
|
|||
// will be too large.
|
||||
b := *attempt
|
||||
b.AttemptID = 3
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
if err != ErrValueExceedsAmt {
|
||||
t.Fatalf("expected ErrValueExceedsAmt, got: %v",
|
||||
err)
|
||||
|
@ -550,7 +550,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
|
|||
// Fail the second attempt.
|
||||
a := attempts[1]
|
||||
htlcFail := HTLCFailUnreadable
|
||||
err = pControl.FailAttempt(
|
||||
_, err = pControl.FailAttempt(
|
||||
info.PaymentHash, a.AttemptID,
|
||||
&HTLCFailInfo{
|
||||
Reason: htlcFail,
|
||||
|
@ -596,7 +596,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
|
|||
t, pControl, info.PaymentHash, info, nil, htlc,
|
||||
)
|
||||
} else {
|
||||
err := pControl.FailAttempt(
|
||||
_, err := pControl.FailAttempt(
|
||||
info.PaymentHash, a.AttemptID,
|
||||
&HTLCFailInfo{
|
||||
Reason: htlcFail,
|
||||
|
@ -634,7 +634,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
|
|||
// that the payment has reached a terminal condition.
|
||||
b = *attempt
|
||||
b.AttemptID = 3
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
if err != ErrPaymentTerminal {
|
||||
t.Fatalf("expected ErrPaymentTerminal, got: %v", err)
|
||||
}
|
||||
|
@ -666,7 +666,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
|
|||
)
|
||||
} else {
|
||||
// Fail the attempt.
|
||||
err := pControl.FailAttempt(
|
||||
_, err := pControl.FailAttempt(
|
||||
info.PaymentHash, a.AttemptID,
|
||||
&HTLCFailInfo{
|
||||
Reason: htlcFail,
|
||||
|
@ -708,7 +708,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
|
|||
assertPaymentStatus(t, pControl, info.PaymentHash, finalStatus)
|
||||
|
||||
// Finally assert we cannot register more attempts.
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
if err != expRegErr {
|
||||
t.Fatalf("expected error %v, got: %v", expRegErr, err)
|
||||
}
|
||||
|
@ -756,7 +756,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
|
|||
info.Value, [32]byte{1},
|
||||
)
|
||||
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send htlc message: %v", err)
|
||||
}
|
||||
|
@ -765,7 +765,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
|
|||
b := *attempt
|
||||
b.AttemptID = 1
|
||||
b.Route.FinalHop().MPP = nil
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
if err != ErrMPPayment {
|
||||
t.Fatalf("expected ErrMPPayment, got: %v", err)
|
||||
}
|
||||
|
@ -774,7 +774,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
|
|||
b.Route.FinalHop().MPP = record.NewMPP(
|
||||
info.Value, [32]byte{2},
|
||||
)
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
if err != ErrMPPPaymentAddrMismatch {
|
||||
t.Fatalf("expected ErrMPPPaymentAddrMismatch, got: %v", err)
|
||||
}
|
||||
|
@ -783,7 +783,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
|
|||
b.Route.FinalHop().MPP = record.NewMPP(
|
||||
info.Value/2, [32]byte{1},
|
||||
)
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
if err != ErrMPPTotalAmountMismatch {
|
||||
t.Fatalf("expected ErrMPPTotalAmountMismatch, got: %v", err)
|
||||
}
|
||||
|
@ -801,7 +801,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
|
|||
}
|
||||
|
||||
attempt.Route.FinalHop().MPP = nil
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send htlc message: %v", err)
|
||||
}
|
||||
|
@ -813,7 +813,7 @@ func TestPaymentControlMPPRecordValidation(t *testing.T) {
|
|||
info.Value, [32]byte{1},
|
||||
)
|
||||
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
_, err = pControl.RegisterAttempt(info.PaymentHash, &b)
|
||||
if err != ErrNonMPPayment {
|
||||
t.Fatalf("expected ErrNonMPPayment, got: %v", err)
|
||||
}
|
||||
|
|
|
@ -46,6 +46,12 @@ var (
|
|||
"<hex_value>,.. For example: --data 3438382=0a21ff. " +
|
||||
"Custom record ids start from 65536.",
|
||||
}
|
||||
|
||||
showInflightFlag = cli.BoolFlag{
|
||||
Name: "show_inflight",
|
||||
Usage: "if set, intermediate payment state updates will be " +
|
||||
"displayed",
|
||||
}
|
||||
)
|
||||
|
||||
// paymentFlags returns common flags for sendpayment and payinvoice.
|
||||
|
@ -82,7 +88,7 @@ func paymentFlags() []cli.Flag {
|
|||
Name: "allow_self_payment",
|
||||
Usage: "allow sending a circular payment to self",
|
||||
},
|
||||
dataFlag,
|
||||
dataFlag, showInflightFlag,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -382,6 +388,8 @@ func sendPaymentRequest(ctx *cli.Context,
|
|||
|
||||
req.FeeLimitSat = feeLimit
|
||||
|
||||
showInflight := ctx.Bool(showInflightFlag.Name)
|
||||
|
||||
stream, err := routerClient.SendPayment(context.Background(), req)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -393,18 +401,22 @@ func sendPaymentRequest(ctx *cli.Context,
|
|||
return err
|
||||
}
|
||||
|
||||
if status.State != routerrpc.PaymentState_IN_FLIGHT {
|
||||
if status.Status != lnrpc.Payment_IN_FLIGHT {
|
||||
printRespJSON(status)
|
||||
|
||||
// If we get a payment error back, we pass an error up
|
||||
// to main which eventually calls fatal() and returns
|
||||
// with a non-zero exit code.
|
||||
if status.State != routerrpc.PaymentState_SUCCEEDED {
|
||||
return errors.New(status.State.String())
|
||||
if status.Status != lnrpc.Payment_SUCCEEDED {
|
||||
return errors.New(status.Status.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if showInflight {
|
||||
printRespJSON(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,7 +466,7 @@ func trackPayment(ctx *cli.Context) error {
|
|||
|
||||
printRespJSON(status)
|
||||
|
||||
if status.State != routerrpc.PaymentState_IN_FLIGHT {
|
||||
if status.Status != lnrpc.Payment_IN_FLIGHT {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,62 +23,6 @@ var _ = math.Inf
|
|||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type PaymentState int32
|
||||
|
||||
const (
|
||||
//*
|
||||
//Payment is still in flight.
|
||||
PaymentState_IN_FLIGHT PaymentState = 0
|
||||
//*
|
||||
//Payment completed successfully.
|
||||
PaymentState_SUCCEEDED PaymentState = 1
|
||||
//*
|
||||
//There are more routes to try, but the payment timeout was exceeded.
|
||||
PaymentState_FAILED_TIMEOUT PaymentState = 2
|
||||
//*
|
||||
//All possible routes were tried and failed permanently. Or were no
|
||||
//routes to the destination at all.
|
||||
PaymentState_FAILED_NO_ROUTE PaymentState = 3
|
||||
//*
|
||||
//A non-recoverable error has occured.
|
||||
PaymentState_FAILED_ERROR PaymentState = 4
|
||||
//*
|
||||
//Payment details incorrect (unknown hash, invalid amt or
|
||||
//invalid final cltv delta)
|
||||
PaymentState_FAILED_INCORRECT_PAYMENT_DETAILS PaymentState = 5
|
||||
//*
|
||||
//Insufficient local balance.
|
||||
PaymentState_FAILED_INSUFFICIENT_BALANCE PaymentState = 6
|
||||
)
|
||||
|
||||
var PaymentState_name = map[int32]string{
|
||||
0: "IN_FLIGHT",
|
||||
1: "SUCCEEDED",
|
||||
2: "FAILED_TIMEOUT",
|
||||
3: "FAILED_NO_ROUTE",
|
||||
4: "FAILED_ERROR",
|
||||
5: "FAILED_INCORRECT_PAYMENT_DETAILS",
|
||||
6: "FAILED_INSUFFICIENT_BALANCE",
|
||||
}
|
||||
|
||||
var PaymentState_value = map[string]int32{
|
||||
"IN_FLIGHT": 0,
|
||||
"SUCCEEDED": 1,
|
||||
"FAILED_TIMEOUT": 2,
|
||||
"FAILED_NO_ROUTE": 3,
|
||||
"FAILED_ERROR": 4,
|
||||
"FAILED_INCORRECT_PAYMENT_DETAILS": 5,
|
||||
"FAILED_INSUFFICIENT_BALANCE": 6,
|
||||
}
|
||||
|
||||
func (x PaymentState) String() string {
|
||||
return proto.EnumName(PaymentState_name, int32(x))
|
||||
}
|
||||
|
||||
func (PaymentState) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{0}
|
||||
}
|
||||
|
||||
type FailureDetail int32
|
||||
|
||||
const (
|
||||
|
@ -164,7 +108,7 @@ func (x FailureDetail) String() string {
|
|||
}
|
||||
|
||||
func (FailureDetail) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{1}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{0}
|
||||
}
|
||||
|
||||
type HtlcEvent_EventType int32
|
||||
|
@ -195,7 +139,7 @@ func (x HtlcEvent_EventType) String() string {
|
|||
}
|
||||
|
||||
func (HtlcEvent_EventType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{18, 0}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{17, 0}
|
||||
}
|
||||
|
||||
type SendPaymentRequest struct {
|
||||
|
@ -460,66 +404,6 @@ func (m *TrackPaymentRequest) GetPaymentHash() []byte {
|
|||
return nil
|
||||
}
|
||||
|
||||
type PaymentStatus struct {
|
||||
/// Current state the payment is in.
|
||||
State PaymentState `protobuf:"varint,1,opt,name=state,proto3,enum=routerrpc.PaymentState" json:"state,omitempty"`
|
||||
//*
|
||||
//The pre-image of the payment when state is SUCCEEDED.
|
||||
Preimage []byte `protobuf:"bytes,2,opt,name=preimage,proto3" json:"preimage,omitempty"`
|
||||
//*
|
||||
//The HTLCs made in attempt to settle the payment.
|
||||
Htlcs []*lnrpc.HTLCAttempt `protobuf:"bytes,4,rep,name=htlcs,proto3" json:"htlcs,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *PaymentStatus) Reset() { *m = PaymentStatus{} }
|
||||
func (m *PaymentStatus) String() string { return proto.CompactTextString(m) }
|
||||
func (*PaymentStatus) ProtoMessage() {}
|
||||
func (*PaymentStatus) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{2}
|
||||
}
|
||||
|
||||
func (m *PaymentStatus) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_PaymentStatus.Unmarshal(m, b)
|
||||
}
|
||||
func (m *PaymentStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_PaymentStatus.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *PaymentStatus) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_PaymentStatus.Merge(m, src)
|
||||
}
|
||||
func (m *PaymentStatus) XXX_Size() int {
|
||||
return xxx_messageInfo_PaymentStatus.Size(m)
|
||||
}
|
||||
func (m *PaymentStatus) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_PaymentStatus.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_PaymentStatus proto.InternalMessageInfo
|
||||
|
||||
func (m *PaymentStatus) GetState() PaymentState {
|
||||
if m != nil {
|
||||
return m.State
|
||||
}
|
||||
return PaymentState_IN_FLIGHT
|
||||
}
|
||||
|
||||
func (m *PaymentStatus) GetPreimage() []byte {
|
||||
if m != nil {
|
||||
return m.Preimage
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PaymentStatus) GetHtlcs() []*lnrpc.HTLCAttempt {
|
||||
if m != nil {
|
||||
return m.Htlcs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type RouteFeeRequest struct {
|
||||
//*
|
||||
//The destination once wishes to obtain a routing fee quote to.
|
||||
|
@ -536,7 +420,7 @@ func (m *RouteFeeRequest) Reset() { *m = RouteFeeRequest{} }
|
|||
func (m *RouteFeeRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*RouteFeeRequest) ProtoMessage() {}
|
||||
func (*RouteFeeRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{3}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{2}
|
||||
}
|
||||
|
||||
func (m *RouteFeeRequest) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -590,7 +474,7 @@ func (m *RouteFeeResponse) Reset() { *m = RouteFeeResponse{} }
|
|||
func (m *RouteFeeResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*RouteFeeResponse) ProtoMessage() {}
|
||||
func (*RouteFeeResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{4}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{3}
|
||||
}
|
||||
|
||||
func (m *RouteFeeResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -639,7 +523,7 @@ func (m *SendToRouteRequest) Reset() { *m = SendToRouteRequest{} }
|
|||
func (m *SendToRouteRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*SendToRouteRequest) ProtoMessage() {}
|
||||
func (*SendToRouteRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{5}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{4}
|
||||
}
|
||||
|
||||
func (m *SendToRouteRequest) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -688,7 +572,7 @@ func (m *SendToRouteResponse) Reset() { *m = SendToRouteResponse{} }
|
|||
func (m *SendToRouteResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*SendToRouteResponse) ProtoMessage() {}
|
||||
func (*SendToRouteResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{6}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{5}
|
||||
}
|
||||
|
||||
func (m *SendToRouteResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -733,7 +617,7 @@ func (m *ResetMissionControlRequest) Reset() { *m = ResetMissionControlR
|
|||
func (m *ResetMissionControlRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ResetMissionControlRequest) ProtoMessage() {}
|
||||
func (*ResetMissionControlRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{7}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{6}
|
||||
}
|
||||
|
||||
func (m *ResetMissionControlRequest) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -764,7 +648,7 @@ func (m *ResetMissionControlResponse) Reset() { *m = ResetMissionControl
|
|||
func (m *ResetMissionControlResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ResetMissionControlResponse) ProtoMessage() {}
|
||||
func (*ResetMissionControlResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{8}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{7}
|
||||
}
|
||||
|
||||
func (m *ResetMissionControlResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -795,7 +679,7 @@ func (m *QueryMissionControlRequest) Reset() { *m = QueryMissionControlR
|
|||
func (m *QueryMissionControlRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*QueryMissionControlRequest) ProtoMessage() {}
|
||||
func (*QueryMissionControlRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{9}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{8}
|
||||
}
|
||||
|
||||
func (m *QueryMissionControlRequest) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -829,7 +713,7 @@ func (m *QueryMissionControlResponse) Reset() { *m = QueryMissionControl
|
|||
func (m *QueryMissionControlResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*QueryMissionControlResponse) ProtoMessage() {}
|
||||
func (*QueryMissionControlResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{10}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{9}
|
||||
}
|
||||
|
||||
func (m *QueryMissionControlResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -873,7 +757,7 @@ func (m *PairHistory) Reset() { *m = PairHistory{} }
|
|||
func (m *PairHistory) String() string { return proto.CompactTextString(m) }
|
||||
func (*PairHistory) ProtoMessage() {}
|
||||
func (*PairHistory) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{11}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{10}
|
||||
}
|
||||
|
||||
func (m *PairHistory) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -941,7 +825,7 @@ func (m *PairData) Reset() { *m = PairData{} }
|
|||
func (m *PairData) String() string { return proto.CompactTextString(m) }
|
||||
func (*PairData) ProtoMessage() {}
|
||||
func (*PairData) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{12}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{11}
|
||||
}
|
||||
|
||||
func (m *PairData) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1020,7 +904,7 @@ func (m *QueryProbabilityRequest) Reset() { *m = QueryProbabilityRequest
|
|||
func (m *QueryProbabilityRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*QueryProbabilityRequest) ProtoMessage() {}
|
||||
func (*QueryProbabilityRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{13}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{12}
|
||||
}
|
||||
|
||||
func (m *QueryProbabilityRequest) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1076,7 +960,7 @@ func (m *QueryProbabilityResponse) Reset() { *m = QueryProbabilityRespon
|
|||
func (m *QueryProbabilityResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*QueryProbabilityResponse) ProtoMessage() {}
|
||||
func (*QueryProbabilityResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{14}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{13}
|
||||
}
|
||||
|
||||
func (m *QueryProbabilityResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1137,7 +1021,7 @@ func (m *BuildRouteRequest) Reset() { *m = BuildRouteRequest{} }
|
|||
func (m *BuildRouteRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*BuildRouteRequest) ProtoMessage() {}
|
||||
func (*BuildRouteRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{15}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{14}
|
||||
}
|
||||
|
||||
func (m *BuildRouteRequest) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1199,7 +1083,7 @@ func (m *BuildRouteResponse) Reset() { *m = BuildRouteResponse{} }
|
|||
func (m *BuildRouteResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*BuildRouteResponse) ProtoMessage() {}
|
||||
func (*BuildRouteResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{16}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{15}
|
||||
}
|
||||
|
||||
func (m *BuildRouteResponse) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1237,7 +1121,7 @@ func (m *SubscribeHtlcEventsRequest) Reset() { *m = SubscribeHtlcEventsR
|
|||
func (m *SubscribeHtlcEventsRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*SubscribeHtlcEventsRequest) ProtoMessage() {}
|
||||
func (*SubscribeHtlcEventsRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{17}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{16}
|
||||
}
|
||||
|
||||
func (m *SubscribeHtlcEventsRequest) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1304,7 +1188,7 @@ func (m *HtlcEvent) Reset() { *m = HtlcEvent{} }
|
|||
func (m *HtlcEvent) String() string { return proto.CompactTextString(m) }
|
||||
func (*HtlcEvent) ProtoMessage() {}
|
||||
func (*HtlcEvent) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{18}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{17}
|
||||
}
|
||||
|
||||
func (m *HtlcEvent) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1458,7 +1342,7 @@ func (m *HtlcInfo) Reset() { *m = HtlcInfo{} }
|
|||
func (m *HtlcInfo) String() string { return proto.CompactTextString(m) }
|
||||
func (*HtlcInfo) ProtoMessage() {}
|
||||
func (*HtlcInfo) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{19}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{18}
|
||||
}
|
||||
|
||||
func (m *HtlcInfo) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1519,7 +1403,7 @@ func (m *ForwardEvent) Reset() { *m = ForwardEvent{} }
|
|||
func (m *ForwardEvent) String() string { return proto.CompactTextString(m) }
|
||||
func (*ForwardEvent) ProtoMessage() {}
|
||||
func (*ForwardEvent) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{20}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{19}
|
||||
}
|
||||
|
||||
func (m *ForwardEvent) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1557,7 +1441,7 @@ func (m *ForwardFailEvent) Reset() { *m = ForwardFailEvent{} }
|
|||
func (m *ForwardFailEvent) String() string { return proto.CompactTextString(m) }
|
||||
func (*ForwardFailEvent) ProtoMessage() {}
|
||||
func (*ForwardFailEvent) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{21}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{20}
|
||||
}
|
||||
|
||||
func (m *ForwardFailEvent) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1588,7 +1472,7 @@ func (m *SettleEvent) Reset() { *m = SettleEvent{} }
|
|||
func (m *SettleEvent) String() string { return proto.CompactTextString(m) }
|
||||
func (*SettleEvent) ProtoMessage() {}
|
||||
func (*SettleEvent) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{22}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{21}
|
||||
}
|
||||
|
||||
func (m *SettleEvent) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1630,7 +1514,7 @@ func (m *LinkFailEvent) Reset() { *m = LinkFailEvent{} }
|
|||
func (m *LinkFailEvent) String() string { return proto.CompactTextString(m) }
|
||||
func (*LinkFailEvent) ProtoMessage() {}
|
||||
func (*LinkFailEvent) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{23}
|
||||
return fileDescriptor_7a0613f69d37b0a5, []int{22}
|
||||
}
|
||||
|
||||
func (m *LinkFailEvent) XXX_Unmarshal(b []byte) error {
|
||||
|
@ -1680,13 +1564,11 @@ func (m *LinkFailEvent) GetFailureString() string {
|
|||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("routerrpc.PaymentState", PaymentState_name, PaymentState_value)
|
||||
proto.RegisterEnum("routerrpc.FailureDetail", FailureDetail_name, FailureDetail_value)
|
||||
proto.RegisterEnum("routerrpc.HtlcEvent_EventType", HtlcEvent_EventType_name, HtlcEvent_EventType_value)
|
||||
proto.RegisterType((*SendPaymentRequest)(nil), "routerrpc.SendPaymentRequest")
|
||||
proto.RegisterMapType((map[uint64][]byte)(nil), "routerrpc.SendPaymentRequest.DestCustomRecordsEntry")
|
||||
proto.RegisterType((*TrackPaymentRequest)(nil), "routerrpc.TrackPaymentRequest")
|
||||
proto.RegisterType((*PaymentStatus)(nil), "routerrpc.PaymentStatus")
|
||||
proto.RegisterType((*RouteFeeRequest)(nil), "routerrpc.RouteFeeRequest")
|
||||
proto.RegisterType((*RouteFeeResponse)(nil), "routerrpc.RouteFeeResponse")
|
||||
proto.RegisterType((*SendToRouteRequest)(nil), "routerrpc.SendToRouteRequest")
|
||||
|
@ -1713,142 +1595,134 @@ func init() {
|
|||
func init() { proto.RegisterFile("routerrpc/router.proto", fileDescriptor_7a0613f69d37b0a5) }
|
||||
|
||||
var fileDescriptor_7a0613f69d37b0a5 = []byte{
|
||||
// 2150 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x58, 0xdd, 0x72, 0xdb, 0xb8,
|
||||
0x15, 0x0e, 0x6d, 0xca, 0x96, 0x8e, 0x7e, 0x4c, 0x43, 0x59, 0x47, 0x95, 0x93, 0x5d, 0x2d, 0xbb,
|
||||
0x9b, 0x68, 0xd2, 0xac, 0x9d, 0x75, 0x3b, 0x6d, 0xa6, 0xed, 0x6e, 0x47, 0x96, 0xe8, 0x88, 0x8e,
|
||||
0x4c, 0x6a, 0x21, 0x3a, 0x3f, 0xcd, 0x05, 0x86, 0x96, 0x20, 0x8b, 0x35, 0x45, 0xaa, 0x24, 0x94,
|
||||
0x8c, 0x2f, 0x3b, 0xbd, 0xeb, 0x8b, 0xf4, 0xae, 0x4f, 0xd0, 0x77, 0xe9, 0x6d, 0x9f, 0xa0, 0xd3,
|
||||
0xcb, 0x1d, 0x80, 0xa0, 0x44, 0xd9, 0x72, 0x76, 0x6f, 0x12, 0xf1, 0x3b, 0x1f, 0x0e, 0xce, 0x39,
|
||||
0xf8, 0x80, 0x03, 0x18, 0xf6, 0xa2, 0x70, 0xce, 0x68, 0x14, 0xcd, 0x86, 0x87, 0xc9, 0xaf, 0x83,
|
||||
0x59, 0x14, 0xb2, 0x10, 0x15, 0x16, 0x78, 0xbd, 0x10, 0xcd, 0x86, 0x09, 0xaa, 0xff, 0x3f, 0x07,
|
||||
0x68, 0x40, 0x83, 0x51, 0xdf, 0xbd, 0x9e, 0xd2, 0x80, 0x61, 0xfa, 0xd7, 0x39, 0x8d, 0x19, 0x42,
|
||||
0xa0, 0x8e, 0x68, 0xcc, 0x6a, 0x4a, 0x43, 0x69, 0x96, 0xb0, 0xf8, 0x8d, 0x34, 0xd8, 0x74, 0xa7,
|
||||
0xac, 0xb6, 0xd1, 0x50, 0x9a, 0x9b, 0x98, 0xff, 0x44, 0xbf, 0x80, 0xbc, 0x3b, 0x65, 0x64, 0x1a,
|
||||
0xbb, 0xac, 0x56, 0x12, 0xf0, 0xb6, 0x3b, 0x65, 0x67, 0xb1, 0xcb, 0xd0, 0x97, 0x50, 0x9a, 0x25,
|
||||
0x2e, 0xc9, 0xc4, 0x8d, 0x27, 0xb5, 0x4d, 0xe1, 0xa8, 0x28, 0xb1, 0xae, 0x1b, 0x4f, 0x50, 0x13,
|
||||
0xb4, 0xb1, 0x17, 0xb8, 0x3e, 0x19, 0xfa, 0xec, 0x03, 0x19, 0x51, 0x9f, 0xb9, 0x35, 0xb5, 0xa1,
|
||||
0x34, 0x73, 0xb8, 0x22, 0xf0, 0xb6, 0xcf, 0x3e, 0x74, 0x38, 0x8a, 0x9e, 0xc0, 0x4e, 0xea, 0x2c,
|
||||
0x4a, 0x02, 0xac, 0xe5, 0x1a, 0x4a, 0xb3, 0x80, 0x2b, 0xb3, 0xd5, 0xb0, 0x9f, 0xc0, 0x0e, 0xf3,
|
||||
0xa6, 0x34, 0x9c, 0x33, 0x12, 0xd3, 0x61, 0x18, 0x8c, 0xe2, 0xda, 0x56, 0xe2, 0x51, 0xc2, 0x83,
|
||||
0x04, 0x45, 0x3a, 0x94, 0xc7, 0x94, 0x12, 0xdf, 0x9b, 0x7a, 0x8c, 0xf0, 0xf0, 0xb7, 0x45, 0xf8,
|
||||
0xc5, 0x31, 0xa5, 0x3d, 0x8e, 0x0d, 0x5c, 0x86, 0xbe, 0x82, 0xca, 0x92, 0x23, 0x72, 0x2c, 0x0b,
|
||||
0x52, 0x29, 0x25, 0x89, 0x44, 0x9f, 0x81, 0x16, 0xce, 0xd9, 0x65, 0xe8, 0x05, 0x97, 0x64, 0x38,
|
||||
0x71, 0x03, 0xe2, 0x8d, 0x6a, 0xf9, 0x86, 0xd2, 0x54, 0x8f, 0x37, 0x9e, 0x2b, 0xb8, 0x92, 0xda,
|
||||
0xda, 0x13, 0x37, 0x30, 0x47, 0xe8, 0x31, 0xec, 0xf8, 0x6e, 0xcc, 0xc8, 0x24, 0x9c, 0x91, 0xd9,
|
||||
0xfc, 0xe2, 0x8a, 0x5e, 0xd7, 0x2a, 0xa2, 0x32, 0x65, 0x0e, 0x77, 0xc3, 0x59, 0x5f, 0x80, 0xe8,
|
||||
0x11, 0x80, 0xa8, 0x8a, 0x98, 0xbc, 0x56, 0x10, 0x39, 0x14, 0x38, 0x22, 0x26, 0x46, 0xdf, 0x42,
|
||||
0x51, 0xac, 0x26, 0x99, 0x78, 0x01, 0x8b, 0x6b, 0xd0, 0xd8, 0x6c, 0x16, 0x8f, 0xb4, 0x03, 0x3f,
|
||||
0xe0, 0x0b, 0x8b, 0xb9, 0xa5, 0xeb, 0x05, 0x0c, 0x43, 0x94, 0xfe, 0x8c, 0xd1, 0x08, 0xaa, 0x7c,
|
||||
0x15, 0xc9, 0x70, 0x1e, 0xb3, 0x70, 0x4a, 0x22, 0x3a, 0x0c, 0xa3, 0x51, 0x5c, 0x2b, 0x8a, 0xa1,
|
||||
0xbf, 0x39, 0x58, 0x88, 0xe3, 0xe0, 0xb6, 0x1a, 0x0e, 0x3a, 0x34, 0x66, 0x6d, 0x31, 0x0e, 0x27,
|
||||
0xc3, 0x8c, 0x80, 0x45, 0xd7, 0x78, 0x77, 0x74, 0x13, 0x47, 0xcf, 0x00, 0xb9, 0xbe, 0x1f, 0x7e,
|
||||
0x24, 0x31, 0xf5, 0xc7, 0x44, 0xae, 0x4e, 0x6d, 0xa7, 0xa1, 0x34, 0xf3, 0x58, 0x13, 0x96, 0x01,
|
||||
0xf5, 0xc7, 0xd2, 0x3d, 0xfa, 0x2d, 0x94, 0x45, 0x4c, 0x63, 0xea, 0xb2, 0x79, 0x44, 0xe3, 0x9a,
|
||||
0xd6, 0xd8, 0x6c, 0x56, 0x8e, 0x76, 0x65, 0x22, 0x27, 0x09, 0x7c, 0xec, 0x31, 0x5c, 0xe2, 0x3c,
|
||||
0xf9, 0x1d, 0xd7, 0x3b, 0xb0, 0xb7, 0x3e, 0x24, 0xae, 0x51, 0x5e, 0x53, 0x2e, 0x5b, 0x15, 0xf3,
|
||||
0x9f, 0xe8, 0x3e, 0xe4, 0x3e, 0xb8, 0xfe, 0x9c, 0x0a, 0xdd, 0x96, 0x70, 0xf2, 0xf1, 0xfb, 0x8d,
|
||||
0x17, 0x8a, 0xfe, 0x02, 0xaa, 0x4e, 0xe4, 0x0e, 0xaf, 0x6e, 0x48, 0xff, 0xa6, 0x72, 0x95, 0x5b,
|
||||
0xca, 0xd5, 0xff, 0xa1, 0x40, 0x59, 0x8e, 0x1a, 0x30, 0x97, 0xcd, 0x63, 0xf4, 0x0d, 0xe4, 0x62,
|
||||
0xe6, 0x32, 0x2a, 0xd8, 0x95, 0xa3, 0x07, 0x99, 0x7a, 0x66, 0x88, 0x14, 0x27, 0x2c, 0x54, 0x87,
|
||||
0xfc, 0x2c, 0xa2, 0xde, 0xd4, 0xbd, 0x4c, 0xe3, 0x5a, 0x7c, 0xa3, 0x26, 0xe4, 0x26, 0xcc, 0x1f,
|
||||
0xc6, 0x35, 0x55, 0x2c, 0x0d, 0x92, 0xc5, 0xe8, 0x3a, 0xbd, 0x76, 0x8b, 0x31, 0x3a, 0x9d, 0x31,
|
||||
0x9c, 0x10, 0x4e, 0xd5, 0xfc, 0xa6, 0xa6, 0xea, 0xdf, 0xc3, 0x8e, 0x58, 0xf1, 0x13, 0x4a, 0x3f,
|
||||
0xb5, 0x7b, 0x1f, 0x00, 0xdf, 0x9b, 0x42, 0xeb, 0xc9, 0x0e, 0xde, 0x72, 0xa7, 0x5c, 0xe6, 0xfa,
|
||||
0x08, 0xb4, 0xe5, 0xf8, 0x78, 0x16, 0x06, 0x31, 0x8f, 0x41, 0xe3, 0x09, 0x70, 0x4d, 0xf3, 0x2d,
|
||||
0x20, 0xc4, 0xaf, 0x88, 0x51, 0x15, 0x89, 0x9f, 0x50, 0x2a, 0xe4, 0xff, 0x38, 0xd9, 0x71, 0xc4,
|
||||
0x0f, 0x87, 0x57, 0x7c, 0x0f, 0xbb, 0xd7, 0xd2, 0x7d, 0x99, 0xc3, 0xbd, 0x70, 0x78, 0xd5, 0xe1,
|
||||
0xa0, 0xfe, 0x3e, 0x39, 0x66, 0x9c, 0x50, 0xcc, 0xf5, 0xf3, 0x6b, 0x8d, 0x74, 0xc8, 0x89, 0x5a,
|
||||
0x0a, 0xb7, 0xc5, 0xa3, 0x52, 0x56, 0xe4, 0x38, 0x31, 0xe9, 0xef, 0xa1, 0xba, 0xe2, 0x5c, 0x66,
|
||||
0x91, 0xad, 0xb2, 0x72, 0xab, 0xca, 0xdb, 0x63, 0xd7, 0xf3, 0xe7, 0x51, 0xea, 0xb8, 0x92, 0x8a,
|
||||
0x2e, 0x41, 0x71, 0x6a, 0xd6, 0x1f, 0x42, 0x1d, 0xd3, 0x98, 0xb2, 0x33, 0x2f, 0x8e, 0xbd, 0x30,
|
||||
0x68, 0x87, 0x01, 0x8b, 0x42, 0x5f, 0x66, 0xa0, 0x3f, 0x82, 0xfd, 0xb5, 0xd6, 0x24, 0x04, 0x3e,
|
||||
0xf8, 0x87, 0x39, 0x8d, 0xae, 0xd7, 0x0f, 0xfe, 0x01, 0xf6, 0xd7, 0x5a, 0x65, 0xfc, 0xcf, 0x20,
|
||||
0x37, 0x73, 0xbd, 0x28, 0xae, 0x6d, 0x08, 0x25, 0xec, 0xad, 0x88, 0xca, 0x8b, 0xba, 0x5e, 0xcc,
|
||||
0xc2, 0xe8, 0x1a, 0x27, 0xa4, 0x53, 0x35, 0xaf, 0x68, 0x1b, 0x5c, 0x9a, 0xc5, 0x8c, 0x11, 0xed,
|
||||
0x43, 0x21, 0x08, 0x47, 0x94, 0x8c, 0xa3, 0x70, 0x9a, 0x16, 0x81, 0x03, 0x27, 0x51, 0x38, 0xe5,
|
||||
0x9a, 0x10, 0x46, 0x16, 0x4a, 0x15, 0x6e, 0xf1, 0x4f, 0x27, 0x44, 0xdf, 0xc0, 0xf6, 0x24, 0x71,
|
||||
0x20, 0x0e, 0xc6, 0xe2, 0x51, 0xf5, 0xc6, 0xdc, 0x1d, 0x97, 0xb9, 0x38, 0xe5, 0x24, 0x42, 0x3c,
|
||||
0x55, 0xf3, 0xaa, 0x96, 0x3b, 0x55, 0xf3, 0x39, 0x6d, 0xeb, 0x54, 0xcd, 0x6f, 0x69, 0xdb, 0xfa,
|
||||
0x7f, 0x15, 0xc8, 0xa7, 0x6c, 0x1e, 0x09, 0x2f, 0x29, 0xe1, 0xba, 0x90, 0x62, 0xca, 0x73, 0xc0,
|
||||
0xf1, 0xa6, 0x14, 0x35, 0xa0, 0x24, 0x8c, 0xab, 0x12, 0x05, 0x8e, 0xb5, 0x84, 0x4c, 0xc5, 0x89,
|
||||
0x9d, 0x32, 0x84, 0x1e, 0x55, 0x79, 0x62, 0x27, 0x94, 0xb4, 0xe9, 0xc4, 0xf3, 0xe1, 0x90, 0xc6,
|
||||
0x71, 0x32, 0x4b, 0x2e, 0xa1, 0x48, 0x4c, 0x4c, 0xf4, 0x18, 0x76, 0x52, 0x4a, 0x3a, 0xd7, 0x56,
|
||||
0xa2, 0x57, 0x09, 0xcb, 0xe9, 0x9a, 0xa0, 0x65, 0x79, 0xd3, 0x65, 0x8f, 0xa8, 0x2c, 0x89, 0x7c,
|
||||
0x52, 0xb9, 0x0b, 0xff, 0x02, 0x0f, 0xc4, 0x52, 0xf6, 0xa3, 0xf0, 0xc2, 0xbd, 0xf0, 0x7c, 0x8f,
|
||||
0x5d, 0xa7, 0x22, 0xe7, 0x89, 0x47, 0xe1, 0x94, 0xf0, 0xda, 0xa6, 0x4b, 0xc0, 0x01, 0x2b, 0x1c,
|
||||
0x51, 0xbe, 0x04, 0x2c, 0x4c, 0x4c, 0x72, 0x09, 0x58, 0x28, 0x0c, 0xd9, 0xde, 0xba, 0xb9, 0xd2,
|
||||
0x5b, 0xf5, 0x2b, 0xa8, 0xdd, 0x9e, 0x4b, 0x6a, 0xa6, 0x01, 0xc5, 0xd9, 0x12, 0x16, 0xd3, 0x29,
|
||||
0x38, 0x0b, 0x65, 0xd7, 0x76, 0xe3, 0xa7, 0xd7, 0x56, 0xff, 0xa7, 0x02, 0xbb, 0xc7, 0x73, 0xcf,
|
||||
0x1f, 0xad, 0x6c, 0xdc, 0x6c, 0x74, 0xca, 0x6a, 0xe7, 0x5f, 0xd7, 0xd6, 0x37, 0xd6, 0xb6, 0xf5,
|
||||
0x75, 0xad, 0x73, 0xf3, 0xce, 0xd6, 0xf9, 0x05, 0x14, 0x97, 0x5d, 0x33, 0x39, 0x1d, 0x4b, 0x18,
|
||||
0x26, 0x69, 0xcb, 0x8c, 0xf5, 0x17, 0x80, 0xb2, 0x81, 0xca, 0x82, 0x2c, 0xce, 0x0f, 0xe5, 0xee,
|
||||
0xf3, 0xe3, 0x21, 0xd4, 0x07, 0xf3, 0x8b, 0x78, 0x18, 0x79, 0x17, 0xb4, 0xcb, 0xfc, 0xa1, 0xf1,
|
||||
0x81, 0x06, 0x2c, 0x4e, 0x77, 0xe9, 0xff, 0x54, 0x28, 0x2c, 0x50, 0x74, 0x00, 0x55, 0x2f, 0x18,
|
||||
0x86, 0xd3, 0x34, 0xe8, 0x80, 0xfa, 0x3c, 0xee, 0xa4, 0xe3, 0xec, 0xa6, 0xa6, 0x76, 0x62, 0x31,
|
||||
0x47, 0x9c, 0xbf, 0x92, 0xa4, 0xe4, 0x6f, 0x24, 0xfc, 0x6c, 0x8e, 0x09, 0xbf, 0x09, 0xda, 0xc2,
|
||||
0x3f, 0x3f, 0xe6, 0x17, 0x45, 0xc1, 0x95, 0x14, 0xe7, 0xc1, 0x24, 0xcc, 0x85, 0xe7, 0x94, 0xa9,
|
||||
0x26, 0xcc, 0x14, 0x97, 0xcc, 0x2f, 0xa1, 0xc4, 0xf7, 0x43, 0xcc, 0xdc, 0xe9, 0x8c, 0x04, 0xb1,
|
||||
0xd8, 0x17, 0x2a, 0x2e, 0x2e, 0x30, 0x2b, 0x46, 0xdf, 0x01, 0x50, 0x9e, 0x1f, 0x61, 0xd7, 0x33,
|
||||
0x2a, 0xb6, 0x44, 0xe5, 0xe8, 0xf3, 0x8c, 0x30, 0x16, 0x05, 0x38, 0x10, 0xff, 0x3a, 0xd7, 0x33,
|
||||
0x8a, 0x0b, 0x34, 0xfd, 0x89, 0xbe, 0x87, 0xf2, 0x38, 0x8c, 0x3e, 0xba, 0xd1, 0x88, 0x08, 0x50,
|
||||
0x1e, 0x1b, 0xd9, 0x3e, 0x78, 0x92, 0xd8, 0xc5, 0xf0, 0xee, 0x3d, 0x5c, 0x1a, 0x67, 0xbe, 0xd1,
|
||||
0x2b, 0x40, 0xe9, 0x78, 0xb1, 0xcb, 0x13, 0x27, 0x79, 0xe1, 0x64, 0xff, 0xb6, 0x13, 0x7e, 0x48,
|
||||
0xa7, 0x8e, 0xb4, 0xf1, 0x0d, 0x0c, 0xfd, 0x01, 0x4a, 0x31, 0x65, 0xcc, 0xa7, 0xd2, 0x4d, 0x41,
|
||||
0xb8, 0xd9, 0x5b, 0xb9, 0xe3, 0x70, 0x73, 0xea, 0xa1, 0x18, 0x2f, 0x3f, 0xd1, 0x31, 0xec, 0xf8,
|
||||
0x5e, 0x70, 0x95, 0x0d, 0x03, 0xc4, 0xf8, 0x5a, 0x66, 0x7c, 0xcf, 0x0b, 0xae, 0xb2, 0x31, 0x94,
|
||||
0xfd, 0x2c, 0xa0, 0xff, 0x11, 0x0a, 0x8b, 0x2a, 0xa1, 0x22, 0x6c, 0x9f, 0x5b, 0xaf, 0x2c, 0xfb,
|
||||
0x8d, 0xa5, 0xdd, 0x43, 0x79, 0x50, 0x07, 0x86, 0xd5, 0xd1, 0x14, 0x0e, 0x63, 0xa3, 0x6d, 0x98,
|
||||
0xaf, 0x0d, 0x6d, 0x83, 0x7f, 0x9c, 0xd8, 0xf8, 0x4d, 0x0b, 0x77, 0xb4, 0xcd, 0xe3, 0x6d, 0xc8,
|
||||
0x89, 0x79, 0xf5, 0x7f, 0x2b, 0x90, 0x17, 0x2b, 0x18, 0x8c, 0x43, 0xf4, 0x2b, 0x58, 0x88, 0x4b,
|
||||
0x1c, 0x6e, 0xbc, 0xe1, 0x0a, 0xd5, 0x95, 0xf1, 0x42, 0x30, 0x8e, 0xc4, 0x39, 0x79, 0x21, 0x8d,
|
||||
0x05, 0x79, 0x23, 0x21, 0xa7, 0x86, 0x05, 0xf9, 0x69, 0xc6, 0xf3, 0xca, 0x91, 0xa3, 0xe2, 0x9d,
|
||||
0xd4, 0x90, 0x9e, 0xb0, 0x4f, 0x33, 0x8e, 0x57, 0x4e, 0x62, 0x15, 0xef, 0xa4, 0x06, 0xc9, 0xd5,
|
||||
0x7f, 0x07, 0xa5, 0xec, 0x9a, 0xa3, 0x27, 0xa0, 0x7a, 0xc1, 0x38, 0x94, 0x1b, 0xb1, 0x7a, 0x43,
|
||||
0x5c, 0x3c, 0x49, 0x2c, 0x08, 0x3a, 0x02, 0xed, 0xe6, 0x3a, 0xeb, 0x65, 0x28, 0x66, 0x16, 0x4d,
|
||||
0xff, 0x8f, 0x02, 0xe5, 0x95, 0x45, 0xf8, 0xd9, 0xde, 0xd1, 0x77, 0x50, 0xfa, 0xe8, 0x45, 0x94,
|
||||
0x64, 0xdb, 0x7f, 0xe5, 0xa8, 0xbe, 0xda, 0xfe, 0xd3, 0xff, 0xdb, 0xe1, 0x88, 0xe2, 0x22, 0xe7,
|
||||
0x4b, 0x00, 0xfd, 0x09, 0x2a, 0x72, 0x24, 0x19, 0x51, 0xe6, 0x7a, 0xbe, 0x28, 0x55, 0x65, 0x45,
|
||||
0x1e, 0x92, 0xdb, 0x11, 0x76, 0x5c, 0x1e, 0x67, 0x3f, 0xd1, 0xd7, 0x4b, 0x07, 0x31, 0x8b, 0xbc,
|
||||
0xe0, 0x52, 0xd4, 0xaf, 0xb0, 0xa0, 0x0d, 0x04, 0xf8, 0xf4, 0x5f, 0x0a, 0x94, 0xb2, 0x57, 0x47,
|
||||
0x54, 0x86, 0x82, 0x69, 0x91, 0x93, 0x9e, 0xf9, 0xb2, 0xeb, 0x68, 0xf7, 0xf8, 0xe7, 0xe0, 0xbc,
|
||||
0xdd, 0x36, 0x8c, 0x8e, 0xc1, 0xe5, 0x84, 0xa0, 0x72, 0xd2, 0x32, 0x7b, 0x46, 0x87, 0x38, 0xe6,
|
||||
0x99, 0x61, 0x9f, 0x3b, 0xda, 0x06, 0xaa, 0xc2, 0x8e, 0xc4, 0x2c, 0x9b, 0x60, 0xfb, 0xdc, 0x31,
|
||||
0xb4, 0x4d, 0xa4, 0x41, 0x49, 0x82, 0x06, 0xc6, 0x36, 0xd6, 0x54, 0xf4, 0x15, 0x34, 0x24, 0x62,
|
||||
0x5a, 0x6d, 0x1b, 0x63, 0xa3, 0xed, 0x90, 0x7e, 0xeb, 0xdd, 0x99, 0x61, 0x39, 0xa4, 0x63, 0x38,
|
||||
0x2d, 0xb3, 0x37, 0xd0, 0x72, 0xe8, 0x0b, 0xd8, 0x5f, 0xb0, 0x06, 0xe7, 0x27, 0x27, 0x66, 0xdb,
|
||||
0xe4, 0x84, 0xe3, 0x56, 0xaf, 0x65, 0xb5, 0x0d, 0x6d, 0xeb, 0xe9, 0xdf, 0x54, 0x28, 0xaf, 0x24,
|
||||
0xbe, 0xaa, 0xfc, 0x32, 0x14, 0x2c, 0x5b, 0xfa, 0xd3, 0x14, 0x1e, 0x86, 0x6d, 0x99, 0xb6, 0x45,
|
||||
0x3a, 0x46, 0xdb, 0xee, 0xf0, 0x3d, 0xf0, 0x19, 0xec, 0xf6, 0x4c, 0xeb, 0x15, 0xb1, 0x6c, 0x87,
|
||||
0x18, 0x3d, 0xf3, 0xa5, 0x79, 0xdc, 0xe3, 0xf1, 0xde, 0x07, 0xcd, 0xb6, 0x48, 0xbb, 0xdb, 0x32,
|
||||
0xad, 0x45, 0x6a, 0x2a, 0x47, 0xf9, 0x85, 0x98, 0x18, 0x6f, 0x79, 0x05, 0x06, 0xe4, 0xac, 0xf5,
|
||||
0x56, 0xcb, 0xa1, 0x1a, 0xdc, 0x5f, 0x1f, 0x1c, 0xda, 0x03, 0xc4, 0x93, 0x3b, 0xeb, 0xf7, 0x0c,
|
||||
0xc7, 0x20, 0xe9, 0x5e, 0xdb, 0xe6, 0x25, 0x12, 0x7e, 0x5a, 0x9d, 0x0e, 0x49, 0xd2, 0xd3, 0xf2,
|
||||
0x3c, 0x12, 0xc9, 0x18, 0x90, 0x8e, 0x39, 0x68, 0x1d, 0x73, 0xb8, 0xc0, 0xe7, 0x34, 0xad, 0xd7,
|
||||
0xb6, 0xd9, 0x36, 0x48, 0x9b, 0xbb, 0xe5, 0x28, 0x70, 0x72, 0x8a, 0x9e, 0x5b, 0x1d, 0x03, 0xf7,
|
||||
0x5b, 0x66, 0x47, 0x2b, 0xa2, 0x7d, 0x78, 0x90, 0xc2, 0xc6, 0xdb, 0xbe, 0x89, 0xdf, 0x11, 0xc7,
|
||||
0xb6, 0xc9, 0xc0, 0xb6, 0x2d, 0xad, 0x94, 0xf5, 0xc4, 0xb3, 0xb5, 0xfb, 0x86, 0xa5, 0x95, 0xd1,
|
||||
0x03, 0xa8, 0x9e, 0xf5, 0xfb, 0x24, 0xb5, 0xa4, 0xc9, 0x56, 0x38, 0xbd, 0xd5, 0xe9, 0x60, 0x63,
|
||||
0x30, 0x20, 0x67, 0xe6, 0xe0, 0xac, 0xe5, 0xb4, 0xbb, 0xda, 0x0e, 0x4f, 0x69, 0x60, 0x38, 0xc4,
|
||||
0xb1, 0x9d, 0x56, 0x6f, 0x89, 0x6b, 0x3c, 0xa0, 0x25, 0xce, 0x27, 0xed, 0xd9, 0x6f, 0xb4, 0x5d,
|
||||
0x5e, 0x70, 0x0e, 0xdb, 0xaf, 0x65, 0x88, 0x88, 0xe7, 0x2e, 0x97, 0x27, 0x9d, 0x53, 0xab, 0x72,
|
||||
0xd0, 0xb4, 0x5e, 0xb7, 0x7a, 0x66, 0x87, 0xbc, 0x32, 0xde, 0x89, 0xb3, 0xea, 0x3e, 0x07, 0x93,
|
||||
0xc8, 0x48, 0x1f, 0xdb, 0x2f, 0x79, 0x20, 0xda, 0x67, 0x5c, 0x71, 0x6d, 0x13, 0xb7, 0xcf, 0x7b,
|
||||
0x2d, 0x2c, 0xc5, 0xb5, 0x77, 0xf4, 0xf7, 0x2d, 0xd8, 0x12, 0x9d, 0x35, 0x42, 0x5d, 0xbe, 0x61,
|
||||
0x17, 0x2f, 0x49, 0xf4, 0xe8, 0x93, 0x2f, 0xcc, 0x7a, 0x6d, 0xfd, 0x83, 0x69, 0x1e, 0x3f, 0x57,
|
||||
0xd0, 0x29, 0x94, 0xb2, 0xef, 0x34, 0x94, 0x6d, 0x4b, 0x6b, 0x1e, 0x70, 0x9f, 0xf4, 0xf5, 0x0a,
|
||||
0x34, 0x23, 0x66, 0xde, 0x94, 0xbf, 0xc5, 0xe4, 0xa3, 0x07, 0xd5, 0x33, 0xfc, 0x1b, 0x2f, 0xa9,
|
||||
0xfa, 0xfe, 0x5a, 0x9b, 0xbc, 0x5a, 0xf4, 0x92, 0x14, 0xe5, 0xb3, 0xe3, 0x56, 0x8a, 0xab, 0x6f,
|
||||
0x9d, 0xfa, 0xe7, 0x77, 0x99, 0xa5, 0xb7, 0x11, 0x54, 0xd7, 0xbc, 0x24, 0xd0, 0xd7, 0xd9, 0x08,
|
||||
0xee, 0x7c, 0x87, 0xd4, 0x1f, 0xff, 0x14, 0x6d, 0x39, 0xcb, 0x9a, 0x27, 0xc7, 0xca, 0x2c, 0x77,
|
||||
0x3f, 0x58, 0x56, 0x66, 0xf9, 0xd4, 0xcb, 0xe5, 0x3d, 0x68, 0x37, 0x6f, 0xa8, 0x48, 0xbf, 0x39,
|
||||
0xf6, 0xf6, 0x55, 0xb9, 0xfe, 0xcb, 0x4f, 0x72, 0xa4, 0x73, 0x13, 0x60, 0x79, 0xcf, 0x43, 0x0f,
|
||||
0x33, 0x43, 0x6e, 0xdd, 0x53, 0xeb, 0x8f, 0xee, 0xb0, 0x4a, 0x57, 0x0e, 0x54, 0xd7, 0x5c, 0xfc,
|
||||
0x56, 0xaa, 0x71, 0xf7, 0xc5, 0xb0, 0x7e, 0x7f, 0xdd, 0xfd, 0xe8, 0xb9, 0x72, 0xfc, 0xed, 0x9f,
|
||||
0x0f, 0x2f, 0x3d, 0x36, 0x99, 0x5f, 0x1c, 0x0c, 0xc3, 0xe9, 0xa1, 0xef, 0x5d, 0x4e, 0x58, 0xe0,
|
||||
0x05, 0x97, 0x01, 0x65, 0x1f, 0xc3, 0xe8, 0xea, 0xd0, 0x0f, 0x46, 0x87, 0xa2, 0xd9, 0x1c, 0x2e,
|
||||
0x86, 0x5f, 0x6c, 0x89, 0xbf, 0xc6, 0xfd, 0xfa, 0xc7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xaf, 0x84,
|
||||
0xd2, 0x59, 0xbd, 0x13, 0x00, 0x00,
|
||||
// 2017 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x58, 0x5d, 0x77, 0xdb, 0x48,
|
||||
0x19, 0x5e, 0xc5, 0x72, 0x62, 0xbf, 0xfe, 0x52, 0xc6, 0xdd, 0xd4, 0x38, 0xed, 0xe2, 0x15, 0x6c,
|
||||
0xeb, 0x53, 0x4a, 0xd2, 0x0d, 0x1c, 0xe8, 0x01, 0xb6, 0xe0, 0x58, 0xca, 0x46, 0x8d, 0x23, 0x79,
|
||||
0xc7, 0x4e, 0xdb, 0xa5, 0x17, 0x73, 0x14, 0x7b, 0x1c, 0x8b, 0xc8, 0x92, 0x91, 0xc6, 0xed, 0xc9,
|
||||
0x25, 0xb7, 0xfc, 0x11, 0xfe, 0x04, 0xff, 0x85, 0x5b, 0xee, 0xb8, 0xe3, 0x70, 0xc9, 0x99, 0x91,
|
||||
0xc6, 0x96, 0x13, 0xa7, 0xbb, 0x37, 0x89, 0xf4, 0xbc, 0xcf, 0xbc, 0x1f, 0xf3, 0x3e, 0xf3, 0x21,
|
||||
0xc3, 0x5e, 0x14, 0x2e, 0x18, 0x8d, 0xa2, 0xf9, 0xe8, 0x30, 0x79, 0x3a, 0x98, 0x47, 0x21, 0x0b,
|
||||
0x51, 0x71, 0x89, 0x37, 0x8b, 0xd1, 0x7c, 0x94, 0xa0, 0xfa, 0xff, 0xf2, 0x80, 0x06, 0x34, 0x18,
|
||||
0xf7, 0xdd, 0x9b, 0x19, 0x0d, 0x18, 0xa6, 0x7f, 0x5d, 0xd0, 0x98, 0x21, 0x04, 0xea, 0x98, 0xc6,
|
||||
0xac, 0xa1, 0xb4, 0x94, 0x76, 0x19, 0x8b, 0x67, 0xa4, 0x41, 0xce, 0x9d, 0xb1, 0xc6, 0x56, 0x4b,
|
||||
0x69, 0xe7, 0x30, 0x7f, 0x44, 0x3f, 0x81, 0x82, 0x3b, 0x63, 0x64, 0x16, 0xbb, 0xac, 0x51, 0x16,
|
||||
0xf0, 0x8e, 0x3b, 0x63, 0xe7, 0xb1, 0xcb, 0xd0, 0x97, 0x50, 0x9e, 0x27, 0x2e, 0xc9, 0xd4, 0x8d,
|
||||
0xa7, 0x8d, 0x9c, 0x70, 0x54, 0x4a, 0xb1, 0x53, 0x37, 0x9e, 0xa2, 0x36, 0x68, 0x13, 0x2f, 0x70,
|
||||
0x7d, 0x32, 0xf2, 0xd9, 0x07, 0x32, 0xa6, 0x3e, 0x73, 0x1b, 0x6a, 0x4b, 0x69, 0xe7, 0x71, 0x55,
|
||||
0xe0, 0x5d, 0x9f, 0x7d, 0x30, 0x38, 0x8a, 0x9e, 0x42, 0x4d, 0x3a, 0x8b, 0x92, 0x04, 0x1b, 0xf9,
|
||||
0x96, 0xd2, 0x2e, 0xe2, 0xea, 0x7c, 0x3d, 0xed, 0xa7, 0x50, 0x63, 0xde, 0x8c, 0x86, 0x0b, 0x46,
|
||||
0x62, 0x3a, 0x0a, 0x83, 0x71, 0xdc, 0xd8, 0x4e, 0x3c, 0xa6, 0xf0, 0x20, 0x41, 0x91, 0x0e, 0x95,
|
||||
0x09, 0xa5, 0xc4, 0xf7, 0x66, 0x1e, 0x23, 0x3c, 0xfd, 0x1d, 0x91, 0x7e, 0x69, 0x42, 0x69, 0x8f,
|
||||
0x63, 0x03, 0x97, 0xa1, 0x9f, 0x43, 0x75, 0xc5, 0x11, 0x35, 0x56, 0x04, 0xa9, 0x2c, 0x49, 0xa2,
|
||||
0xd0, 0xe7, 0xa0, 0x85, 0x0b, 0x76, 0x15, 0x7a, 0xc1, 0x15, 0x19, 0x4d, 0xdd, 0x80, 0x78, 0xe3,
|
||||
0x46, 0xa1, 0xa5, 0xb4, 0xd5, 0xe3, 0xad, 0x17, 0x0a, 0xae, 0x4a, 0x5b, 0x77, 0xea, 0x06, 0xd6,
|
||||
0x18, 0x3d, 0x81, 0x9a, 0xef, 0xc6, 0x8c, 0x4c, 0xc3, 0x39, 0x99, 0x2f, 0x2e, 0xaf, 0xe9, 0x4d,
|
||||
0xa3, 0x2a, 0x66, 0xa6, 0xc2, 0xe1, 0xd3, 0x70, 0xde, 0x17, 0x20, 0x7a, 0x0c, 0x20, 0x66, 0x45,
|
||||
0x04, 0x6f, 0x14, 0x45, 0x0d, 0x45, 0x8e, 0x88, 0xc0, 0xe8, 0x6b, 0x28, 0x89, 0x6e, 0x92, 0xa9,
|
||||
0x17, 0xb0, 0xb8, 0x01, 0xad, 0x5c, 0xbb, 0x74, 0xa4, 0x1d, 0xf8, 0x01, 0x6f, 0x2c, 0xe6, 0x96,
|
||||
0x53, 0x2f, 0x60, 0x18, 0x22, 0xf9, 0x18, 0xa3, 0x31, 0xd4, 0x79, 0x17, 0xc9, 0x68, 0x11, 0xb3,
|
||||
0x70, 0x46, 0x22, 0x3a, 0x0a, 0xa3, 0x71, 0xdc, 0x28, 0x89, 0xa1, 0xbf, 0x3e, 0x58, 0x8a, 0xe3,
|
||||
0xe0, 0xae, 0x1a, 0x0e, 0x0c, 0x1a, 0xb3, 0xae, 0x18, 0x87, 0x93, 0x61, 0x66, 0xc0, 0xa2, 0x1b,
|
||||
0xbc, 0x3b, 0xbe, 0x8d, 0xa3, 0xe7, 0x80, 0x5c, 0xdf, 0x0f, 0x3f, 0x92, 0x98, 0xfa, 0x13, 0x92,
|
||||
0x76, 0xa7, 0x51, 0x6b, 0x29, 0xed, 0x02, 0xd6, 0x84, 0x65, 0x40, 0xfd, 0x49, 0xea, 0x1e, 0xfd,
|
||||
0x06, 0x2a, 0x22, 0xa7, 0x09, 0x75, 0xd9, 0x22, 0xa2, 0x71, 0x43, 0x6b, 0xe5, 0xda, 0xd5, 0xa3,
|
||||
0xdd, 0xb4, 0x90, 0x93, 0x04, 0x3e, 0xf6, 0x18, 0x2e, 0x73, 0x5e, 0xfa, 0x1e, 0x37, 0x0d, 0xd8,
|
||||
0xdb, 0x9c, 0x12, 0xd7, 0x28, 0x9f, 0x53, 0x2e, 0x5b, 0x15, 0xf3, 0x47, 0xf4, 0x00, 0xf2, 0x1f,
|
||||
0x5c, 0x7f, 0x41, 0x85, 0x6e, 0xcb, 0x38, 0x79, 0xf9, 0xdd, 0xd6, 0x4b, 0x45, 0x7f, 0x09, 0xf5,
|
||||
0x61, 0xe4, 0x8e, 0xae, 0x6f, 0x49, 0xff, 0xb6, 0x72, 0x95, 0x3b, 0xca, 0xd5, 0x5f, 0x41, 0x4d,
|
||||
0x4c, 0xf2, 0x09, 0xa5, 0x9f, 0x5a, 0x30, 0x0f, 0x81, 0x2f, 0x07, 0x21, 0xaf, 0x64, 0xd1, 0x6c,
|
||||
0xbb, 0x33, 0xae, 0x2c, 0x7d, 0x0c, 0xda, 0x6a, 0x7c, 0x3c, 0x0f, 0x83, 0x98, 0xf2, 0xd5, 0xc0,
|
||||
0x7b, 0xc0, 0x65, 0xc4, 0x55, 0x27, 0xf4, 0xa6, 0x88, 0x51, 0xd5, 0x14, 0x3f, 0xa1, 0x54, 0x28,
|
||||
0xee, 0x49, 0x22, 0x72, 0xe2, 0x87, 0xa3, 0x6b, 0xbe, 0x6c, 0xdc, 0x9b, 0xd4, 0x7d, 0x85, 0xc3,
|
||||
0xbd, 0x70, 0x74, 0x6d, 0x70, 0x50, 0x7f, 0x9f, 0xac, 0xec, 0x61, 0x28, 0x62, 0xfd, 0xf8, 0xf2,
|
||||
0x90, 0x0e, 0x79, 0x21, 0x07, 0xe1, 0xb6, 0x74, 0x54, 0xce, 0xea, 0x0a, 0x27, 0x26, 0xfd, 0x3d,
|
||||
0xd4, 0xd7, 0x9c, 0xa7, 0x55, 0x34, 0xa1, 0x30, 0x8f, 0xa8, 0x37, 0x73, 0xaf, 0x68, 0xea, 0x79,
|
||||
0xf9, 0x8e, 0xda, 0xb0, 0x33, 0x71, 0x3d, 0x7f, 0x11, 0x49, 0xc7, 0x55, 0xd9, 0xe7, 0x04, 0xc5,
|
||||
0xd2, 0xac, 0x3f, 0x82, 0x26, 0xa6, 0x31, 0x65, 0xe7, 0x5e, 0x1c, 0x7b, 0x61, 0xd0, 0x0d, 0x03,
|
||||
0x16, 0x85, 0x7e, 0x5a, 0x81, 0xfe, 0x18, 0xf6, 0x37, 0x5a, 0x93, 0x14, 0xf8, 0xe0, 0xef, 0x16,
|
||||
0x34, 0xba, 0xd9, 0x3c, 0xf8, 0x3b, 0xd8, 0xdf, 0x68, 0x4d, 0xf3, 0x7f, 0x0e, 0xf9, 0xb9, 0xeb,
|
||||
0x45, 0x71, 0x63, 0x4b, 0xac, 0x8b, 0xbd, 0xcc, 0xba, 0xe8, 0xbb, 0x5e, 0x74, 0xea, 0xc5, 0x2c,
|
||||
0x8c, 0x6e, 0x70, 0x42, 0x7a, 0xad, 0x16, 0x14, 0x6d, 0x4b, 0xff, 0xbb, 0x02, 0xa5, 0x8c, 0x11,
|
||||
0xed, 0x43, 0x31, 0x08, 0xc7, 0x94, 0x4c, 0xa2, 0x70, 0x26, 0x27, 0x81, 0x03, 0x27, 0x51, 0x38,
|
||||
0xe3, 0x9a, 0x10, 0x46, 0x16, 0xa6, 0x82, 0xdc, 0xe6, 0xaf, 0xc3, 0x10, 0xfd, 0x12, 0x76, 0xa6,
|
||||
0x89, 0x03, 0xb1, 0x17, 0x95, 0x8e, 0xea, 0xb7, 0x62, 0x1b, 0x2e, 0x73, 0xb1, 0xe4, 0xbc, 0x56,
|
||||
0x0b, 0x39, 0x4d, 0x7d, 0xad, 0x16, 0x54, 0x2d, 0xff, 0x5a, 0x2d, 0xe4, 0xb5, 0xed, 0xd7, 0x6a,
|
||||
0x61, 0x5b, 0xdb, 0xd1, 0xff, 0xad, 0x40, 0x41, 0xb2, 0x79, 0x26, 0x7c, 0x4a, 0x09, 0xd7, 0x45,
|
||||
0x2a, 0xa6, 0x02, 0x07, 0x86, 0xde, 0x8c, 0xa2, 0x16, 0x94, 0x85, 0x71, 0x5d, 0xa2, 0xc0, 0xb1,
|
||||
0x8e, 0x90, 0xa9, 0xd8, 0x24, 0x25, 0x43, 0xe8, 0x51, 0x4d, 0x37, 0xc9, 0x84, 0x22, 0xf7, 0xf9,
|
||||
0x78, 0x31, 0x1a, 0xd1, 0x38, 0x4e, 0xa2, 0xe4, 0x13, 0x4a, 0x8a, 0x89, 0x40, 0x4f, 0xa0, 0x26,
|
||||
0x29, 0x32, 0xd6, 0x76, 0xa2, 0xd7, 0x14, 0x4e, 0xc3, 0xb5, 0x41, 0xcb, 0xf2, 0x66, 0xab, 0x6d,
|
||||
0xb9, 0xba, 0x22, 0xf2, 0xa0, 0x49, 0xf1, 0xfa, 0x5f, 0xe0, 0xa1, 0x68, 0x65, 0x3f, 0x0a, 0x2f,
|
||||
0xdd, 0x4b, 0xcf, 0xf7, 0xd8, 0x8d, 0x14, 0x39, 0x2f, 0x3c, 0x0a, 0x67, 0x84, 0xcf, 0xad, 0x6c,
|
||||
0x01, 0x07, 0xec, 0x70, 0x4c, 0x79, 0x0b, 0x58, 0x98, 0x98, 0xd2, 0x16, 0xb0, 0x50, 0x18, 0xb2,
|
||||
0xc7, 0x59, 0x6e, 0xed, 0x38, 0xd3, 0xaf, 0xa1, 0x71, 0x37, 0x56, 0xaa, 0x99, 0x16, 0x94, 0xe6,
|
||||
0x2b, 0x58, 0x84, 0x53, 0x70, 0x16, 0xca, 0xf6, 0x76, 0xeb, 0x87, 0x7b, 0xab, 0xff, 0x43, 0x81,
|
||||
0xdd, 0xe3, 0x85, 0xe7, 0x8f, 0xd7, 0x16, 0x6e, 0x36, 0x3b, 0x65, 0xfd, 0xb0, 0xdd, 0x74, 0x92,
|
||||
0x6e, 0x6d, 0x3c, 0x49, 0x37, 0x9d, 0x56, 0xb9, 0x7b, 0x4f, 0xab, 0x9f, 0x42, 0x69, 0x75, 0x50,
|
||||
0xc5, 0x0d, 0xb5, 0x95, 0x6b, 0x97, 0x31, 0x4c, 0xe5, 0x29, 0x15, 0xeb, 0x2f, 0x01, 0x65, 0x13,
|
||||
0x4d, 0x27, 0x64, 0xb9, 0x7f, 0x28, 0xf7, 0xef, 0x1f, 0x8f, 0xa0, 0x39, 0x58, 0x5c, 0xc6, 0xa3,
|
||||
0xc8, 0xbb, 0xa4, 0xa7, 0xcc, 0x1f, 0x99, 0x1f, 0x68, 0xc0, 0x62, 0xb9, 0x4a, 0xff, 0xab, 0x42,
|
||||
0x71, 0x89, 0xa2, 0x03, 0xa8, 0x7b, 0xc1, 0x28, 0x9c, 0xc9, 0xa4, 0x03, 0xea, 0xf3, 0xbc, 0x93,
|
||||
0x4d, 0x7e, 0x57, 0x9a, 0xba, 0x89, 0xc5, 0x1a, 0x73, 0xfe, 0x5a, 0x91, 0x29, 0x7f, 0x2b, 0xe1,
|
||||
0x67, 0x6b, 0x4c, 0xf8, 0x6d, 0xd0, 0x96, 0xfe, 0xa7, 0xcc, 0x1f, 0x2d, 0x27, 0x05, 0x57, 0x25,
|
||||
0xce, 0x93, 0x49, 0x98, 0x4b, 0xcf, 0x92, 0xa9, 0x26, 0x4c, 0x89, 0xa7, 0xcc, 0x2f, 0xa1, 0xcc,
|
||||
0xd7, 0x43, 0xcc, 0xdc, 0xd9, 0x9c, 0x04, 0xb1, 0x58, 0x17, 0x2a, 0x2e, 0x2d, 0x31, 0x3b, 0x46,
|
||||
0xdf, 0x00, 0x50, 0x5e, 0x1f, 0x61, 0x37, 0x73, 0x2a, 0x96, 0x44, 0xf5, 0xe8, 0x8b, 0x8c, 0x30,
|
||||
0x96, 0x13, 0x70, 0x20, 0xfe, 0x0e, 0x6f, 0xe6, 0x14, 0x17, 0xa9, 0x7c, 0x44, 0xaf, 0xa0, 0x32,
|
||||
0x09, 0xa3, 0x8f, 0x6e, 0x34, 0x26, 0x02, 0x4c, 0xb7, 0x8d, 0x87, 0x19, 0x0f, 0x27, 0x89, 0x5d,
|
||||
0x0c, 0x3f, 0xfd, 0x0c, 0x97, 0x27, 0x99, 0x77, 0x74, 0x06, 0x48, 0x8e, 0x17, 0xab, 0x3c, 0x71,
|
||||
0x52, 0x10, 0x4e, 0xf6, 0xef, 0x3a, 0xe1, 0x9b, 0xb4, 0x74, 0xa4, 0x4d, 0x6e, 0x61, 0xe8, 0xf7,
|
||||
0x50, 0x8e, 0x29, 0x63, 0x3e, 0x4d, 0xdd, 0x14, 0x85, 0x9b, 0xbd, 0xb5, 0x6b, 0x05, 0x37, 0x4b,
|
||||
0x0f, 0xa5, 0x78, 0xf5, 0x8a, 0x8e, 0xa1, 0xe6, 0x7b, 0xc1, 0x75, 0x36, 0x0d, 0x10, 0xe3, 0x1b,
|
||||
0x99, 0xf1, 0x3d, 0x2f, 0xb8, 0xce, 0xe6, 0x50, 0xf1, 0xb3, 0x80, 0xfe, 0x07, 0x28, 0x2e, 0x67,
|
||||
0x09, 0x95, 0x60, 0xe7, 0xc2, 0x3e, 0xb3, 0x9d, 0xb7, 0xb6, 0xf6, 0x19, 0x2a, 0x80, 0x3a, 0x30,
|
||||
0x6d, 0x43, 0x53, 0x38, 0x8c, 0xcd, 0xae, 0x69, 0xbd, 0x31, 0xb5, 0x2d, 0xfe, 0x72, 0xe2, 0xe0,
|
||||
0xb7, 0x1d, 0x6c, 0x68, 0xb9, 0xe3, 0x1d, 0xc8, 0x8b, 0xb8, 0xfa, 0x3f, 0x15, 0x28, 0x88, 0x0e,
|
||||
0x06, 0x93, 0x10, 0xfd, 0x02, 0x96, 0xe2, 0x12, 0x9b, 0x1b, 0x3f, 0x70, 0x85, 0xea, 0x2a, 0x78,
|
||||
0x29, 0x98, 0x61, 0x8a, 0x73, 0xf2, 0x52, 0x1a, 0x4b, 0xf2, 0x56, 0x42, 0x96, 0x86, 0x25, 0xf9,
|
||||
0x59, 0xc6, 0xf3, 0xda, 0x96, 0xa3, 0xe2, 0x9a, 0x34, 0xc8, 0x1d, 0xf6, 0x59, 0xc6, 0xf1, 0xda,
|
||||
0x4e, 0xac, 0xe2, 0x9a, 0x34, 0xa4, 0x5c, 0xfd, 0xb7, 0x50, 0xce, 0xf6, 0x1c, 0x3d, 0x05, 0xd5,
|
||||
0x0b, 0x26, 0x61, 0xba, 0x10, 0xeb, 0xb7, 0xc4, 0xc5, 0x8b, 0xc4, 0x82, 0xa0, 0x23, 0xd0, 0x6e,
|
||||
0xf7, 0x59, 0xaf, 0x40, 0x29, 0xd3, 0x34, 0xfd, 0x5f, 0x0a, 0x54, 0xd6, 0x9a, 0xf0, 0xa3, 0xbd,
|
||||
0xa3, 0x6f, 0xa0, 0xfc, 0xd1, 0x8b, 0x28, 0xc9, 0x1e, 0xff, 0xd5, 0xa3, 0xe6, 0xfa, 0xf1, 0x2f,
|
||||
0xff, 0x77, 0xc3, 0x31, 0xc5, 0x25, 0xce, 0x4f, 0x01, 0xf4, 0x47, 0xa8, 0xa6, 0x23, 0xc9, 0x98,
|
||||
0x32, 0xd7, 0xf3, 0xc5, 0x54, 0x55, 0xd7, 0xe4, 0x91, 0x72, 0x0d, 0x61, 0xc7, 0x95, 0x49, 0xf6,
|
||||
0x15, 0x7d, 0xb5, 0x72, 0x10, 0xb3, 0xc8, 0x0b, 0xae, 0xc4, 0xfc, 0x15, 0x97, 0xb4, 0x81, 0x00,
|
||||
0x9f, 0xfd, 0x4d, 0x85, 0xca, 0x9a, 0x9f, 0x75, 0x21, 0x55, 0xa0, 0x68, 0x3b, 0xc4, 0x30, 0x87,
|
||||
0x1d, 0xab, 0xa7, 0x29, 0x48, 0x83, 0xb2, 0x63, 0x5b, 0x8e, 0x4d, 0x0c, 0xb3, 0xeb, 0x18, 0x5c,
|
||||
0x52, 0x9f, 0xc3, 0x6e, 0xcf, 0xb2, 0xcf, 0x88, 0xed, 0x0c, 0x89, 0xd9, 0xb3, 0xbe, 0xb5, 0x8e,
|
||||
0x7b, 0xa6, 0x96, 0x43, 0x0f, 0x40, 0x73, 0x6c, 0xd2, 0x3d, 0xed, 0x58, 0x36, 0x19, 0x5a, 0xe7,
|
||||
0xa6, 0x73, 0x31, 0xd4, 0x54, 0x8e, 0x9e, 0x0e, 0x7b, 0x5d, 0x62, 0xbe, 0xeb, 0x9a, 0xa6, 0x31,
|
||||
0x20, 0xe7, 0x9d, 0x77, 0x5a, 0x1e, 0x35, 0xe0, 0x81, 0x65, 0x0f, 0x2e, 0x4e, 0x4e, 0xac, 0xae,
|
||||
0x65, 0xda, 0x43, 0x72, 0xdc, 0xe9, 0x75, 0xec, 0xae, 0xa9, 0x6d, 0xa3, 0x3d, 0x40, 0x96, 0xdd,
|
||||
0x75, 0xce, 0xfb, 0x3d, 0x73, 0x68, 0x12, 0x29, 0xdd, 0x1d, 0x54, 0x87, 0x9a, 0xf0, 0xd3, 0x31,
|
||||
0x0c, 0x72, 0xd2, 0xb1, 0x7a, 0xa6, 0xa1, 0x15, 0x78, 0x26, 0x29, 0x63, 0x40, 0x0c, 0x6b, 0xd0,
|
||||
0x39, 0xe6, 0x70, 0x91, 0xc7, 0xb4, 0xec, 0x37, 0x8e, 0xd5, 0x35, 0x49, 0x97, 0xbb, 0xe5, 0x28,
|
||||
0x70, 0xb2, 0x44, 0x2f, 0x6c, 0xc3, 0xc4, 0xfd, 0x8e, 0x65, 0x68, 0x25, 0xb4, 0x0f, 0x0f, 0x25,
|
||||
0x6c, 0xbe, 0xeb, 0x5b, 0xf8, 0x7b, 0x32, 0x74, 0x1c, 0x32, 0x70, 0x1c, 0x5b, 0x2b, 0x67, 0x3d,
|
||||
0xf1, 0x6a, 0x9d, 0xbe, 0x69, 0x6b, 0x15, 0xf4, 0x10, 0xea, 0xe7, 0xfd, 0x3e, 0x91, 0x16, 0x59,
|
||||
0x6c, 0x95, 0xd3, 0x3b, 0x86, 0x81, 0xcd, 0xc1, 0x80, 0x9c, 0x5b, 0x83, 0xf3, 0xce, 0xb0, 0x7b,
|
||||
0xaa, 0xd5, 0x78, 0x49, 0x03, 0x73, 0x48, 0x86, 0xce, 0xb0, 0xd3, 0x5b, 0xe1, 0x1a, 0x4f, 0x68,
|
||||
0x85, 0xf3, 0xa0, 0x3d, 0xe7, 0xad, 0xb6, 0xcb, 0x27, 0x9c, 0xc3, 0xce, 0x9b, 0x34, 0x45, 0xc4,
|
||||
0x6b, 0x4f, 0xdb, 0x23, 0x63, 0x6a, 0x75, 0x0e, 0x5a, 0xf6, 0x9b, 0x4e, 0xcf, 0x32, 0xc8, 0x99,
|
||||
0xf9, 0xbd, 0x58, 0xfa, 0x0f, 0x38, 0x98, 0x64, 0x46, 0xfa, 0xd8, 0xf9, 0x96, 0x27, 0xa2, 0x7d,
|
||||
0x8e, 0x10, 0x54, 0xbb, 0x16, 0xee, 0x5e, 0xf4, 0x3a, 0x98, 0x60, 0xe7, 0x62, 0x68, 0x6a, 0x7b,
|
||||
0x47, 0xff, 0xc9, 0xc3, 0xb6, 0x38, 0xa8, 0x22, 0xf4, 0x8a, 0xeb, 0x7f, 0xf9, 0x2d, 0x84, 0x1e,
|
||||
0x7f, 0xf2, 0x1b, 0xa9, 0x29, 0x2f, 0xb3, 0x29, 0xfc, 0x42, 0x41, 0x7f, 0x82, 0x72, 0xf6, 0xfb,
|
||||
0x02, 0x65, 0xf7, 0xf6, 0x0d, 0x1f, 0x1e, 0x1b, 0x3c, 0x9c, 0x81, 0x66, 0xc6, 0xcc, 0x9b, 0xb9,
|
||||
0x8c, 0xca, 0xef, 0x05, 0xd4, 0xcc, 0x78, 0xb9, 0xf5, 0x11, 0xd2, 0xdc, 0xdf, 0x68, 0x4b, 0x4f,
|
||||
0xe5, 0x5e, 0x52, 0x4e, 0x7a, 0x63, 0xbf, 0x53, 0xce, 0xfa, 0x67, 0x42, 0xf3, 0x8b, 0xfb, 0xcc,
|
||||
0xa9, 0xb7, 0x31, 0xd4, 0x37, 0x5c, 0xc2, 0xd1, 0x57, 0xd9, 0x0c, 0xee, 0xbd, 0xc2, 0x37, 0x9f,
|
||||
0xfc, 0x10, 0x6d, 0x15, 0x65, 0xc3, 0x6d, 0x7d, 0x2d, 0xca, 0xfd, 0x77, 0xfd, 0xb5, 0x28, 0x9f,
|
||||
0xba, 0xf4, 0xbf, 0x07, 0xed, 0xf6, 0xe5, 0x0e, 0xe9, 0xb7, 0xc7, 0xde, 0xbd, 0x65, 0x36, 0x7f,
|
||||
0xf6, 0x49, 0x4e, 0xea, 0xdc, 0x02, 0x58, 0x5d, 0x91, 0xd0, 0xa3, 0xcc, 0x90, 0x3b, 0x57, 0xbc,
|
||||
0xe6, 0xe3, 0x7b, 0xac, 0xa9, 0xab, 0x21, 0xd4, 0x37, 0xdc, 0x99, 0xd6, 0x66, 0xe3, 0xfe, 0x3b,
|
||||
0x55, 0xf3, 0xc1, 0xa6, 0xab, 0xc5, 0x0b, 0xe5, 0xf8, 0xeb, 0x3f, 0x1f, 0x5e, 0x79, 0x6c, 0xba,
|
||||
0xb8, 0x3c, 0x18, 0x85, 0xb3, 0x43, 0xdf, 0xbb, 0x9a, 0xb2, 0xc0, 0x0b, 0xae, 0x02, 0xca, 0x3e,
|
||||
0x86, 0xd1, 0xf5, 0xa1, 0x1f, 0x8c, 0x0f, 0x85, 0x2e, 0x0f, 0x97, 0xc3, 0x2f, 0xb7, 0xc5, 0x6f,
|
||||
0x47, 0xbf, 0xfa, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x74, 0xbe, 0x98, 0x4d, 0x6b, 0x12, 0x00,
|
||||
0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
@ -1866,7 +1740,7 @@ type RouterClient interface {
|
|||
//*
|
||||
//SendPayment attempts to route a payment described by the passed
|
||||
//PaymentRequest to the final destination. The call returns a stream of
|
||||
//payment status updates.
|
||||
//payment updates.
|
||||
SendPayment(ctx context.Context, in *SendPaymentRequest, opts ...grpc.CallOption) (Router_SendPaymentClient, error)
|
||||
//*
|
||||
//TrackPayment returns an update stream for the payment identified by the
|
||||
|
@ -1928,7 +1802,7 @@ func (c *routerClient) SendPayment(ctx context.Context, in *SendPaymentRequest,
|
|||
}
|
||||
|
||||
type Router_SendPaymentClient interface {
|
||||
Recv() (*PaymentStatus, error)
|
||||
Recv() (*lnrpc.Payment, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
|
@ -1936,8 +1810,8 @@ type routerSendPaymentClient struct {
|
|||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *routerSendPaymentClient) Recv() (*PaymentStatus, error) {
|
||||
m := new(PaymentStatus)
|
||||
func (x *routerSendPaymentClient) Recv() (*lnrpc.Payment, error) {
|
||||
m := new(lnrpc.Payment)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1960,7 +1834,7 @@ func (c *routerClient) TrackPayment(ctx context.Context, in *TrackPaymentRequest
|
|||
}
|
||||
|
||||
type Router_TrackPaymentClient interface {
|
||||
Recv() (*PaymentStatus, error)
|
||||
Recv() (*lnrpc.Payment, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
|
@ -1968,8 +1842,8 @@ type routerTrackPaymentClient struct {
|
|||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *routerTrackPaymentClient) Recv() (*PaymentStatus, error) {
|
||||
m := new(PaymentStatus)
|
||||
func (x *routerTrackPaymentClient) Recv() (*lnrpc.Payment, error) {
|
||||
m := new(lnrpc.Payment)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -2067,7 +1941,7 @@ type RouterServer interface {
|
|||
//*
|
||||
//SendPayment attempts to route a payment described by the passed
|
||||
//PaymentRequest to the final destination. The call returns a stream of
|
||||
//payment status updates.
|
||||
//payment updates.
|
||||
SendPayment(*SendPaymentRequest, Router_SendPaymentServer) error
|
||||
//*
|
||||
//TrackPayment returns an update stream for the payment identified by the
|
||||
|
@ -2118,7 +1992,7 @@ func _Router_SendPayment_Handler(srv interface{}, stream grpc.ServerStream) erro
|
|||
}
|
||||
|
||||
type Router_SendPaymentServer interface {
|
||||
Send(*PaymentStatus) error
|
||||
Send(*lnrpc.Payment) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
|
@ -2126,7 +2000,7 @@ type routerSendPaymentServer struct {
|
|||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *routerSendPaymentServer) Send(m *PaymentStatus) error {
|
||||
func (x *routerSendPaymentServer) Send(m *lnrpc.Payment) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
|
@ -2139,7 +2013,7 @@ func _Router_TrackPayment_Handler(srv interface{}, stream grpc.ServerStream) err
|
|||
}
|
||||
|
||||
type Router_TrackPaymentServer interface {
|
||||
Send(*PaymentStatus) error
|
||||
Send(*lnrpc.Payment) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
|
@ -2147,7 +2021,7 @@ type routerTrackPaymentServer struct {
|
|||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *routerTrackPaymentServer) Send(m *PaymentStatus) error {
|
||||
func (x *routerTrackPaymentServer) Send(m *lnrpc.Payment) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
|
|
|
@ -121,62 +121,6 @@ message TrackPaymentRequest {
|
|||
bytes payment_hash = 1;
|
||||
}
|
||||
|
||||
enum PaymentState {
|
||||
/**
|
||||
Payment is still in flight.
|
||||
*/
|
||||
IN_FLIGHT = 0;
|
||||
|
||||
/**
|
||||
Payment completed successfully.
|
||||
*/
|
||||
SUCCEEDED = 1;
|
||||
|
||||
/**
|
||||
There are more routes to try, but the payment timeout was exceeded.
|
||||
*/
|
||||
FAILED_TIMEOUT = 2;
|
||||
|
||||
/**
|
||||
All possible routes were tried and failed permanently. Or were no
|
||||
routes to the destination at all.
|
||||
*/
|
||||
FAILED_NO_ROUTE = 3;
|
||||
|
||||
/**
|
||||
A non-recoverable error has occured.
|
||||
*/
|
||||
FAILED_ERROR = 4;
|
||||
|
||||
/**
|
||||
Payment details incorrect (unknown hash, invalid amt or
|
||||
invalid final cltv delta)
|
||||
*/
|
||||
FAILED_INCORRECT_PAYMENT_DETAILS = 5;
|
||||
|
||||
/**
|
||||
Insufficient local balance.
|
||||
*/
|
||||
FAILED_INSUFFICIENT_BALANCE = 6;
|
||||
}
|
||||
|
||||
message PaymentStatus {
|
||||
/// Current state the payment is in.
|
||||
PaymentState state = 1;
|
||||
|
||||
/**
|
||||
The pre-image of the payment when state is SUCCEEDED.
|
||||
*/
|
||||
bytes preimage = 2;
|
||||
|
||||
reserved 3;
|
||||
|
||||
/**
|
||||
The HTLCs made in attempt to settle the payment.
|
||||
*/
|
||||
repeated lnrpc.HTLCAttempt htlcs = 4;
|
||||
}
|
||||
|
||||
message RouteFeeRequest {
|
||||
/**
|
||||
The destination once wishes to obtain a routing fee quote to.
|
||||
|
@ -465,15 +409,15 @@ service Router {
|
|||
/**
|
||||
SendPayment attempts to route a payment described by the passed
|
||||
PaymentRequest to the final destination. The call returns a stream of
|
||||
payment status updates.
|
||||
payment updates.
|
||||
*/
|
||||
rpc SendPayment (SendPaymentRequest) returns (stream PaymentStatus);
|
||||
rpc SendPayment (SendPaymentRequest) returns (stream lnrpc.Payment);
|
||||
|
||||
/**
|
||||
TrackPayment returns an update stream for the payment identified by the
|
||||
payment hash.
|
||||
*/
|
||||
rpc TrackPayment (TrackPaymentRequest) returns (stream PaymentStatus);
|
||||
rpc TrackPayment (TrackPaymentRequest) returns (stream lnrpc.Payment);
|
||||
|
||||
/**
|
||||
EstimateRouteFee allows callers to obtain a lower bound w.r.t how much it
|
||||
|
|
|
@ -1094,3 +1094,131 @@ func marshallChannelUpdate(update *lnwire.ChannelUpdate) *lnrpc.ChannelUpdate {
|
|||
ExtraOpaqueData: update.ExtraOpaqueData,
|
||||
}
|
||||
}
|
||||
|
||||
// MarshallPayment marshall a payment to its rpc representation.
|
||||
func (r *RouterBackend) MarshallPayment(payment *channeldb.MPPayment) (
|
||||
*lnrpc.Payment, error) {
|
||||
|
||||
// Fetch the payment's route and preimage. If no HTLC was
|
||||
// successful, an empty route and preimage will be used.
|
||||
var (
|
||||
route route.Route
|
||||
preimage lntypes.Preimage
|
||||
)
|
||||
for _, htlc := range payment.HTLCs {
|
||||
// Display the last route attempted.
|
||||
route = htlc.Route
|
||||
|
||||
// If any of the htlcs have settled, extract a valid
|
||||
// preimage.
|
||||
if htlc.Settle != nil {
|
||||
preimage = htlc.Settle.Preimage
|
||||
}
|
||||
}
|
||||
|
||||
// Encode the hops from the successful route, if any.
|
||||
path := make([]string, len(route.Hops))
|
||||
for i, hop := range route.Hops {
|
||||
path[i] = hex.EncodeToString(hop.PubKeyBytes[:])
|
||||
}
|
||||
|
||||
msatValue := int64(payment.Info.Value)
|
||||
satValue := int64(payment.Info.Value.ToSatoshis())
|
||||
|
||||
status, err := convertPaymentStatus(payment.Status)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
htlcs := make([]*lnrpc.HTLCAttempt, 0, len(payment.HTLCs))
|
||||
for _, dbHTLC := range payment.HTLCs {
|
||||
htlc, err := r.MarshalHTLCAttempt(dbHTLC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
htlcs = append(htlcs, htlc)
|
||||
}
|
||||
|
||||
paymentHash := payment.Info.PaymentHash
|
||||
creationTimeNS := MarshalTimeNano(payment.Info.CreationTime)
|
||||
|
||||
failureReason, err := marshallPaymentFailureReason(
|
||||
payment.FailureReason,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &lnrpc.Payment{
|
||||
PaymentHash: hex.EncodeToString(paymentHash[:]),
|
||||
Value: satValue,
|
||||
ValueMsat: msatValue,
|
||||
ValueSat: satValue,
|
||||
CreationDate: payment.Info.CreationTime.Unix(),
|
||||
CreationTimeNs: creationTimeNS,
|
||||
Path: path,
|
||||
Fee: int64(route.TotalFees().ToSatoshis()),
|
||||
FeeSat: int64(route.TotalFees().ToSatoshis()),
|
||||
FeeMsat: int64(route.TotalFees()),
|
||||
PaymentPreimage: hex.EncodeToString(preimage[:]),
|
||||
PaymentRequest: string(payment.Info.PaymentRequest),
|
||||
Status: status,
|
||||
Htlcs: htlcs,
|
||||
PaymentIndex: payment.SequenceNum,
|
||||
FailureReason: failureReason,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// convertPaymentStatus converts a channeldb.PaymentStatus to the type expected
|
||||
// by the RPC.
|
||||
func convertPaymentStatus(dbStatus channeldb.PaymentStatus) (
|
||||
lnrpc.Payment_PaymentStatus, error) {
|
||||
|
||||
switch dbStatus {
|
||||
case channeldb.StatusUnknown:
|
||||
return lnrpc.Payment_UNKNOWN, nil
|
||||
|
||||
case channeldb.StatusInFlight:
|
||||
return lnrpc.Payment_IN_FLIGHT, nil
|
||||
|
||||
case channeldb.StatusSucceeded:
|
||||
return lnrpc.Payment_SUCCEEDED, nil
|
||||
|
||||
case channeldb.StatusFailed:
|
||||
return lnrpc.Payment_FAILED, nil
|
||||
|
||||
default:
|
||||
return 0, fmt.Errorf("unhandled payment status %v", dbStatus)
|
||||
}
|
||||
}
|
||||
|
||||
// marshallPaymentFailureReason marshalls the failure reason to the corresponding rpc
|
||||
// type.
|
||||
func marshallPaymentFailureReason(reason *channeldb.FailureReason) (
|
||||
lnrpc.PaymentFailureReason, error) {
|
||||
|
||||
if reason == nil {
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_NONE, nil
|
||||
}
|
||||
|
||||
switch *reason {
|
||||
|
||||
case channeldb.FailureReasonTimeout:
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_TIMEOUT, nil
|
||||
|
||||
case channeldb.FailureReasonNoRoute:
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_NO_ROUTE, nil
|
||||
|
||||
case channeldb.FailureReasonError:
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_ERROR, nil
|
||||
|
||||
case channeldb.FailureReasonPaymentDetails:
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_INCORRECT_PAYMENT_DETAILS, nil
|
||||
|
||||
case channeldb.FailureReasonInsufficientBalance:
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_INSUFFICIENT_BALANCE, nil
|
||||
}
|
||||
|
||||
return 0, errors.New("unknown failure reason")
|
||||
}
|
||||
|
|
|
@ -441,7 +441,7 @@ func (s *Server) trackPayment(paymentHash lntypes.Hash,
|
|||
router := s.cfg.RouterBackend
|
||||
|
||||
// Subscribe to the outcome of this payment.
|
||||
inFlight, resultChan, err := router.Tower.SubscribePayment(
|
||||
subscription, err := router.Tower.SubscribePayment(
|
||||
paymentHash,
|
||||
)
|
||||
switch {
|
||||
|
@ -450,95 +450,37 @@ func (s *Server) trackPayment(paymentHash lntypes.Hash,
|
|||
case err != nil:
|
||||
return err
|
||||
}
|
||||
defer subscription.Close()
|
||||
|
||||
// If it is in flight, send a state update to the client. Payment status
|
||||
// update streams are expected to always send the current payment state
|
||||
// immediately.
|
||||
if inFlight {
|
||||
err = stream.Send(&PaymentStatus{
|
||||
State: PaymentState_IN_FLIGHT,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the outcome of the payment. For payments that have
|
||||
// completed, the result should already be waiting on the channel.
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
// Marshall result to rpc type.
|
||||
var status PaymentStatus
|
||||
if result.Success {
|
||||
log.Debugf("Payment %v successfully completed",
|
||||
paymentHash)
|
||||
|
||||
status.State = PaymentState_SUCCEEDED
|
||||
status.Preimage = result.Preimage[:]
|
||||
} else {
|
||||
state, err := marshallFailureReason(
|
||||
result.FailureReason,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
// Stream updates back to the client. The first update is always the
|
||||
// current state of the payment.
|
||||
for {
|
||||
select {
|
||||
case item, ok := <-subscription.Updates:
|
||||
if !ok {
|
||||
// No more payment updates.
|
||||
return nil
|
||||
}
|
||||
status.State = state
|
||||
}
|
||||
|
||||
// Marshal our list of HTLCs that have been tried for this
|
||||
// payment.
|
||||
htlcs := make([]*lnrpc.HTLCAttempt, 0, len(result.HTLCs))
|
||||
for _, dbHtlc := range result.HTLCs {
|
||||
htlc, err := router.MarshalHTLCAttempt(dbHtlc)
|
||||
result := item.(*channeldb.MPPayment)
|
||||
rpcPayment, err := router.MarshallPayment(result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
htlcs = append(htlcs, htlc)
|
||||
// Send event to the client.
|
||||
err = stream.Send(rpcPayment)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case <-s.quit:
|
||||
return errServerShuttingDown
|
||||
|
||||
case <-stream.Context().Done():
|
||||
log.Debugf("Payment status stream %v canceled", paymentHash)
|
||||
return stream.Context().Err()
|
||||
}
|
||||
status.Htlcs = htlcs
|
||||
|
||||
// Send event to the client.
|
||||
err = stream.Send(&status)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case <-s.quit:
|
||||
return errServerShuttingDown
|
||||
|
||||
case <-stream.Context().Done():
|
||||
log.Debugf("Payment status stream %v canceled", paymentHash)
|
||||
return stream.Context().Err()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// marshallFailureReason marshalls the failure reason to the corresponding rpc
|
||||
// type.
|
||||
func marshallFailureReason(reason channeldb.FailureReason) (
|
||||
PaymentState, error) {
|
||||
|
||||
switch reason {
|
||||
|
||||
case channeldb.FailureReasonTimeout:
|
||||
return PaymentState_FAILED_TIMEOUT, nil
|
||||
|
||||
case channeldb.FailureReasonNoRoute:
|
||||
return PaymentState_FAILED_NO_ROUTE, nil
|
||||
|
||||
case channeldb.FailureReasonError:
|
||||
return PaymentState_FAILED_ERROR, nil
|
||||
|
||||
case channeldb.FailureReasonPaymentDetails:
|
||||
return PaymentState_FAILED_INCORRECT_PAYMENT_DETAILS, nil
|
||||
|
||||
case channeldb.FailureReasonInsufficientBalance:
|
||||
return PaymentState_FAILED_INSUFFICIENT_BALANCE, nil
|
||||
}
|
||||
|
||||
return 0, errors.New("unknown failure reason")
|
||||
}
|
||||
|
||||
// BuildRoute builds a route from a list of hop addresses.
|
||||
|
|
1572
lnrpc/rpc.pb.go
1572
lnrpc/rpc.pb.go
File diff suppressed because it is too large
Load diff
|
@ -3053,6 +3053,40 @@ message InvoiceSubscription {
|
|||
uint64 settle_index = 2;
|
||||
}
|
||||
|
||||
enum PaymentFailureReason {
|
||||
/**
|
||||
Payment isn't failed (yet).
|
||||
*/
|
||||
FAILURE_REASON_NONE = 0;
|
||||
|
||||
/**
|
||||
There are more routes to try, but the payment timeout was exceeded.
|
||||
*/
|
||||
FAILURE_REASON_TIMEOUT = 1;
|
||||
|
||||
/**
|
||||
All possible routes were tried and failed permanently. Or were no
|
||||
routes to the destination at all.
|
||||
*/
|
||||
FAILURE_REASON_NO_ROUTE = 2;
|
||||
|
||||
/**
|
||||
A non-recoverable error has occured.
|
||||
*/
|
||||
FAILURE_REASON_ERROR = 3;
|
||||
|
||||
/**
|
||||
Payment details incorrect (unknown hash, invalid amt or
|
||||
invalid final cltv delta)
|
||||
*/
|
||||
FAILURE_REASON_INCORRECT_PAYMENT_DETAILS = 4;
|
||||
|
||||
/**
|
||||
Insufficient local balance.
|
||||
*/
|
||||
FAILURE_REASON_INSUFFICIENT_BALANCE = 5;
|
||||
}
|
||||
|
||||
message Payment {
|
||||
/// The payment hash
|
||||
string payment_hash = 1;
|
||||
|
@ -3109,6 +3143,8 @@ message Payment {
|
|||
older versions of lnd.
|
||||
*/
|
||||
uint64 payment_index = 15;
|
||||
|
||||
PaymentFailureReason failure_reason = 16;
|
||||
}
|
||||
|
||||
message HTLCAttempt {
|
||||
|
|
|
@ -3996,9 +3996,25 @@
|
|||
"type": "string",
|
||||
"format": "uint64",
|
||||
"description": "*\nThe creation index of this payment. Each payment can be uniquely identified\nby this index, which may not strictly increment by 1 for payments made in\nolder versions of lnd."
|
||||
},
|
||||
"failure_reason": {
|
||||
"$ref": "#/definitions/lnrpcPaymentFailureReason"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lnrpcPaymentFailureReason": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"FAILURE_REASON_NONE",
|
||||
"FAILURE_REASON_TIMEOUT",
|
||||
"FAILURE_REASON_NO_ROUTE",
|
||||
"FAILURE_REASON_ERROR",
|
||||
"FAILURE_REASON_INCORRECT_PAYMENT_DETAILS",
|
||||
"FAILURE_REASON_INSUFFICIENT_BALANCE"
|
||||
],
|
||||
"default": "FAILURE_REASON_NONE",
|
||||
"description": " - FAILURE_REASON_NONE: *\nPayment isn't failed (yet).\n - FAILURE_REASON_TIMEOUT: *\nThere are more routes to try, but the payment timeout was exceeded.\n - FAILURE_REASON_NO_ROUTE: *\nAll possible routes were tried and failed permanently. Or were no\nroutes to the destination at all.\n - FAILURE_REASON_ERROR: *\nA non-recoverable error has occured.\n - FAILURE_REASON_INCORRECT_PAYMENT_DETAILS: *\nPayment details incorrect (unknown hash, invalid amt or\ninvalid final cltv delta)\n - FAILURE_REASON_INSUFFICIENT_BALANCE: *\nInsufficient local balance."
|
||||
},
|
||||
"lnrpcPeer": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -14271,13 +14271,13 @@ func testHoldInvoicePersistence(net *lntest.NetworkHarness, t *harnessTest) {
|
|||
|
||||
// Wait for inlight status update.
|
||||
for _, payStream := range paymentStreams {
|
||||
status, err := payStream.Recv()
|
||||
payment, err := payStream.Recv()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed receiving status update: %v", err)
|
||||
}
|
||||
|
||||
if status.State != routerrpc.PaymentState_IN_FLIGHT {
|
||||
t.Fatalf("state not in flight: %v", status.State)
|
||||
if payment.Status != lnrpc.Payment_IN_FLIGHT {
|
||||
t.Fatalf("state not in flight: %v", payment.Status)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14355,7 +14355,7 @@ func testHoldInvoicePersistence(net *lntest.NetworkHarness, t *harnessTest) {
|
|||
// Now after a restart, we must re-track the payments. We set up a
|
||||
// goroutine for each to track thir status updates.
|
||||
var (
|
||||
statusUpdates []chan *routerrpc.PaymentStatus
|
||||
statusUpdates []chan *lnrpc.Payment
|
||||
wg sync.WaitGroup
|
||||
quit = make(chan struct{})
|
||||
)
|
||||
|
@ -14377,20 +14377,20 @@ func testHoldInvoicePersistence(net *lntest.NetworkHarness, t *harnessTest) {
|
|||
}
|
||||
|
||||
// We set up a channel where we'll forward any status update.
|
||||
upd := make(chan *routerrpc.PaymentStatus)
|
||||
upd := make(chan *lnrpc.Payment)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
for {
|
||||
status, err := payStream.Recv()
|
||||
payment, err := payStream.Recv()
|
||||
if err != nil {
|
||||
close(upd)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case upd <- status:
|
||||
case upd <- payment:
|
||||
case <-quit:
|
||||
return
|
||||
}
|
||||
|
@ -14400,17 +14400,17 @@ func testHoldInvoicePersistence(net *lntest.NetworkHarness, t *harnessTest) {
|
|||
statusUpdates = append(statusUpdates, upd)
|
||||
}
|
||||
|
||||
// Wait for the infligt status update.
|
||||
// Wait for the in-flight status update.
|
||||
for _, upd := range statusUpdates {
|
||||
select {
|
||||
case status, ok := <-upd:
|
||||
case payment, ok := <-upd:
|
||||
if !ok {
|
||||
t.Fatalf("failed getting status update")
|
||||
t.Fatalf("failed getting payment update")
|
||||
}
|
||||
|
||||
if status.State != routerrpc.PaymentState_IN_FLIGHT {
|
||||
if payment.Status != lnrpc.Payment_IN_FLIGHT {
|
||||
t.Fatalf("state not in in flight: %v",
|
||||
status.State)
|
||||
payment.Status)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("in flight status not recevied")
|
||||
|
@ -14439,25 +14439,38 @@ func testHoldInvoicePersistence(net *lntest.NetworkHarness, t *harnessTest) {
|
|||
|
||||
// Make sure we get the expected status update.
|
||||
for i, upd := range statusUpdates {
|
||||
select {
|
||||
case status, ok := <-upd:
|
||||
if !ok {
|
||||
t.Fatalf("failed getting status update")
|
||||
}
|
||||
// Read until the payment is in a terminal state.
|
||||
var payment *lnrpc.Payment
|
||||
for payment == nil {
|
||||
select {
|
||||
case p, ok := <-upd:
|
||||
if !ok {
|
||||
t.Fatalf("failed getting payment update")
|
||||
}
|
||||
|
||||
if i%2 == 0 {
|
||||
if status.State != routerrpc.PaymentState_SUCCEEDED {
|
||||
t.Fatalf("state not suceeded : %v",
|
||||
status.State)
|
||||
}
|
||||
} else {
|
||||
if status.State != routerrpc.PaymentState_FAILED_INCORRECT_PAYMENT_DETAILS {
|
||||
t.Fatalf("state not failed: %v",
|
||||
status.State)
|
||||
if p.Status == lnrpc.Payment_IN_FLIGHT {
|
||||
continue
|
||||
}
|
||||
|
||||
payment = p
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("in flight status not recevied")
|
||||
}
|
||||
}
|
||||
|
||||
// Assert terminal payment state.
|
||||
if i%2 == 0 {
|
||||
if payment.Status != lnrpc.Payment_SUCCEEDED {
|
||||
t.Fatalf("state not suceeded : %v",
|
||||
payment.Status)
|
||||
}
|
||||
} else {
|
||||
if payment.FailureReason !=
|
||||
lnrpc.PaymentFailureReason_FAILURE_REASON_INCORRECT_PAYMENT_DETAILS {
|
||||
|
||||
t.Fatalf("state not failed: %v",
|
||||
payment.FailureReason)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("in flight status not recevied")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
90
multimutex/hash_mutex.go
Normal file
90
multimutex/hash_mutex.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
package multimutex
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
)
|
||||
|
||||
// HashMutex is a struct that keeps track of a set of mutexes with a given hash.
|
||||
// It can be used for making sure only one goroutine gets given the mutex per
|
||||
// hash.
|
||||
type HashMutex struct {
|
||||
// mutexes is a map of hashes to a cntMutex. The cntMutex for
|
||||
// a given hash will hold the mutex to be used by all
|
||||
// callers requesting access for the hash, in addition to
|
||||
// the count of callers.
|
||||
mutexes map[lntypes.Hash]*cntMutex
|
||||
|
||||
// mapMtx is used to give synchronize concurrent access
|
||||
// to the mutexes map.
|
||||
mapMtx sync.Mutex
|
||||
}
|
||||
|
||||
// NewHashMutex creates a new Mutex.
|
||||
func NewHashMutex() *HashMutex {
|
||||
return &HashMutex{
|
||||
mutexes: make(map[lntypes.Hash]*cntMutex),
|
||||
}
|
||||
}
|
||||
|
||||
// Lock locks the mutex by the given hash. If the mutex is already
|
||||
// locked by this hash, Lock blocks until the mutex is available.
|
||||
func (c *HashMutex) Lock(hash lntypes.Hash) {
|
||||
c.mapMtx.Lock()
|
||||
mtx, ok := c.mutexes[hash]
|
||||
if ok {
|
||||
// If the mutex already existed in the map, we
|
||||
// increment its counter, to indicate that there
|
||||
// now is one more goroutine waiting for it.
|
||||
mtx.cnt++
|
||||
} else {
|
||||
// If it was not in the map, it means no other
|
||||
// goroutine has locked the mutex for this hash,
|
||||
// and we can create a new mutex with count 1
|
||||
// and add it to the map.
|
||||
mtx = &cntMutex{
|
||||
cnt: 1,
|
||||
}
|
||||
c.mutexes[hash] = mtx
|
||||
}
|
||||
c.mapMtx.Unlock()
|
||||
|
||||
// Acquire the mutex for this hash.
|
||||
mtx.Lock()
|
||||
}
|
||||
|
||||
// Unlock unlocks the mutex by the given hash. It is a run-time
|
||||
// error if the mutex is not locked by the hash on entry to Unlock.
|
||||
func (c *HashMutex) Unlock(hash lntypes.Hash) {
|
||||
// Since we are done with all the work for this
|
||||
// update, we update the map to reflect that.
|
||||
c.mapMtx.Lock()
|
||||
|
||||
mtx, ok := c.mutexes[hash]
|
||||
if !ok {
|
||||
// The mutex not existing in the map means
|
||||
// an unlock for an hash not currently locked
|
||||
// was attempted.
|
||||
panic(fmt.Sprintf("double unlock for hash %v",
|
||||
hash))
|
||||
}
|
||||
|
||||
// Decrement the counter. If the count goes to
|
||||
// zero, it means this caller was the last one
|
||||
// to wait for the mutex, and we can delete it
|
||||
// from the map. We can do this safely since we
|
||||
// are under the mapMtx, meaning that all other
|
||||
// goroutines waiting for the mutex already
|
||||
// have incremented it, or will create a new
|
||||
// mutex when they get the mapMtx.
|
||||
mtx.cnt--
|
||||
if mtx.cnt == 0 {
|
||||
delete(c.mutexes, hash)
|
||||
}
|
||||
c.mapMtx.Unlock()
|
||||
|
||||
// Unlock the mutex for this hash.
|
||||
mtx.Unlock()
|
||||
}
|
|
@ -58,6 +58,7 @@ func (cq *ConcurrentQueue) start() {
|
|||
go func() {
|
||||
defer cq.wg.Done()
|
||||
|
||||
readLoop:
|
||||
for {
|
||||
nextElement := cq.overflow.Front()
|
||||
if nextElement == nil {
|
||||
|
@ -65,7 +66,10 @@ func (cq *ConcurrentQueue) start() {
|
|||
// directly to the output channel. If output channel is full
|
||||
// though, push to overflow.
|
||||
select {
|
||||
case item := <-cq.chanIn:
|
||||
case item, ok := <-cq.chanIn:
|
||||
if !ok {
|
||||
break readLoop
|
||||
}
|
||||
select {
|
||||
case cq.chanOut <- item:
|
||||
// Optimistically push directly to chanOut
|
||||
|
@ -79,7 +83,10 @@ func (cq *ConcurrentQueue) start() {
|
|||
// Overflow queue is not empty, so any new items get pushed to
|
||||
// the back to preserve order.
|
||||
select {
|
||||
case item := <-cq.chanIn:
|
||||
case item, ok := <-cq.chanIn:
|
||||
if !ok {
|
||||
break readLoop
|
||||
}
|
||||
cq.overflow.PushBack(item)
|
||||
case cq.chanOut <- nextElement.Value:
|
||||
cq.overflow.Remove(nextElement)
|
||||
|
@ -88,6 +95,22 @@ func (cq *ConcurrentQueue) start() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Incoming channel has been closed. Empty overflow queue into
|
||||
// the outgoing channel.
|
||||
nextElement := cq.overflow.Front()
|
||||
for nextElement != nil {
|
||||
select {
|
||||
case cq.chanOut <- nextElement.Value:
|
||||
cq.overflow.Remove(nextElement)
|
||||
case <-cq.quit:
|
||||
return
|
||||
}
|
||||
nextElement = cq.overflow.Front()
|
||||
}
|
||||
|
||||
// Close outgoing channel.
|
||||
close(cq.chanOut)
|
||||
}()
|
||||
}
|
||||
|
||||
|
|
|
@ -63,3 +63,25 @@ func TestConcurrentQueueIdempotentStop(t *testing.T) {
|
|||
|
||||
testQueueAddDrain(t, 100, 1, 10, 1000, 1000)
|
||||
}
|
||||
|
||||
// TestQueueCloseIncoming tests that the queue properly handles an incoming
|
||||
// channel that is closed.
|
||||
func TestQueueCloseIncoming(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
queue := queue.NewConcurrentQueue(10)
|
||||
queue.Start()
|
||||
|
||||
queue.ChanIn() <- 1
|
||||
close(queue.ChanIn())
|
||||
|
||||
item := <-queue.ChanOut()
|
||||
if item.(int) != 1 {
|
||||
t.Fatalf("unexpected item")
|
||||
}
|
||||
|
||||
_, ok := <-queue.ChanOut()
|
||||
if ok {
|
||||
t.Fatalf("expected outgoing channel being closed")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package routing
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/multimutex"
|
||||
"github.com/lightningnetwork/lnd/queue"
|
||||
)
|
||||
|
||||
// ControlTower tracks all outgoing payments made, whose primary purpose is to
|
||||
|
@ -50,29 +51,43 @@ type ControlTower interface {
|
|||
FetchInFlightPayments() ([]*channeldb.InFlightPayment, error)
|
||||
|
||||
// SubscribePayment subscribes to updates for the payment with the given
|
||||
// hash. It returns a boolean indicating whether the payment is still in
|
||||
// flight and a channel that provides the final outcome of the payment.
|
||||
SubscribePayment(paymentHash lntypes.Hash) (bool, chan PaymentResult,
|
||||
// hash. A first update with the current state of the payment is always
|
||||
// sent out immediately.
|
||||
SubscribePayment(paymentHash lntypes.Hash) (*ControlTowerSubscriber,
|
||||
error)
|
||||
}
|
||||
|
||||
// PaymentResult is the struct describing the events received by payment
|
||||
// subscribers.
|
||||
type PaymentResult struct {
|
||||
// Success indicates whether the payment was successful.
|
||||
Success bool
|
||||
// ControlTowerSubscriber contains the state for a payment update subscriber.
|
||||
type ControlTowerSubscriber struct {
|
||||
// Updates is the channel over which *channeldb.MPPayment updates can be
|
||||
// received.
|
||||
Updates <-chan interface{}
|
||||
|
||||
// Preimage is the preimage of a successful payment. This serves as a
|
||||
// proof of payment. It is only set for successful payments.
|
||||
Preimage lntypes.Preimage
|
||||
queue *queue.ConcurrentQueue
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
// FailureReason is a failure reason code indicating the reason the
|
||||
// payment failed. It is only set for failed payments.
|
||||
FailureReason channeldb.FailureReason
|
||||
// newControlTowerSubscriber instantiates a new subscriber state object.
|
||||
func newControlTowerSubscriber() *ControlTowerSubscriber {
|
||||
// Create a queue for payment updates.
|
||||
queue := queue.NewConcurrentQueue(20)
|
||||
queue.Start()
|
||||
|
||||
// HTLCs is a list of HTLCs that have been attempted in order to settle
|
||||
// the payment.
|
||||
HTLCs []channeldb.HTLCAttempt
|
||||
return &ControlTowerSubscriber{
|
||||
Updates: queue.ChanOut(),
|
||||
queue: queue,
|
||||
quit: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Close signals that the subscriber is no longer interested in updates.
|
||||
func (s *ControlTowerSubscriber) Close() {
|
||||
// Close quit channel so that any pending writes to the queue are
|
||||
// cancelled.
|
||||
close(s.quit)
|
||||
|
||||
// Stop the queue goroutine so that it won't leak.
|
||||
s.queue.Stop()
|
||||
}
|
||||
|
||||
// controlTower is persistent implementation of ControlTower to restrict
|
||||
|
@ -80,15 +95,21 @@ type PaymentResult struct {
|
|||
type controlTower struct {
|
||||
db *channeldb.PaymentControl
|
||||
|
||||
subscribers map[lntypes.Hash][]chan PaymentResult
|
||||
subscribers map[lntypes.Hash][]*ControlTowerSubscriber
|
||||
subscribersMtx sync.Mutex
|
||||
|
||||
// paymentsMtx provides synchronization on the payment level to ensure
|
||||
// that no race conditions occur in between updating the database and
|
||||
// sending a notification.
|
||||
paymentsMtx *multimutex.HashMutex
|
||||
}
|
||||
|
||||
// NewControlTower creates a new instance of the controlTower.
|
||||
func NewControlTower(db *channeldb.PaymentControl) ControlTower {
|
||||
return &controlTower{
|
||||
db: db,
|
||||
subscribers: make(map[lntypes.Hash][]chan PaymentResult),
|
||||
subscribers: make(map[lntypes.Hash][]*ControlTowerSubscriber),
|
||||
paymentsMtx: multimutex.NewHashMutex(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +128,18 @@ func (p *controlTower) InitPayment(paymentHash lntypes.Hash,
|
|||
func (p *controlTower) RegisterAttempt(paymentHash lntypes.Hash,
|
||||
attempt *channeldb.HTLCAttemptInfo) error {
|
||||
|
||||
return p.db.RegisterAttempt(paymentHash, attempt)
|
||||
p.paymentsMtx.Lock(paymentHash)
|
||||
defer p.paymentsMtx.Unlock(paymentHash)
|
||||
|
||||
payment, err := p.db.RegisterAttempt(paymentHash, attempt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Notify subscribers of the attempt registration.
|
||||
p.notifySubscribers(paymentHash, payment)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SettleAttempt marks the given attempt settled with the preimage. If
|
||||
|
@ -116,15 +148,16 @@ func (p *controlTower) RegisterAttempt(paymentHash lntypes.Hash,
|
|||
func (p *controlTower) SettleAttempt(paymentHash lntypes.Hash,
|
||||
attemptID uint64, settleInfo *channeldb.HTLCSettleInfo) error {
|
||||
|
||||
p.paymentsMtx.Lock(paymentHash)
|
||||
defer p.paymentsMtx.Unlock(paymentHash)
|
||||
|
||||
payment, err := p.db.SettleAttempt(paymentHash, attemptID, settleInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Notify subscribers of success event.
|
||||
p.notifyFinalEvent(
|
||||
paymentHash, createSuccessResult(payment.HTLCs),
|
||||
)
|
||||
p.notifySubscribers(paymentHash, payment)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -133,7 +166,18 @@ func (p *controlTower) SettleAttempt(paymentHash lntypes.Hash,
|
|||
func (p *controlTower) FailAttempt(paymentHash lntypes.Hash,
|
||||
attemptID uint64, failInfo *channeldb.HTLCFailInfo) error {
|
||||
|
||||
return p.db.FailAttempt(paymentHash, attemptID, failInfo)
|
||||
p.paymentsMtx.Lock(paymentHash)
|
||||
defer p.paymentsMtx.Unlock(paymentHash)
|
||||
|
||||
payment, err := p.db.FailAttempt(paymentHash, attemptID, failInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Notify subscribers of failed attempt.
|
||||
p.notifySubscribers(paymentHash, payment)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FetchPayment fetches the payment corresponding to the given payment hash.
|
||||
|
@ -143,35 +187,6 @@ func (p *controlTower) FetchPayment(paymentHash lntypes.Hash) (
|
|||
return p.db.FetchPayment(paymentHash)
|
||||
}
|
||||
|
||||
// createSuccessResult creates a success result to send to subscribers.
|
||||
func createSuccessResult(htlcs []channeldb.HTLCAttempt) *PaymentResult {
|
||||
// Extract any preimage from the list of HTLCs.
|
||||
var preimage lntypes.Preimage
|
||||
for _, htlc := range htlcs {
|
||||
if htlc.Settle != nil {
|
||||
preimage = htlc.Settle.Preimage
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return &PaymentResult{
|
||||
Success: true,
|
||||
Preimage: preimage,
|
||||
HTLCs: htlcs,
|
||||
}
|
||||
}
|
||||
|
||||
// createFailResult creates a failed result to send to subscribers.
|
||||
func createFailedResult(htlcs []channeldb.HTLCAttempt,
|
||||
reason channeldb.FailureReason) *PaymentResult {
|
||||
|
||||
return &PaymentResult{
|
||||
Success: false,
|
||||
FailureReason: reason,
|
||||
HTLCs: htlcs,
|
||||
}
|
||||
}
|
||||
|
||||
// Fail transitions a payment into the Failed state, and records the reason the
|
||||
// payment failed. After invoking this method, InitPayment should return nil on
|
||||
// its next call for this payment hash, allowing the switch to make a
|
||||
|
@ -179,17 +194,16 @@ func createFailedResult(htlcs []channeldb.HTLCAttempt,
|
|||
func (p *controlTower) Fail(paymentHash lntypes.Hash,
|
||||
reason channeldb.FailureReason) error {
|
||||
|
||||
p.paymentsMtx.Lock(paymentHash)
|
||||
defer p.paymentsMtx.Unlock(paymentHash)
|
||||
|
||||
payment, err := p.db.Fail(paymentHash, reason)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Notify subscribers of fail event.
|
||||
p.notifyFinalEvent(
|
||||
paymentHash, createFailedResult(
|
||||
payment.HTLCs, reason,
|
||||
),
|
||||
)
|
||||
p.notifySubscribers(paymentHash, payment)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -199,86 +213,81 @@ func (p *controlTower) FetchInFlightPayments() ([]*channeldb.InFlightPayment, er
|
|||
return p.db.FetchInFlightPayments()
|
||||
}
|
||||
|
||||
// SubscribePayment subscribes to updates for the payment with the given hash.
|
||||
// It returns a boolean indicating whether the payment is still in flight and a
|
||||
// channel that provides the final outcome of the payment.
|
||||
// SubscribePayment subscribes to updates for the payment with the given hash. A
|
||||
// first update with the current state of the payment is always sent out
|
||||
// immediately.
|
||||
func (p *controlTower) SubscribePayment(paymentHash lntypes.Hash) (
|
||||
bool, chan PaymentResult, error) {
|
||||
*ControlTowerSubscriber, error) {
|
||||
|
||||
// Create a channel with buffer size 1. For every payment there will be
|
||||
// exactly one event sent.
|
||||
c := make(chan PaymentResult, 1)
|
||||
|
||||
// Take lock before querying the db to prevent this scenario:
|
||||
// FetchPayment returns us an in-flight state -> payment succeeds, but
|
||||
// there is no subscriber to notify yet -> we add ourselves as a
|
||||
// subscriber -> ... we will never receive a notification.
|
||||
p.subscribersMtx.Lock()
|
||||
defer p.subscribersMtx.Unlock()
|
||||
// Take lock before querying the db to prevent missing or duplicating an
|
||||
// update.
|
||||
p.paymentsMtx.Lock(paymentHash)
|
||||
defer p.paymentsMtx.Unlock(paymentHash)
|
||||
|
||||
payment, err := p.db.FetchPayment(paymentHash)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var event PaymentResult
|
||||
subscriber := newControlTowerSubscriber()
|
||||
|
||||
switch payment.Status {
|
||||
// Always write current payment state to the channel.
|
||||
subscriber.queue.ChanIn() <- payment
|
||||
|
||||
// Payment is currently in flight. Register this subscriber and
|
||||
// return without writing a result to the channel yet.
|
||||
case channeldb.StatusInFlight:
|
||||
// Payment is currently in flight. Register this subscriber for further
|
||||
// updates. Otherwise this update is the final update and the incoming
|
||||
// channel can be closed. This will close the queue's outgoing channel
|
||||
// when all updates have been written.
|
||||
if payment.Status == channeldb.StatusInFlight {
|
||||
p.subscribersMtx.Lock()
|
||||
p.subscribers[paymentHash] = append(
|
||||
p.subscribers[paymentHash], c,
|
||||
p.subscribers[paymentHash], subscriber,
|
||||
)
|
||||
|
||||
return true, c, nil
|
||||
|
||||
// Payment already succeeded. It is not necessary to register as
|
||||
// a subscriber, because we can send the result on the channel
|
||||
// immediately.
|
||||
case channeldb.StatusSucceeded:
|
||||
event = *createSuccessResult(payment.HTLCs)
|
||||
|
||||
// Payment already failed. It is not necessary to register as a
|
||||
// subscriber, because we can send the result on the channel
|
||||
// immediately.
|
||||
case channeldb.StatusFailed:
|
||||
event = *createFailedResult(
|
||||
payment.HTLCs, *payment.FailureReason,
|
||||
)
|
||||
|
||||
default:
|
||||
return false, nil, errors.New("unknown payment status")
|
||||
p.subscribersMtx.Unlock()
|
||||
} else {
|
||||
close(subscriber.queue.ChanIn())
|
||||
}
|
||||
|
||||
// Write immediate result to the channel.
|
||||
c <- event
|
||||
close(c)
|
||||
|
||||
return false, c, nil
|
||||
return subscriber, nil
|
||||
}
|
||||
|
||||
// notifyFinalEvent sends a final payment event to all subscribers of this
|
||||
// payment. The channel will be closed after this.
|
||||
func (p *controlTower) notifyFinalEvent(paymentHash lntypes.Hash,
|
||||
event *PaymentResult) {
|
||||
// notifySubscribers sends a final payment event to all subscribers of this
|
||||
// payment. The channel will be closed after this. Note that this function must
|
||||
// be executed atomically (by means of a lock) with the database update to
|
||||
// guarantuee consistency of the notifications.
|
||||
func (p *controlTower) notifySubscribers(paymentHash lntypes.Hash,
|
||||
event *channeldb.MPPayment) {
|
||||
|
||||
// Get all subscribers for this hash. As there is only a single outcome,
|
||||
// the subscriber list can be cleared.
|
||||
// Get all subscribers for this payment.
|
||||
p.subscribersMtx.Lock()
|
||||
list, ok := p.subscribers[paymentHash]
|
||||
if !ok {
|
||||
p.subscribersMtx.Unlock()
|
||||
return
|
||||
}
|
||||
delete(p.subscribers, paymentHash)
|
||||
|
||||
// If the payment reached a terminal state, the subscriber list can be
|
||||
// cleared. There won't be any more updates.
|
||||
terminal := event.Status != channeldb.StatusInFlight
|
||||
if terminal {
|
||||
delete(p.subscribers, paymentHash)
|
||||
}
|
||||
p.subscribersMtx.Unlock()
|
||||
|
||||
// Notify all subscribers of the event. The subscriber channel is
|
||||
// buffered, so it cannot block here.
|
||||
// Notify all subscribers of the event.
|
||||
for _, subscriber := range list {
|
||||
subscriber <- *event
|
||||
close(subscriber)
|
||||
select {
|
||||
case subscriber.queue.ChanIn() <- event:
|
||||
// If this event is the last, close the incoming channel
|
||||
// of the queue. This will signal the subscriber that
|
||||
// there won't be any more updates.
|
||||
if terminal {
|
||||
close(subscriber.queue.ChanIn())
|
||||
}
|
||||
|
||||
// If subscriber disappeared, skip notification. For further
|
||||
// notifications, we'll keep skipping over this subscriber.
|
||||
case <-subscriber.quit:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ func TestControlTowerSubscribeUnknown(t *testing.T) {
|
|||
pControl := NewControlTower(channeldb.NewPaymentControl(db))
|
||||
|
||||
// Subscription should fail when the payment is not known.
|
||||
_, _, err = pControl.SubscribePayment(lntypes.Hash{1})
|
||||
_, err = pControl.SubscribePayment(lntypes.Hash{1})
|
||||
if err != channeldb.ErrPaymentNotInitiated {
|
||||
t.Fatal("expected subscribe to fail for unknown payment")
|
||||
}
|
||||
|
@ -86,13 +86,10 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
|||
|
||||
// Subscription should succeed and immediately report the InFlight
|
||||
// status.
|
||||
inFlight, subscriber1, err := pControl.SubscribePayment(info.PaymentHash)
|
||||
subscriber1, err := pControl.SubscribePayment(info.PaymentHash)
|
||||
if err != nil {
|
||||
t.Fatalf("expected subscribe to succeed, but got: %v", err)
|
||||
}
|
||||
if !inFlight {
|
||||
t.Fatalf("unexpected payment to be in flight")
|
||||
}
|
||||
|
||||
// Register an attempt.
|
||||
err = pControl.RegisterAttempt(info.PaymentHash, attempt)
|
||||
|
@ -101,13 +98,10 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
|||
}
|
||||
|
||||
// Register a second subscriber after the first attempt has started.
|
||||
inFlight, subscriber2, err := pControl.SubscribePayment(info.PaymentHash)
|
||||
subscriber2, err := pControl.SubscribePayment(info.PaymentHash)
|
||||
if err != nil {
|
||||
t.Fatalf("expected subscribe to succeed, but got: %v", err)
|
||||
}
|
||||
if !inFlight {
|
||||
t.Fatalf("unexpected payment to be in flight")
|
||||
}
|
||||
|
||||
// Mark the payment as successful.
|
||||
err = pControl.SettleAttempt(
|
||||
|
@ -121,32 +115,33 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
|||
}
|
||||
|
||||
// Register a third subscriber after the payment succeeded.
|
||||
inFlight, subscriber3, err := pControl.SubscribePayment(info.PaymentHash)
|
||||
subscriber3, err := pControl.SubscribePayment(info.PaymentHash)
|
||||
if err != nil {
|
||||
t.Fatalf("expected subscribe to succeed, but got: %v", err)
|
||||
}
|
||||
if inFlight {
|
||||
t.Fatalf("expected payment to be finished")
|
||||
}
|
||||
|
||||
// We expect all subscribers to now report the final outcome followed by
|
||||
// no other events.
|
||||
subscribers := []chan PaymentResult{
|
||||
subscribers := []*ControlTowerSubscriber{
|
||||
subscriber1, subscriber2, subscriber3,
|
||||
}
|
||||
|
||||
for _, s := range subscribers {
|
||||
var result PaymentResult
|
||||
select {
|
||||
case result = <-s:
|
||||
case <-time.After(testTimeout):
|
||||
t.Fatal("timeout waiting for payment result")
|
||||
var result *channeldb.MPPayment
|
||||
for result == nil || result.Status == channeldb.StatusInFlight {
|
||||
select {
|
||||
case item := <-s.Updates:
|
||||
result = item.(*channeldb.MPPayment)
|
||||
case <-time.After(testTimeout):
|
||||
t.Fatal("timeout waiting for payment result")
|
||||
}
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
if result.Status != channeldb.StatusSucceeded {
|
||||
t.Fatal("unexpected payment state")
|
||||
}
|
||||
if result.Preimage != preimg {
|
||||
settle, _ := result.TerminalInfo()
|
||||
if settle.Preimage != preimg {
|
||||
t.Fatal("unexpected preimage")
|
||||
}
|
||||
if len(result.HTLCs) != 1 {
|
||||
|
@ -161,7 +156,7 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
|||
|
||||
// After the final event, we expect the channel to be closed.
|
||||
select {
|
||||
case _, ok := <-s:
|
||||
case _, ok := <-s.Updates:
|
||||
if ok {
|
||||
t.Fatal("expected channel to be closed")
|
||||
}
|
||||
|
@ -204,7 +199,7 @@ func testPaymentControlSubscribeFail(t *testing.T, registerAttempt bool) {
|
|||
}
|
||||
|
||||
// Subscription should succeed.
|
||||
_, subscriber1, err := pControl.SubscribePayment(info.PaymentHash)
|
||||
subscriber1, err := pControl.SubscribePayment(info.PaymentHash)
|
||||
if err != nil {
|
||||
t.Fatalf("expected subscribe to succeed, but got: %v", err)
|
||||
}
|
||||
|
@ -235,29 +230,29 @@ func testPaymentControlSubscribeFail(t *testing.T, registerAttempt bool) {
|
|||
}
|
||||
|
||||
// Register a second subscriber after the payment failed.
|
||||
inFlight, subscriber2, err := pControl.SubscribePayment(info.PaymentHash)
|
||||
subscriber2, err := pControl.SubscribePayment(info.PaymentHash)
|
||||
if err != nil {
|
||||
t.Fatalf("expected subscribe to succeed, but got: %v", err)
|
||||
}
|
||||
if inFlight {
|
||||
t.Fatalf("expected payment to be finished")
|
||||
}
|
||||
|
||||
// We expect all subscribers to now report the final outcome followed by
|
||||
// no other events.
|
||||
subscribers := []chan PaymentResult{
|
||||
subscribers := []*ControlTowerSubscriber{
|
||||
subscriber1, subscriber2,
|
||||
}
|
||||
|
||||
for _, s := range subscribers {
|
||||
var result PaymentResult
|
||||
select {
|
||||
case result = <-s:
|
||||
case <-time.After(testTimeout):
|
||||
t.Fatal("timeout waiting for payment result")
|
||||
var result *channeldb.MPPayment
|
||||
for result == nil || result.Status == channeldb.StatusInFlight {
|
||||
select {
|
||||
case item := <-s.Updates:
|
||||
result = item.(*channeldb.MPPayment)
|
||||
case <-time.After(testTimeout):
|
||||
t.Fatal("timeout waiting for payment result")
|
||||
}
|
||||
}
|
||||
|
||||
if result.Success {
|
||||
if result.Status == channeldb.StatusSucceeded {
|
||||
t.Fatal("unexpected payment state")
|
||||
}
|
||||
|
||||
|
@ -282,13 +277,13 @@ func testPaymentControlSubscribeFail(t *testing.T, registerAttempt bool) {
|
|||
len(result.HTLCs))
|
||||
}
|
||||
|
||||
if result.FailureReason != channeldb.FailureReasonTimeout {
|
||||
if *result.FailureReason != channeldb.FailureReasonTimeout {
|
||||
t.Fatal("unexpected failure reason")
|
||||
}
|
||||
|
||||
// After the final event, we expect the channel to be closed.
|
||||
select {
|
||||
case _, ok := <-s:
|
||||
case _, ok := <-s.Updates:
|
||||
if ok {
|
||||
t.Fatal("expected channel to be closed")
|
||||
}
|
||||
|
|
|
@ -457,7 +457,7 @@ func (m *mockControlTower) FetchInFlightPayments() (
|
|||
}
|
||||
|
||||
func (m *mockControlTower) SubscribePayment(paymentHash lntypes.Hash) (
|
||||
bool, chan PaymentResult, error) {
|
||||
*ControlTowerSubscriber, error) {
|
||||
|
||||
return false, nil, errors.New("not implemented")
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
|
|
@ -207,7 +207,7 @@ func (p *paymentLifecycle) resumePayment() ([32]byte, *route.Route, error) {
|
|||
uint32(state.numShardsInFlight), uint32(p.currentHeight),
|
||||
)
|
||||
if err != nil {
|
||||
log.Warnf("Failed to find route for payment %x: %v",
|
||||
log.Warnf("Failed to find route for payment %v: %v",
|
||||
p.paymentHash, err)
|
||||
|
||||
routeErr, ok := err.(noRouteError)
|
||||
|
@ -489,7 +489,7 @@ func (p *shardHandler) collectResult(attempt *channeldb.HTLCAttemptInfo) (
|
|||
// case we can safely send a new payment attempt, and wait for its
|
||||
// result to be available.
|
||||
case err == htlcswitch.ErrPaymentIDNotFound:
|
||||
log.Debugf("Payment ID %v for hash %x not found in "+
|
||||
log.Debugf("Payment ID %v for hash %v not found in "+
|
||||
"the Switch, retrying.", attempt.AttemptID,
|
||||
p.paymentHash)
|
||||
|
||||
|
@ -544,7 +544,7 @@ func (p *shardHandler) collectResult(attempt *channeldb.HTLCAttemptInfo) (
|
|||
}
|
||||
|
||||
// We successfully got a payment result back from the switch.
|
||||
log.Debugf("Payment %x succeeded with pid=%v",
|
||||
log.Debugf("Payment %v succeeded with pid=%v",
|
||||
p.paymentHash, attempt.AttemptID)
|
||||
|
||||
// Report success to mission control.
|
||||
|
@ -637,7 +637,7 @@ func (p *shardHandler) sendPaymentAttempt(
|
|||
attempt *channeldb.HTLCAttemptInfo, firstHop lnwire.ShortChannelID,
|
||||
htlcAdd *lnwire.UpdateAddHTLC) error {
|
||||
|
||||
log.Tracef("Attempting to send payment %x (pid=%v), "+
|
||||
log.Tracef("Attempting to send payment %v (pid=%v), "+
|
||||
"using route: %v", p.paymentHash, attempt.AttemptID,
|
||||
newLogClosure(func() string {
|
||||
return spew.Sdump(attempt.Route)
|
||||
|
@ -653,12 +653,12 @@ func (p *shardHandler) sendPaymentAttempt(
|
|||
)
|
||||
if err != nil {
|
||||
log.Errorf("Failed sending attempt %d for payment "+
|
||||
"%x to switch: %v", attempt.AttemptID,
|
||||
"%v to switch: %v", attempt.AttemptID,
|
||||
p.paymentHash, err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("Payment %x (pid=%v) successfully sent to switch, route: %v",
|
||||
log.Debugf("Payment %v (pid=%v) successfully sent to switch, route: %v",
|
||||
p.paymentHash, attempt.AttemptID, &attempt.Route)
|
||||
|
||||
return nil
|
||||
|
@ -678,7 +678,7 @@ func (p *shardHandler) handleSendError(attempt *channeldb.HTLCAttemptInfo,
|
|||
return nil
|
||||
}
|
||||
|
||||
log.Debugf("Payment %x failed: final_outcome=%v, raw_err=%v",
|
||||
log.Debugf("Payment %v failed: final_outcome=%v, raw_err=%v",
|
||||
p.paymentHash, *reason, sendErr)
|
||||
|
||||
err := p.router.cfg.Control.Fail(p.paymentHash, *reason)
|
||||
|
|
83
rpcserver.go
83
rpcserver.go
|
@ -5184,94 +5184,21 @@ func (r *rpcServer) ListPayments(ctx context.Context,
|
|||
}
|
||||
|
||||
for _, payment := range paymentsQuerySlice.Payments {
|
||||
// Fetch the payment's route and preimage. If no HTLC was
|
||||
// successful, an empty route and preimage will be used.
|
||||
var (
|
||||
route route.Route
|
||||
preimage lntypes.Preimage
|
||||
)
|
||||
for _, htlc := range payment.HTLCs {
|
||||
// Display the last route attempted.
|
||||
route = htlc.Route
|
||||
payment := payment
|
||||
|
||||
// If any of the htlcs have settled, extract a valid
|
||||
// preimage.
|
||||
if htlc.Settle != nil {
|
||||
preimage = htlc.Settle.Preimage
|
||||
}
|
||||
}
|
||||
|
||||
// Encode the hops from the successful route, if any.
|
||||
path := make([]string, len(route.Hops))
|
||||
for i, hop := range route.Hops {
|
||||
path[i] = hex.EncodeToString(hop.PubKeyBytes[:])
|
||||
}
|
||||
|
||||
msatValue := int64(payment.Info.Value)
|
||||
satValue := int64(payment.Info.Value.ToSatoshis())
|
||||
|
||||
status, err := convertPaymentStatus(payment.Status)
|
||||
rpcPayment, err := r.routerBackend.MarshallPayment(&payment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
htlcs := make([]*lnrpc.HTLCAttempt, 0, len(payment.HTLCs))
|
||||
for _, dbHTLC := range payment.HTLCs {
|
||||
htlc, err := r.routerBackend.MarshalHTLCAttempt(dbHTLC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
htlcs = append(htlcs, htlc)
|
||||
}
|
||||
|
||||
paymentHash := payment.Info.PaymentHash
|
||||
creationTimeNS := routerrpc.MarshalTimeNano(payment.Info.CreationTime)
|
||||
paymentsResp.Payments = append(paymentsResp.Payments, &lnrpc.Payment{
|
||||
PaymentHash: hex.EncodeToString(paymentHash[:]),
|
||||
Value: satValue,
|
||||
ValueMsat: msatValue,
|
||||
ValueSat: satValue,
|
||||
CreationDate: payment.Info.CreationTime.Unix(),
|
||||
CreationTimeNs: creationTimeNS,
|
||||
Path: path,
|
||||
Fee: int64(route.TotalFees().ToSatoshis()),
|
||||
FeeSat: int64(route.TotalFees().ToSatoshis()),
|
||||
FeeMsat: int64(route.TotalFees()),
|
||||
PaymentPreimage: hex.EncodeToString(preimage[:]),
|
||||
PaymentRequest: string(payment.Info.PaymentRequest),
|
||||
Status: status,
|
||||
Htlcs: htlcs,
|
||||
PaymentIndex: payment.SequenceNum,
|
||||
})
|
||||
paymentsResp.Payments = append(
|
||||
paymentsResp.Payments, rpcPayment,
|
||||
)
|
||||
}
|
||||
|
||||
return paymentsResp, nil
|
||||
}
|
||||
|
||||
// convertPaymentStatus converts a channeldb.PaymentStatus to the type expected
|
||||
// by the RPC.
|
||||
func convertPaymentStatus(dbStatus channeldb.PaymentStatus) (
|
||||
lnrpc.Payment_PaymentStatus, error) {
|
||||
|
||||
switch dbStatus {
|
||||
case channeldb.StatusUnknown:
|
||||
return lnrpc.Payment_UNKNOWN, nil
|
||||
|
||||
case channeldb.StatusInFlight:
|
||||
return lnrpc.Payment_IN_FLIGHT, nil
|
||||
|
||||
case channeldb.StatusSucceeded:
|
||||
return lnrpc.Payment_SUCCEEDED, nil
|
||||
|
||||
case channeldb.StatusFailed:
|
||||
return lnrpc.Payment_FAILED, nil
|
||||
|
||||
default:
|
||||
return 0, fmt.Errorf("unhandled payment status %v", dbStatus)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteAllPayments deletes all outgoing payments from DB.
|
||||
func (r *rpcServer) DeleteAllPayments(ctx context.Context,
|
||||
_ *lnrpc.DeleteAllPaymentsRequest) (*lnrpc.DeleteAllPaymentsResponse, error) {
|
||||
|
|
Loading…
Add table
Reference in a new issue