diff --git a/Makefile b/Makefile index 8bf0cb847..23e5ae098 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,10 @@ build-filrewardsd: $(GOVVV) $(TXTL_BUILD_FLAGS) go build -ldflags="${GOVVV_FLAGS}" ./api/filrewardsd .PHONY: build-filrewardsd +build-sendfild: $(GOVVV) + $(TXTL_BUILD_FLAGS) go build -ldflags="${GOVVV_FLAGS}" ./api/sendfild +.PHONY: build-sendfild + build-mindexd: $(GOVVV) $(TXTL_BUILD_FLAGS) go build -ldflags="${GOVVV_FLAGS}" ./api/mindexd .PHONY: build-mindexd @@ -74,6 +78,10 @@ install-filrewardsd: $(GOVVV) $(TXTL_BUILD_FLAGS) go install -ldflags="${GOVVV_FLAGS}" ./api/filrewardsd .PHONY: install-filrewardsd +install-sendfild: $(GOVVV) + $(TXTL_BUILD_FLAGS) go install -ldflags="${GOVVV_FLAGS}" ./api/sendfild +.PHONY: install-sendfild + install-mindexd: $(GOVVV) $(TXTL_BUILD_FLAGS) go install -ldflags="${GOVVV_FLAGS}" ./api/mindexd .PHONY: install-mindexd diff --git a/api/filrewardsd/service/service.go b/api/filrewardsd/service/service.go index 1409d007c..1c2c1f3a0 100644 --- a/api/filrewardsd/service/service.go +++ b/api/filrewardsd/service/service.go @@ -162,8 +162,7 @@ func New(config Config) (*Service, error) { } // Populate caches. - opts := options.Find() - cursor, err := rewardsCol.Find(ctx, bson.M{}, opts) + cursor, err := rewardsCol.Find(ctx, bson.M{}, options.Find()) if err != nil { cancel() return nil, fmt.Errorf("querying RewardRecords to populate cache: %s", err) @@ -307,13 +306,13 @@ func (s *Service) ProcessAnalyticsEvent(ctx context.Context, req *pb.ProcessAnal func (s *Service) ListRewards(ctx context.Context, req *pb.ListRewardsRequest) (*pb.ListRewardsResponse, error) { findOpts := options.Find() if req.Limit > 0 { - findOpts.Limit = &req.Limit + findOpts = findOpts.SetLimit(req.Limit) } sort := -1 if req.Ascending { sort = 1 } - findOpts.Sort = bson.D{primitive.E{Key: "created_at", Value: sort}} + findOpts = findOpts.SetSort(bson.D{primitive.E{Key: "created_at", Value: sort}}) filter := bson.M{} if req.OrgKeyFilter != "" { filter["org_key"] = req.OrgKeyFilter @@ -480,13 +479,13 @@ func (s *Service) FinalizeClaim(ctx context.Context, req *pb.FinalizeClaimReques func (s *Service) ListClaims(ctx context.Context, req *pb.ListClaimsRequest) (*pb.ListClaimsResponse, error) { findOpts := options.Find() if req.Limit > 0 { - findOpts.Limit = &req.Limit + findOpts = findOpts.SetLimit(req.Limit) } sort := -1 if req.Ascending { sort = 1 } - findOpts.Sort = bson.D{primitive.E{Key: "created_at", Value: sort}} + findOpts = findOpts.SetSort(bson.D{primitive.E{Key: "created_at", Value: sort}}) filter := bson.M{} if req.OrgKeyFilter != "" { filter["org_key"] = req.OrgKeyFilter diff --git a/api/sendfild/Dockerfile b/api/sendfild/Dockerfile new file mode 100644 index 000000000..37460e165 --- /dev/null +++ b/api/sendfild/Dockerfile @@ -0,0 +1,74 @@ +FROM golang:1.15.5-buster +MAINTAINER Textile + +# This is (in large part) copied (with love) from +# https://hub.docker.com/r/ipfs/go-ipfs/dockerfile + +# Install deps +RUN apt-get update && apt-get install -y \ + libssl-dev \ + ca-certificates + +ENV SRC_DIR /textile + +# Download packages first so they can be cached. +COPY go.mod go.sum $SRC_DIR/ +RUN cd $SRC_DIR \ + && go mod download + +COPY . $SRC_DIR + +# Build the thing. +RUN cd $SRC_DIR \ + && TXTL_BUILD_FLAGS="CGO_ENABLED=0 GOOS=linux" make build-sendfild + +# Get su-exec, a very minimal tool for dropping privileges, +# and tini, a very minimal init daemon for containers +ENV SUEXEC_VERSION v0.2 +ENV TINI_VERSION v0.19.0 +RUN set -eux; \ + dpkgArch="$(dpkg --print-architecture)"; \ + case "${dpkgArch##*-}" in \ + "amd64" | "armhf" | "arm64") tiniArch="tini-static-$dpkgArch" ;;\ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac; \ + cd /tmp \ + && git clone https://github.com/ncopa/su-exec.git \ + && cd su-exec \ + && git checkout -q $SUEXEC_VERSION \ + && make su-exec-static \ + && cd /tmp \ + && wget -q -O tini https://github.com/krallin/tini/releases/download/$TINI_VERSION/$tiniArch \ + && chmod +x tini + +# Now comes the actual target image, which aims to be as small as possible. +FROM busybox:1.31.1-glibc +LABEL maintainer="Textile " + +# Get the textile binary, entrypoint script, and TLS CAs from the build container. +ENV SRC_DIR /textile +COPY --from=0 $SRC_DIR/sendfild /usr/local/bin/sendfild +COPY --from=0 /tmp/su-exec/su-exec-static /sbin/su-exec +COPY --from=0 /tmp/tini /sbin/tini +COPY --from=0 /etc/ssl/certs /etc/ssl/certs + +# This shared lib (part of glibc) doesn't seem to be included with busybox. +COPY --from=0 /lib/*-linux-gnu*/libdl.so.2 /lib/ + +# Copy over SSL libraries. +COPY --from=0 /usr/lib/*-linux-gnu*/libssl.so* /usr/lib/ +COPY --from=0 /usr/lib/*-linux-gnu*/libcrypto.so* /usr/lib/ + +# listenAddrs +EXPOSE 5000 + +# Create the repo directory. +ENV SENDFIL_PATH /data/sendfil +RUN mkdir -p $SENDFIL_PATH \ + && adduser -D -h $SENDFIL_PATH -u 1000 -G users sendfil \ + && chown sendfil:users $SENDFIL_PATH + +# Switch to a non-privileged user. +USER sendfil + +ENTRYPOINT ["/sbin/tini", "--", "sendfild"] diff --git a/api/sendfild/Dockerfile.dev b/api/sendfild/Dockerfile.dev new file mode 100644 index 000000000..40afc7e82 --- /dev/null +++ b/api/sendfild/Dockerfile.dev @@ -0,0 +1,35 @@ +FROM golang:1.15.5-buster + +RUN apt-get update && apt-get install -y \ + libssl-dev \ + ca-certificates + +RUN go get github.com/go-delve/delve/cmd/dlv + +ENV SRC_DIR /textile + +COPY go.mod go.sum $SRC_DIR/ +RUN cd $SRC_DIR \ + && go mod download + +COPY . $SRC_DIR + +RUN cd $SRC_DIR \ + && CGO_ENABLED=0 GOOS=linux go build -gcflags "all=-N -l" -o sendfild api/sendfild/main.go + +FROM debian:buster +LABEL maintainer="Textile " + +ENV SRC_DIR /textile +COPY --from=0 /go/bin/dlv /usr/local/bin/dlv +COPY --from=0 /etc/ssl/certs /etc/ssl/certs +COPY --from=0 $SRC_DIR/sendfild /usr/local/bin/sendfild + +EXPOSE 5000 + +ENV SENDFIL_PATH /data/sendfil +RUN adduser --home $SENDFIL_PATH --disabled-login --gecos "" --ingroup users sendfil + +USER sendfil + +ENTRYPOINT ["dlv", "--listen=0.0.0.0:40000", "--headless=true", "--accept-multiclient", "--continue", "--api-version=2", "exec", "/usr/local/bin/sendfild"] diff --git a/api/sendfild/client/client.go b/api/sendfild/client/client.go new file mode 100644 index 000000000..0e0c15494 --- /dev/null +++ b/api/sendfild/client/client.go @@ -0,0 +1,199 @@ +package client + +import ( + "context" + "fmt" + "time" + + "github.com/textileio/textile/v2/api/sendfild/pb" + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/timestamppb" +) + +type Client struct { + c pb.SendFilServiceClient + conn *grpc.ClientConn +} + +func New(target string, opts ...grpc.DialOption) (*Client, error) { + conn, err := grpc.Dial(target, opts...) + if err != nil { + return nil, fmt.Errorf("creating gRPC client conn: %v", err) + } + + c := pb.NewSendFilServiceClient(conn) + + return &Client{ + c: c, + conn: conn, + }, nil +} + +type SendFilOption = func(*pb.SendFilRequest) + +func SendFilWait() SendFilOption { + return func(req *pb.SendFilRequest) { + req.Wait = true + } +} + +func (c *Client) SendFil(ctx context.Context, from, to string, amountNanoFil int64, opts ...SendFilOption) (*pb.Txn, error) { + req := &pb.SendFilRequest{ + From: from, + To: to, + AmountNanoFil: amountNanoFil, + } + for _, opt := range opts { + opt(req) + } + res, err := c.c.SendFil(ctx, req) + if err != nil { + return nil, err + } + return res.Txn, nil +} + +type GetTxnOption = func(*pb.GetTxnRequest) + +func GetTxnWait() GetTxnOption { + return func(req *pb.GetTxnRequest) { + req.Wait = true + } +} + +func (c *Client) GetTxn(ctx context.Context, messageCid string, opts ...GetTxnOption) (*pb.Txn, error) { + req := &pb.GetTxnRequest{ + MessageCid: messageCid, + } + for _, opt := range opts { + opt(req) + } + res, err := c.c.GetTxn(ctx, req) + if err != nil { + return nil, err + } + return res.Txn, nil +} + +type ListTxnsOption = func(*pb.ListTxnsRequest) + +func ListTxnsFrom(from string) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.FromFilter = from + } +} + +func ListTxnsTo(to string) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.ToFilter = to + } +} + +func ListTxnsInvolvingAddress(involving string) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.InvolvingAddressFilter = involving + } +} + +func ListTxnsAmountNanoFilLt(amountNanoFil int64) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.AmountNanoFilLtFilter = amountNanoFil + } +} + +func ListTxnsAmountNanoFilGt(amountNanoFil int64) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.AmountNanoFilGtFilter = amountNanoFil + } +} + +func ListTxnsAmountNanoFilLteq(amountNanoFil int64) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.AmountNanoFilLteqFilter = amountNanoFil + } +} + +func ListTxnsAmountNanoFilGteq(amountNanoFil int64) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.AmountNanoFilGteqFilter = amountNanoFil + } +} + +func ListTxnsAmountNanoFilEq(amountNanoFil int64) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.AmountNanoFilEqFilter = amountNanoFil + } +} + +func ListTxnsMessageState(messageState pb.MessageState) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.MessageStateFilter = messageState + } +} + +func ListTxnsWaiting(waitingFilter pb.WaitingFilter) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.WaitingFilter = waitingFilter + } +} + +func ListTxnsCreatedAfter(time time.Time) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.CreatedAfter = timestamppb.New(time) + } +} + +func ListTxnsCreatedBefore(time time.Time) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.CreatedBefore = timestamppb.New(time) + } +} + +func ListTxnsUpdatedAfter(time time.Time) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.UpdatedAfter = timestamppb.New(time) + } +} + +func ListTxnsUpdatedBefore(time time.Time) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.UpdatedBefore = timestamppb.New(time) + } +} + +func ListTxnsAscending() ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.Ascending = true + } +} + +func ListTxnsMoreToken(moreToken int64) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.MoreToken = moreToken + } +} + +func ListTxnsLimit(limit int64) ListTxnsOption { + return func(req *pb.ListTxnsRequest) { + req.Limit = limit + } +} + +func (c *Client) ListTxns(ctx context.Context, opts ...ListTxnsOption) ([]*pb.Txn, bool, int64, error) { + req := &pb.ListTxnsRequest{} + for _, opt := range opts { + opt(req) + } + res, err := c.c.ListTxns(ctx, req) + if err != nil { + return nil, false, 0, err + } + return res.Txns, res.More, res.MoreToken, nil +} + +func (c *Client) Close() error { + if c == nil { + return nil + } + return c.conn.Close() +} diff --git a/api/sendfild/main.go b/api/sendfild/main.go new file mode 100644 index 000000000..5b9d65067 --- /dev/null +++ b/api/sendfild/main.go @@ -0,0 +1,207 @@ +package main + +import ( + "encoding/json" + "fmt" + "net" + "time" + + logging "github.com/ipfs/go-log/v2" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/textileio/go-threads/util" + "github.com/textileio/powergate/v2/lotus" + "github.com/textileio/textile/v2/api/sendfild/service" + "github.com/textileio/textile/v2/cmd" +) + +const daemonName = "sendfild" + +var ( + log = logging.Logger(daemonName) + + config = &cmd.Config{ + Viper: viper.New(), + Dir: "." + daemonName, + Name: "config", + Flags: map[string]cmd.Flag{ + "debug": { + Key: "debug", + DefValue: false, + }, + "logFile": { + Key: "log_file", + DefValue: "", // no log file + }, + "listenAddr": { + Key: "listen_addr", + DefValue: "127.0.0.1:5000", + }, + "lotusAddr": { + Key: "lotus_addr", + DefValue: "127.0.0.1:7777", + }, + "lotusAuthToken": { + Key: "lotus_auth_token", + DefValue: "", + }, + "lotusConnRetries": { + Key: "lotus_conn_retries", + DefValue: 2, + }, + "mongoUri": { + Key: "mongo_uri", + DefValue: "mongodb://127.0.0.1:27017", + }, + "mongoDb": { + Key: "mongo_db", + DefValue: "textile_sendfil", + }, + "messageWaitTimeout": { + Key: "message_wait_timeout", + DefValue: time.Minute * 5, + }, + "messageConfidence": { + Key: "message_confidence", + DefValue: uint64(5), + }, + "retryWaitFrequency": { + Key: "retry_wait_frequency", + DefValue: time.Minute, + }, + }, + EnvPre: "SENDFIL", + Global: true, + } +) + +func init() { + cobra.OnInitialize(cmd.InitConfig(config)) + cmd.InitConfigCmd(rootCmd, config.Viper, config.Dir) + + rootCmd.PersistentFlags().StringVar( + &config.File, + "config", + "", + "Config file (default ${HOME}/"+config.Dir+"/"+config.Name+".yml)") + rootCmd.PersistentFlags().BoolP( + "debug", + "d", + config.Flags["debug"].DefValue.(bool), + "Enable debug logging") + rootCmd.PersistentFlags().String( + "logFile", + config.Flags["logFile"].DefValue.(string), + "Write logs to file") + + rootCmd.PersistentFlags().String( + "listenAddr", + config.Flags["listenAddr"].DefValue.(string), + "Sendfil API listen address") + + rootCmd.PersistentFlags().String( + "lotusAddr", + config.Flags["lotusAddr"].DefValue.(string), + "Lotus API address") + rootCmd.PersistentFlags().String( + "lotusAuthToken", + config.Flags["lotusAuthToken"].DefValue.(string), + "Lotus API auth token") + rootCmd.PersistentFlags().Int( + "lotusConnRetries", + config.Flags["lotusConnRetries"].DefValue.(int), + "Lotus API connection retry count") + + rootCmd.PersistentFlags().String( + "mongoUri", + config.Flags["mongoUri"].DefValue.(string), + "MongoDB connection URI") + rootCmd.PersistentFlags().String( + "mongoDb", + config.Flags["mongoDb"].DefValue.(string), + "MongoDB database name") + + rootCmd.PersistentFlags().Duration( + "messageWaitTimeout", + config.Flags["messageWaitTimeout"].DefValue.(time.Duration), + "Timeout for listening for messages to become active on chain") + rootCmd.PersistentFlags().Uint64( + "messageConfidence", + config.Flags["messageConfidence"].DefValue.(uint64), + "Confidence, in epochs, used to consider a message active on chain") + rootCmd.PersistentFlags().Duration( + "retryWaitFrequency", + config.Flags["retryWaitFrequency"].DefValue.(time.Duration), + "Frequency with which to query for txns that need to be monitored for completion") + + err := cmd.BindFlags(config.Viper, rootCmd, config.Flags) + cmd.ErrCheck(err) +} + +func main() { + cmd.ErrCheck(rootCmd.Execute()) +} + +var rootCmd = &cobra.Command{ + Use: daemonName, + Short: "Sendfil daemon", + Long: `Textile's sendfil daemon.`, + PersistentPreRun: func(c *cobra.Command, args []string) { + config.Viper.SetConfigType("yaml") + cmd.ExpandConfigVars(config.Viper, config.Flags) + + if config.Viper.GetBool("debug") { + err := util.SetLogLevels(map[string]logging.LogLevel{ + daemonName: logging.LevelDebug, + }) + cmd.ErrCheck(err) + } + }, + Run: func(c *cobra.Command, args []string) { + settings, err := json.MarshalIndent(config.Viper.AllSettings(), "", " ") + cmd.ErrCheck(err) + log.Debugf("loaded config: %s", string(settings)) + + debug := config.Viper.GetBool("debug") + logFile := config.Viper.GetString("log_file") + listenAddr := config.Viper.GetString("listen_addr") + lotusAddr := config.Viper.GetString("lotus_addr") + lotusAuthToken := config.Viper.GetString("lotus_auth_token") + lotusConnRetries := config.Viper.GetInt("lotus_conn_retries") + mongoUri := config.Viper.GetString("mongo_uri") + mongoDb := config.Viper.GetString("mongo_db") + messageTimeout := config.Viper.GetDuration("message_timeout") + messageConfidence := config.Viper.GetUint64("message_confidence") + retryWaitFrequency := config.Viper.GetDuration("retry_wait_frequency") + + if logFile != "" { + err = cmd.SetupDefaultLoggingConfig(logFile) + cmd.ErrCheck(err) + } + + listener, err := net.Listen("tcp", listenAddr) + cmd.ErrCheck(err) + + cb, err := lotus.NewBuilder(lotusAddr, lotusAuthToken, lotusConnRetries) + cmd.ErrCheck(err) + + conf := service.Config{ + Listener: listener, + ClientBuilder: cb, + MongoUri: mongoUri, + MongoDbName: mongoDb, + MessageWaitTimeout: messageTimeout, + MessageConfidence: messageConfidence, + RetryWaitFrequency: retryWaitFrequency, + Debug: debug, + } + api, err := service.New(conf) + cmd.ErrCheck(err) + + fmt.Println("Welcome to Hub Sendfil!") + + cmd.HandleInterrupt(func() { + cmd.ErrCheck(api.Close()) + }) + }, +} diff --git a/api/sendfild/pb/sendfil.pb.go b/api/sendfild/pb/sendfil.pb.go new file mode 100644 index 000000000..01b4b01cd --- /dev/null +++ b/api/sendfild/pb/sendfil.pb.go @@ -0,0 +1,1467 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.13.0 +// source: api/sendfild/pb/sendfil.proto + +package pb + +import ( + context "context" + proto "github.com/golang/protobuf/proto" + timestamp "github.com/golang/protobuf/ptypes/timestamp" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type MessageState int32 + +const ( + MessageState_MESSAGE_STATE_UNSPECIFIED MessageState = 0 + MessageState_MESSAGE_STATE_PENDING MessageState = 1 + MessageState_MESSAGE_STATE_ACTIVE MessageState = 2 + MessageState_MESSAGE_STATE_FAILED MessageState = 3 +) + +// Enum value maps for MessageState. +var ( + MessageState_name = map[int32]string{ + 0: "MESSAGE_STATE_UNSPECIFIED", + 1: "MESSAGE_STATE_PENDING", + 2: "MESSAGE_STATE_ACTIVE", + 3: "MESSAGE_STATE_FAILED", + } + MessageState_value = map[string]int32{ + "MESSAGE_STATE_UNSPECIFIED": 0, + "MESSAGE_STATE_PENDING": 1, + "MESSAGE_STATE_ACTIVE": 2, + "MESSAGE_STATE_FAILED": 3, + } +) + +func (x MessageState) Enum() *MessageState { + p := new(MessageState) + *p = x + return p +} + +func (x MessageState) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (MessageState) Descriptor() protoreflect.EnumDescriptor { + return file_api_sendfild_pb_sendfil_proto_enumTypes[0].Descriptor() +} + +func (MessageState) Type() protoreflect.EnumType { + return &file_api_sendfild_pb_sendfil_proto_enumTypes[0] +} + +func (x MessageState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use MessageState.Descriptor instead. +func (MessageState) EnumDescriptor() ([]byte, []int) { + return file_api_sendfild_pb_sendfil_proto_rawDescGZIP(), []int{0} +} + +type WaitingFilter int32 + +const ( + WaitingFilter_WAITING_FILTER_UNSPECIFIED WaitingFilter = 0 + WaitingFilter_WAITING_FILTER_WAITING WaitingFilter = 1 + WaitingFilter_WAITING_FILTER_NOT_WAITING WaitingFilter = 2 +) + +// Enum value maps for WaitingFilter. +var ( + WaitingFilter_name = map[int32]string{ + 0: "WAITING_FILTER_UNSPECIFIED", + 1: "WAITING_FILTER_WAITING", + 2: "WAITING_FILTER_NOT_WAITING", + } + WaitingFilter_value = map[string]int32{ + "WAITING_FILTER_UNSPECIFIED": 0, + "WAITING_FILTER_WAITING": 1, + "WAITING_FILTER_NOT_WAITING": 2, + } +) + +func (x WaitingFilter) Enum() *WaitingFilter { + p := new(WaitingFilter) + *p = x + return p +} + +func (x WaitingFilter) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (WaitingFilter) Descriptor() protoreflect.EnumDescriptor { + return file_api_sendfild_pb_sendfil_proto_enumTypes[1].Descriptor() +} + +func (WaitingFilter) Type() protoreflect.EnumType { + return &file_api_sendfild_pb_sendfil_proto_enumTypes[1] +} + +func (x WaitingFilter) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use WaitingFilter.Descriptor instead. +func (WaitingFilter) EnumDescriptor() ([]byte, []int) { + return file_api_sendfild_pb_sendfil_proto_rawDescGZIP(), []int{1} +} + +type Txn struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + From string `protobuf:"bytes,2,opt,name=from,proto3" json:"from,omitempty"` + To string `protobuf:"bytes,3,opt,name=to,proto3" json:"to,omitempty"` + AmountNanoFil int64 `protobuf:"varint,4,opt,name=amount_nano_fil,json=amountNanoFil,proto3" json:"amount_nano_fil,omitempty"` + MessageCid string `protobuf:"bytes,5,opt,name=message_cid,json=messageCid,proto3" json:"message_cid,omitempty"` + MessageState MessageState `protobuf:"varint,6,opt,name=message_state,json=messageState,proto3,enum=api.sendfild.pb.MessageState" json:"message_state,omitempty"` + Waiting bool `protobuf:"varint,7,opt,name=waiting,proto3" json:"waiting,omitempty"` + FailureMsg string `protobuf:"bytes,8,opt,name=failure_msg,json=failureMsg,proto3" json:"failure_msg,omitempty"` + CreatedAt *timestamp.Timestamp `protobuf:"bytes,9,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt *timestamp.Timestamp `protobuf:"bytes,10,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` +} + +func (x *Txn) Reset() { + *x = Txn{} + if protoimpl.UnsafeEnabled { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Txn) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Txn) ProtoMessage() {} + +func (x *Txn) ProtoReflect() protoreflect.Message { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Txn.ProtoReflect.Descriptor instead. +func (*Txn) Descriptor() ([]byte, []int) { + return file_api_sendfild_pb_sendfil_proto_rawDescGZIP(), []int{0} +} + +func (x *Txn) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Txn) GetFrom() string { + if x != nil { + return x.From + } + return "" +} + +func (x *Txn) GetTo() string { + if x != nil { + return x.To + } + return "" +} + +func (x *Txn) GetAmountNanoFil() int64 { + if x != nil { + return x.AmountNanoFil + } + return 0 +} + +func (x *Txn) GetMessageCid() string { + if x != nil { + return x.MessageCid + } + return "" +} + +func (x *Txn) GetMessageState() MessageState { + if x != nil { + return x.MessageState + } + return MessageState_MESSAGE_STATE_UNSPECIFIED +} + +func (x *Txn) GetWaiting() bool { + if x != nil { + return x.Waiting + } + return false +} + +func (x *Txn) GetFailureMsg() string { + if x != nil { + return x.FailureMsg + } + return "" +} + +func (x *Txn) GetCreatedAt() *timestamp.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *Txn) GetUpdatedAt() *timestamp.Timestamp { + if x != nil { + return x.UpdatedAt + } + return nil +} + +type SendFilRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + From string `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` + To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` + AmountNanoFil int64 `protobuf:"varint,3,opt,name=amount_nano_fil,json=amountNanoFil,proto3" json:"amount_nano_fil,omitempty"` + Wait bool `protobuf:"varint,4,opt,name=wait,proto3" json:"wait,omitempty"` +} + +func (x *SendFilRequest) Reset() { + *x = SendFilRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendFilRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendFilRequest) ProtoMessage() {} + +func (x *SendFilRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendFilRequest.ProtoReflect.Descriptor instead. +func (*SendFilRequest) Descriptor() ([]byte, []int) { + return file_api_sendfild_pb_sendfil_proto_rawDescGZIP(), []int{1} +} + +func (x *SendFilRequest) GetFrom() string { + if x != nil { + return x.From + } + return "" +} + +func (x *SendFilRequest) GetTo() string { + if x != nil { + return x.To + } + return "" +} + +func (x *SendFilRequest) GetAmountNanoFil() int64 { + if x != nil { + return x.AmountNanoFil + } + return 0 +} + +func (x *SendFilRequest) GetWait() bool { + if x != nil { + return x.Wait + } + return false +} + +type SendFilResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Txn *Txn `protobuf:"bytes,1,opt,name=txn,proto3" json:"txn,omitempty"` +} + +func (x *SendFilResponse) Reset() { + *x = SendFilResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendFilResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendFilResponse) ProtoMessage() {} + +func (x *SendFilResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendFilResponse.ProtoReflect.Descriptor instead. +func (*SendFilResponse) Descriptor() ([]byte, []int) { + return file_api_sendfild_pb_sendfil_proto_rawDescGZIP(), []int{2} +} + +func (x *SendFilResponse) GetTxn() *Txn { + if x != nil { + return x.Txn + } + return nil +} + +type GetTxnRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MessageCid string `protobuf:"bytes,1,opt,name=message_cid,json=messageCid,proto3" json:"message_cid,omitempty"` + Wait bool `protobuf:"varint,2,opt,name=wait,proto3" json:"wait,omitempty"` +} + +func (x *GetTxnRequest) Reset() { + *x = GetTxnRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTxnRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTxnRequest) ProtoMessage() {} + +func (x *GetTxnRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTxnRequest.ProtoReflect.Descriptor instead. +func (*GetTxnRequest) Descriptor() ([]byte, []int) { + return file_api_sendfild_pb_sendfil_proto_rawDescGZIP(), []int{3} +} + +func (x *GetTxnRequest) GetMessageCid() string { + if x != nil { + return x.MessageCid + } + return "" +} + +func (x *GetTxnRequest) GetWait() bool { + if x != nil { + return x.Wait + } + return false +} + +type GetTxnResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Txn *Txn `protobuf:"bytes,1,opt,name=txn,proto3" json:"txn,omitempty"` +} + +func (x *GetTxnResponse) Reset() { + *x = GetTxnResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTxnResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTxnResponse) ProtoMessage() {} + +func (x *GetTxnResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTxnResponse.ProtoReflect.Descriptor instead. +func (*GetTxnResponse) Descriptor() ([]byte, []int) { + return file_api_sendfild_pb_sendfil_proto_rawDescGZIP(), []int{4} +} + +func (x *GetTxnResponse) GetTxn() *Txn { + if x != nil { + return x.Txn + } + return nil +} + +type ListTxnsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FromFilter string `protobuf:"bytes,1,opt,name=from_filter,json=fromFilter,proto3" json:"from_filter,omitempty"` + ToFilter string `protobuf:"bytes,2,opt,name=to_filter,json=toFilter,proto3" json:"to_filter,omitempty"` + InvolvingAddressFilter string `protobuf:"bytes,3,opt,name=involving_address_filter,json=involvingAddressFilter,proto3" json:"involving_address_filter,omitempty"` + AmountNanoFilLtFilter int64 `protobuf:"varint,4,opt,name=amount_nano_fil_lt_filter,json=amountNanoFilLtFilter,proto3" json:"amount_nano_fil_lt_filter,omitempty"` + AmountNanoFilGtFilter int64 `protobuf:"varint,5,opt,name=amount_nano_fil_gt_filter,json=amountNanoFilGtFilter,proto3" json:"amount_nano_fil_gt_filter,omitempty"` + AmountNanoFilLteqFilter int64 `protobuf:"varint,6,opt,name=amount_nano_fil_lteq_filter,json=amountNanoFilLteqFilter,proto3" json:"amount_nano_fil_lteq_filter,omitempty"` + AmountNanoFilGteqFilter int64 `protobuf:"varint,7,opt,name=amount_nano_fil_gteq_filter,json=amountNanoFilGteqFilter,proto3" json:"amount_nano_fil_gteq_filter,omitempty"` + AmountNanoFilEqFilter int64 `protobuf:"varint,8,opt,name=amount_nano_fil_eq_filter,json=amountNanoFilEqFilter,proto3" json:"amount_nano_fil_eq_filter,omitempty"` + MessageStateFilter MessageState `protobuf:"varint,9,opt,name=message_state_filter,json=messageStateFilter,proto3,enum=api.sendfild.pb.MessageState" json:"message_state_filter,omitempty"` + WaitingFilter WaitingFilter `protobuf:"varint,10,opt,name=waiting_filter,json=waitingFilter,proto3,enum=api.sendfild.pb.WaitingFilter" json:"waiting_filter,omitempty"` + CreatedBefore *timestamp.Timestamp `protobuf:"bytes,11,opt,name=created_before,json=createdBefore,proto3" json:"created_before,omitempty"` + CreatedAfter *timestamp.Timestamp `protobuf:"bytes,12,opt,name=created_after,json=createdAfter,proto3" json:"created_after,omitempty"` + UpdatedBefore *timestamp.Timestamp `protobuf:"bytes,13,opt,name=updated_before,json=updatedBefore,proto3" json:"updated_before,omitempty"` + UpdatedAfter *timestamp.Timestamp `protobuf:"bytes,14,opt,name=updated_after,json=updatedAfter,proto3" json:"updated_after,omitempty"` + Ascending bool `protobuf:"varint,15,opt,name=ascending,proto3" json:"ascending,omitempty"` + MoreToken int64 `protobuf:"varint,16,opt,name=more_token,json=moreToken,proto3" json:"more_token,omitempty"` + Limit int64 `protobuf:"varint,17,opt,name=limit,proto3" json:"limit,omitempty"` +} + +func (x *ListTxnsRequest) Reset() { + *x = ListTxnsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListTxnsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListTxnsRequest) ProtoMessage() {} + +func (x *ListTxnsRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListTxnsRequest.ProtoReflect.Descriptor instead. +func (*ListTxnsRequest) Descriptor() ([]byte, []int) { + return file_api_sendfild_pb_sendfil_proto_rawDescGZIP(), []int{5} +} + +func (x *ListTxnsRequest) GetFromFilter() string { + if x != nil { + return x.FromFilter + } + return "" +} + +func (x *ListTxnsRequest) GetToFilter() string { + if x != nil { + return x.ToFilter + } + return "" +} + +func (x *ListTxnsRequest) GetInvolvingAddressFilter() string { + if x != nil { + return x.InvolvingAddressFilter + } + return "" +} + +func (x *ListTxnsRequest) GetAmountNanoFilLtFilter() int64 { + if x != nil { + return x.AmountNanoFilLtFilter + } + return 0 +} + +func (x *ListTxnsRequest) GetAmountNanoFilGtFilter() int64 { + if x != nil { + return x.AmountNanoFilGtFilter + } + return 0 +} + +func (x *ListTxnsRequest) GetAmountNanoFilLteqFilter() int64 { + if x != nil { + return x.AmountNanoFilLteqFilter + } + return 0 +} + +func (x *ListTxnsRequest) GetAmountNanoFilGteqFilter() int64 { + if x != nil { + return x.AmountNanoFilGteqFilter + } + return 0 +} + +func (x *ListTxnsRequest) GetAmountNanoFilEqFilter() int64 { + if x != nil { + return x.AmountNanoFilEqFilter + } + return 0 +} + +func (x *ListTxnsRequest) GetMessageStateFilter() MessageState { + if x != nil { + return x.MessageStateFilter + } + return MessageState_MESSAGE_STATE_UNSPECIFIED +} + +func (x *ListTxnsRequest) GetWaitingFilter() WaitingFilter { + if x != nil { + return x.WaitingFilter + } + return WaitingFilter_WAITING_FILTER_UNSPECIFIED +} + +func (x *ListTxnsRequest) GetCreatedBefore() *timestamp.Timestamp { + if x != nil { + return x.CreatedBefore + } + return nil +} + +func (x *ListTxnsRequest) GetCreatedAfter() *timestamp.Timestamp { + if x != nil { + return x.CreatedAfter + } + return nil +} + +func (x *ListTxnsRequest) GetUpdatedBefore() *timestamp.Timestamp { + if x != nil { + return x.UpdatedBefore + } + return nil +} + +func (x *ListTxnsRequest) GetUpdatedAfter() *timestamp.Timestamp { + if x != nil { + return x.UpdatedAfter + } + return nil +} + +func (x *ListTxnsRequest) GetAscending() bool { + if x != nil { + return x.Ascending + } + return false +} + +func (x *ListTxnsRequest) GetMoreToken() int64 { + if x != nil { + return x.MoreToken + } + return 0 +} + +func (x *ListTxnsRequest) GetLimit() int64 { + if x != nil { + return x.Limit + } + return 0 +} + +type ListTxnsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Txns []*Txn `protobuf:"bytes,1,rep,name=txns,proto3" json:"txns,omitempty"` + More bool `protobuf:"varint,2,opt,name=more,proto3" json:"more,omitempty"` + MoreToken int64 `protobuf:"varint,3,opt,name=more_token,json=moreToken,proto3" json:"more_token,omitempty"` +} + +func (x *ListTxnsResponse) Reset() { + *x = ListTxnsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListTxnsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListTxnsResponse) ProtoMessage() {} + +func (x *ListTxnsResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListTxnsResponse.ProtoReflect.Descriptor instead. +func (*ListTxnsResponse) Descriptor() ([]byte, []int) { + return file_api_sendfild_pb_sendfil_proto_rawDescGZIP(), []int{6} +} + +func (x *ListTxnsResponse) GetTxns() []*Txn { + if x != nil { + return x.Txns + } + return nil +} + +func (x *ListTxnsResponse) GetMore() bool { + if x != nil { + return x.More + } + return false +} + +func (x *ListTxnsResponse) GetMoreToken() int64 { + if x != nil { + return x.MoreToken + } + return 0 +} + +type SummaryRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + After *timestamp.Timestamp `protobuf:"bytes,1,opt,name=after,proto3" json:"after,omitempty"` + Before *timestamp.Timestamp `protobuf:"bytes,2,opt,name=before,proto3" json:"before,omitempty"` +} + +func (x *SummaryRequest) Reset() { + *x = SummaryRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SummaryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SummaryRequest) ProtoMessage() {} + +func (x *SummaryRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SummaryRequest.ProtoReflect.Descriptor instead. +func (*SummaryRequest) Descriptor() ([]byte, []int) { + return file_api_sendfild_pb_sendfil_proto_rawDescGZIP(), []int{7} +} + +func (x *SummaryRequest) GetAfter() *timestamp.Timestamp { + if x != nil { + return x.After + } + return nil +} + +func (x *SummaryRequest) GetBefore() *timestamp.Timestamp { + if x != nil { + return x.Before + } + return nil +} + +type SummaryResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CountTxns int64 `protobuf:"varint,1,opt,name=count_txns,json=countTxns,proto3" json:"count_txns,omitempty"` + CountPending int64 `protobuf:"varint,2,opt,name=count_pending,json=countPending,proto3" json:"count_pending,omitempty"` + CountActive int64 `protobuf:"varint,3,opt,name=count_active,json=countActive,proto3" json:"count_active,omitempty"` + CountFailed int64 `protobuf:"varint,4,opt,name=count_failed,json=countFailed,proto3" json:"count_failed,omitempty"` + CountWaiting int64 `protobuf:"varint,5,opt,name=count_waiting,json=countWaiting,proto3" json:"count_waiting,omitempty"` + CountFromAddrs int64 `protobuf:"varint,6,opt,name=count_from_addrs,json=countFromAddrs,proto3" json:"count_from_addrs,omitempty"` + CountToAddrs int64 `protobuf:"varint,7,opt,name=count_to_addrs,json=countToAddrs,proto3" json:"count_to_addrs,omitempty"` + TotalNanoFilSent int64 `protobuf:"varint,8,opt,name=total_nano_fil_sent,json=totalNanoFilSent,proto3" json:"total_nano_fil_sent,omitempty"` + AvgNanoFilSent float64 `protobuf:"fixed64,9,opt,name=avg_nano_fil_sent,json=avgNanoFilSent,proto3" json:"avg_nano_fil_sent,omitempty"` + MaxNanoFilSent int64 `protobuf:"varint,10,opt,name=max_nano_fil_sent,json=maxNanoFilSent,proto3" json:"max_nano_fil_sent,omitempty"` + MinNanoFilSent int64 `protobuf:"varint,11,opt,name=min_nano_fil_sent,json=minNanoFilSent,proto3" json:"min_nano_fil_sent,omitempty"` +} + +func (x *SummaryResponse) Reset() { + *x = SummaryResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SummaryResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SummaryResponse) ProtoMessage() {} + +func (x *SummaryResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_sendfild_pb_sendfil_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SummaryResponse.ProtoReflect.Descriptor instead. +func (*SummaryResponse) Descriptor() ([]byte, []int) { + return file_api_sendfild_pb_sendfil_proto_rawDescGZIP(), []int{8} +} + +func (x *SummaryResponse) GetCountTxns() int64 { + if x != nil { + return x.CountTxns + } + return 0 +} + +func (x *SummaryResponse) GetCountPending() int64 { + if x != nil { + return x.CountPending + } + return 0 +} + +func (x *SummaryResponse) GetCountActive() int64 { + if x != nil { + return x.CountActive + } + return 0 +} + +func (x *SummaryResponse) GetCountFailed() int64 { + if x != nil { + return x.CountFailed + } + return 0 +} + +func (x *SummaryResponse) GetCountWaiting() int64 { + if x != nil { + return x.CountWaiting + } + return 0 +} + +func (x *SummaryResponse) GetCountFromAddrs() int64 { + if x != nil { + return x.CountFromAddrs + } + return 0 +} + +func (x *SummaryResponse) GetCountToAddrs() int64 { + if x != nil { + return x.CountToAddrs + } + return 0 +} + +func (x *SummaryResponse) GetTotalNanoFilSent() int64 { + if x != nil { + return x.TotalNanoFilSent + } + return 0 +} + +func (x *SummaryResponse) GetAvgNanoFilSent() float64 { + if x != nil { + return x.AvgNanoFilSent + } + return 0 +} + +func (x *SummaryResponse) GetMaxNanoFilSent() int64 { + if x != nil { + return x.MaxNanoFilSent + } + return 0 +} + +func (x *SummaryResponse) GetMinNanoFilSent() int64 { + if x != nil { + return x.MinNanoFilSent + } + return 0 +} + +var File_api_sendfild_pb_sendfil_proto protoreflect.FileDescriptor + +var file_api_sendfild_pb_sendfil_proto_rawDesc = []byte{ + 0x0a, 0x1d, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x6e, 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2f, 0x70, + 0x62, 0x2f, 0x73, 0x65, 0x6e, 0x64, 0x66, 0x69, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x0f, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, + 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0xf7, 0x02, 0x0a, 0x03, 0x54, 0x78, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, + 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, + 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x26, 0x0a, + 0x0f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x5f, 0x66, 0x69, 0x6c, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, + 0x6e, 0x6f, 0x46, 0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x63, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x43, 0x69, 0x64, 0x12, 0x42, 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x77, 0x61, + 0x69, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x77, 0x61, 0x69, + 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, + 0x6d, 0x73, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x61, 0x69, 0x6c, 0x75, + 0x72, 0x65, 0x4d, 0x73, 0x67, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x70, 0x0a, 0x0e, 0x53, + 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, + 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, + 0x6f, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, + 0x5f, 0x66, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x46, 0x69, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x61, 0x69, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x77, 0x61, 0x69, 0x74, 0x22, 0x39, 0x0a, + 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x26, 0x0a, 0x03, 0x74, 0x78, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, + 0x54, 0x78, 0x6e, 0x52, 0x03, 0x74, 0x78, 0x6e, 0x22, 0x44, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x54, + 0x78, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x61, + 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x77, 0x61, 0x69, 0x74, 0x22, 0x38, + 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x54, 0x78, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x26, 0x0a, 0x03, 0x74, 0x78, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, + 0x54, 0x78, 0x6e, 0x52, 0x03, 0x74, 0x78, 0x6e, 0x22, 0xa6, 0x07, 0x0a, 0x0f, 0x4c, 0x69, 0x73, + 0x74, 0x54, 0x78, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, + 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x66, 0x72, 0x6f, 0x6d, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1b, 0x0a, + 0x09, 0x74, 0x6f, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x74, 0x6f, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x18, 0x69, 0x6e, + 0x76, 0x6f, 0x6c, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x69, 0x6e, + 0x76, 0x6f, 0x6c, 0x76, 0x69, 0x6e, 0x67, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x19, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, + 0x61, 0x6e, 0x6f, 0x5f, 0x66, 0x69, 0x6c, 0x5f, 0x6c, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x4e, + 0x61, 0x6e, 0x6f, 0x46, 0x69, 0x6c, 0x4c, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x38, + 0x0a, 0x19, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x5f, 0x66, 0x69, + 0x6c, 0x5f, 0x67, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x15, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x46, 0x69, 0x6c, + 0x47, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x3c, 0x0a, 0x1b, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x5f, 0x66, 0x69, 0x6c, 0x5f, 0x6c, 0x74, 0x65, 0x71, + 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x17, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x46, 0x69, 0x6c, 0x4c, 0x74, 0x65, 0x71, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x3c, 0x0a, 0x1b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x5f, 0x66, 0x69, 0x6c, 0x5f, 0x67, 0x74, 0x65, 0x71, 0x5f, 0x66, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x17, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x46, 0x69, 0x6c, 0x47, 0x74, 0x65, 0x71, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x19, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, + 0x61, 0x6e, 0x6f, 0x5f, 0x66, 0x69, 0x6c, 0x5f, 0x65, 0x71, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x4e, + 0x61, 0x6e, 0x6f, 0x46, 0x69, 0x6c, 0x45, 0x71, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x4f, + 0x0a, 0x14, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x12, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, + 0x45, 0x0a, 0x0e, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, + 0x6e, 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, + 0x67, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0d, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, + 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0e, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x3f, 0x0a, + 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x0e, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x1c, + 0x0a, 0x09, 0x61, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x0f, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x09, 0x61, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x1d, 0x0a, 0x0a, + 0x6d, 0x6f, 0x72, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x09, 0x6d, 0x6f, 0x72, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x22, 0x6f, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x78, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x04, 0x74, 0x78, 0x6e, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x66, 0x69, + 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x78, 0x6e, 0x52, 0x04, 0x74, 0x78, 0x6e, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x6d, + 0x6f, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x72, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6d, 0x6f, 0x72, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x22, 0x76, 0x0a, 0x0e, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x05, 0x61, 0x66, 0x74, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x06, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x06, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x22, 0xc0, 0x03, 0x0a, 0x0f, 0x53, + 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, + 0x0a, 0x0a, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x78, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x78, 0x6e, 0x73, 0x12, 0x23, 0x0a, + 0x0d, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x66, + 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x5f, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x0a, + 0x10, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x46, 0x72, + 0x6f, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x5f, 0x74, 0x6f, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12, 0x2d, 0x0a, + 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x5f, 0x66, 0x69, 0x6c, 0x5f, + 0x73, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x4e, 0x61, 0x6e, 0x6f, 0x46, 0x69, 0x6c, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x11, + 0x61, 0x76, 0x67, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x5f, 0x66, 0x69, 0x6c, 0x5f, 0x73, 0x65, 0x6e, + 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0e, 0x61, 0x76, 0x67, 0x4e, 0x61, 0x6e, 0x6f, + 0x46, 0x69, 0x6c, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x6e, + 0x61, 0x6e, 0x6f, 0x5f, 0x66, 0x69, 0x6c, 0x5f, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x46, 0x69, 0x6c, 0x53, 0x65, + 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x5f, 0x66, + 0x69, 0x6c, 0x5f, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6d, + 0x69, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x46, 0x69, 0x6c, 0x53, 0x65, 0x6e, 0x74, 0x2a, 0x7c, 0x0a, + 0x0c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, + 0x19, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, + 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, + 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, + 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x45, 0x53, 0x53, 0x41, + 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, + 0x02, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x6b, 0x0a, 0x0d, 0x57, + 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x1a, + 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x46, 0x49, 0x4c, 0x54, 0x45, 0x52, 0x5f, 0x55, + 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, + 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x46, 0x49, 0x4c, 0x54, 0x45, 0x52, 0x5f, 0x57, + 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1e, 0x0a, 0x1a, 0x57, 0x41, 0x49, 0x54, + 0x49, 0x4e, 0x47, 0x5f, 0x46, 0x49, 0x4c, 0x54, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x57, + 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x32, 0xd0, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x6e, + 0x64, 0x46, 0x69, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4e, 0x0a, 0x07, 0x53, + 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, + 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x69, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, + 0x6e, 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x46, 0x69, + 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x06, 0x47, + 0x65, 0x74, 0x54, 0x78, 0x6e, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, 0x64, + 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x78, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, 0x64, + 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x78, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, + 0x54, 0x78, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x66, + 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x78, 0x6e, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, + 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x78, 0x6e, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x07, 0x53, + 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x6e, + 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, + 0x6e, 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x69, 0x6c, + 0x65, 0x69, 0x6f, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x69, 0x6c, 0x65, 0x2f, 0x76, 0x32, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x73, 0x65, 0x6e, 0x64, 0x66, 0x69, 0x6c, 0x64, 0x2f, 0x70, 0x62, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_api_sendfild_pb_sendfil_proto_rawDescOnce sync.Once + file_api_sendfild_pb_sendfil_proto_rawDescData = file_api_sendfild_pb_sendfil_proto_rawDesc +) + +func file_api_sendfild_pb_sendfil_proto_rawDescGZIP() []byte { + file_api_sendfild_pb_sendfil_proto_rawDescOnce.Do(func() { + file_api_sendfild_pb_sendfil_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_sendfild_pb_sendfil_proto_rawDescData) + }) + return file_api_sendfild_pb_sendfil_proto_rawDescData +} + +var file_api_sendfild_pb_sendfil_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_api_sendfild_pb_sendfil_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_api_sendfild_pb_sendfil_proto_goTypes = []interface{}{ + (MessageState)(0), // 0: api.sendfild.pb.MessageState + (WaitingFilter)(0), // 1: api.sendfild.pb.WaitingFilter + (*Txn)(nil), // 2: api.sendfild.pb.Txn + (*SendFilRequest)(nil), // 3: api.sendfild.pb.SendFilRequest + (*SendFilResponse)(nil), // 4: api.sendfild.pb.SendFilResponse + (*GetTxnRequest)(nil), // 5: api.sendfild.pb.GetTxnRequest + (*GetTxnResponse)(nil), // 6: api.sendfild.pb.GetTxnResponse + (*ListTxnsRequest)(nil), // 7: api.sendfild.pb.ListTxnsRequest + (*ListTxnsResponse)(nil), // 8: api.sendfild.pb.ListTxnsResponse + (*SummaryRequest)(nil), // 9: api.sendfild.pb.SummaryRequest + (*SummaryResponse)(nil), // 10: api.sendfild.pb.SummaryResponse + (*timestamp.Timestamp)(nil), // 11: google.protobuf.Timestamp +} +var file_api_sendfild_pb_sendfil_proto_depIdxs = []int32{ + 0, // 0: api.sendfild.pb.Txn.message_state:type_name -> api.sendfild.pb.MessageState + 11, // 1: api.sendfild.pb.Txn.created_at:type_name -> google.protobuf.Timestamp + 11, // 2: api.sendfild.pb.Txn.updated_at:type_name -> google.protobuf.Timestamp + 2, // 3: api.sendfild.pb.SendFilResponse.txn:type_name -> api.sendfild.pb.Txn + 2, // 4: api.sendfild.pb.GetTxnResponse.txn:type_name -> api.sendfild.pb.Txn + 0, // 5: api.sendfild.pb.ListTxnsRequest.message_state_filter:type_name -> api.sendfild.pb.MessageState + 1, // 6: api.sendfild.pb.ListTxnsRequest.waiting_filter:type_name -> api.sendfild.pb.WaitingFilter + 11, // 7: api.sendfild.pb.ListTxnsRequest.created_before:type_name -> google.protobuf.Timestamp + 11, // 8: api.sendfild.pb.ListTxnsRequest.created_after:type_name -> google.protobuf.Timestamp + 11, // 9: api.sendfild.pb.ListTxnsRequest.updated_before:type_name -> google.protobuf.Timestamp + 11, // 10: api.sendfild.pb.ListTxnsRequest.updated_after:type_name -> google.protobuf.Timestamp + 2, // 11: api.sendfild.pb.ListTxnsResponse.txns:type_name -> api.sendfild.pb.Txn + 11, // 12: api.sendfild.pb.SummaryRequest.after:type_name -> google.protobuf.Timestamp + 11, // 13: api.sendfild.pb.SummaryRequest.before:type_name -> google.protobuf.Timestamp + 3, // 14: api.sendfild.pb.SendFilService.SendFil:input_type -> api.sendfild.pb.SendFilRequest + 5, // 15: api.sendfild.pb.SendFilService.GetTxn:input_type -> api.sendfild.pb.GetTxnRequest + 7, // 16: api.sendfild.pb.SendFilService.ListTxns:input_type -> api.sendfild.pb.ListTxnsRequest + 9, // 17: api.sendfild.pb.SendFilService.Summary:input_type -> api.sendfild.pb.SummaryRequest + 4, // 18: api.sendfild.pb.SendFilService.SendFil:output_type -> api.sendfild.pb.SendFilResponse + 6, // 19: api.sendfild.pb.SendFilService.GetTxn:output_type -> api.sendfild.pb.GetTxnResponse + 8, // 20: api.sendfild.pb.SendFilService.ListTxns:output_type -> api.sendfild.pb.ListTxnsResponse + 10, // 21: api.sendfild.pb.SendFilService.Summary:output_type -> api.sendfild.pb.SummaryResponse + 18, // [18:22] is the sub-list for method output_type + 14, // [14:18] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name +} + +func init() { file_api_sendfild_pb_sendfil_proto_init() } +func file_api_sendfild_pb_sendfil_proto_init() { + if File_api_sendfild_pb_sendfil_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_api_sendfild_pb_sendfil_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Txn); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_sendfild_pb_sendfil_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendFilRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_sendfild_pb_sendfil_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendFilResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_sendfild_pb_sendfil_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetTxnRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_sendfild_pb_sendfil_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetTxnResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_sendfild_pb_sendfil_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListTxnsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_sendfild_pb_sendfil_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListTxnsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_sendfild_pb_sendfil_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SummaryRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_sendfild_pb_sendfil_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SummaryResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_api_sendfild_pb_sendfil_proto_rawDesc, + NumEnums: 2, + NumMessages: 9, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_api_sendfild_pb_sendfil_proto_goTypes, + DependencyIndexes: file_api_sendfild_pb_sendfil_proto_depIdxs, + EnumInfos: file_api_sendfild_pb_sendfil_proto_enumTypes, + MessageInfos: file_api_sendfild_pb_sendfil_proto_msgTypes, + }.Build() + File_api_sendfild_pb_sendfil_proto = out.File + file_api_sendfild_pb_sendfil_proto_rawDesc = nil + file_api_sendfild_pb_sendfil_proto_goTypes = nil + file_api_sendfild_pb_sendfil_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// SendFilServiceClient is the client API for SendFilService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type SendFilServiceClient interface { + SendFil(ctx context.Context, in *SendFilRequest, opts ...grpc.CallOption) (*SendFilResponse, error) + GetTxn(ctx context.Context, in *GetTxnRequest, opts ...grpc.CallOption) (*GetTxnResponse, error) + ListTxns(ctx context.Context, in *ListTxnsRequest, opts ...grpc.CallOption) (*ListTxnsResponse, error) + Summary(ctx context.Context, in *SummaryRequest, opts ...grpc.CallOption) (*SummaryResponse, error) +} + +type sendFilServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewSendFilServiceClient(cc grpc.ClientConnInterface) SendFilServiceClient { + return &sendFilServiceClient{cc} +} + +func (c *sendFilServiceClient) SendFil(ctx context.Context, in *SendFilRequest, opts ...grpc.CallOption) (*SendFilResponse, error) { + out := new(SendFilResponse) + err := c.cc.Invoke(ctx, "/api.sendfild.pb.SendFilService/SendFil", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sendFilServiceClient) GetTxn(ctx context.Context, in *GetTxnRequest, opts ...grpc.CallOption) (*GetTxnResponse, error) { + out := new(GetTxnResponse) + err := c.cc.Invoke(ctx, "/api.sendfild.pb.SendFilService/GetTxn", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sendFilServiceClient) ListTxns(ctx context.Context, in *ListTxnsRequest, opts ...grpc.CallOption) (*ListTxnsResponse, error) { + out := new(ListTxnsResponse) + err := c.cc.Invoke(ctx, "/api.sendfild.pb.SendFilService/ListTxns", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sendFilServiceClient) Summary(ctx context.Context, in *SummaryRequest, opts ...grpc.CallOption) (*SummaryResponse, error) { + out := new(SummaryResponse) + err := c.cc.Invoke(ctx, "/api.sendfild.pb.SendFilService/Summary", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SendFilServiceServer is the server API for SendFilService service. +type SendFilServiceServer interface { + SendFil(context.Context, *SendFilRequest) (*SendFilResponse, error) + GetTxn(context.Context, *GetTxnRequest) (*GetTxnResponse, error) + ListTxns(context.Context, *ListTxnsRequest) (*ListTxnsResponse, error) + Summary(context.Context, *SummaryRequest) (*SummaryResponse, error) +} + +// UnimplementedSendFilServiceServer can be embedded to have forward compatible implementations. +type UnimplementedSendFilServiceServer struct { +} + +func (*UnimplementedSendFilServiceServer) SendFil(context.Context, *SendFilRequest) (*SendFilResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendFil not implemented") +} +func (*UnimplementedSendFilServiceServer) GetTxn(context.Context, *GetTxnRequest) (*GetTxnResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTxn not implemented") +} +func (*UnimplementedSendFilServiceServer) ListTxns(context.Context, *ListTxnsRequest) (*ListTxnsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListTxns not implemented") +} +func (*UnimplementedSendFilServiceServer) Summary(context.Context, *SummaryRequest) (*SummaryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Summary not implemented") +} + +func RegisterSendFilServiceServer(s *grpc.Server, srv SendFilServiceServer) { + s.RegisterService(&_SendFilService_serviceDesc, srv) +} + +func _SendFilService_SendFil_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SendFilRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SendFilServiceServer).SendFil(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.sendfild.pb.SendFilService/SendFil", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SendFilServiceServer).SendFil(ctx, req.(*SendFilRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _SendFilService_GetTxn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTxnRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SendFilServiceServer).GetTxn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.sendfild.pb.SendFilService/GetTxn", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SendFilServiceServer).GetTxn(ctx, req.(*GetTxnRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _SendFilService_ListTxns_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListTxnsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SendFilServiceServer).ListTxns(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.sendfild.pb.SendFilService/ListTxns", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SendFilServiceServer).ListTxns(ctx, req.(*ListTxnsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _SendFilService_Summary_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SummaryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SendFilServiceServer).Summary(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.sendfild.pb.SendFilService/Summary", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SendFilServiceServer).Summary(ctx, req.(*SummaryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _SendFilService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "api.sendfild.pb.SendFilService", + HandlerType: (*SendFilServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SendFil", + Handler: _SendFilService_SendFil_Handler, + }, + { + MethodName: "GetTxn", + Handler: _SendFilService_GetTxn_Handler, + }, + { + MethodName: "ListTxns", + Handler: _SendFilService_ListTxns_Handler, + }, + { + MethodName: "Summary", + Handler: _SendFilService_Summary_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "api/sendfild/pb/sendfil.proto", +} diff --git a/api/sendfild/pb/sendfil.proto b/api/sendfild/pb/sendfil.proto new file mode 100644 index 000000000..6e432be10 --- /dev/null +++ b/api/sendfild/pb/sendfil.proto @@ -0,0 +1,103 @@ +syntax = "proto3"; +package api.sendfild.pb; +option go_package = "github.com/textileio/textile/v2/api/sendfild/pb"; + +import "google/protobuf/timestamp.proto"; + +enum MessageState { + MESSAGE_STATE_UNSPECIFIED = 0; + MESSAGE_STATE_PENDING = 1; + MESSAGE_STATE_ACTIVE = 2; + MESSAGE_STATE_FAILED = 3; +} + +enum WaitingFilter { + WAITING_FILTER_UNSPECIFIED = 0; + WAITING_FILTER_WAITING = 1; + WAITING_FILTER_NOT_WAITING = 2; +} + +message Txn { + string id = 1; + string from = 2; + string to = 3; + int64 amount_nano_fil = 4; + string message_cid = 5; + MessageState message_state = 6; + bool waiting = 7; + string failure_msg = 8; + google.protobuf.Timestamp created_at = 9; + google.protobuf.Timestamp updated_at = 10; +} + +message SendFilRequest { + string from = 1; + string to = 2; + int64 amount_nano_fil = 3; + bool wait = 4; +} + +message SendFilResponse { + Txn txn = 1; +} + +message GetTxnRequest { + string message_cid = 1; + bool wait = 2; +} + +message GetTxnResponse { + Txn txn = 1; +} + +message ListTxnsRequest { + string from_filter = 1; + string to_filter = 2; + string involving_address_filter = 3; + int64 amount_nano_fil_lt_filter = 4; + int64 amount_nano_fil_gt_filter = 5; + int64 amount_nano_fil_lteq_filter = 6; + int64 amount_nano_fil_gteq_filter = 7; + int64 amount_nano_fil_eq_filter = 8; + MessageState message_state_filter = 9; + WaitingFilter waiting_filter = 10; + google.protobuf.Timestamp created_before = 11; + google.protobuf.Timestamp created_after = 12; + google.protobuf.Timestamp updated_before = 13; + google.protobuf.Timestamp updated_after = 14; + bool ascending = 15; + int64 more_token = 16; + int64 limit = 17; +} + +message ListTxnsResponse { + repeated Txn txns = 1; + bool more = 2; + int64 more_token = 3; +} + +message SummaryRequest { + google.protobuf.Timestamp after = 1; + google.protobuf.Timestamp before = 2; +} + +message SummaryResponse { + int64 count_txns = 1; + int64 count_pending = 2; + int64 count_active = 3; + int64 count_failed = 4; + int64 count_waiting = 5; + int64 count_from_addrs = 6; + int64 count_to_addrs = 7; + int64 total_nano_fil_sent = 8; + double avg_nano_fil_sent = 9; + int64 max_nano_fil_sent = 10; + int64 min_nano_fil_sent = 11; +} + +service SendFilService { + rpc SendFil(SendFilRequest) returns (SendFilResponse) {} + rpc GetTxn(GetTxnRequest) returns (GetTxnResponse) {} + rpc ListTxns(ListTxnsRequest) returns (ListTxnsResponse) {} + rpc Summary(SummaryRequest) returns (SummaryResponse) {} +} \ No newline at end of file diff --git a/api/sendfild/service/service.go b/api/sendfild/service/service.go new file mode 100644 index 000000000..2468b99ee --- /dev/null +++ b/api/sendfild/service/service.go @@ -0,0 +1,732 @@ +package service + +import ( + "context" + "errors" + "fmt" + "math" + "math/big" + "net" + "strings" + "sync" + "time" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" + "github.com/textileio/go-threads/util" + "github.com/textileio/powergate/v2/lotus" + pb "github.com/textileio/textile/v2/api/sendfild/pb" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" +) + +const ( + collectionName = "sendfil" +) + +var _ pb.SendFilServiceServer = (*Service)(nil) + +var log = logging.Logger("sendfil") + +type msgCid struct { + Cid string `bson:"cid"` + CreatedAt time.Time `bson:"created_at"` +} + +type txn struct { + ID primitive.ObjectID `bson:"_id"` + From string `bson:"from"` + To string `bson:"to"` + AmountNanoFil int64 `bson:"amount_nano_fil"` + MessageCids []msgCid `bson:"message_cids"` + MessageState pb.MessageState `bson:"message_state"` + Waiting bool `bson:"waiting"` + FailureMsg string `bson:"failure_msg"` + CreatedAt time.Time `bson:"created_at"` + UpdatedAt time.Time `bson:"updated_at"` +} + +func (t txn) latestMsgCid() (msgCid, error) { + if len(t.MessageCids) == 0 { + log.Errorf("no message cid found for txn object id %v", t.ID.Hex()) + return msgCid{}, fmt.Errorf("no message cids found") + } + return t.MessageCids[len(t.MessageCids)-1], nil +} + +type Service struct { + clientBuilder lotus.ClientBuilder + col *mongo.Collection + server *grpc.Server + waiting map[primitive.ObjectID]chan waitResult + config Config + ticker *time.Ticker + waitingLck sync.Mutex + mainCtxCancel context.CancelFunc +} + +type Config struct { + Listener net.Listener + ClientBuilder lotus.ClientBuilder + MongoUri string + MongoDbName string + MessageWaitTimeout time.Duration + MessageConfidence uint64 + RetryWaitFrequency time.Duration + Debug bool +} + +func New(config Config) (*Service, error) { + ctx, cancel := context.WithCancel(context.Background()) + if config.Debug { + if err := util.SetLogLevels(map[string]logging.LogLevel{ + "sendfil": logging.LevelDebug, + }); err != nil { + cancel() + return nil, err + } + } + + client, err := mongo.Connect(ctx, options.Client().ApplyURI(config.MongoUri)) + if err != nil { + cancel() + return nil, fmt.Errorf("connecting to mongo: %v", err) + } + db := client.Database(config.MongoDbName) + col := db.Collection(collectionName) + if _, err := col.Indexes().CreateMany(ctx, []mongo.IndexModel{ + { + Keys: bson.D{primitive.E{Key: "from", Value: 1}}, + }, + { + Keys: bson.D{primitive.E{Key: "to", Value: 1}}, + }, + { + Keys: bson.D{primitive.E{Key: "amount_nano_fil", Value: 1}}, + }, + // MongoDB automatically creates a multikey index if any indexed field is an array; + // you do not need to explicitly specify the multikey type. + // https://docs.mongodb.com/manual/core/index-multikey/ + { + Keys: bson.D{primitive.E{Key: "message_cids.cid", Value: 1}}, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{primitive.E{Key: "message_state", Value: 1}}, + }, + { + Keys: bson.D{primitive.E{Key: "waiting", Value: 1}}, + }, + { + Keys: bson.D{primitive.E{Key: "created_at", Value: 1}}, + }, + { + Keys: bson.D{primitive.E{Key: "updated_at", Value: 1}}, + }, + }); err != nil { + cancel() + return nil, fmt.Errorf("creating collection indexes: %v", err) + } + + s := &Service{ + clientBuilder: config.ClientBuilder, + col: col, + waiting: make(map[primitive.ObjectID]chan waitResult), + config: config, + ticker: time.NewTicker(config.RetryWaitFrequency), + mainCtxCancel: cancel, + } + + s.server = grpc.NewServer() + go func() { + pb.RegisterSendFilServiceServer(s.server, s) + if err := s.server.Serve(config.Listener); err != nil && !errors.Is(err, grpc.ErrServerStopped) { + log.Errorf("serve error: %v", err) + } + }() + + if err := s.waitAllPending(ctx, true); err != nil { + cancel() + return nil, fmt.Errorf("calling waitAllPending: %v", err) + } + + s.bindTicker(ctx) + + return s, nil +} + +func (s *Service) waitAllPending(ctx context.Context, isInitialRun bool) error { + filter := bson.M{"message_state": pb.MessageState_MESSAGE_STATE_PENDING} + if !isInitialRun { + filter["waiting"] = false + } + cursor, err := s.col.Find(ctx, filter) + if err != nil { + return status.Errorf(codes.Internal, "querying txns: %v", err) + } + defer cursor.Close(ctx) + var txns []txn + err = cursor.All(ctx, &txns) + if err != nil { + return status.Errorf(codes.Internal, "decoding txns query results: %v", err) + } + log.Infof("found %v txns to initiate waiting on", len(txns)) + for _, txn := range txns { + s.wait(txn) + } + return nil +} + +func (s *Service) bindTicker(ctx context.Context) { + go func() { + for { + select { + case <-s.ticker.C: + if err := s.waitAllPending(ctx, false); err != nil { + log.Errorf("waitAllPending from ticker: %v", err) + } + case <-ctx.Done(): + log.Info("unbinding ticker") + return + } + } + }() +} + +func (s *Service) SendFil(ctx context.Context, req *pb.SendFilRequest) (*pb.SendFilResponse, error) { + f, err := address.NewFromString(req.From) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "parsing from address: %v", err) + } + t, err := address.NewFromString(req.To) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "parsing to address: %v", err) + } + nanoAmount := (&big.Int{}).SetInt64(req.AmountNanoFil) + factor := (&big.Int{}).SetInt64(int64(math.Pow10(9))) + amount := (&big.Int{}).Mul(nanoAmount, factor) + msg := &types.Message{ + From: f, + To: t, + Value: types.BigInt{Int: amount}, + } + client, cls, err := s.clientBuilder(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "creating filecoin client: %v", err) + } + defer cls() + + sm, err := client.MpoolPushMessage(ctx, msg, nil) + if err != nil { + return nil, status.Errorf(codes.Internal, "pushing message: %v", err) + } + + now := time.Now() + + tx := txn{ + ID: primitive.NewObjectID(), + From: req.From, + To: req.To, + AmountNanoFil: req.AmountNanoFil, + MessageCids: []msgCid{{Cid: sm.Message.Cid().String(), CreatedAt: now}}, + MessageState: pb.MessageState_MESSAGE_STATE_PENDING, + CreatedAt: now, + UpdatedAt: now, + } + + if _, err = s.col.InsertOne(ctx, &tx); err != nil { + return nil, status.Errorf(codes.Internal, "inserting txn into collection: %v", err) + } + + wait := s.wait(tx) + + if req.Wait { + res := <-wait + if res.err != nil { + return nil, status.Errorf(codes.Internal, "waiting for result: %v", res.err) + } + tx = res.txn + } + + pbTx, err := toPbTxn(tx) + if err != nil { + return nil, status.Errorf(codes.Internal, "converting to pb txn: %v", err) + } + + return &pb.SendFilResponse{Txn: pbTx}, nil +} + +func (s *Service) GetTxn(ctx context.Context, req *pb.GetTxnRequest) (*pb.GetTxnResponse, error) { + res := s.col.FindOne(ctx, bson.M{"message_cids.cid": req.MessageCid}) + if res.Err() == mongo.ErrNoDocuments { + return nil, status.Error(codes.NotFound, "no txn found for cid") + } + if res.Err() != nil { + return nil, status.Errorf(codes.Internal, "querying for cid txn: %v", res.Err()) + } + + var tx txn + if err := res.Decode(&tx); err != nil { + return nil, status.Errorf(codes.Internal, "decoding cid txn result: %v", res.Err()) + } + + if tx.MessageState == pb.MessageState_MESSAGE_STATE_PENDING && req.Wait { + res := <-s.wait(tx) + if res.err != nil { + return nil, status.Errorf(codes.Internal, "waiting for result: %v", res.err) + } + tx = res.txn + } + + pbTx, err := toPbTxn(tx) + if err != nil { + return nil, status.Errorf(codes.Internal, "converting to pb txn: %v", err) + } + + return &pb.GetTxnResponse{Txn: pbTx}, nil +} + +func (s *Service) ListTxns(ctx context.Context, req *pb.ListTxnsRequest) (*pb.ListTxnsResponse, error) { + findOpts := options.Find() + if req.Limit > 0 { + findOpts = findOpts.SetLimit(req.Limit) + } + sort := -1 + if req.Ascending { + sort = 1 + } + findOpts = findOpts.SetSort(bson.D{primitive.E{Key: "created_at", Value: sort}}) + + filter := bson.M{} + + // Involving/from/to + if req.InvolvingAddressFilter != "" { + filter["$or"] = bson.A{bson.M{"from": req.InvolvingAddressFilter}, bson.M{"to": req.InvolvingAddressFilter}} + } else { + if req.FromFilter != "" { + filter["from"] = req.FromFilter + } + if req.ToFilter != "" { + filter["to"] = req.ToFilter + } + } + + // MessageState + if req.MessageStateFilter != pb.MessageState_MESSAGE_STATE_UNSPECIFIED { + filter["message_state"] = req.MessageStateFilter + } + + // Waiting + if req.WaitingFilter != pb.WaitingFilter_WAITING_FILTER_UNSPECIFIED { + filter["waiting"] = req.WaitingFilter == pb.WaitingFilter_WAITING_FILTER_WAITING + } + + ands := bson.A{} + + // Amount eq/gte/lts/gt/lt + if req.AmountNanoFilEqFilter != 0 { + filter["amount_nano_fil"] = req.AmountNanoFilEqFilter + } else { + if req.AmountNanoFilGteqFilter != 0 { + ands = append(ands, bson.M{"amount_nano_fil": bson.M{"$gte": req.AmountNanoFilGteqFilter}}) + } else if req.AmountNanoFilGtFilter != 0 { + ands = append(ands, bson.M{"amount_nano_fil": bson.M{"$gt": req.AmountNanoFilGtFilter}}) + } + + if req.AmountNanoFilLteqFilter != 0 { + ands = append(ands, bson.M{"amount_nano_fil": bson.M{"$lte": req.AmountNanoFilLteqFilter}}) + } else if req.AmountNanoFilLtFilter != 0 { + ands = append(ands, bson.M{"amount_nano_fil": bson.M{"$lt": req.AmountNanoFilLtFilter}}) + } + } + + // Updated after/before + if req.UpdatedAfter != nil { + ands = append(ands, bson.M{"updated_at": bson.M{"$gt": req.UpdatedAfter.AsTime()}}) + } + if req.UpdatedBefore != nil { + ands = append(ands, bson.M{"updated_at": bson.M{"$lt": req.UpdatedBefore.AsTime()}}) + } + + // Created after/before + if req.CreatedAfter != nil { + ands = append(ands, bson.M{"created_at": bson.M{"$gt": req.CreatedAfter.AsTime()}}) + } + if req.CreatedBefore != nil { + ands = append(ands, bson.M{"created_at": bson.M{"$lt": req.CreatedBefore.AsTime()}}) + } + + // Apply paging info + comp := "$lt" + if req.MoreToken != 0 { + if req.Ascending { + comp = "$gt" + } + t := time.Unix(0, req.MoreToken) + ands = append(ands, bson.M{"created_at": bson.M{comp: &t}}) + } + + if len(ands) > 0 { + filter["$and"] = ands + } + + cursor, err := s.col.Find(ctx, filter, findOpts) + if err != nil { + return nil, status.Errorf(codes.Internal, "querying txns: %v", err) + } + defer cursor.Close(ctx) + var txns []txn + err = cursor.All(ctx, &txns) + if err != nil { + return nil, status.Errorf(codes.Internal, "decoding txns query results: %v", err) + } + + more := false + var startAt *time.Time + if len(txns) > 0 { + lastCreatedAt := &txns[len(txns)-1].CreatedAt + filter["created_at"] = bson.M{comp: *lastCreatedAt} + res := s.col.FindOne(ctx, filter) + if res.Err() != nil && res.Err() != mongo.ErrNoDocuments { + return nil, status.Errorf(codes.Internal, "checking for more data: %v", err) + } + if res.Err() != mongo.ErrNoDocuments { + more = true + startAt = lastCreatedAt + } + } + var pbTxns []*pb.Txn + for _, rec := range txns { + pbTxn, err := toPbTxn(rec) + if err != nil { + return nil, status.Errorf(codes.Internal, "converting txn to pb: %v", err) + } + pbTxns = append(pbTxns, pbTxn) + } + res := &pb.ListTxnsResponse{ + Txns: pbTxns, + More: more, + } + if startAt != nil { + res.MoreToken = startAt.UnixNano() + } + return res, nil +} + +func (s *Service) Summary(ctx context.Context, req *pb.SummaryRequest) (*pb.SummaryResponse, error) { + type entityCount struct { + ID interface{} `bson:"_id"` + Count int64 `bson:"count"` + } + type stats struct { + ID string `bson:"_id"` + Total int64 `bson:"total"` + Avg float64 `bson:"avg"` + Min int64 `bson:"min"` + Max int64 `bson:"max"` + } + type report struct { + All []entityCount `bson:"all"` + ByMessageState []entityCount `bson:"by_message_state"` + Waiting []entityCount `bson:"waiting"` + UniqueFrom []entityCount `bson:"unique_from"` + UniqueTo []entityCount `bson:"unique_to"` + SentFilStats []stats `bson:"sent_fil_stats"` + } + + createdAtMatch := bson.M{} + if req.Before != nil { + createdAtMatch["$lt"] = req.Before.AsTime() + } + if req.After != nil { + createdAtMatch["$gt"] = req.After.AsTime() + } + match := bson.M{} + if len(createdAtMatch) > 0 { + match["created_at"] = createdAtMatch + } + cursor, err := s.col.Aggregate(ctx, bson.A{ + bson.M{"$match": match}, + bson.M{"$facet": bson.M{ + "all": bson.A{ + bson.M{"$group": bson.M{"_id": nil, "count": bson.M{"$sum": 1}}}, + }, + "by_message_state": bson.A{ + bson.M{"$group": bson.M{"_id": "$message_state", "count": bson.M{"$sum": 1}}}, + }, + "waiting": bson.A{ + bson.M{"$match": bson.M{"waiting": true}}, + bson.M{"$group": bson.M{"_id": nil, "count": bson.M{"$sum": 1}}}, + }, + "unique_from": bson.A{ + bson.M{"$group": bson.M{"_id": "$from", "count": bson.M{"$sum": 1}}}, + }, + "unique_to": bson.A{ + bson.M{"$group": bson.M{"_id": "$to", "count": bson.M{"$sum": 1}}}, + }, + "sent_fil_stats": bson.A{ + bson.M{"$group": bson.M{ + "_id": nil, + "total": bson.M{"$sum": "$amount_nano_fil"}, + "avg": bson.M{"$avg": "$amount_nano_fil"}, + "max": bson.M{"$max": "$amount_nano_fil"}, + "min": bson.M{"$min": "$amount_nano_fil"}, + }}, + }, + }}, + }) + if err != nil { + return nil, status.Errorf(codes.Internal, "calling aggregate: %v", err) + } + var res []report + if err = cursor.All(ctx, &res); err != nil { + return nil, status.Errorf(codes.Internal, "decoding cursor results: %v", err) + } + if len(res) != 1 { + return nil, status.Errorf(codes.Internal, "unexpected number of aggregate results: %v", len(res)) + } + + r := res[0] + + resp := &pb.SummaryResponse{} + + if len(r.All) == 1 { + resp.CountTxns = r.All[0].Count + } + + for _, state := range r.ByMessageState { + switch pb.MessageState(state.ID.(int32)) { + case pb.MessageState_MESSAGE_STATE_PENDING: + resp.CountPending = state.Count + case pb.MessageState_MESSAGE_STATE_ACTIVE: + resp.CountActive = state.Count + case pb.MessageState_MESSAGE_STATE_FAILED: + resp.CountFailed = state.Count + } + } + + if len(r.Waiting) == 1 { + resp.CountWaiting = r.Waiting[0].Count + } + + resp.CountFromAddrs = int64(len(r.UniqueFrom)) + resp.CountToAddrs = int64(len(r.UniqueTo)) + + if len(r.SentFilStats) == 1 { + resp.TotalNanoFilSent = r.SentFilStats[0].Total + resp.AvgNanoFilSent = r.SentFilStats[0].Avg + resp.MaxNanoFilSent = r.SentFilStats[0].Max + resp.MinNanoFilSent = r.SentFilStats[0].Min + } + + return resp, nil +} + +type waitResult struct { + txn txn + err error +} + +func (s *Service) wait(tx txn) chan waitResult { + s.waitingLck.Lock() + defer s.waitingLck.Unlock() + + waitCh, found := s.waiting[tx.ID] + if found { + return waitCh + } + + ch := make(chan waitResult) + s.waiting[tx.ID] = ch + + go func() { + ctx, cancel := context.WithTimeout(context.Background(), s.config.MessageWaitTimeout) + + client, closeClient, err := s.clientBuilder(ctx) + defer func() { + closeClient() + close(ch) + cancel() + }() + if err != nil { + log.Errorf("creating lotus client: %v", err) + ch <- waitResult{err: fmt.Errorf("creating lotus client: %v", err)} + return + } + + lastestMsgCid, err := tx.latestMsgCid() + if err != nil { + tx.MessageState = pb.MessageState_MESSAGE_STATE_FAILED + tx.FailureMsg = fmt.Sprintf("getting latest message cid from txn: %v", err) + tx.UpdatedAt = time.Now() + if err := s.updateTxn(ctx, tx); err != nil { + ch <- waitResult{err: err} + return + } + ch <- waitResult{txn: tx} + return + } + c, err := cid.Decode(lastestMsgCid.Cid) + if err != nil { + log.Errorf("decoding message cid: %s", tx.FailureMsg) + tx.MessageState = pb.MessageState_MESSAGE_STATE_FAILED + tx.FailureMsg = fmt.Sprintf("decoding latest message cid for txn: %v", err) + tx.UpdatedAt = time.Now() + if err := s.updateTxn(ctx, tx); err != nil { + ch <- waitResult{err: err} + return + } + ch <- waitResult{txn: tx} + return + } + + tx.Waiting = true + if err := s.updateTxn(ctx, tx); err != nil { + ch <- waitResult{err: err} + return + } + + res, err := client.StateWaitMsg(ctx, c, s.config.MessageConfidence) + tx.Waiting = false + if err != nil { + // If for some reason the lotus node doesn't know about the cid, consider that a final error. + if strings.Contains(err.Error(), "block not found") { + tx.MessageState = pb.MessageState_MESSAGE_STATE_FAILED + tx.FailureMsg = err.Error() + tx.UpdatedAt = time.Now() + log.Warnf("failing txn with err: %s", tx.FailureMsg) + } + if err := s.updateTxn(ctx, tx); err != nil { + ch <- waitResult{err: err} + return + } + if tx.MessageState == pb.MessageState_MESSAGE_STATE_FAILED { + ch <- waitResult{txn: tx} + } else { + ch <- waitResult{err: fmt.Errorf("calling StateWaitMsg: %v", err)} + } + return + } + + if res.Receipt.ExitCode.IsError() { + tx.MessageState = pb.MessageState_MESSAGE_STATE_FAILED + tx.FailureMsg = fmt.Sprintf("error exit code: %v", res.Receipt.ExitCode.Error()) + tx.UpdatedAt = time.Now() + log.Warnf("failing txn with err: %s", tx.FailureMsg) + if err := s.updateTxn(ctx, tx); err != nil { + ch <- waitResult{err: err} + return + } + ch <- waitResult{txn: tx} + if res.Receipt.ExitCode.IsSendFailure() { + log.Errorf("received exit code send failure: %s", res.Receipt.ExitCode.String()) + } else { + log.Infof("received exit code error: %s", res.Receipt.ExitCode.String()) + } + return + } + + tx.MessageState = pb.MessageState_MESSAGE_STATE_ACTIVE + tx.UpdatedAt = time.Now() + + // This would probably not ever be true because we would already know about and have tracked + // the new message cid if we replaced the message with a new one. Checking just in case. + isNewCid := true + for _, msgCid := range tx.MessageCids { + if res.Message.String() == msgCid.Cid { + isNewCid = false + break + } + } + + if isNewCid { + tx.MessageCids = append(tx.MessageCids, msgCid{Cid: res.Message.String(), CreatedAt: time.Now()}) + } + + if err := s.updateTxn(ctx, tx); err != nil { + ch <- waitResult{err: err} + return + } + + s.waitingLck.Lock() + delete(s.waiting, tx.ID) + s.waitingLck.Unlock() + + ch <- waitResult{txn: tx} + }() + + return ch +} + +func (s *Service) Close() error { + var e error + + s.ticker.Stop() + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + if err := s.col.Database().Client().Disconnect(ctx); err != nil { + log.Errorf("disconnecting mongo client: %s", err) + e = err + } else { + log.Info("mongo client disconnected") + } + + stopped := make(chan struct{}) + go func() { + s.server.GracefulStop() + close(stopped) + }() + t := time.NewTimer(10 * time.Second) + select { + case <-t.C: + s.server.Stop() + case <-stopped: + t.Stop() + } + log.Info("gRPC server stopped") + + s.mainCtxCancel() + + return e +} + +func (s *Service) updateTxn(ctx context.Context, t txn) error { + res, err := s.col.ReplaceOne(ctx, bson.M{"_id": t.ID}, &t) + if err != nil { + log.Errorf("calling ReplaceOne to update txn: %v", err) + return err + } + if res.MatchedCount == 0 { + log.Error("no document matched calling ReplaceOne to update txn") + return fmt.Errorf("no matched txn document to replace") + } + return nil +} + +func toPbTxn(txn txn) (*pb.Txn, error) { + latestMsgCid, err := txn.latestMsgCid() + if err != nil { + return nil, err + } + return &pb.Txn{ + Id: txn.ID.Hex(), + From: txn.From, + To: txn.To, + AmountNanoFil: txn.AmountNanoFil, + MessageCid: latestMsgCid.Cid, + MessageState: txn.MessageState, + Waiting: txn.Waiting, + FailureMsg: txn.FailureMsg, + CreatedAt: timestamppb.New(txn.CreatedAt), + UpdatedAt: timestamppb.New(txn.UpdatedAt), + }, nil +} diff --git a/api/sendfild/service/service_test.go b/api/sendfild/service/service_test.go new file mode 100644 index 000000000..76b8bc99c --- /dev/null +++ b/api/sendfild/service/service_test.go @@ -0,0 +1,646 @@ +package service + +import ( + "context" + "math/rand" + "net" + "os" + "testing" + "time" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api/apistruct" + "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" + mh "github.com/multiformats/go-multihash" + "github.com/stretchr/testify/require" + "github.com/textileio/go-ds-mongo/test" + "github.com/textileio/powergate/v2/lotus" + "github.com/textileio/powergate/v2/tests" + powutil "github.com/textileio/powergate/v2/util" + pb "github.com/textileio/textile/v2/api/sendfild/pb" + "github.com/textileio/textile/v2/util" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/grpc/test/bufconn" +) + +const ( + bufSize = 1024 * 1024 + oneFil = 1000000000 +) + +var ( + ctx, _ = context.WithTimeout(context.Background(), 2*time.Minute) +) + +func TestMain(m *testing.M) { + powutil.AvgBlockTime = time.Millisecond * 100 + logging.SetAllLoggers(logging.LevelError) + + cleanup := func() {} + if os.Getenv("SKIP_SERVICES") != "true" { + cleanup = test.StartMongoDB() + } + exitVal := m.Run() + cleanup() + os.Exit(exitVal) +} + +func TestRestartWaiting(t *testing.T) { + cb, lc, dAddr, cleanupLotus := requireSetupLotus(t, ctx, setupWithSpeed(1000)) + defer cleanupLotus() + + c, cleanupService := requireSetupService(t, ctx, cb, setupWithDbName("restart_waiting")) + addr := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr.String(), oneFil, true) + requireSendFil(t, ctx, c, dAddr.String(), addr.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr.String(), oneFil, false) + time.Sleep(time.Millisecond * 100) // Little time to allow the monitoring process to start waiting for all the txns. + res, err := c.Summary(ctx, &pb.SummaryRequest{}) + require.NoError(t, err) + require.Equal(t, int64(3), res.CountWaiting) + require.Equal(t, int64(3), res.CountPending) + require.Equal(t, int64(1), res.CountActive) + cleanupService() + c, cleanupService = requireSetupService(t, ctx, cb, setupWithDbName("restart_waiting")) + defer cleanupService() + time.Sleep(time.Millisecond * 100) // Little time to allow the monitoring process to start waiting for all the txns. + res, err = c.Summary(ctx, &pb.SummaryRequest{}) + require.NoError(t, err) + require.Equal(t, int64(3), res.CountWaiting) + require.Equal(t, int64(3), res.CountPending) + require.Equal(t, int64(1), res.CountActive) +} + +func TestSendFil(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr := requireLotusAddress(t, ctx, lc) + txn := requireSendFil(t, ctx, c, dAddr.String(), addr.String(), oneFil, false) + require.Equal(t, pb.MessageState_MESSAGE_STATE_PENDING, txn.MessageState) +} + +func TestSendFilWait(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr := requireLotusAddress(t, ctx, lc) + txn := requireSendFil(t, ctx, c, dAddr.String(), addr.String(), oneFil, true) + require.Equal(t, pb.MessageState_MESSAGE_STATE_ACTIVE, txn.MessageState) +} + +func TestGetTxn(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx, setupWithSpeed(1000)) + defer cleanup() + addr := requireLotusAddress(t, ctx, lc) + txn := requireSendFil(t, ctx, c, dAddr.String(), addr.String(), oneFil, false) + res, err := c.GetTxn(ctx, &pb.GetTxnRequest{MessageCid: txn.MessageCid, Wait: false}) + require.NoError(t, err) + require.Equal(t, txn.MessageCid, res.Txn.MessageCid) + require.Equal(t, pb.MessageState_MESSAGE_STATE_PENDING, res.Txn.MessageState) +} + +func TestGetTxnWait(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr := requireLotusAddress(t, ctx, lc) + txn1 := requireSendFil(t, ctx, c, dAddr.String(), addr.String(), oneFil, false) + res, err := c.GetTxn(ctx, &pb.GetTxnRequest{MessageCid: txn1.MessageCid, Wait: true}) + require.NoError(t, err) + require.Equal(t, txn1.MessageCid, res.Txn.MessageCid) + require.Equal(t, pb.MessageState_MESSAGE_STATE_ACTIVE, res.Txn.MessageState) +} + +func TestGetTxnNonExistent(t *testing.T) { + c, _, _, cleanup := requireSetup(t, ctx) + defer cleanup() + _, err := c.GetTxn(ctx, &pb.GetTxnRequest{MessageCid: randomCid().String()}) + require.Equal(t, codes.NotFound, status.Code(err)) +} + +func TestListTxns(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{}) + require.NoError(t, err) + require.Len(t, res.Txns, 3) +} + +func TestListTxnsFrom(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + addr2 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr2.String(), oneFil*2, true) + requireSendFil(t, ctx, c, addr2.String(), addr1.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{FromFilter: dAddr.String()}) + require.NoError(t, err) + require.Len(t, res.Txns, 3) + res, err = c.ListTxns(ctx, &pb.ListTxnsRequest{FromFilter: addr2.String()}) + require.NoError(t, err) + require.Len(t, res.Txns, 1) +} + +func TestListTxnsTo(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + addr2 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr2.String(), oneFil*2, true) + requireSendFil(t, ctx, c, addr2.String(), addr1.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{ToFilter: addr1.String()}) + require.NoError(t, err) + require.Len(t, res.Txns, 3) + res, err = c.ListTxns(ctx, &pb.ListTxnsRequest{ToFilter: addr2.String()}) + require.NoError(t, err) + require.Len(t, res.Txns, 1) +} + +func TestListTxnsInvolvingAddress(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + addr2 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr2.String(), oneFil*2, true) + requireSendFil(t, ctx, c, addr2.String(), addr1.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{InvolvingAddressFilter: dAddr.String()}) + require.NoError(t, err) + require.Len(t, res.Txns, 3) + res, err = c.ListTxns(ctx, &pb.ListTxnsRequest{InvolvingAddressFilter: addr1.String()}) + require.NoError(t, err) + require.Len(t, res.Txns, 3) + res, err = c.ListTxns(ctx, &pb.ListTxnsRequest{InvolvingAddressFilter: addr2.String()}) + require.NoError(t, err) + require.Len(t, res.Txns, 2) +} + +func TestListTxnsAmtGt(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil/2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*2, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilGtFilter: oneFil}) + require.NoError(t, err) + require.Len(t, res.Txns, 1) + res, err = c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilGtFilter: oneFil * 2}) + require.NoError(t, err) + require.Len(t, res.Txns, 0) +} + +func TestListTxnsAmtGteq(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil/2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*2, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilGteqFilter: oneFil}) + require.NoError(t, err) + require.Len(t, res.Txns, 2) + res, err = c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilGteqFilter: oneFil * 3}) + require.NoError(t, err) + require.Len(t, res.Txns, 0) +} + +func TestListTxnsAmtLt(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil/2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*2, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilLtFilter: oneFil}) + require.NoError(t, err) + require.Len(t, res.Txns, 1) + res, err = c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilLtFilter: oneFil / 2}) + require.NoError(t, err) + require.Len(t, res.Txns, 0) +} + +func TestListTxnsAmtLteq(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil/2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*2, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilLteqFilter: oneFil}) + require.NoError(t, err) + require.Len(t, res.Txns, 2) + res, err = c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilLteqFilter: oneFil / 3}) + require.NoError(t, err) + require.Len(t, res.Txns, 0) +} + +func TestListTxnsAmtGtLt(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil/2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*2, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilGtFilter: oneFil / 2, AmountNanoFilLtFilter: oneFil * 3 / 2}) + require.NoError(t, err) + require.Len(t, res.Txns, 1) +} + +func TestListTxnsAmtGteqLteq(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil/2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*3, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilGteqFilter: oneFil, AmountNanoFilLteqFilter: oneFil * 2}) + require.NoError(t, err) + require.Len(t, res.Txns, 2) +} + +func TestListTxnsAmtGteqLt(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil/2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*2, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilGteqFilter: oneFil / 2, AmountNanoFilLtFilter: oneFil * 3 / 2}) + require.NoError(t, err) + require.Len(t, res.Txns, 2) +} + +func TestListTxnsAmtGtLteq(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil/2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*3, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilGtFilter: oneFil, AmountNanoFilLteqFilter: oneFil * 2}) + require.NoError(t, err) + require.Len(t, res.Txns, 1) +} + +func TestListTxnsAmtEq(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil/2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*3, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{AmountNanoFilEqFilter: oneFil}) + require.NoError(t, err) + require.Len(t, res.Txns, 1) +} + +func TestListTxnsMessageState(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx, setupWithSpeed(1000)) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, true) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{MessageStateFilter: pb.MessageState_MESSAGE_STATE_ACTIVE}) + require.NoError(t, err) + require.Len(t, res.Txns, 1) + res, err = c.ListTxns(ctx, &pb.ListTxnsRequest{MessageStateFilter: pb.MessageState_MESSAGE_STATE_PENDING}) + require.NoError(t, err) + require.Len(t, res.Txns, 2) +} + +func TestListTxnsWaiting(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx, setupWithSpeed(1000)) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, true) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + time.Sleep(time.Millisecond * 100) // Little time to allow the monitoring process to start waiting for all the txns. + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{WaitingFilter: pb.WaitingFilter_WAITING_FILTER_NOT_WAITING}) + require.NoError(t, err) + require.Len(t, res.Txns, 1) + res, err = c.ListTxns(ctx, &pb.ListTxnsRequest{WaitingFilter: pb.WaitingFilter_WAITING_FILTER_WAITING}) + require.NoError(t, err) + require.Len(t, res.Txns, 2) +} + +func TestListTxnsCreatedAfter(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + t1 := requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{CreatedAfter: t1.CreatedAt}) + require.NoError(t, err) + require.Len(t, res.Txns, 2) +} + +func TestListTxnsCreatedBefore(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + t3 := requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{CreatedBefore: t3.CreatedAt}) + require.NoError(t, err) + require.Len(t, res.Txns, 2) +} + +func TestListTxnsCreatedAfterBefore(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + t1 := requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + t3 := requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{CreatedAfter: t1.CreatedAt, CreatedBefore: t3.CreatedAt}) + require.NoError(t, err) + require.Len(t, res.Txns, 1) +} + +func TestListTxnsUpdatedAfter(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + t1 := requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{UpdatedAfter: t1.UpdatedAt}) + require.NoError(t, err) + require.Len(t, res.Txns, 2) +} + +func TestListTxnsUpdatedBefore(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + t3 := requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{UpdatedBefore: t3.UpdatedAt}) + require.NoError(t, err) + require.Len(t, res.Txns, 2) +} + +func TestListTxnsUpdatedAfterBefore(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + t1 := requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + t3 := requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{UpdatedAfter: t1.UpdatedAt, UpdatedBefore: t3.UpdatedAt}) + require.NoError(t, err) + require.Len(t, res.Txns, 1) +} + +func TestListTxnsOrder(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + res, err := c.ListTxns(ctx, &pb.ListTxnsRequest{Ascending: false}) + require.NoError(t, err) + require.Len(t, res.Txns, 3) + requireTxnsOrder(t, res.Txns, false) + res, err = c.ListTxns(ctx, &pb.ListTxnsRequest{Ascending: true}) + require.NoError(t, err) + require.Len(t, res.Txns, 3) + requireTxnsOrder(t, res.Txns, true) +} + +func TestListTxnsPaging(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + txFirst := requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + txLast := requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil, false) + + pageResults := func(ascending bool) { + numPages := 0 + more := true + var moreToken int64 = 0 + for more { + req := &pb.ListTxnsRequest{CreatedAfter: txFirst.CreatedAt, CreatedBefore: txLast.CreatedAt, Limit: 3, Ascending: ascending} + if moreToken != 0 { + req.MoreToken = moreToken + } + res, err := c.ListTxns(ctx, req) + require.NoError(t, err) + requireTxnsOrder(t, res.Txns, ascending) + numPages++ + if numPages < 3 { + require.True(t, res.More) + require.Greater(t, res.MoreToken, int64(0)) + require.Len(t, res.Txns, 3) + } + if numPages == 3 { + require.False(t, res.More) + require.Equal(t, int64(0), res.MoreToken) + require.Len(t, res.Txns, 2) + } + moreToken = res.MoreToken + more = res.More + } + require.Equal(t, 3, numPages) + } + pageResults(false) + pageResults(true) +} + +func TestSummary(t *testing.T) { + c, lc, dAddr, cleanup := requireSetup(t, ctx, setupWithSpeed(1000)) + defer cleanup() + addr1 := requireLotusAddress(t, ctx, lc) + addr2 := requireLotusAddress(t, ctx, lc) + txFirst := requireSendFil(t, ctx, c, dAddr.String(), addr2.String(), oneFil*3, true) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*2, false) + requireSendFil(t, ctx, c, dAddr.String(), addr1.String(), oneFil*2, false) + txLast := requireSendFil(t, ctx, c, addr2.String(), addr1.String(), oneFil, false) + time.Sleep(time.Millisecond * 100) // Little time to allow the monitoring process to start waiting for all the txns. + res, err := c.Summary(ctx, &pb.SummaryRequest{}) + require.NoError(t, err) + require.Equal(t, float64(oneFil*2), res.AvgNanoFilSent) + require.Equal(t, int64(1), res.CountActive) + require.Equal(t, int64(0), res.CountFailed) + require.Equal(t, int64(2), res.CountFromAddrs) + require.Equal(t, int64(3), res.CountPending) + require.Equal(t, int64(2), res.CountToAddrs) + require.Equal(t, int64(4), res.CountTxns) + require.Equal(t, int64(3), res.CountWaiting) + require.Equal(t, int64(oneFil*3), res.MaxNanoFilSent) + require.Equal(t, int64(oneFil), res.MinNanoFilSent) + require.Equal(t, int64(oneFil*8), res.TotalNanoFilSent) + res, err = c.Summary(ctx, &pb.SummaryRequest{After: txFirst.CreatedAt, Before: txLast.CreatedAt}) + require.NoError(t, err) + require.Equal(t, float64(oneFil*2), res.AvgNanoFilSent) + require.Equal(t, int64(0), res.CountActive) + require.Equal(t, int64(0), res.CountFailed) + require.Equal(t, int64(1), res.CountFromAddrs) + require.Equal(t, int64(2), res.CountPending) + require.Equal(t, int64(1), res.CountToAddrs) + require.Equal(t, int64(2), res.CountTxns) + require.Equal(t, int64(2), res.CountWaiting) + require.Equal(t, int64(oneFil*2), res.MaxNanoFilSent) + require.Equal(t, int64(oneFil*2), res.MinNanoFilSent) + require.Equal(t, int64(oneFil*4), res.TotalNanoFilSent) +} + +type setupConfig struct { + dbName string + speed int +} + +type setupOption = func(*setupConfig) + +func setupWithSpeed(speed int) setupOption { + return func(config *setupConfig) { + config.speed = speed + } +} + +func setupWithDbName(dbName string) setupOption { + return func(config *setupConfig) { + config.dbName = dbName + } +} + +func requireSetupLotus(t *testing.T, ctx context.Context, opts ...setupOption) (lotus.ClientBuilder, *apistruct.FullNodeStruct, address.Address, func()) { + config := &setupConfig{ + speed: 300, + } + for _, opt := range opts { + opt(config) + } + clientBuilder, addr, _ := tests.CreateLocalDevnet(t, 1, config.speed) + time.Sleep(time.Millisecond * 500) // Allow the network to some tipsets + + lotusClient, closeLotusClient, err := clientBuilder(ctx) + require.NoError(t, err) + + cleanup := func() { + closeLotusClient() + } + return clientBuilder, lotusClient, addr, cleanup +} + +func requireSetupService(t *testing.T, ctx context.Context, cb lotus.ClientBuilder, opts ...setupOption) (pb.SendFilServiceClient, func()) { + config := &setupConfig{ + dbName: util.MakeToken(12), + } + for _, opt := range opts { + opt(config) + } + listener := bufconn.Listen(bufSize) + + conf := Config{ + Listener: listener, + ClientBuilder: cb, + MongoUri: test.GetMongoUri(), + MongoDbName: config.dbName, + MessageWaitTimeout: time.Minute, + MessageConfidence: 2, + RetryWaitFrequency: time.Minute, + Debug: true, + } + s, err := New(conf) + require.NoError(t, err) + + bufDialer := func(context.Context, string) (net.Conn, error) { + return listener.Dial() + } + + conn, err := grpc.Dial("bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure()) + require.NoError(t, err) + client := pb.NewSendFilServiceClient(conn) + + cleanup := func() { + conn.Close() + s.Close() + } + + return client, cleanup +} + +func requireSetup(t *testing.T, ctx context.Context, opts ...setupOption) (pb.SendFilServiceClient, *apistruct.FullNodeStruct, address.Address, func()) { + + cb, lotusClient, addr, cleanupLouts := requireSetupLotus(t, ctx, opts...) + serviceClient, cleanupService := requireSetupService(t, ctx, cb, opts...) + + cleanup := func() { + cleanupLouts() + cleanupService() + } + + return serviceClient, lotusClient, addr, cleanup +} + +func requireLotusAddress(t *testing.T, ctx context.Context, lotusClient *apistruct.FullNodeStruct) address.Address { + addr, err := lotusClient.WalletNew(ctx, types.KTBLS) + require.NoError(t, err) + require.Greater(t, len(addr.String()), 0) + return addr +} + +func requireSendFil(t *testing.T, ctx context.Context, c pb.SendFilServiceClient, from, to string, amt int64, wait bool) *pb.Txn { + res, err := c.SendFil(ctx, &pb.SendFilRequest{From: from, To: to, AmountNanoFil: amt, Wait: wait}) + require.NoError(t, err) + require.Equal(t, from, res.Txn.From) + require.Equal(t, to, res.Txn.To) + require.Equal(t, amt, res.Txn.AmountNanoFil) + require.NotEmpty(t, res.Txn.MessageCid) + return res.Txn +} + +func requireTxnsOrder(t *testing.T, txns []*pb.Txn, ascending bool) { + var last *time.Time + for _, txn := range txns { + if last != nil { + a := *last + b := txn.CreatedAt.AsTime() + if ascending { + a = txn.CreatedAt.AsTime() + b = *last + } + require.True(t, a.After(b)) + } + t := txn.CreatedAt.AsTime() + last = &t + } +} + +func randomCid() cid.Cid { + data := make([]byte, 20) + rand.Read(data) + hash, _ := mh.Sum(data, mh.SHA2_256, -1) + return cid.NewCidV1(cid.DagCBOR, hash) +} diff --git a/go.mod b/go.mod index c92cdeefb..f822f0983 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,9 @@ require ( github.com/customerio/go-customerio v2.0.0+incompatible github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dustin/go-humanize v1.0.0 + github.com/filecoin-project/go-address v0.0.5 github.com/filecoin-project/go-fil-markets v1.1.9 + github.com/filecoin-project/lotus v1.5.0 github.com/gin-contrib/location v0.0.2 github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2 github.com/gin-gonic/gin v1.6.3 @@ -75,7 +77,7 @@ require ( github.com/textileio/go-assets v0.0.0-20200430191519-b341e634e2b7 github.com/textileio/go-ds-mongo v0.1.5-0.20201230201018-2b7fdca787a5 github.com/textileio/go-threads v1.0.3-0.20201216032729-f7b034a0de80 - github.com/textileio/powergate/v2 v2.2.0 + github.com/textileio/powergate/v2 v2.2.1-0.20210303232835-2587790b227c github.com/textileio/swagger-ui v0.3.29-0.20210224180244-7d73a7a32fe7 github.com/xakep666/mongo-migrate v0.2.1 github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect diff --git a/go.sum b/go.sum index 8baca4d0a..354093225 100644 --- a/go.sum +++ b/go.sum @@ -1669,6 +1669,7 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -1681,6 +1682,7 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/src-d/envconfig v1.0.0 h1:/AJi6DtjFhZKNx3OB2qMsq7y4yT5//AeSZIe7rk+PX8= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -1723,8 +1725,8 @@ github.com/textileio/go-ds-mongo v0.1.5-0.20201230201018-2b7fdca787a5 h1:wy2WAFw github.com/textileio/go-ds-mongo v0.1.5-0.20201230201018-2b7fdca787a5/go.mod h1:Zf6JlMPiIQUUmGlFFn5Z65C9p9LAvPg7XvX+qdGmTsU= github.com/textileio/go-threads v1.0.3-0.20201216032729-f7b034a0de80 h1:UJbiLtEmaRp9zUif+thvxsIOkeZnTECIWcaURCBaXS4= github.com/textileio/go-threads v1.0.3-0.20201216032729-f7b034a0de80/go.mod h1:kvIXqo4T4fS6fDyNeqRAIE5CXDguBXUi8kZVb4FGg0U= -github.com/textileio/powergate/v2 v2.2.0 h1:OizZ2XPIfVBGG3xbtcOSqj6SJwVijJTEFmFTPW6yrgo= -github.com/textileio/powergate/v2 v2.2.0/go.mod h1:MxwU95rhpoSBsrKk5hWf4y6tGXbW4na8ta1FPlzWIFI= +github.com/textileio/powergate/v2 v2.2.1-0.20210303232835-2587790b227c h1:/zBUukCG1U2jyKL8YpO9Xgu+AN2aKJpLtNW2uDxmMN8= +github.com/textileio/powergate/v2 v2.2.1-0.20210303232835-2587790b227c/go.mod h1:MxwU95rhpoSBsrKk5hWf4y6tGXbW4na8ta1FPlzWIFI= github.com/textileio/swagger-ui v0.3.29-0.20210224180244-7d73a7a32fe7 h1:qUEurT6kJF+nFkiNjUPMJJ7hgg9OIDnb8iLn6VtBukE= github.com/textileio/swagger-ui v0.3.29-0.20210224180244-7d73a7a32fe7/go.mod h1:IG3de1dcR5Hmcz57nScHHoq5Ju1AABd8z5GnLDgDCks= github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g= @@ -1787,6 +1789,7 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20200806213330-63aa96ca5488/go.mod h1:f github.com/whyrusleeping/cbor-gen v0.0.0-20200810223238-211df3b9e24c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20210118024343-169e9d70c0c2 h1:7HzUKl5d/dELS9lLeT4W6YvliZx+s9k/eOOIdHKrA/w= github.com/whyrusleeping/cbor-gen v0.0.0-20210118024343-169e9d70c0c2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 h1:bsUlNhdmbtlfdLVXAVfuvKQ01RnWAM09TVrJkI7NZs4= github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= @@ -1812,6 +1815,7 @@ github.com/whyrusleeping/pubsub v0.0.0-20190708150250-92bcb0691325/go.mod h1:g7c github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8= +github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/xakep666/mongo-migrate v0.2.1 h1:pRK966a44ujuGMEl73MOzv4MajcH8Q6MWo+TBlxjhvs= github.com/xakep666/mongo-migrate v0.2.1/go.mod h1:pVQysP+es2wX4TaeVd7zLkRZhKMcBqcC/KRyLms6Eyk= @@ -2138,6 +2142,7 @@ golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201218084310-7d0127a74742 h1:+CBz4km/0KPU3RGTwARGh/noP3bEwtHcq+0YcBQM2JQ= golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2354,6 +2359,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/segmentio/analytics-go.v3 v3.1.0 h1:UzxH1uaGZRpMKDhJyBz0pexz6yUoBU3x8bJsRk/HV6U= gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw= gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= +gopkg.in/src-d/go-log.v1 v1.0.1 h1:heWvX7J6qbGWbeFS/aRmiy1eYaT+QMV6wNvHDyMjQV4= gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=