lncli: live table-based payment updates
This commit is contained in:
parent
ce0a61abeb
commit
8d7e07d96b
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
@ -8,9 +9,13 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jedib0t/go-pretty/table"
|
||||
"github.com/jedib0t/go-pretty/text"
|
||||
"github.com/lightninglabs/protobuf-hex-display/jsonpb"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
@ -47,10 +52,10 @@ var (
|
||||
"Custom record ids start from 65536.",
|
||||
}
|
||||
|
||||
showInflightFlag = cli.BoolFlag{
|
||||
Name: "show_inflight",
|
||||
inflightUpdatesFlag = cli.BoolFlag{
|
||||
Name: "inflight_updates",
|
||||
Usage: "if set, intermediate payment state updates will be " +
|
||||
"displayed",
|
||||
"displayed. Only valid in combination with --json.",
|
||||
}
|
||||
|
||||
maxShardsFlag = cli.UintFlag{
|
||||
@ -59,6 +64,13 @@ var (
|
||||
"used",
|
||||
Value: 1,
|
||||
}
|
||||
|
||||
jsonFlag = cli.BoolFlag{
|
||||
Name: "json",
|
||||
Usage: "if set, payment updates are printed as json " +
|
||||
"messages. Set by default on Windows because table " +
|
||||
"formatting is unsupported.",
|
||||
}
|
||||
)
|
||||
|
||||
// paymentFlags returns common flags for sendpayment and payinvoice.
|
||||
@ -95,7 +107,7 @@ func paymentFlags() []cli.Flag {
|
||||
Name: "allow_self_payment",
|
||||
Usage: "allow sending a circular payment to self",
|
||||
},
|
||||
dataFlag, showInflightFlag, maxShardsFlag,
|
||||
dataFlag, inflightUpdatesFlag, maxShardsFlag, jsonFlag,
|
||||
}
|
||||
}
|
||||
|
||||
@ -397,32 +409,30 @@ func sendPaymentRequest(ctx *cli.Context,
|
||||
|
||||
req.FeeLimitSat = feeLimit
|
||||
|
||||
req.NoInflightUpdates = !ctx.Bool(showInflightFlag.Name)
|
||||
// Always print in-flight updates for the table output.
|
||||
printJSON := ctx.Bool(jsonFlag.Name)
|
||||
req.NoInflightUpdates = !ctx.Bool(inflightUpdatesFlag.Name) && printJSON
|
||||
|
||||
stream, err := routerClient.SendPaymentV2(context.Background(), req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
status, err := stream.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printRespJSON(status)
|
||||
|
||||
if status.Status != lnrpc.Payment_IN_FLIGHT {
|
||||
// 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.Status != lnrpc.Payment_SUCCEEDED {
|
||||
return errors.New(status.Status.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
finalState, err := printLivePayment(
|
||||
stream, client, printJSON,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 finalState.Status != lnrpc.Payment_SUCCEEDED {
|
||||
return errors.New(finalState.Status.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var trackPaymentCommand = cli.Command{
|
||||
@ -443,7 +453,7 @@ func trackPayment(ctx *cli.Context) error {
|
||||
conn := getClientConn(ctx, false)
|
||||
defer conn.Close()
|
||||
|
||||
client := routerrpc.NewRouterClient(conn)
|
||||
routerClient := routerrpc.NewRouterClient(conn)
|
||||
|
||||
if !args.Present() {
|
||||
return fmt.Errorf("hash argument missing")
|
||||
@ -458,25 +468,206 @@ func trackPayment(ctx *cli.Context) error {
|
||||
PaymentHash: hash,
|
||||
}
|
||||
|
||||
stream, err := client.TrackPaymentV2(context.Background(), req)
|
||||
stream, err := routerClient.TrackPaymentV2(context.Background(), req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := lnrpc.NewLightningClient(conn)
|
||||
_, err = printLivePayment(stream, client, ctx.Bool(jsonFlag.Name))
|
||||
return err
|
||||
}
|
||||
|
||||
// printLivePayment receives payment updates from the given stream and either
|
||||
// outputs them as json or as a more user-friendly formatted table. The table
|
||||
// option uses terminal control codes to rewrite the output. This call
|
||||
// terminates when the payment reaches a final state.
|
||||
func printLivePayment(stream routerrpc.Router_TrackPaymentV2Client,
|
||||
client lnrpc.LightningClient, json bool) (*lnrpc.Payment, error) {
|
||||
|
||||
// Terminal escape codes aren't supported on Windows, fall back to json.
|
||||
if !json && runtime.GOOS == "windows" {
|
||||
json = true
|
||||
}
|
||||
|
||||
aliases := newAliasCache(client)
|
||||
|
||||
first := true
|
||||
var lastLineCount int
|
||||
for {
|
||||
status, err := stream.Recv()
|
||||
payment, err := stream.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
printRespJSON(status)
|
||||
if json {
|
||||
// Delimit json messages by newlines (inspired by
|
||||
// grpc over rest chunking).
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
if status.Status != lnrpc.Payment_IN_FLIGHT {
|
||||
return nil
|
||||
// Write raw json to stdout.
|
||||
printRespJSON(payment)
|
||||
} else {
|
||||
table := formatPayment(payment, aliases)
|
||||
|
||||
// Clear all previously written lines and print the
|
||||
// updated table.
|
||||
clearLines(lastLineCount)
|
||||
fmt.Print(table)
|
||||
|
||||
// Store the number of lines written for the next update
|
||||
// pass.
|
||||
lastLineCount = 0
|
||||
for _, b := range table {
|
||||
if b == '\n' {
|
||||
lastLineCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Terminate loop if payments state is final.
|
||||
if payment.Status != lnrpc.Payment_IN_FLIGHT {
|
||||
return payment, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// aliasCache allows cached retrieval of node aliases.
|
||||
type aliasCache struct {
|
||||
cache map[string]string
|
||||
client lnrpc.LightningClient
|
||||
}
|
||||
|
||||
func newAliasCache(client lnrpc.LightningClient) *aliasCache {
|
||||
return &aliasCache{
|
||||
client: client,
|
||||
cache: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// get returns a node alias either from cache or freshly requested from lnd.
|
||||
func (a *aliasCache) get(pubkey string) string {
|
||||
alias, ok := a.cache[pubkey]
|
||||
if ok {
|
||||
return alias
|
||||
}
|
||||
|
||||
// Request node info.
|
||||
resp, err := a.client.GetNodeInfo(
|
||||
context.Background(),
|
||||
&lnrpc.NodeInfoRequest{
|
||||
PubKey: pubkey,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
// If no info is available, use the
|
||||
// pubkey as identifier.
|
||||
alias = pubkey[:6]
|
||||
} else {
|
||||
alias = resp.Node.Alias
|
||||
}
|
||||
a.cache[pubkey] = alias
|
||||
|
||||
return alias
|
||||
}
|
||||
|
||||
// formatMsat formats msat amounts as fractional sats.
|
||||
func formatMsat(amt int64) string {
|
||||
return strconv.FormatFloat(float64(amt)/1000.0, 'f', -1, 64)
|
||||
}
|
||||
|
||||
// formatPayment formats the payment state as an ascii table.
|
||||
func formatPayment(payment *lnrpc.Payment, aliases *aliasCache) string {
|
||||
t := table.NewWriter()
|
||||
|
||||
// Build table header.
|
||||
t.AppendHeader(table.Row{
|
||||
"HTLC_STATE", "ATTEMPT_TIME", "RESOLVE_TIME", "RECEIVER_AMT",
|
||||
"FEE", "TIMELOCK", "CHAN_OUT", "ROUTE",
|
||||
})
|
||||
t.SetColumnConfigs([]table.ColumnConfig{
|
||||
{Name: "ATTEMPT_TIME", Align: text.AlignRight},
|
||||
{Name: "RESOLVE_TIME", Align: text.AlignRight},
|
||||
{Name: "CHAN_OUT", Align: text.AlignLeft,
|
||||
AlignHeader: text.AlignLeft},
|
||||
})
|
||||
|
||||
// Add all htlcs as rows.
|
||||
createTime := time.Unix(0, payment.CreationTimeNs)
|
||||
var totalPaid, totalFees int64
|
||||
for _, htlc := range payment.Htlcs {
|
||||
formatTime := func(timeNs int64) string {
|
||||
if timeNs == 0 {
|
||||
return "-"
|
||||
}
|
||||
resolveTime := time.Unix(0, timeNs)
|
||||
resolveTimeMs := resolveTime.Sub(createTime).
|
||||
Milliseconds()
|
||||
return fmt.Sprintf(
|
||||
"%.3f", float64(resolveTimeMs)/1000.0,
|
||||
)
|
||||
}
|
||||
|
||||
attemptTime := formatTime(htlc.AttemptTimeNs)
|
||||
resolveTime := formatTime(htlc.ResolveTimeNs)
|
||||
|
||||
route := htlc.Route
|
||||
lastHop := route.Hops[len(route.Hops)-1]
|
||||
|
||||
hops := []string{}
|
||||
for _, h := range route.Hops {
|
||||
alias := aliases.get(h.PubKey)
|
||||
hops = append(hops, alias)
|
||||
}
|
||||
|
||||
state := htlc.Status.String()
|
||||
if htlc.Failure != nil {
|
||||
state = fmt.Sprintf(
|
||||
"%v @ %v",
|
||||
htlc.Failure.Code,
|
||||
htlc.Failure.FailureSourceIndex,
|
||||
)
|
||||
}
|
||||
|
||||
t.AppendRow([]interface{}{
|
||||
state, attemptTime, resolveTime,
|
||||
formatMsat(lastHop.AmtToForwardMsat),
|
||||
formatMsat(route.TotalFeesMsat),
|
||||
route.TotalTimeLock, route.Hops[0].ChanId,
|
||||
strings.Join(hops, "->")},
|
||||
)
|
||||
|
||||
if htlc.Status == lnrpc.HTLCAttempt_SUCCEEDED {
|
||||
totalPaid += lastHop.AmtToForwardMsat
|
||||
totalFees += route.TotalFeesMsat
|
||||
}
|
||||
}
|
||||
|
||||
// Render table.
|
||||
b := &bytes.Buffer{}
|
||||
t.SetOutputMirror(b)
|
||||
t.Render()
|
||||
|
||||
// Add additional payment-level data.
|
||||
fmt.Fprintf(b, "Amount + fee: %v + %v sat\n",
|
||||
formatMsat(totalPaid), formatMsat(totalFees))
|
||||
fmt.Fprintf(b, "Payment hash: %v\n", payment.PaymentHash)
|
||||
fmt.Fprintf(b, "Payment status: %v", payment.Status)
|
||||
switch payment.Status {
|
||||
case lnrpc.Payment_SUCCEEDED:
|
||||
fmt.Fprintf(b, ", preimage: %v", payment.PaymentPreimage)
|
||||
case lnrpc.Payment_FAILED:
|
||||
fmt.Fprintf(b, ", reason: %v", payment.FailureReason)
|
||||
}
|
||||
fmt.Fprintf(b, "\n")
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
var payInvoiceCommand = cli.Command{
|
||||
Name: "payinvoice",
|
||||
Category: "Payments",
|
||||
@ -672,3 +863,15 @@ func sendToRouteRequest(ctx *cli.Context, req *lnrpc.SendToRouteRequest) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ESC is the ASCII code for escape character
|
||||
const ESC = 27
|
||||
|
||||
// clearCode defines a terminal escape code to clear the currently line and move
|
||||
// the cursor up.
|
||||
var clearCode = fmt.Sprintf("%c[%dA%c[2K", ESC, 1, ESC)
|
||||
|
||||
// clearLines erases the last count lines in the terminal window.
|
||||
func clearLines(count int) {
|
||||
_, _ = fmt.Print(strings.Repeat(clearCode, count))
|
||||
}
|
||||
|
4
go.mod
4
go.mod
@ -17,12 +17,14 @@ require (
|
||||
github.com/btcsuite/fastsha256 v0.0.0-20160815193821-637e65642941
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/go-errors/errors v1.0.1
|
||||
github.com/go-openapi/strfmt v0.19.5 // indirect
|
||||
github.com/golang/protobuf v1.3.1
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.6
|
||||
github.com/jackpal/gateway v1.0.5
|
||||
github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad
|
||||
github.com/jedib0t/go-pretty v4.3.0+incompatible
|
||||
github.com/jessevdk/go-flags v1.4.0
|
||||
github.com/jrick/logrotate v1.0.0
|
||||
github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c // indirect
|
||||
@ -40,6 +42,7 @@ require (
|
||||
github.com/lightningnetwork/lnd/queue v1.0.3
|
||||
github.com/lightningnetwork/lnd/ticker v1.0.0
|
||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8
|
||||
github.com/prometheus/client_golang v0.9.3
|
||||
github.com/rogpeppe/fastuuid v1.2.0 // indirect
|
||||
@ -47,6 +50,7 @@ require (
|
||||
github.com/urfave/cli v1.18.0
|
||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d
|
||||
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 // indirect
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2
|
||||
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922
|
||||
google.golang.org/grpc v1.19.0
|
||||
|
28
go.sum
28
go.sum
@ -15,6 +15,8 @@ github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
@ -66,6 +68,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||
github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=
|
||||
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
@ -79,6 +82,11 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY=
|
||||
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||
github.com/go-openapi/strfmt v0.19.5 h1:0utjKrw+BAh8s57XE9Xz8DUBsVvPmRUB6styvl9wWIM=
|
||||
github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
@ -90,6 +98,10 @@ github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42 h1:q3pnF5JFBNRz8sRD+IRj7Y6DMyYGTNqnZ9axTbSfoNI=
|
||||
github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
||||
@ -102,6 +114,8 @@ github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc
|
||||
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
|
||||
github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad h1:heFfj7z0pGsNCekUlsFhO2jstxO4b5iQ665LjwM5mDc=
|
||||
github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo=
|
||||
github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
@ -145,10 +159,14 @@ github.com/lightningnetwork/lightning-onion v1.0.1/go.mod h1:rigfi6Af/KqsF7Za0hO
|
||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=
|
||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY=
|
||||
github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8 h1:PRMAcldsl4mXKJeRNB/KVNz6TlbS6hk2Rs42PqgU3Ws=
|
||||
github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
@ -178,15 +196,23 @@ github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02 h1:tcJ6OjwOMvExLlzrAVZute09ocAGa7KqOON60++Gz4E=
|
||||
github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S068ZqfrO6S8HsoJq2bF3ETfTL+kt4tInY=
|
||||
github.com/urfave/cli v1.18.0 h1:m9MfmZWX7bwr9kUcs/Asr95j0IVXzGNNc+/5ku2m26Q=
|
||||
github.com/urfave/cli v1.18.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.mongodb.org/mongo-driver v1.0.3 h1:GKoji1ld3tw2aC+GX1wbr/J2fX13yNacEYoJ8Nhr0yU=
|
||||
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@ -214,6 +240,8 @@ golang.org/x/sys v0.0.0-20190209173611-3b5209105503 h1:5SvYFrOM3W8Mexn9/oA44Ji7v
|
||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
Loading…
Reference in New Issue
Block a user