rpcserver: use BOLT-11 compatible zpay32 package.
This commit changes the rpcserver to rely on the new zpay32 package, and support the new payment request options available in the BOLT-11 invoice format.
This commit is contained in:
parent
070eb0ec3e
commit
15d753fd9e
335
rpcserver.go
335
rpcserver.go
@ -1372,6 +1372,18 @@ func (r *rpcServer) savePayment(route *routing.Route, amount lnwire.MilliSatoshi
|
|||||||
return r.server.chanDB.AddPayment(payment)
|
return r.server.chanDB.AddPayment(payment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validatePayReqExpiry checks if the passed payment request has expired. In
|
||||||
|
// the case it has expired, an error will be returned.
|
||||||
|
func validatePayReqExpiry(payReq *zpay32.Invoice) error {
|
||||||
|
expiry := payReq.Expiry()
|
||||||
|
validUntil := payReq.Timestamp.Add(expiry)
|
||||||
|
if time.Now().After(validUntil) {
|
||||||
|
return fmt.Errorf("invoice expired. Valid until %v", validUntil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SendPayment dispatches a bi-directional streaming RPC for sending payments
|
// SendPayment dispatches a bi-directional streaming RPC for sending payments
|
||||||
// through the Lightning Network. A single RPC invocation creates a persistent
|
// through the Lightning Network. A single RPC invocation creates a persistent
|
||||||
// bi-directional stream allowing clients to rapidly send payments through the
|
// bi-directional stream allowing clients to rapidly send payments through the
|
||||||
@ -1385,8 +1397,15 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For each payment we need to know the msat amount, the destination
|
||||||
|
// public key, and the payment hash.
|
||||||
|
type payment struct {
|
||||||
|
msat lnwire.MilliSatoshi
|
||||||
|
dest []byte
|
||||||
|
pHash []byte
|
||||||
|
}
|
||||||
|
payChan := make(chan *payment)
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
payChan := make(chan *lnrpc.SendRequest)
|
|
||||||
|
|
||||||
// TODO(roasbeef): enforce fee limits, pass into router, ditch if exceed limit
|
// TODO(roasbeef): enforce fee limits, pass into router, ditch if exceed limit
|
||||||
// * limit either a %, or absolute, or iff more than sending
|
// * limit either a %, or absolute, or iff more than sending
|
||||||
@ -1443,31 +1462,67 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Populate the next payment, either from the
|
||||||
|
// payment request, or from the explicitly set
|
||||||
|
// fields.
|
||||||
|
p := &payment{}
|
||||||
|
|
||||||
// If the payment request field isn't blank,
|
// If the payment request field isn't blank,
|
||||||
// then the details of the invoice are encoded
|
// then the details of the invoice are encoded
|
||||||
// entirely within the encode payReq. So we'll
|
// entirely within the encoded payReq. So we'll
|
||||||
// attempt to decode it, populating the
|
// attempt to decode it, populating the
|
||||||
// nextPayment accordingly.
|
// payment accordingly.
|
||||||
if nextPayment.PaymentRequest != "" {
|
if nextPayment.PaymentRequest != "" {
|
||||||
payReq, err := zpay32.Decode(nextPayment.PaymentRequest)
|
payReq, err := zpay32.Decode(nextPayment.PaymentRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
select {
|
select {
|
||||||
case errChan <- err:
|
case errChan <- err:
|
||||||
case <-reqQuit:
|
case <-reqQuit:
|
||||||
return
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): eliminate necessary
|
// TODO(roasbeef): eliminate necessary
|
||||||
// encode/decode
|
// encode/decode
|
||||||
nextPayment.Dest = payReq.Destination.SerializeCompressed()
|
|
||||||
nextPayment.Amt = int64(payReq.Amount)
|
// We first check that this payment
|
||||||
nextPayment.PaymentHash = payReq.PaymentHash[:]
|
// request has not expired.
|
||||||
|
err = validatePayReqExpiry(payReq)
|
||||||
|
if err != nil {
|
||||||
|
select {
|
||||||
|
case errChan <- err:
|
||||||
|
case <-reqQuit:
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.dest = payReq.Destination.SerializeCompressed()
|
||||||
|
|
||||||
|
if payReq.MilliSat == nil {
|
||||||
|
err := fmt.Errorf("only payment" +
|
||||||
|
" requests specifying" +
|
||||||
|
" the amount are" +
|
||||||
|
" currently supported")
|
||||||
|
select {
|
||||||
|
case errChan <- err:
|
||||||
|
case <-reqQuit:
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.msat = *payReq.MilliSat
|
||||||
|
p.pHash = payReq.PaymentHash[:]
|
||||||
|
} else {
|
||||||
|
// If the payment request field was not
|
||||||
|
// specified, construct the payment from
|
||||||
|
// the other fields.
|
||||||
|
p.msat = lnwire.NewMSatFromSatoshis(
|
||||||
|
btcutil.Amount(nextPayment.Amt),
|
||||||
|
)
|
||||||
|
p.dest = nextPayment.Dest
|
||||||
|
p.pHash = nextPayment.PaymentHash
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case payChan <- nextPayment:
|
case payChan <- p:
|
||||||
case <-reqQuit:
|
case <-reqQuit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1479,20 +1534,17 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
select {
|
select {
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
return err
|
return err
|
||||||
case nextPayment := <-payChan:
|
case p := <-payChan:
|
||||||
// Currently, within the bootstrap phase of the
|
// Currently, within the bootstrap phase of the
|
||||||
// network, we limit the largest payment size allotted
|
// network, we limit the largest payment size allotted
|
||||||
// to (2^32) - 1 mSAT or 4.29 million satoshis.
|
// to (2^32) - 1 mSAT or 4.29 million satoshis.
|
||||||
amt := btcutil.Amount(nextPayment.Amt)
|
if p.msat > maxPaymentMSat {
|
||||||
amtMSat := lnwire.NewMSatFromSatoshis(amt)
|
|
||||||
if amtMSat > maxPaymentMSat {
|
|
||||||
// In this case, we'll send an error to the
|
// In this case, we'll send an error to the
|
||||||
// caller, but continue our loop for the next
|
// caller, but continue our loop for the next
|
||||||
// payment.
|
// payment.
|
||||||
pErr := fmt.Errorf("payment of %v is too "+
|
pErr := fmt.Errorf("payment of %v is too "+
|
||||||
"large, max payment allowed is %v",
|
"large, max payment allowed is %v",
|
||||||
nextPayment.Amt,
|
p.msat, maxPaymentMSat)
|
||||||
maxPaymentMSat.ToSatoshis())
|
|
||||||
|
|
||||||
if err := paymentStream.Send(&lnrpc.SendResponse{
|
if err := paymentStream.Send(&lnrpc.SendResponse{
|
||||||
PaymentError: pErr.Error(),
|
PaymentError: pErr.Error(),
|
||||||
@ -1504,8 +1556,7 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
|
|
||||||
// Parse the details of the payment which include the
|
// Parse the details of the payment which include the
|
||||||
// pubkey of the destination and the payment amount.
|
// pubkey of the destination and the payment amount.
|
||||||
dest := nextPayment.Dest
|
destNode, err := btcec.ParsePubKey(p.dest, btcec.S256())
|
||||||
destNode, err := btcec.ParsePubKey(dest, btcec.S256())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1514,10 +1565,10 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
// will pay to the same debug rHash. Otherwise, we pay
|
// will pay to the same debug rHash. Otherwise, we pay
|
||||||
// to the rHash specified within the RPC request.
|
// to the rHash specified within the RPC request.
|
||||||
var rHash [32]byte
|
var rHash [32]byte
|
||||||
if cfg.DebugHTLC && len(nextPayment.PaymentHash) == 0 {
|
if cfg.DebugHTLC && len(p.pHash) == 0 {
|
||||||
rHash = debugHash
|
rHash = debugHash
|
||||||
} else {
|
} else {
|
||||||
copy(rHash[:], nextPayment.PaymentHash)
|
copy(rHash[:], p.pHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We launch a new goroutine to execute the current
|
// We launch a new goroutine to execute the current
|
||||||
@ -1539,7 +1590,7 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
// error.
|
// error.
|
||||||
payment := &routing.LightningPayment{
|
payment := &routing.LightningPayment{
|
||||||
Target: destNode,
|
Target: destNode,
|
||||||
Amount: amtMSat,
|
Amount: p.msat,
|
||||||
PaymentHash: rHash,
|
PaymentHash: rHash,
|
||||||
}
|
}
|
||||||
preImage, route, err := r.server.chanRouter.SendPayment(payment)
|
preImage, route, err := r.server.chanRouter.SendPayment(payment)
|
||||||
@ -1558,7 +1609,7 @@ func (r *rpcServer) SendPayment(paymentStream lnrpc.Lightning_SendPaymentServer)
|
|||||||
|
|
||||||
// Save the completed payment to the database
|
// Save the completed payment to the database
|
||||||
// for record keeping purposes.
|
// for record keeping purposes.
|
||||||
if err := r.savePayment(route, amtMSat, rHash[:]); err != nil {
|
if err := r.savePayment(route, p.msat, rHash[:]); err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1604,7 +1655,7 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context,
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
destPub *btcec.PublicKey
|
destPub *btcec.PublicKey
|
||||||
amt btcutil.Amount
|
amtMSat lnwire.MilliSatoshi
|
||||||
rHash [32]byte
|
rHash [32]byte
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1615,9 +1666,20 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We first check that this payment request has not expired.
|
||||||
|
if err := validatePayReqExpiry(payReq); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
destPub = payReq.Destination
|
destPub = payReq.Destination
|
||||||
amt = payReq.Amount
|
|
||||||
rHash = payReq.PaymentHash
|
if payReq.MilliSat == nil {
|
||||||
|
return nil, fmt.Errorf("payment requests with no " +
|
||||||
|
"amount specified not currently supported")
|
||||||
|
}
|
||||||
|
amtMSat = *payReq.MilliSat
|
||||||
|
rHash = *payReq.PaymentHash
|
||||||
|
|
||||||
// Otherwise, the payment conditions have been manually
|
// Otherwise, the payment conditions have been manually
|
||||||
// specified in the proto.
|
// specified in the proto.
|
||||||
@ -1645,13 +1707,14 @@ func (r *rpcServer) SendPaymentSync(ctx context.Context,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
amt = btcutil.Amount(nextPayment.Amt)
|
amtMSat = lnwire.NewMSatFromSatoshis(
|
||||||
|
btcutil.Amount(nextPayment.Amt),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently, within the bootstrap phase of the network, we limit the
|
// Currently, within the bootstrap phase of the network, we limit the
|
||||||
// largest payment size allotted to (2^32) - 1 mSAT or 4.29 million
|
// largest payment size allotted to (2^32) - 1 mSAT or 4.29 million
|
||||||
// satoshis.
|
// satoshis.
|
||||||
amtMSat := lnwire.NewMSatFromSatoshis(amt)
|
|
||||||
if amtMSat > maxPaymentMSat {
|
if amtMSat > maxPaymentMSat {
|
||||||
return nil, fmt.Errorf("payment of %v is too large, max payment "+
|
return nil, fmt.Errorf("payment of %v is too large, max payment "+
|
||||||
"allowed is %v", nextPayment.Amt,
|
"allowed is %v", nextPayment.Amt,
|
||||||
@ -1718,8 +1781,8 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
|
|||||||
copy(paymentPreimage[:], invoice.RPreimage[:])
|
copy(paymentPreimage[:], invoice.RPreimage[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// The size of the memo and receipt attached must not exceed the
|
// The size of the memo, receipt and description hash attached must not
|
||||||
// maximum values for either of the fields.
|
// exceed the maximum values for either of the fields.
|
||||||
if len(invoice.Memo) > channeldb.MaxMemoSize {
|
if len(invoice.Memo) > channeldb.MaxMemoSize {
|
||||||
return nil, fmt.Errorf("memo too large: %v bytes "+
|
return nil, fmt.Errorf("memo too large: %v bytes "+
|
||||||
"(maxsize=%v)", len(invoice.Memo), channeldb.MaxMemoSize)
|
"(maxsize=%v)", len(invoice.Memo), channeldb.MaxMemoSize)
|
||||||
@ -1728,6 +1791,10 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
|
|||||||
return nil, fmt.Errorf("receipt too large: %v bytes "+
|
return nil, fmt.Errorf("receipt too large: %v bytes "+
|
||||||
"(maxsize=%v)", len(invoice.Receipt), channeldb.MaxReceiptSize)
|
"(maxsize=%v)", len(invoice.Receipt), channeldb.MaxReceiptSize)
|
||||||
}
|
}
|
||||||
|
if len(invoice.DescriptionHash) > 0 && len(invoice.DescriptionHash) != 32 {
|
||||||
|
return nil, fmt.Errorf("description hash is %v bytes, must be %v",
|
||||||
|
len(invoice.DescriptionHash), channeldb.MaxPaymentRequestSize)
|
||||||
|
}
|
||||||
|
|
||||||
amt := btcutil.Amount(invoice.Value)
|
amt := btcutil.Amount(invoice.Value)
|
||||||
amtMSat := lnwire.NewMSatFromSatoshis(amt)
|
amtMSat := lnwire.NewMSatFromSatoshis(amt)
|
||||||
@ -1743,10 +1810,78 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
|
|||||||
"payment allowed is %v", amt, maxPaymentMSat.ToSatoshis())
|
"payment allowed is %v", amt, maxPaymentMSat.ToSatoshis())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Next, generate the payment hash itself from the preimage. This will
|
||||||
|
// be used by clients to query for the state of a particular invoice.
|
||||||
|
rHash := sha256.Sum256(paymentPreimage[:])
|
||||||
|
|
||||||
|
// We also create an encoded payment request which allows the
|
||||||
|
// caller to compactly send the invoice to the payer. We'll create a
|
||||||
|
// list of options to be added to the encoded payment request. For now
|
||||||
|
// we only support the required fields description/description_hash,
|
||||||
|
// expiry, fallback address, and the amount field.
|
||||||
|
var options []func(*zpay32.Invoice)
|
||||||
|
|
||||||
|
// Add the amount. This field is optional by the BOLT-11 format, but
|
||||||
|
// we require it for now.
|
||||||
|
options = append(options, zpay32.Amount(amtMSat))
|
||||||
|
|
||||||
|
// If specified, add a fallback address to the payment request.
|
||||||
|
if len(invoice.FallbackAddr) > 0 {
|
||||||
|
addr, err := btcutil.DecodeAddress(invoice.FallbackAddr,
|
||||||
|
activeNetParams.Params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid fallback address: %v",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
options = append(options, zpay32.FallbackAddr(addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// If expiry is set, specify it. If it is not provided, no expiry time
|
||||||
|
// will be explicitly added to this payment request, which will imply
|
||||||
|
// the default 3600 seconds.
|
||||||
|
if invoice.Expiry > 0 {
|
||||||
|
exp := time.Duration(invoice.Expiry) * time.Second
|
||||||
|
options = append(options, zpay32.Expiry(exp))
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the description hash is set, then we add it do the list of options.
|
||||||
|
// If not, use the memo field as the payment request description.
|
||||||
|
if len(invoice.DescriptionHash) > 0 {
|
||||||
|
var descHash [32]byte
|
||||||
|
copy(descHash[:], invoice.DescriptionHash[:])
|
||||||
|
options = append(options, zpay32.DescriptionHash(descHash))
|
||||||
|
} else {
|
||||||
|
// Use the memo field as the description. If this is not set
|
||||||
|
// this will just be an empty string.
|
||||||
|
options = append(options, zpay32.Description(invoice.Memo))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and encode the payment request as a bech32 (zpay32) string.
|
||||||
|
creationDate := time.Now()
|
||||||
|
payReq, err := zpay32.NewInvoice(
|
||||||
|
activeNetParams.Params,
|
||||||
|
rHash,
|
||||||
|
creationDate,
|
||||||
|
options...,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
payReqString, err := payReq.Encode(
|
||||||
|
zpay32.MessageSigner{
|
||||||
|
SignCompact: r.server.nodeSigner.SignDigestCompact,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
i := &channeldb.Invoice{
|
i := &channeldb.Invoice{
|
||||||
CreationDate: time.Now(),
|
CreationDate: creationDate,
|
||||||
Memo: []byte(invoice.Memo),
|
Memo: []byte(invoice.Memo),
|
||||||
Receipt: invoice.Receipt,
|
Receipt: invoice.Receipt,
|
||||||
|
PaymentRequest: []byte(payReqString),
|
||||||
Terms: channeldb.ContractTerm{
|
Terms: channeldb.ContractTerm{
|
||||||
Value: amtMSat,
|
Value: amtMSat,
|
||||||
},
|
},
|
||||||
@ -1763,24 +1898,53 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, generate the payment hash itself from the preimage. This will
|
|
||||||
// be used by clients to query for the state of a particular invoice.
|
|
||||||
rHash := sha256.Sum256(paymentPreimage[:])
|
|
||||||
|
|
||||||
// Finally we also create an encoded payment request which allows the
|
|
||||||
// caller to compactly send the invoice to the payer.
|
|
||||||
payReqString := zpay32.Encode(&zpay32.PaymentRequest{
|
|
||||||
Destination: r.server.identityPriv.PubKey(),
|
|
||||||
PaymentHash: rHash,
|
|
||||||
Amount: amt,
|
|
||||||
})
|
|
||||||
|
|
||||||
return &lnrpc.AddInvoiceResponse{
|
return &lnrpc.AddInvoiceResponse{
|
||||||
RHash: rHash[:],
|
RHash: rHash[:],
|
||||||
PaymentRequest: payReqString,
|
PaymentRequest: payReqString,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createRPCInvoice creates an *lnrpc.Invoice from the *channeldb.Invoice.
|
||||||
|
func createRPCInvoice(invoice *channeldb.Invoice) (*lnrpc.Invoice, error) {
|
||||||
|
paymentRequest := string(invoice.PaymentRequest)
|
||||||
|
decoded, err := zpay32.Decode(paymentRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to decode payment request: %v",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
descHash := []byte("")
|
||||||
|
if decoded.DescriptionHash != nil {
|
||||||
|
descHash = decoded.DescriptionHash[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
fallbackAddr := ""
|
||||||
|
if decoded.FallbackAddr != nil {
|
||||||
|
fallbackAddr = decoded.FallbackAddr.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expiry time will default to 3600 seconds if not specified
|
||||||
|
// explicitly.
|
||||||
|
expiry := int64(decoded.Expiry().Seconds())
|
||||||
|
|
||||||
|
preimage := invoice.Terms.PaymentPreimage
|
||||||
|
satAmt := invoice.Terms.Value.ToSatoshis()
|
||||||
|
|
||||||
|
return &lnrpc.Invoice{
|
||||||
|
Memo: string(invoice.Memo[:]),
|
||||||
|
Receipt: invoice.Receipt[:],
|
||||||
|
RHash: decoded.PaymentHash[:],
|
||||||
|
RPreimage: preimage[:],
|
||||||
|
Value: int64(satAmt),
|
||||||
|
CreationDate: invoice.CreationDate.Unix(),
|
||||||
|
Settled: invoice.Terms.Settled,
|
||||||
|
PaymentRequest: paymentRequest,
|
||||||
|
DescriptionHash: descHash,
|
||||||
|
Expiry: expiry,
|
||||||
|
FallbackAddr: fallbackAddr,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// LookupInvoice attemps to look up an invoice according to its payment hash.
|
// LookupInvoice attemps to look up an invoice according to its payment hash.
|
||||||
// The passed payment hash *must* be exactly 32 bytes, if not an error is
|
// The passed payment hash *must* be exactly 32 bytes, if not an error is
|
||||||
// returned.
|
// returned.
|
||||||
@ -1831,22 +1995,12 @@ func (r *rpcServer) LookupInvoice(ctx context.Context,
|
|||||||
return spew.Sdump(invoice)
|
return spew.Sdump(invoice)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
preimage := invoice.Terms.PaymentPreimage
|
rpcInvoice, err := createRPCInvoice(invoice)
|
||||||
satAmt := invoice.Terms.Value.ToSatoshis()
|
if err != nil {
|
||||||
return &lnrpc.Invoice{
|
return nil, err
|
||||||
Memo: string(invoice.Memo[:]),
|
}
|
||||||
Receipt: invoice.Receipt[:],
|
|
||||||
RHash: rHash,
|
return rpcInvoice, nil
|
||||||
RPreimage: preimage[:],
|
|
||||||
Value: int64(satAmt),
|
|
||||||
CreationDate: invoice.CreationDate.Unix(),
|
|
||||||
Settled: invoice.Terms.Settled,
|
|
||||||
PaymentRequest: zpay32.Encode(&zpay32.PaymentRequest{
|
|
||||||
Destination: r.server.identityPriv.PubKey(),
|
|
||||||
PaymentHash: sha256.Sum256(preimage[:]),
|
|
||||||
Amount: satAmt,
|
|
||||||
}),
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListInvoices returns a list of all the invoices currently stored within the
|
// ListInvoices returns a list of all the invoices currently stored within the
|
||||||
@ -1869,26 +2023,13 @@ func (r *rpcServer) ListInvoices(ctx context.Context,
|
|||||||
|
|
||||||
invoices := make([]*lnrpc.Invoice, len(dbInvoices))
|
invoices := make([]*lnrpc.Invoice, len(dbInvoices))
|
||||||
for i, dbInvoice := range dbInvoices {
|
for i, dbInvoice := range dbInvoices {
|
||||||
invoiceAmount := dbInvoice.Terms.Value.ToSatoshis()
|
|
||||||
paymentPreimge := dbInvoice.Terms.PaymentPreimage[:]
|
|
||||||
rHash := sha256.Sum256(paymentPreimge)
|
|
||||||
|
|
||||||
invoice := &lnrpc.Invoice{
|
rpcInvoice, err := createRPCInvoice(dbInvoice)
|
||||||
Memo: string(dbInvoice.Memo[:]),
|
if err != nil {
|
||||||
Receipt: dbInvoice.Receipt[:],
|
return nil, err
|
||||||
RHash: rHash[:],
|
|
||||||
RPreimage: paymentPreimge,
|
|
||||||
Value: int64(invoiceAmount),
|
|
||||||
Settled: dbInvoice.Terms.Settled,
|
|
||||||
CreationDate: dbInvoice.CreationDate.Unix(),
|
|
||||||
PaymentRequest: zpay32.Encode(&zpay32.PaymentRequest{
|
|
||||||
Destination: r.server.identityPriv.PubKey(),
|
|
||||||
PaymentHash: sha256.Sum256(paymentPreimge),
|
|
||||||
Amount: invoiceAmount,
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
invoices[i] = invoice
|
invoices[i] = rpcInvoice
|
||||||
}
|
}
|
||||||
|
|
||||||
return &lnrpc.ListInvoiceResponse{
|
return &lnrpc.ListInvoiceResponse{
|
||||||
@ -1916,17 +2057,13 @@ func (r *rpcServer) SubscribeInvoices(req *lnrpc.InvoiceSubscription,
|
|||||||
select {
|
select {
|
||||||
// TODO(roasbeef): include newly added invoices?
|
// TODO(roasbeef): include newly added invoices?
|
||||||
case settledInvoice := <-invoiceClient.SettledInvoices:
|
case settledInvoice := <-invoiceClient.SettledInvoices:
|
||||||
preImage := settledInvoice.Terms.PaymentPreimage[:]
|
|
||||||
rHash := sha256.Sum256(preImage)
|
rpcInvoice, err := createRPCInvoice(settledInvoice)
|
||||||
invoice := &lnrpc.Invoice{
|
if err != nil {
|
||||||
Memo: string(settledInvoice.Memo[:]),
|
return err
|
||||||
Receipt: settledInvoice.Receipt[:],
|
|
||||||
RHash: rHash[:],
|
|
||||||
RPreimage: preImage,
|
|
||||||
Value: int64(settledInvoice.Terms.Value.ToSatoshis()),
|
|
||||||
Settled: settledInvoice.Terms.Settled,
|
|
||||||
}
|
}
|
||||||
if err := updateStream.Send(invoice); err != nil {
|
|
||||||
|
if err := updateStream.Send(rpcInvoice); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case <-r.quit:
|
case <-r.quit:
|
||||||
@ -2713,11 +2850,41 @@ func (r *rpcServer) DecodePayReq(ctx context.Context,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Let the fields default to empty strings.
|
||||||
|
desc := ""
|
||||||
|
if payReq.Description != nil {
|
||||||
|
desc = *payReq.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
descHash := []byte("")
|
||||||
|
if payReq.DescriptionHash != nil {
|
||||||
|
descHash = payReq.DescriptionHash[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
fallbackAddr := ""
|
||||||
|
if payReq.FallbackAddr != nil {
|
||||||
|
fallbackAddr = payReq.FallbackAddr.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expiry time will default to 3600 seconds if not specified
|
||||||
|
// explicitly.
|
||||||
|
expiry := int64(payReq.Expiry().Seconds())
|
||||||
|
|
||||||
|
amt := int64(0)
|
||||||
|
if payReq.MilliSat != nil {
|
||||||
|
amt = int64(payReq.MilliSat.ToSatoshis())
|
||||||
|
}
|
||||||
|
|
||||||
dest := payReq.Destination.SerializeCompressed()
|
dest := payReq.Destination.SerializeCompressed()
|
||||||
return &lnrpc.PayReq{
|
return &lnrpc.PayReq{
|
||||||
Destination: hex.EncodeToString(dest),
|
Destination: hex.EncodeToString(dest),
|
||||||
PaymentHash: hex.EncodeToString(payReq.PaymentHash[:]),
|
PaymentHash: hex.EncodeToString(payReq.PaymentHash[:]),
|
||||||
NumSatoshis: int64(payReq.Amount),
|
NumSatoshis: amt,
|
||||||
|
Timestamp: payReq.Timestamp.Unix(),
|
||||||
|
Description: desc,
|
||||||
|
DescriptionHash: hex.EncodeToString(descHash[:]),
|
||||||
|
FallbackAddr: fallbackAddr,
|
||||||
|
Expiry: expiry,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user