diff --git a/lnrpc/wtclientrpc/config_active.go b/lnrpc/wtclientrpc/config_active.go new file mode 100644 index 00000000..7a50efef --- /dev/null +++ b/lnrpc/wtclientrpc/config_active.go @@ -0,0 +1,27 @@ +// +build wtclientrpc + +package wtclientrpc + +import ( + "github.com/lightningnetwork/lnd/lncfg" + "github.com/lightningnetwork/lnd/watchtower/wtclient" +) + +// Config is the primary configuration struct for the watchtower RPC server. It +// contains all the items required for the RPC server to carry out its duties. +// The fields with struct tags are meant to be parsed as normal configuration +// options, while if able to be populated, the latter fields MUST also be +// specified. +type Config struct { + // Active indicates if the watchtower client is enabled. + Active bool + + // Client is the backing watchtower client that we'll interact with + // through the watchtower RPC subserver. + Client wtclient.Client + + // Resolver is a custom resolver that will be used to resolve watchtower + // addresses to ensure we don't leak any information when running over + // non-clear networks, e.g. Tor, etc. + Resolver lncfg.TCPResolver +} diff --git a/lnrpc/wtclientrpc/config_default.go b/lnrpc/wtclientrpc/config_default.go new file mode 100644 index 00000000..a23813cb --- /dev/null +++ b/lnrpc/wtclientrpc/config_default.go @@ -0,0 +1,6 @@ +// +build !wtclientrpc + +package wtclientrpc + +// Config is empty for non-wtclientrpc builds. +type Config struct{} diff --git a/lnrpc/wtclientrpc/driver.go b/lnrpc/wtclientrpc/driver.go new file mode 100644 index 00000000..7c9c3c5a --- /dev/null +++ b/lnrpc/wtclientrpc/driver.go @@ -0,0 +1,63 @@ +// +build wtclientrpc + +package wtclientrpc + +import ( + "errors" + "fmt" + + "github.com/lightningnetwork/lnd/lnrpc" +) + +// createNewSubServer is a helper method that will create the new sub server +// given the main config dispatcher method. If we're unable to find the config +// that is meant for us in the config dispatcher, then we'll exit with an +// error. +func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) ( + lnrpc.SubServer, lnrpc.MacaroonPerms, error) { + + // We'll attempt to look up the config that we expect, according to our + // subServerName name. If we can't find this, then we'll exit with an + // error, as we're unable to properly initialize ourselves without this + // config. + subServerConf, ok := configRegistry.FetchConfig(subServerName) + if !ok { + return nil, nil, fmt.Errorf("unable to find config for "+ + "subserver type %s", subServerName) + } + + // Now that we've found an object mapping to our service name, we'll + // ensure that it's the type we need. + config, ok := subServerConf.(*Config) + if !ok { + return nil, nil, fmt.Errorf("wrong type of config for "+ + "subserver %s, expected %T got %T", subServerName, + &Config{}, subServerConf) + } + + // Before we try to make the new service instance, we'll perform + // some sanity checks on the arguments to ensure that they're useable. + switch { + case config.Resolver == nil: + return nil, nil, errors.New("a lncfg.TCPResolver is required") + } + + return New(config) +} + +func init() { + subServer := &lnrpc.SubServerDriver{ + SubServerName: subServerName, + New: func(c lnrpc.SubServerConfigDispatcher) (lnrpc.SubServer, + lnrpc.MacaroonPerms, error) { + return createNewSubServer(c) + }, + } + + // If the build tag is active, then we'll register ourselves as a + // sub-RPC server within the global lnrpc package namespace. + if err := lnrpc.RegisterSubServer(subServer); err != nil { + panic(fmt.Sprintf("failed to register sub server driver "+ + "'%s': %v", subServerName, err)) + } +} diff --git a/lnrpc/wtclientrpc/log.go b/lnrpc/wtclientrpc/log.go new file mode 100644 index 00000000..7387e4f4 --- /dev/null +++ b/lnrpc/wtclientrpc/log.go @@ -0,0 +1,48 @@ +package wtclientrpc + +import ( + "github.com/btcsuite/btclog" + "github.com/lightningnetwork/lnd/build" +) + +// Subsystem defines the logging code for this subsystem. +const Subsystem = "WTCL" + +// log is a logger that is initialized with no output filters. This means the +// package will not perform any logging by default until the caller requests +// it. +var log btclog.Logger + +// The default amount of logging is none. +func init() { + UseLogger(build.NewSubLogger(Subsystem, nil)) +} + +// DisableLog disables all library log output. Logging output is disabled by +// by default until UseLogger is called. +func DisableLog() { + UseLogger(btclog.Disabled) +} + +// UseLogger uses a specified Logger to output package logging info. This +// should be used in preference to SetLogWriter if the caller is also using +// btclog. +func UseLogger(logger btclog.Logger) { + log = logger +} + +// logClosure is used to provide a closure over expensive logging operations so +// don't have to be performed when the logging level doesn't warrant it. +type logClosure func() string + +// String invokes the underlying function and returns the result. +func (c logClosure) String() string { + return c() +} + +// newLogClosure returns a new closure over a function that returns a string +// which itself provides a Stringer interface so that it can be used with the +// logging system. +func newLogClosure(c func() string) logClosure { + return logClosure(c) +} diff --git a/lnrpc/wtclientrpc/wtclient.go b/lnrpc/wtclientrpc/wtclient.go new file mode 100644 index 00000000..bae77daf --- /dev/null +++ b/lnrpc/wtclientrpc/wtclient.go @@ -0,0 +1,309 @@ +// +build wtclientrpc + +package wtclientrpc + +import ( + "context" + "errors" + "fmt" + "net" + "strconv" + + "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/lncfg" + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/watchtower" + "github.com/lightningnetwork/lnd/watchtower/wtclient" + "google.golang.org/grpc" + "gopkg.in/macaroon-bakery.v2/bakery" +) + +const ( + // subServerName is the name of the sub rpc server. We'll use this name + // to register ourselves, and we also require that the main + // SubServerConfigDispatcher instance recognizes it as the name of our + // RPC service. + subServerName = "WatchtowerClientRPC" +) + +var ( + // macPermissions maps RPC calls to the permissions they require. + // + // TODO(wilmer): create tower macaroon? + macPermissions = map[string][]bakery.Op{ + "/wtclientrpc.WatchtowerClient/AddTower": {{ + Entity: "offchain", + Action: "write", + }}, + "/wtclientrpc.WatchtowerClient/RemoveTower": {{ + Entity: "offchain", + Action: "write", + }}, + "/wtclientrpc.WatchtowerClient/ListTowers": {{ + Entity: "offchain", + Action: "read", + }}, + "/wtclientrpc.WatchtowerClient/GetTowerInfo": {{ + Entity: "offchain", + Action: "read", + }}, + "/wtclientrpc.WatchtowerClient/Stats": {{ + Entity: "offchain", + Action: "read", + }}, + "/wtclientrpc.WatchtowerClient/Policy": {{ + Entity: "offchain", + Action: "read", + }}, + } + + // ErrWtclientNotActive signals that RPC calls cannot be processed + // because the watchtower client is not active. + ErrWtclientNotActive = errors.New("watchtower client not active") +) + +// WatchtowerClient is the RPC server we'll use to interact with the backing +// active watchtower client. +// +// TODO(wilmer): better name? +type WatchtowerClient struct { + cfg Config +} + +// A compile time check to ensure that WatchtowerClient fully implements the +// WatchtowerClientWatchtowerClient gRPC service. +var _ WatchtowerClientServer = (*WatchtowerClient)(nil) + +// New returns a new instance of the wtclientrpc WatchtowerClient sub-server. +// We also return the set of permissions for the macaroons that we may create +// within this method. If the macaroons we need aren't found in the filepath, +// then we'll create them on start up. If we're unable to locate, or create the +// macaroons we need, then we'll return with an error. +func New(cfg *Config) (*WatchtowerClient, lnrpc.MacaroonPerms, error) { + return &WatchtowerClient{*cfg}, macPermissions, nil +} + +// Start launches any helper goroutines required for the WatchtowerClient to +// function. +// +// NOTE: This is part of the lnrpc.SubWatchtowerClient interface. +func (c *WatchtowerClient) Start() error { + return nil +} + +// Stop signals any active goroutines for a graceful closure. +// +// NOTE: This is part of the lnrpc.SubServer interface. +func (c *WatchtowerClient) Stop() error { + return nil +} + +// Name returns a unique string representation of the sub-server. This can be +// used to identify the sub-server and also de-duplicate them. +// +// NOTE: This is part of the lnrpc.SubServer interface. +func (c *WatchtowerClient) Name() string { + return subServerName +} + +// RegisterWithRootServer will be called by the root gRPC server to direct a sub +// RPC server to register itself with the main gRPC root server. Until this is +// called, each sub-server won't be able to have requests routed towards it. +// +// NOTE: This is part of the lnrpc.SubServer interface. +func (c *WatchtowerClient) RegisterWithRootServer(grpcServer *grpc.Server) error { + // We make sure that we register it with the main gRPC server to ensure + // all our methods are routed properly. + RegisterWatchtowerClientServer(grpcServer, c) + + log.Debugf("WatchtowerClient RPC server successfully registered with " + + "root gRPC server") + + return nil +} + +// isActive returns nil if the watchtower client is initialized so that we can +// process RPC requests. +func (c *WatchtowerClient) isActive() error { + if c.cfg.Active { + return nil + } + return ErrWtclientNotActive +} + +// AddTower adds a new watchtower reachable at the given address and considers +// it for new sessions. If the watchtower already exists, then any new addresses +// included will be considered when dialing it for session negotiations and +// backups. +func (c *WatchtowerClient) AddTower(ctx context.Context, + req *AddTowerRequest) (*AddTowerResponse, error) { + + if err := c.isActive(); err != nil { + return nil, err + } + + pubKey, err := btcec.ParsePubKey(req.Pubkey, btcec.S256()) + if err != nil { + return nil, err + } + addr, err := lncfg.ParseAddressString( + req.Address, strconv.Itoa(watchtower.DefaultPeerPort), + c.cfg.Resolver, + ) + if err != nil { + return nil, fmt.Errorf("invalid address %v: %v", req.Address, err) + } + + towerAddr := &lnwire.NetAddress{ + IdentityKey: pubKey, + Address: addr, + } + if err := c.cfg.Client.AddTower(towerAddr); err != nil { + return nil, err + } + + return &AddTowerResponse{}, nil +} + +// RemoveTower removes a watchtower from being considered for future session +// negotiations and from being used for any subsequent backups until it's added +// again. If an address is provided, then this RPC only serves as a way of +// removing the address from the watchtower instead. +func (c *WatchtowerClient) RemoveTower(ctx context.Context, + req *RemoveTowerRequest) (*RemoveTowerResponse, error) { + + if err := c.isActive(); err != nil { + return nil, err + } + + pubKey, err := btcec.ParsePubKey(req.Pubkey, btcec.S256()) + if err != nil { + return nil, err + } + + var addr net.Addr + if req.Address != "" { + addr, err = lncfg.ParseAddressString( + req.Address, strconv.Itoa(watchtower.DefaultPeerPort), + c.cfg.Resolver, + ) + if err != nil { + return nil, fmt.Errorf("unable to parse tower "+ + "address %v: %v", req.Address, err) + } + } + + if err := c.cfg.Client.RemoveTower(pubKey, addr); err != nil { + return nil, err + } + + return &RemoveTowerResponse{}, nil +} + +// ListTowers returns the list of watchtowers registered with the client. +func (c *WatchtowerClient) ListTowers(ctx context.Context, + req *ListTowersRequest) (*ListTowersResponse, error) { + + if err := c.isActive(); err != nil { + return nil, err + } + + towers, err := c.cfg.Client.RegisteredTowers() + if err != nil { + return nil, err + } + + rpcTowers := make([]*Tower, 0, len(towers)) + for _, tower := range towers { + rpcTower := marshallTower(tower, req.IncludeSessions) + rpcTowers = append(rpcTowers, rpcTower) + } + + return &ListTowersResponse{Towers: rpcTowers}, nil +} + +// GetTowerInfo retrieves information for a registered watchtower. +func (c *WatchtowerClient) GetTowerInfo(ctx context.Context, + req *GetTowerInfoRequest) (*Tower, error) { + + if err := c.isActive(); err != nil { + return nil, err + } + + pubKey, err := btcec.ParsePubKey(req.Pubkey, btcec.S256()) + if err != nil { + return nil, err + } + + tower, err := c.cfg.Client.LookupTower(pubKey) + if err != nil { + return nil, err + } + + return marshallTower(tower, req.IncludeSessions), nil +} + +// Stats returns the in-memory statistics of the client since startup. +func (c *WatchtowerClient) Stats(ctx context.Context, + req *StatsRequest) (*StatsResponse, error) { + + if err := c.isActive(); err != nil { + return nil, err + } + + stats := c.cfg.Client.Stats() + return &StatsResponse{ + NumBackups: uint32(stats.NumTasksAccepted), + NumFailedBackups: uint32(stats.NumTasksIneligible), + NumPendingBackups: uint32(stats.NumTasksReceived), + NumSessionsAcquired: uint32(stats.NumSessionsAcquired), + NumSessionsExhausted: uint32(stats.NumSessionsExhausted), + }, nil +} + +// Policy returns the active watchtower client policy configuration. +func (c *WatchtowerClient) Policy(ctx context.Context, + req *PolicyRequest) (*PolicyResponse, error) { + + if err := c.isActive(); err != nil { + return nil, err + } + + policy := c.cfg.Client.Policy() + return &PolicyResponse{ + MaxUpdates: uint32(policy.MaxUpdates), + SweepSatPerByte: uint32(policy.SweepFeeRate.FeePerKVByte() / 1000), + }, nil +} + +// marshallTower converts a client registered watchtower into its corresponding +// RPC type. +func marshallTower(tower *wtclient.RegisteredTower, includeSessions bool) *Tower { + rpcAddrs := make([]string, 0, len(tower.Addresses)) + for _, addr := range tower.Addresses { + rpcAddrs = append(rpcAddrs, addr.String()) + } + + var rpcSessions []*TowerSession + if includeSessions { + rpcSessions = make([]*TowerSession, 0, len(tower.Sessions)) + for _, session := range tower.Sessions { + satPerByte := session.Policy.SweepFeeRate.FeePerKVByte() / 1000 + rpcSessions = append(rpcSessions, &TowerSession{ + NumBackups: uint32(len(session.AckedUpdates)), + NumPendingBackups: uint32(len(session.CommittedUpdates)), + MaxBackups: uint32(session.Policy.MaxUpdates), + SweepSatPerByte: uint32(satPerByte), + }) + } + } + + return &Tower{ + Pubkey: tower.IdentityKey.SerializeCompressed(), + Addresses: rpcAddrs, + ActiveSessionCandidate: tower.ActiveSessionCandidate, + NumSessions: uint32(len(tower.Sessions)), + Sessions: rpcSessions, + } +} diff --git a/lnrpc/wtclientrpc/wtclient.pb.go b/lnrpc/wtclientrpc/wtclient.pb.go new file mode 100644 index 00000000..f99dbc6e --- /dev/null +++ b/lnrpc/wtclientrpc/wtclient.pb.go @@ -0,0 +1,988 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: wtclientrpc/wtclient.proto + +package wtclientrpc + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type AddTowerRequest struct { + // The identifying public key of the watchtower to add. + Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` + // A network address the watchtower is reachable over. + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddTowerRequest) Reset() { *m = AddTowerRequest{} } +func (m *AddTowerRequest) String() string { return proto.CompactTextString(m) } +func (*AddTowerRequest) ProtoMessage() {} +func (*AddTowerRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{0} +} + +func (m *AddTowerRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddTowerRequest.Unmarshal(m, b) +} +func (m *AddTowerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddTowerRequest.Marshal(b, m, deterministic) +} +func (m *AddTowerRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddTowerRequest.Merge(m, src) +} +func (m *AddTowerRequest) XXX_Size() int { + return xxx_messageInfo_AddTowerRequest.Size(m) +} +func (m *AddTowerRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AddTowerRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AddTowerRequest proto.InternalMessageInfo + +func (m *AddTowerRequest) GetPubkey() []byte { + if m != nil { + return m.Pubkey + } + return nil +} + +func (m *AddTowerRequest) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +type AddTowerResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddTowerResponse) Reset() { *m = AddTowerResponse{} } +func (m *AddTowerResponse) String() string { return proto.CompactTextString(m) } +func (*AddTowerResponse) ProtoMessage() {} +func (*AddTowerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{1} +} + +func (m *AddTowerResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AddTowerResponse.Unmarshal(m, b) +} +func (m *AddTowerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AddTowerResponse.Marshal(b, m, deterministic) +} +func (m *AddTowerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddTowerResponse.Merge(m, src) +} +func (m *AddTowerResponse) XXX_Size() int { + return xxx_messageInfo_AddTowerResponse.Size(m) +} +func (m *AddTowerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_AddTowerResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_AddTowerResponse proto.InternalMessageInfo + +type RemoveTowerRequest struct { + // The identifying public key of the watchtower to remove. + Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` + // + //If set, then the record for this address will be removed, indicating that is + //is stale. Otherwise, the watchtower will no longer be used for future + //session negotiations and backups. + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveTowerRequest) Reset() { *m = RemoveTowerRequest{} } +func (m *RemoveTowerRequest) String() string { return proto.CompactTextString(m) } +func (*RemoveTowerRequest) ProtoMessage() {} +func (*RemoveTowerRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{2} +} + +func (m *RemoveTowerRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveTowerRequest.Unmarshal(m, b) +} +func (m *RemoveTowerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveTowerRequest.Marshal(b, m, deterministic) +} +func (m *RemoveTowerRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveTowerRequest.Merge(m, src) +} +func (m *RemoveTowerRequest) XXX_Size() int { + return xxx_messageInfo_RemoveTowerRequest.Size(m) +} +func (m *RemoveTowerRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveTowerRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveTowerRequest proto.InternalMessageInfo + +func (m *RemoveTowerRequest) GetPubkey() []byte { + if m != nil { + return m.Pubkey + } + return nil +} + +func (m *RemoveTowerRequest) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +type RemoveTowerResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveTowerResponse) Reset() { *m = RemoveTowerResponse{} } +func (m *RemoveTowerResponse) String() string { return proto.CompactTextString(m) } +func (*RemoveTowerResponse) ProtoMessage() {} +func (*RemoveTowerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{3} +} + +func (m *RemoveTowerResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RemoveTowerResponse.Unmarshal(m, b) +} +func (m *RemoveTowerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RemoveTowerResponse.Marshal(b, m, deterministic) +} +func (m *RemoveTowerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveTowerResponse.Merge(m, src) +} +func (m *RemoveTowerResponse) XXX_Size() int { + return xxx_messageInfo_RemoveTowerResponse.Size(m) +} +func (m *RemoveTowerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveTowerResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RemoveTowerResponse proto.InternalMessageInfo + +type GetTowerInfoRequest struct { + // The identifying public key of the watchtower to retrieve information for. + Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` + // Whether we should include sessions with the watchtower in the response. + IncludeSessions bool `protobuf:"varint,2,opt,name=include_sessions,proto3" json:"include_sessions,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetTowerInfoRequest) Reset() { *m = GetTowerInfoRequest{} } +func (m *GetTowerInfoRequest) String() string { return proto.CompactTextString(m) } +func (*GetTowerInfoRequest) ProtoMessage() {} +func (*GetTowerInfoRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{4} +} + +func (m *GetTowerInfoRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetTowerInfoRequest.Unmarshal(m, b) +} +func (m *GetTowerInfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetTowerInfoRequest.Marshal(b, m, deterministic) +} +func (m *GetTowerInfoRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetTowerInfoRequest.Merge(m, src) +} +func (m *GetTowerInfoRequest) XXX_Size() int { + return xxx_messageInfo_GetTowerInfoRequest.Size(m) +} +func (m *GetTowerInfoRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetTowerInfoRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetTowerInfoRequest proto.InternalMessageInfo + +func (m *GetTowerInfoRequest) GetPubkey() []byte { + if m != nil { + return m.Pubkey + } + return nil +} + +func (m *GetTowerInfoRequest) GetIncludeSessions() bool { + if m != nil { + return m.IncludeSessions + } + return false +} + +type TowerSession struct { + // + //The total number of successful backups that have been made to the + //watchtower session. + NumBackups uint32 `protobuf:"varint,1,opt,name=num_backups,proto3" json:"num_backups,omitempty"` + // + //The total number of backups in the session that are currently pending to be + //acknowledged by the watchtower. + NumPendingBackups uint32 `protobuf:"varint,2,opt,name=num_pending_backups,proto3" json:"num_pending_backups,omitempty"` + // The maximum number of backups allowed by the watchtower session. + MaxBackups uint32 `protobuf:"varint,3,opt,name=max_backups,proto3" json:"max_backups,omitempty"` + // + //The fee rate, in satoshis per vbyte, that will be used by the watchtower for + //the justice transaction in the event of a channel breach. + SweepSatPerByte uint32 `protobuf:"varint,4,opt,name=sweep_sat_per_byte,proto3" json:"sweep_sat_per_byte,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TowerSession) Reset() { *m = TowerSession{} } +func (m *TowerSession) String() string { return proto.CompactTextString(m) } +func (*TowerSession) ProtoMessage() {} +func (*TowerSession) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{5} +} + +func (m *TowerSession) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TowerSession.Unmarshal(m, b) +} +func (m *TowerSession) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TowerSession.Marshal(b, m, deterministic) +} +func (m *TowerSession) XXX_Merge(src proto.Message) { + xxx_messageInfo_TowerSession.Merge(m, src) +} +func (m *TowerSession) XXX_Size() int { + return xxx_messageInfo_TowerSession.Size(m) +} +func (m *TowerSession) XXX_DiscardUnknown() { + xxx_messageInfo_TowerSession.DiscardUnknown(m) +} + +var xxx_messageInfo_TowerSession proto.InternalMessageInfo + +func (m *TowerSession) GetNumBackups() uint32 { + if m != nil { + return m.NumBackups + } + return 0 +} + +func (m *TowerSession) GetNumPendingBackups() uint32 { + if m != nil { + return m.NumPendingBackups + } + return 0 +} + +func (m *TowerSession) GetMaxBackups() uint32 { + if m != nil { + return m.MaxBackups + } + return 0 +} + +func (m *TowerSession) GetSweepSatPerByte() uint32 { + if m != nil { + return m.SweepSatPerByte + } + return 0 +} + +type Tower struct { + // The identifying public key of the watchtower. + Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` + // The list of addresses the watchtower is reachable over. + Addresses []string `protobuf:"bytes,2,rep,name=addresses,proto3" json:"addresses,omitempty"` + // Whether the watchtower is currently a candidate for new sessions. + ActiveSessionCandidate bool `protobuf:"varint,3,opt,name=active_session_candidate,proto3" json:"active_session_candidate,omitempty"` + // The number of sessions that have been negotiated with the watchtower. + NumSessions uint32 `protobuf:"varint,4,opt,name=num_sessions,proto3" json:"num_sessions,omitempty"` + // The list of sessions that have been negotiated with the watchtower. + Sessions []*TowerSession `protobuf:"bytes,5,rep,name=sessions,proto3" json:"sessions,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Tower) Reset() { *m = Tower{} } +func (m *Tower) String() string { return proto.CompactTextString(m) } +func (*Tower) ProtoMessage() {} +func (*Tower) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{6} +} + +func (m *Tower) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Tower.Unmarshal(m, b) +} +func (m *Tower) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Tower.Marshal(b, m, deterministic) +} +func (m *Tower) XXX_Merge(src proto.Message) { + xxx_messageInfo_Tower.Merge(m, src) +} +func (m *Tower) XXX_Size() int { + return xxx_messageInfo_Tower.Size(m) +} +func (m *Tower) XXX_DiscardUnknown() { + xxx_messageInfo_Tower.DiscardUnknown(m) +} + +var xxx_messageInfo_Tower proto.InternalMessageInfo + +func (m *Tower) GetPubkey() []byte { + if m != nil { + return m.Pubkey + } + return nil +} + +func (m *Tower) GetAddresses() []string { + if m != nil { + return m.Addresses + } + return nil +} + +func (m *Tower) GetActiveSessionCandidate() bool { + if m != nil { + return m.ActiveSessionCandidate + } + return false +} + +func (m *Tower) GetNumSessions() uint32 { + if m != nil { + return m.NumSessions + } + return 0 +} + +func (m *Tower) GetSessions() []*TowerSession { + if m != nil { + return m.Sessions + } + return nil +} + +type ListTowersRequest struct { + // Whether we should include sessions with the watchtower in the response. + IncludeSessions bool `protobuf:"varint,1,opt,name=include_sessions,proto3" json:"include_sessions,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListTowersRequest) Reset() { *m = ListTowersRequest{} } +func (m *ListTowersRequest) String() string { return proto.CompactTextString(m) } +func (*ListTowersRequest) ProtoMessage() {} +func (*ListTowersRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{7} +} + +func (m *ListTowersRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListTowersRequest.Unmarshal(m, b) +} +func (m *ListTowersRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListTowersRequest.Marshal(b, m, deterministic) +} +func (m *ListTowersRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListTowersRequest.Merge(m, src) +} +func (m *ListTowersRequest) XXX_Size() int { + return xxx_messageInfo_ListTowersRequest.Size(m) +} +func (m *ListTowersRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListTowersRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ListTowersRequest proto.InternalMessageInfo + +func (m *ListTowersRequest) GetIncludeSessions() bool { + if m != nil { + return m.IncludeSessions + } + return false +} + +type ListTowersResponse struct { + // The list of watchtowers available for new backups. + Towers []*Tower `protobuf:"bytes,1,rep,name=towers,proto3" json:"towers,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListTowersResponse) Reset() { *m = ListTowersResponse{} } +func (m *ListTowersResponse) String() string { return proto.CompactTextString(m) } +func (*ListTowersResponse) ProtoMessage() {} +func (*ListTowersResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{8} +} + +func (m *ListTowersResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListTowersResponse.Unmarshal(m, b) +} +func (m *ListTowersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListTowersResponse.Marshal(b, m, deterministic) +} +func (m *ListTowersResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListTowersResponse.Merge(m, src) +} +func (m *ListTowersResponse) XXX_Size() int { + return xxx_messageInfo_ListTowersResponse.Size(m) +} +func (m *ListTowersResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListTowersResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ListTowersResponse proto.InternalMessageInfo + +func (m *ListTowersResponse) GetTowers() []*Tower { + if m != nil { + return m.Towers + } + return nil +} + +type StatsRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatsRequest) Reset() { *m = StatsRequest{} } +func (m *StatsRequest) String() string { return proto.CompactTextString(m) } +func (*StatsRequest) ProtoMessage() {} +func (*StatsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{9} +} + +func (m *StatsRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StatsRequest.Unmarshal(m, b) +} +func (m *StatsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StatsRequest.Marshal(b, m, deterministic) +} +func (m *StatsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatsRequest.Merge(m, src) +} +func (m *StatsRequest) XXX_Size() int { + return xxx_messageInfo_StatsRequest.Size(m) +} +func (m *StatsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StatsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_StatsRequest proto.InternalMessageInfo + +type StatsResponse struct { + // + //The total number of backups made to all active and exhausted watchtower + //sessions. + NumBackups uint32 `protobuf:"varint,1,opt,name=num_backups,proto3" json:"num_backups,omitempty"` + // + //The total number of backups that are pending to be acknowledged by all + //active and exhausted watchtower sessions. + NumPendingBackups uint32 `protobuf:"varint,2,opt,name=num_pending_backups,proto3" json:"num_pending_backups,omitempty"` + // + //The total number of backups that all active and exhausted watchtower + //sessions have failed to acknowledge. + NumFailedBackups uint32 `protobuf:"varint,3,opt,name=num_failed_backups,proto3" json:"num_failed_backups,omitempty"` + // The total number of new sessions made to watchtowers. + NumSessionsAcquired uint32 `protobuf:"varint,4,opt,name=num_sessions_acquired,proto3" json:"num_sessions_acquired,omitempty"` + // The total number of watchtower sessions that have been exhausted. + NumSessionsExhausted uint32 `protobuf:"varint,5,opt,name=num_sessions_exhausted,proto3" json:"num_sessions_exhausted,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatsResponse) Reset() { *m = StatsResponse{} } +func (m *StatsResponse) String() string { return proto.CompactTextString(m) } +func (*StatsResponse) ProtoMessage() {} +func (*StatsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{10} +} + +func (m *StatsResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StatsResponse.Unmarshal(m, b) +} +func (m *StatsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StatsResponse.Marshal(b, m, deterministic) +} +func (m *StatsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatsResponse.Merge(m, src) +} +func (m *StatsResponse) XXX_Size() int { + return xxx_messageInfo_StatsResponse.Size(m) +} +func (m *StatsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StatsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_StatsResponse proto.InternalMessageInfo + +func (m *StatsResponse) GetNumBackups() uint32 { + if m != nil { + return m.NumBackups + } + return 0 +} + +func (m *StatsResponse) GetNumPendingBackups() uint32 { + if m != nil { + return m.NumPendingBackups + } + return 0 +} + +func (m *StatsResponse) GetNumFailedBackups() uint32 { + if m != nil { + return m.NumFailedBackups + } + return 0 +} + +func (m *StatsResponse) GetNumSessionsAcquired() uint32 { + if m != nil { + return m.NumSessionsAcquired + } + return 0 +} + +func (m *StatsResponse) GetNumSessionsExhausted() uint32 { + if m != nil { + return m.NumSessionsExhausted + } + return 0 +} + +type PolicyRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PolicyRequest) Reset() { *m = PolicyRequest{} } +func (m *PolicyRequest) String() string { return proto.CompactTextString(m) } +func (*PolicyRequest) ProtoMessage() {} +func (*PolicyRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{11} +} + +func (m *PolicyRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PolicyRequest.Unmarshal(m, b) +} +func (m *PolicyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PolicyRequest.Marshal(b, m, deterministic) +} +func (m *PolicyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PolicyRequest.Merge(m, src) +} +func (m *PolicyRequest) XXX_Size() int { + return xxx_messageInfo_PolicyRequest.Size(m) +} +func (m *PolicyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PolicyRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_PolicyRequest proto.InternalMessageInfo + +type PolicyResponse struct { + // + //The maximum number of updates each session we negotiate with watchtowers + //should allow. + MaxUpdates uint32 `protobuf:"varint,1,opt,name=max_updates,proto3" json:"max_updates,omitempty"` + // + //The fee rate, in satoshis per vbyte, that will be used by watchtowers for + //justice transactions in response to channel breaches. + SweepSatPerByte uint32 `protobuf:"varint,2,opt,name=sweep_sat_per_byte,proto3" json:"sweep_sat_per_byte,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PolicyResponse) Reset() { *m = PolicyResponse{} } +func (m *PolicyResponse) String() string { return proto.CompactTextString(m) } +func (*PolicyResponse) ProtoMessage() {} +func (*PolicyResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b5f4e7d95a641af2, []int{12} +} + +func (m *PolicyResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PolicyResponse.Unmarshal(m, b) +} +func (m *PolicyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PolicyResponse.Marshal(b, m, deterministic) +} +func (m *PolicyResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PolicyResponse.Merge(m, src) +} +func (m *PolicyResponse) XXX_Size() int { + return xxx_messageInfo_PolicyResponse.Size(m) +} +func (m *PolicyResponse) XXX_DiscardUnknown() { + xxx_messageInfo_PolicyResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_PolicyResponse proto.InternalMessageInfo + +func (m *PolicyResponse) GetMaxUpdates() uint32 { + if m != nil { + return m.MaxUpdates + } + return 0 +} + +func (m *PolicyResponse) GetSweepSatPerByte() uint32 { + if m != nil { + return m.SweepSatPerByte + } + return 0 +} + +func init() { + proto.RegisterType((*AddTowerRequest)(nil), "wtclientrpc.AddTowerRequest") + proto.RegisterType((*AddTowerResponse)(nil), "wtclientrpc.AddTowerResponse") + proto.RegisterType((*RemoveTowerRequest)(nil), "wtclientrpc.RemoveTowerRequest") + proto.RegisterType((*RemoveTowerResponse)(nil), "wtclientrpc.RemoveTowerResponse") + proto.RegisterType((*GetTowerInfoRequest)(nil), "wtclientrpc.GetTowerInfoRequest") + proto.RegisterType((*TowerSession)(nil), "wtclientrpc.TowerSession") + proto.RegisterType((*Tower)(nil), "wtclientrpc.Tower") + proto.RegisterType((*ListTowersRequest)(nil), "wtclientrpc.ListTowersRequest") + proto.RegisterType((*ListTowersResponse)(nil), "wtclientrpc.ListTowersResponse") + proto.RegisterType((*StatsRequest)(nil), "wtclientrpc.StatsRequest") + proto.RegisterType((*StatsResponse)(nil), "wtclientrpc.StatsResponse") + proto.RegisterType((*PolicyRequest)(nil), "wtclientrpc.PolicyRequest") + proto.RegisterType((*PolicyResponse)(nil), "wtclientrpc.PolicyResponse") +} + +func init() { proto.RegisterFile("wtclientrpc/wtclient.proto", fileDescriptor_b5f4e7d95a641af2) } + +var fileDescriptor_b5f4e7d95a641af2 = []byte{ + // 634 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xcb, 0x6e, 0xd3, 0x40, + 0x14, 0x95, 0x13, 0x12, 0xd2, 0x9b, 0xf4, 0xc1, 0xad, 0x5a, 0x19, 0x53, 0x68, 0xe4, 0x55, 0xd4, + 0x45, 0x02, 0x2d, 0xb0, 0x60, 0x01, 0x94, 0x22, 0x2a, 0x24, 0x90, 0x2a, 0x17, 0x09, 0xc1, 0xc6, + 0xf2, 0x63, 0x9a, 0x8c, 0xea, 0x8c, 0x5d, 0xcf, 0xb8, 0x69, 0x97, 0xfc, 0x13, 0xbf, 0xc0, 0x1f, + 0xf0, 0x41, 0xc8, 0xe3, 0x47, 0xc6, 0x8d, 0x2d, 0x16, 0x88, 0x5d, 0xe6, 0x9c, 0x93, 0x33, 0x37, + 0xf7, 0x9e, 0xdc, 0x01, 0x63, 0x21, 0xbc, 0x80, 0x12, 0x26, 0xe2, 0xc8, 0x9b, 0x14, 0x9f, 0xc7, + 0x51, 0x1c, 0x8a, 0x10, 0xfb, 0x0a, 0x67, 0x9e, 0xc0, 0xe6, 0xb1, 0xef, 0x7f, 0x09, 0x17, 0x24, + 0xb6, 0xc8, 0x55, 0x42, 0xb8, 0xc0, 0x5d, 0xe8, 0x46, 0x89, 0x7b, 0x49, 0x6e, 0x75, 0x6d, 0xa8, + 0x8d, 0x06, 0x56, 0x7e, 0x42, 0x1d, 0xee, 0x3b, 0xbe, 0x1f, 0x13, 0xce, 0xf5, 0xd6, 0x50, 0x1b, + 0xad, 0x59, 0xc5, 0xd1, 0x44, 0xd8, 0x5a, 0x9a, 0xf0, 0x28, 0x64, 0x9c, 0x98, 0x1f, 0x00, 0x2d, + 0x32, 0x0f, 0xaf, 0xc9, 0x3f, 0x7a, 0xef, 0xc0, 0x76, 0xc5, 0x27, 0xb7, 0xff, 0x06, 0xdb, 0xa7, + 0x44, 0x48, 0xec, 0x23, 0xbb, 0x08, 0xff, 0xe6, 0x7f, 0x00, 0x5b, 0x94, 0x79, 0x41, 0xe2, 0x13, + 0x9b, 0x13, 0xce, 0x69, 0xc8, 0xb2, 0x8b, 0x7a, 0xd6, 0x0a, 0x6e, 0xfe, 0xd4, 0x60, 0x20, 0x8d, + 0xcf, 0x33, 0x04, 0x87, 0xd0, 0x67, 0xc9, 0xdc, 0x76, 0x1d, 0xef, 0x32, 0x89, 0xb8, 0x74, 0x5e, + 0xb7, 0x54, 0x08, 0x9f, 0xc2, 0x76, 0x7a, 0x8c, 0x08, 0xf3, 0x29, 0x9b, 0x96, 0xca, 0x96, 0x54, + 0xd6, 0x51, 0xa9, 0xe7, 0xdc, 0xb9, 0x29, 0x95, 0xed, 0xcc, 0x53, 0x81, 0x70, 0x0c, 0xc8, 0x17, + 0x84, 0x44, 0x36, 0x77, 0x84, 0x1d, 0x91, 0xd8, 0x76, 0x6f, 0x05, 0xd1, 0xef, 0x49, 0x61, 0x0d, + 0x63, 0xfe, 0xd6, 0xa0, 0x23, 0xcb, 0x6e, 0x6c, 0xc2, 0x1e, 0xac, 0xe5, 0x5d, 0x25, 0x69, 0x6d, + 0xed, 0xd1, 0x9a, 0xb5, 0x04, 0xf0, 0x15, 0xe8, 0x8e, 0x27, 0xe8, 0x75, 0xd9, 0x09, 0xdb, 0x73, + 0x98, 0x4f, 0x7d, 0x47, 0x10, 0x59, 0x5e, 0xcf, 0x6a, 0xe4, 0xd1, 0x84, 0x41, 0xfa, 0x23, 0xcb, + 0xd6, 0x66, 0x55, 0x56, 0x30, 0x7c, 0x01, 0xbd, 0x92, 0xef, 0x0c, 0xdb, 0xa3, 0xfe, 0xe1, 0xc3, + 0xb1, 0x92, 0xc4, 0xb1, 0xda, 0x72, 0xab, 0x94, 0x9a, 0x6f, 0xe0, 0xc1, 0x27, 0xca, 0xb3, 0x49, + 0xf3, 0x62, 0xcc, 0x75, 0xe3, 0xd4, 0x1a, 0xc6, 0xf9, 0x16, 0x50, 0x35, 0xc8, 0xf2, 0x83, 0x07, + 0xd0, 0x15, 0x12, 0xd1, 0x35, 0x59, 0x0b, 0xae, 0xd6, 0x62, 0xe5, 0x0a, 0x73, 0x03, 0x06, 0xe7, + 0xc2, 0x11, 0xc5, 0xed, 0xe6, 0x8f, 0x16, 0xac, 0xe7, 0x40, 0xee, 0xf6, 0x3f, 0x12, 0x32, 0x06, + 0x4c, 0xe1, 0x0b, 0x87, 0x06, 0xc4, 0xbf, 0x13, 0x94, 0x1a, 0x06, 0x9f, 0xc3, 0x8e, 0xda, 0x6f, + 0xdb, 0xf1, 0xae, 0x12, 0x1a, 0x13, 0x3f, 0x1f, 0x46, 0x3d, 0x89, 0x2f, 0x61, 0xb7, 0x42, 0x90, + 0x9b, 0x99, 0x93, 0x70, 0x41, 0x7c, 0xbd, 0x23, 0xbf, 0xd6, 0xc0, 0x9a, 0x9b, 0xb0, 0x7e, 0x16, + 0x06, 0xd4, 0xbb, 0x2d, 0x9a, 0xe2, 0xc2, 0x46, 0x01, 0x2c, 0x9b, 0x92, 0xe6, 0x39, 0x89, 0xd2, + 0x88, 0x94, 0x4d, 0x51, 0xa0, 0x86, 0x88, 0xb7, 0x9a, 0x22, 0x7e, 0xf8, 0xab, 0x0d, 0x5b, 0x5f, + 0x1d, 0xe1, 0xcd, 0xe4, 0x60, 0x4e, 0xe4, 0xb8, 0xf0, 0x14, 0x7a, 0xc5, 0xf2, 0xc1, 0xbd, 0xca, + 0x14, 0xef, 0x2c, 0x36, 0xe3, 0x71, 0x03, 0x9b, 0xd7, 0x7b, 0x06, 0x7d, 0x65, 0xd3, 0xe0, 0x7e, + 0x45, 0xbd, 0xba, 0xcb, 0x8c, 0x61, 0xb3, 0x20, 0x77, 0xfc, 0x0c, 0xb0, 0x8c, 0x1e, 0x3e, 0xa9, + 0xe8, 0x57, 0x42, 0x6d, 0xec, 0x37, 0xf2, 0xb9, 0xdd, 0x7b, 0x18, 0xa8, 0x3b, 0x0f, 0xab, 0x05, + 0xd4, 0xac, 0x43, 0xa3, 0x26, 0xd5, 0xf8, 0x1a, 0x3a, 0x32, 0xbc, 0x58, 0xfd, 0xfb, 0xa9, 0x09, + 0x37, 0x8c, 0x3a, 0x2a, 0xaf, 0xe2, 0x18, 0xba, 0xd9, 0xa0, 0xb1, 0xaa, 0xaa, 0xc4, 0xc1, 0x78, + 0x54, 0xcb, 0x65, 0x16, 0xef, 0x8e, 0xbe, 0x3f, 0x9b, 0x52, 0x31, 0x4b, 0xdc, 0xb1, 0x17, 0xce, + 0x27, 0x01, 0x9d, 0xce, 0x04, 0xa3, 0x6c, 0xca, 0x88, 0x58, 0x84, 0xf1, 0xe5, 0x24, 0x60, 0xfe, + 0x24, 0x60, 0xea, 0xcb, 0x15, 0x47, 0x9e, 0xdb, 0x95, 0xaf, 0xd7, 0xd1, 0x9f, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xdd, 0x33, 0x97, 0x54, 0xdb, 0x06, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// 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.SupportPackageIsVersion4 + +// WatchtowerClientClient is the client API for WatchtowerClient service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type WatchtowerClientClient interface { + // + //AddTower adds a new watchtower reachable at the given address and + //considers it for new sessions. If the watchtower already exists, then + //any new addresses included will be considered when dialing it for + //session negotiations and backups. + AddTower(ctx context.Context, in *AddTowerRequest, opts ...grpc.CallOption) (*AddTowerResponse, error) + // + //RemoveTower removes a watchtower from being considered for future session + //negotiations and from being used for any subsequent backups until it's added + //again. If an address is provided, then this RPC only serves as a way of + //removing the address from the watchtower instead. + RemoveTower(ctx context.Context, in *RemoveTowerRequest, opts ...grpc.CallOption) (*RemoveTowerResponse, error) + // ListTowers returns the list of watchtowers registered with the client. + ListTowers(ctx context.Context, in *ListTowersRequest, opts ...grpc.CallOption) (*ListTowersResponse, error) + // GetTowerInfo retrieves information for a registered watchtower. + GetTowerInfo(ctx context.Context, in *GetTowerInfoRequest, opts ...grpc.CallOption) (*Tower, error) + // Stats returns the in-memory statistics of the client since startup. + Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error) + // Policy returns the active watchtower client policy configuration. + Policy(ctx context.Context, in *PolicyRequest, opts ...grpc.CallOption) (*PolicyResponse, error) +} + +type watchtowerClientClient struct { + cc *grpc.ClientConn +} + +func NewWatchtowerClientClient(cc *grpc.ClientConn) WatchtowerClientClient { + return &watchtowerClientClient{cc} +} + +func (c *watchtowerClientClient) AddTower(ctx context.Context, in *AddTowerRequest, opts ...grpc.CallOption) (*AddTowerResponse, error) { + out := new(AddTowerResponse) + err := c.cc.Invoke(ctx, "/wtclientrpc.WatchtowerClient/AddTower", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *watchtowerClientClient) RemoveTower(ctx context.Context, in *RemoveTowerRequest, opts ...grpc.CallOption) (*RemoveTowerResponse, error) { + out := new(RemoveTowerResponse) + err := c.cc.Invoke(ctx, "/wtclientrpc.WatchtowerClient/RemoveTower", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *watchtowerClientClient) ListTowers(ctx context.Context, in *ListTowersRequest, opts ...grpc.CallOption) (*ListTowersResponse, error) { + out := new(ListTowersResponse) + err := c.cc.Invoke(ctx, "/wtclientrpc.WatchtowerClient/ListTowers", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *watchtowerClientClient) GetTowerInfo(ctx context.Context, in *GetTowerInfoRequest, opts ...grpc.CallOption) (*Tower, error) { + out := new(Tower) + err := c.cc.Invoke(ctx, "/wtclientrpc.WatchtowerClient/GetTowerInfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *watchtowerClientClient) Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error) { + out := new(StatsResponse) + err := c.cc.Invoke(ctx, "/wtclientrpc.WatchtowerClient/Stats", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *watchtowerClientClient) Policy(ctx context.Context, in *PolicyRequest, opts ...grpc.CallOption) (*PolicyResponse, error) { + out := new(PolicyResponse) + err := c.cc.Invoke(ctx, "/wtclientrpc.WatchtowerClient/Policy", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// WatchtowerClientServer is the server API for WatchtowerClient service. +type WatchtowerClientServer interface { + // + //AddTower adds a new watchtower reachable at the given address and + //considers it for new sessions. If the watchtower already exists, then + //any new addresses included will be considered when dialing it for + //session negotiations and backups. + AddTower(context.Context, *AddTowerRequest) (*AddTowerResponse, error) + // + //RemoveTower removes a watchtower from being considered for future session + //negotiations and from being used for any subsequent backups until it's added + //again. If an address is provided, then this RPC only serves as a way of + //removing the address from the watchtower instead. + RemoveTower(context.Context, *RemoveTowerRequest) (*RemoveTowerResponse, error) + // ListTowers returns the list of watchtowers registered with the client. + ListTowers(context.Context, *ListTowersRequest) (*ListTowersResponse, error) + // GetTowerInfo retrieves information for a registered watchtower. + GetTowerInfo(context.Context, *GetTowerInfoRequest) (*Tower, error) + // Stats returns the in-memory statistics of the client since startup. + Stats(context.Context, *StatsRequest) (*StatsResponse, error) + // Policy returns the active watchtower client policy configuration. + Policy(context.Context, *PolicyRequest) (*PolicyResponse, error) +} + +func RegisterWatchtowerClientServer(s *grpc.Server, srv WatchtowerClientServer) { + s.RegisterService(&_WatchtowerClient_serviceDesc, srv) +} + +func _WatchtowerClient_AddTower_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddTowerRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WatchtowerClientServer).AddTower(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/wtclientrpc.WatchtowerClient/AddTower", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WatchtowerClientServer).AddTower(ctx, req.(*AddTowerRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WatchtowerClient_RemoveTower_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveTowerRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WatchtowerClientServer).RemoveTower(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/wtclientrpc.WatchtowerClient/RemoveTower", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WatchtowerClientServer).RemoveTower(ctx, req.(*RemoveTowerRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WatchtowerClient_ListTowers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListTowersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WatchtowerClientServer).ListTowers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/wtclientrpc.WatchtowerClient/ListTowers", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WatchtowerClientServer).ListTowers(ctx, req.(*ListTowersRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WatchtowerClient_GetTowerInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTowerInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WatchtowerClientServer).GetTowerInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/wtclientrpc.WatchtowerClient/GetTowerInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WatchtowerClientServer).GetTowerInfo(ctx, req.(*GetTowerInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WatchtowerClient_Stats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StatsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WatchtowerClientServer).Stats(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/wtclientrpc.WatchtowerClient/Stats", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WatchtowerClientServer).Stats(ctx, req.(*StatsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _WatchtowerClient_Policy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PolicyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(WatchtowerClientServer).Policy(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/wtclientrpc.WatchtowerClient/Policy", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WatchtowerClientServer).Policy(ctx, req.(*PolicyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _WatchtowerClient_serviceDesc = grpc.ServiceDesc{ + ServiceName: "wtclientrpc.WatchtowerClient", + HandlerType: (*WatchtowerClientServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddTower", + Handler: _WatchtowerClient_AddTower_Handler, + }, + { + MethodName: "RemoveTower", + Handler: _WatchtowerClient_RemoveTower_Handler, + }, + { + MethodName: "ListTowers", + Handler: _WatchtowerClient_ListTowers_Handler, + }, + { + MethodName: "GetTowerInfo", + Handler: _WatchtowerClient_GetTowerInfo_Handler, + }, + { + MethodName: "Stats", + Handler: _WatchtowerClient_Stats_Handler, + }, + { + MethodName: "Policy", + Handler: _WatchtowerClient_Policy_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "wtclientrpc/wtclient.proto", +} diff --git a/lnrpc/wtclientrpc/wtclient.proto b/lnrpc/wtclientrpc/wtclient.proto new file mode 100644 index 00000000..fa2910e9 --- /dev/null +++ b/lnrpc/wtclientrpc/wtclient.proto @@ -0,0 +1,165 @@ +syntax = "proto3"; + +package wtclientrpc; + +option go_package = "github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"; + +message AddTowerRequest { + // The identifying public key of the watchtower to add. + bytes pubkey = 1 [json_name = "pubkey"]; + + // A network address the watchtower is reachable over. + string address = 2 [json_name = "address"]; +} + +message AddTowerResponse { +} + +message RemoveTowerRequest { + // The identifying public key of the watchtower to remove. + bytes pubkey = 1 [json_name = "pubkey"]; + + /* + If set, then the record for this address will be removed, indicating that is + is stale. Otherwise, the watchtower will no longer be used for future + session negotiations and backups. + */ + string address = 2 [json_name = "address"]; +} + +message RemoveTowerResponse { +} + +message GetTowerInfoRequest { + // The identifying public key of the watchtower to retrieve information for. + bytes pubkey = 1 [json_name = "pubkey"]; + + // Whether we should include sessions with the watchtower in the response. + bool include_sessions = 2 [json_name = "include_sessions"]; +} + +message TowerSession { + /* + The total number of successful backups that have been made to the + watchtower session. + */ + uint32 num_backups = 1 [json_name = "num_backups"]; + + /* + The total number of backups in the session that are currently pending to be + acknowledged by the watchtower. + */ + uint32 num_pending_backups = 2 [json_name = "num_pending_backups"]; + + // The maximum number of backups allowed by the watchtower session. + uint32 max_backups = 3 [json_name = "max_backups"]; + + /* + The fee rate, in satoshis per vbyte, that will be used by the watchtower for + the justice transaction in the event of a channel breach. + */ + uint32 sweep_sat_per_byte = 4 [json_name = "sweep_sat_per_byte"]; +} + +message Tower { + // The identifying public key of the watchtower. + bytes pubkey = 1 [json_name = "pubkey"]; + + // The list of addresses the watchtower is reachable over. + repeated string addresses = 2 [json_name = "addresses"]; + + // Whether the watchtower is currently a candidate for new sessions. + bool active_session_candidate = 3 [json_name = "active_session_candidate"]; + + // The number of sessions that have been negotiated with the watchtower. + uint32 num_sessions = 4 [json_name = "num_sessions"]; + + // The list of sessions that have been negotiated with the watchtower. + repeated TowerSession sessions = 5 [json_name = "sessions"]; +} + +message ListTowersRequest { + // Whether we should include sessions with the watchtower in the response. + bool include_sessions = 1 [json_name = "include_sessions"]; +} + +message ListTowersResponse { + // The list of watchtowers available for new backups. + repeated Tower towers = 1 [json_name = "towers"]; +} + +message StatsRequest { +} + +message StatsResponse { + /* + The total number of backups made to all active and exhausted watchtower + sessions. + */ + uint32 num_backups = 1 [json_name = "num_backups"]; + + /* + The total number of backups that are pending to be acknowledged by all + active and exhausted watchtower sessions. + */ + uint32 num_pending_backups = 2 [json_name = "num_pending_backups"]; + + /* + The total number of backups that all active and exhausted watchtower + sessions have failed to acknowledge. + */ + uint32 num_failed_backups = 3 [json_name = "num_failed_backups"]; + + // The total number of new sessions made to watchtowers. + uint32 num_sessions_acquired = 4 [json_name = "num_sessions_acquired"]; + + // The total number of watchtower sessions that have been exhausted. + uint32 num_sessions_exhausted = 5 [json_name = "num_sessions_exhausted"]; +} + +message PolicyRequest { +} + +message PolicyResponse { + /* + The maximum number of updates each session we negotiate with watchtowers + should allow. + */ + uint32 max_updates = 1 [json_name = "max_updates"]; + + /* + The fee rate, in satoshis per vbyte, that will be used by watchtowers for + justice transactions in response to channel breaches. + */ + uint32 sweep_sat_per_byte = 2 [json_name = "sweep_sat_per_byte"]; +} + +service WatchtowerClient { + /* + AddTower adds a new watchtower reachable at the given address and + considers it for new sessions. If the watchtower already exists, then + any new addresses included will be considered when dialing it for + session negotiations and backups. + */ + rpc AddTower(AddTowerRequest) returns (AddTowerResponse); + + /* + RemoveTower removes a watchtower from being considered for future session + negotiations and from being used for any subsequent backups until it's added + again. If an address is provided, then this RPC only serves as a way of + removing the address from the watchtower instead. + */ + rpc RemoveTower(RemoveTowerRequest) returns (RemoveTowerResponse); + + // ListTowers returns the list of watchtowers registered with the client. + rpc ListTowers(ListTowersRequest) returns (ListTowersResponse); + + // GetTowerInfo retrieves information for a registered watchtower. + rpc GetTowerInfo(GetTowerInfoRequest) returns (Tower); + + // Stats returns the in-memory statistics of the client since startup. + rpc Stats(StatsRequest) returns (StatsResponse); + + // Policy returns the active watchtower client policy configuration. + rpc Policy(PolicyRequest) returns (PolicyResponse); +} diff --git a/lntest/itest/lnd_test.go b/lntest/itest/lnd_test.go index cbb796a1..e14a2a18 100644 --- a/lntest/itest/lnd_test.go +++ b/lntest/itest/lnd_test.go @@ -7677,7 +7677,7 @@ func testRevokedCloseRetributionAltruistWatchtower(net *lntest.NetworkHarness, defer shutdownAndAssert(net, t, willy) ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) - willyInfo, err := willy.WatchtowerClient.GetInfo( + willyInfo, err := willy.Watchtower.GetInfo( ctxt, &watchtowerrpc.GetInfoRequest{}, ) if err != nil { diff --git a/lntest/node.go b/lntest/node.go index 53caec46..2eeda37e 100644 --- a/lntest/node.go +++ b/lntest/node.go @@ -26,11 +26,12 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/watchtowerrpc" + "github.com/lightningnetwork/lnd/lnrpc/wtclientrpc" "github.com/lightningnetwork/lnd/macaroons" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/credentials" - macaroon "gopkg.in/macaroon.v2" + "gopkg.in/macaroon.v2" ) const ( @@ -265,7 +266,8 @@ type HarnessNode struct { // because a name collision would occur with LightningClient. RouterClient routerrpc.RouterClient WalletKitClient walletrpc.WalletKitClient - WatchtowerClient watchtowerrpc.WatchtowerClient + Watchtower watchtowerrpc.WatchtowerClient + WatchtowerClient wtclientrpc.WatchtowerClientClient } // Assert *HarnessNode implements the lnrpc.LightningClient interface. @@ -526,7 +528,8 @@ func (hn *HarnessNode) initLightningClient(conn *grpc.ClientConn) error { hn.InvoicesClient = invoicesrpc.NewInvoicesClient(conn) hn.RouterClient = routerrpc.NewRouterClient(conn) hn.WalletKitClient = walletrpc.NewWalletKitClient(conn) - hn.WatchtowerClient = watchtowerrpc.NewWatchtowerClient(conn) + hn.Watchtower = watchtowerrpc.NewWatchtowerClient(conn) + hn.WatchtowerClient = wtclientrpc.NewWatchtowerClientClient(conn) // Set the harness node's pubkey to what the node claims in GetInfo. err := hn.FetchNodeInfo() @@ -729,6 +732,7 @@ func (hn *HarnessNode) stop() error { hn.processExit = nil hn.LightningClient = nil hn.WalletUnlockerClient = nil + hn.Watchtower = nil hn.WatchtowerClient = nil return nil } diff --git a/log.go b/log.go index b79fa047..6cca176e 100644 --- a/log.go +++ b/log.go @@ -27,6 +27,7 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/signrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc" + "github.com/lightningnetwork/lnd/lnrpc/wtclientrpc" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/monitoring" "github.com/lightningnetwork/lnd/netann" @@ -120,6 +121,7 @@ func init() { wtclient.UseLogger(wtclLog) addSubLogger(routerrpc.Subsystem, routerrpc.UseLogger) + addSubLogger(wtclientrpc.Subsystem, wtclientrpc.UseLogger) } // addSubLogger is a helper method to conveniently register the logger of a sub diff --git a/make/testing_flags.mk b/make/testing_flags.mk index 297fd1ea..5105d190 100644 --- a/make/testing_flags.mk +++ b/make/testing_flags.mk @@ -56,7 +56,7 @@ endif # Construct the integration test command with the added build flags. -ITEST_TAGS := $(DEV_TAGS) rpctest chainrpc walletrpc signrpc invoicesrpc autopilotrpc routerrpc watchtowerrpc +ITEST_TAGS := $(DEV_TAGS) rpctest chainrpc walletrpc signrpc invoicesrpc autopilotrpc routerrpc watchtowerrpc wtclientrpc # Default to btcd backend if not set. ifneq ($(backend),) diff --git a/rpcserver.go b/rpcserver.go index 99234497..1363df26 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -497,8 +497,8 @@ func newRPCServer(s *server, macService *macaroons.Service, err = subServerCgs.PopulateDependencies( s.cc, networkDir, macService, atpl, invoiceRegistry, s.htlcSwitch, activeNetParams.Params, s.chanRouter, - routerBackend, s.nodeSigner, s.chanDB, s.sweeper, - tower, + routerBackend, s.nodeSigner, s.chanDB, s.sweeper, tower, + s.towerClient, cfg.net.ResolveTCPAddr, ) if err != nil { return nil, err diff --git a/subrpcserver_config.go b/subrpcserver_config.go index dffac0b6..06b9dfc5 100644 --- a/subrpcserver_config.go +++ b/subrpcserver_config.go @@ -9,6 +9,7 @@ import ( "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/invoices" + "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc/autopilotrpc" "github.com/lightningnetwork/lnd/lnrpc/chainrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" @@ -16,11 +17,13 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/signrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/watchtowerrpc" + "github.com/lightningnetwork/lnd/lnrpc/wtclientrpc" "github.com/lightningnetwork/lnd/macaroons" "github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/sweep" "github.com/lightningnetwork/lnd/watchtower" + "github.com/lightningnetwork/lnd/watchtower/wtclient" ) // subRPCServerConfigs is special sub-config in the main configuration that @@ -62,6 +65,12 @@ type subRPCServerConfigs struct { // WatchtowerRPC is a sub-RPC server that exposes functionality allowing // clients to monitor and control their embedded watchtower. WatchtowerRPC *watchtowerrpc.Config `group:"watchtowerrpc" namespace:"watchtowerrpc"` + + // WatchtowerClientRPC is a sub-RPC server that exposes functionality + // that allows clients to interact with the active watchtower client + // instance within lnd in order to add, remove, list registered client + // towers, etc. + WatchtowerClientRPC *wtclientrpc.Config `group:"wtclientrpc" namespace:"wtclientrpc"` } // PopulateDependencies attempts to iterate through all the sub-server configs @@ -81,7 +90,9 @@ func (s *subRPCServerConfigs) PopulateDependencies(cc *chainControl, nodeSigner *netann.NodeSigner, chanDB *channeldb.DB, sweeper *sweep.UtxoSweeper, - tower *watchtower.Standalone) error { + tower *watchtower.Standalone, + towerClient wtclient.Client, + tcpResolver lncfg.TCPResolver) error { // First, we'll use reflect to obtain a version of the config struct // that allows us to programmatically inspect its fields. @@ -223,6 +234,21 @@ func (s *subRPCServerConfigs) PopulateDependencies(cc *chainControl, reflect.ValueOf(tower), ) + case *wtclientrpc.Config: + subCfgValue := extractReflectValue(subCfg) + + if towerClient != nil { + subCfgValue.FieldByName("Active").Set( + reflect.ValueOf(towerClient != nil), + ) + subCfgValue.FieldByName("Client").Set( + reflect.ValueOf(towerClient), + ) + } + subCfgValue.FieldByName("Resolver").Set( + reflect.ValueOf(tcpResolver), + ) + default: return fmt.Errorf("unknown field: %v, %T", fieldName, cfg)