diff --git a/htlcswitch/interfaces.go b/htlcswitch/interfaces.go index 8ca781e1ff9..f978682d5cc 100644 --- a/htlcswitch/interfaces.go +++ b/htlcswitch/interfaces.go @@ -1,7 +1,6 @@ package htlcswitch import ( - "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/lnpeer" @@ -77,9 +76,6 @@ type ChannelLink interface { // possible). HandleChannelUpdate(lnwire.Message) - // ChannelPoint returns the channel outpoint for the channel link. - ChannelPoint() *wire.OutPoint - // ChanID returns the channel ID for the channel link. The channel ID // is a more compact representation of a channel's full outpoint. ChanID() lnwire.ChannelID diff --git a/htlcswitch/virtual_link.go b/htlcswitch/virtual_link.go new file mode 100644 index 00000000000..644aa518966 --- /dev/null +++ b/htlcswitch/virtual_link.go @@ -0,0 +1,233 @@ +package htlcswitch + +import ( + "encoding/hex" + "errors" + "fmt" + "net" + + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/wire" + + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/lnpeer" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnwire" +) + +type virtualLink struct { + mailBox MailBox + id lnwire.ChannelID + peer *virtualPeer + packet *htlcPacket + forwardPackets func(chan struct{}, ...*htlcPacket) chan error + quit chan struct{} + circuitModifier CircuitModifier + htlcAccepted func(lnwire.ChannelID, lnwire.Message, uint32) +} + +type VirtualLink interface { + SettleHtlc(preimage lntypes.Preimage) error +} + +func NewVirtualLink(pubKey [33]byte, chanId [32]byte, + fwdPackets func(chan struct{}, ...*htlcPacket) chan error, + circuitModifier CircuitModifier, + htlcAccepted func(lnwire.ChannelID, lnwire.Message, uint32)) ChannelLink { + + identityKey, err := btcec.ParsePubKey(pubKey[:], btcec.S256()) + if err != nil { + panic(fmt.Sprintf("Failed to parse pubkey for peer: %v", err)) + } + + // FIXME: I need an HTLCNotifier instance so I can tell it all about the HTLCs here + return &virtualLink{ + id: chanId, + peer: &virtualPeer{ + pubKey: pubKey, + identityKey: identityKey, + }, + forwardPackets: fwdPackets, + circuitModifier: circuitModifier, + htlcAccepted: htlcAccepted, + } +} + +func (v *virtualLink) SettleHtlc(preimage lntypes.Preimage) error { + log.Errorf("Settling %v", preimage.String()) + + log.Errorf("Out %v In %v", v.packet.outgoingChanID, v.packet.incomingChanID) + + settlePacket := &htlcPacket{ + outgoingChanID: v.ShortChanID(), + outgoingHTLCID: v.packet.outgoingHTLCID, + incomingHTLCID: v.packet.incomingHTLCID, + incomingChanID: v.packet.incomingChanID, + htlc: &lnwire.UpdateFulfillHTLC{ + PaymentPreimage: preimage, + }, + } + + errChan := v.forwardPackets(v.quit, settlePacket) + go func() { + for { + err, ok := <-errChan + if !ok { + // Err chan has been drained or switch is shutting + // down. Either way, return. + return + } + + if err == nil { + continue + } + + log.Errorf("unhandled error while forwarding htlc packet over htlcswitch: %v", err) + } + }() + + return nil +} + +func (v *virtualLink) HandleSwitchPacket(packet *htlcPacket) error { + log.Errorf("HandleSwitchPacket %v", packet) + v.packet = packet + v.circuitModifier.OpenCircuits(packet.keystone()) + + htlc := packet.htlc.(*lnwire.UpdateAddHTLC) + log.Errorf("Payment hash = %v\n", hex.EncodeToString(htlc.PaymentHash[:])) + + // This id actually needs to increment! Otherwise we use already existing circuits + // That, or we have to, you know, close circuits :D + packet.outgoingHTLCID = 0 + packet.outgoingChanID = v.ShortChanID() + + go v.htlcAccepted(v.id, packet.htlc, packet.outgoingTimeout) + + // TODO: We need to be able to cancel forwards at some point + return nil +} + +func (v *virtualLink) HandleChannelUpdate(msg lnwire.Message) { + log.Errorf("HandleChannelUpdate %v", msg) +} + +func (v *virtualLink) ChanID() lnwire.ChannelID { + log.Errorf("Got asked for ChanID") + return v.id +} + +func (v *virtualLink) ShortChanID() lnwire.ShortChannelID { + log.Errorf("Got asked for ShortChanID") + short := lnwire.ShortChannelID{ + BlockHeight: 1, + TxIndex: 1, + TxPosition: 0, + } + log.Errorf("short chan id = %v", short.ToUint64()) + + return short +} + +func (v *virtualLink) UpdateShortChanID() (lnwire.ShortChannelID, error) { + // Noop + return v.ShortChanID(), nil +} + +func (v *virtualLink) UpdateForwardingPolicy(ForwardingPolicy) { + // Noop +} + +func (v *virtualLink) CheckHtlcForward(payHash [32]byte, incomingAmt lnwire.MilliSatoshi, + amtToForward lnwire.MilliSatoshi, incomingTimeout, outgoingTimeout uint32, heightNow uint32) LinkError { + log.Errorf("CheckHtlcForward %v", hex.EncodeToString(payHash[:])) + return nil +} + +func (v *virtualLink) CheckHtlcTransit(payHash [32]byte, amt lnwire.MilliSatoshi, + timeout uint32, heightNow uint32) LinkError { + log.Errorf("CheckHtlcTransit %v", hex.EncodeToString(payHash[:])) + return nil +} + +func (v *virtualLink) Bandwidth() lnwire.MilliSatoshi { + // There's no good value here, so we just settle for a fixed value + // This is 0.1BTC + return 100000000 * 1000 +} + +func (v *virtualLink) Stats() (uint64, lnwire.MilliSatoshi, lnwire.MilliSatoshi) { + // FIXME: record and return stats + return 0, 0, 0 +} + +func (v *virtualLink) Peer() lnpeer.Peer { + return v.peer +} + +func (v *virtualLink) EligibleToForward() bool { + return true +} + +func (v *virtualLink) AttachMailBox(mailBox MailBox) { + // FIXME: The mailbox is a mandatory thing, other subsystems might write directly to it + v.mailBox = mailBox +} + +func (v *virtualLink) Start() error { + // TODO: Needs impl + return nil +} + +func (v *virtualLink) Stop() { + // TODO: Needs impl + close(v.quit) +} + +type virtualPeer struct { + pubKey [33]byte + identityKey *btcec.PublicKey +} + +func (vp *virtualPeer) SendMessage(sync bool, msgs ...lnwire.Message) error { + // This would seem to be used by subsystems other than the htlcswitch, so it should be safe to not implement + panic("Cant send messages to virtual peers") +} + +func (vp *virtualPeer) SendMessageLazy(sync bool, msgs ...lnwire.Message) error { + // This would seem to be used by subsystems other than the htlcswitch, so it should be safe to not implement + panic("Cant send messages to virtual peers") +} + +func (vp *virtualPeer) AddNewChannel(channel *channeldb.OpenChannel, cancel <-chan struct{}) error { + return errors.New("can't add a channel to a virtual link") +} + +func (vp *virtualPeer) WipeChannel(*wire.OutPoint) error { + return errors.New("can't wipe a channel from a virtual link") +} + +func (vp *virtualPeer) PubKey() [33]byte { + return vp.pubKey +} + +func (vp *virtualPeer) IdentityKey() *btcec.PublicKey { + return vp.identityKey +} + +func (vp *virtualPeer) Address() net.Addr { + panic("can't ask the Address from a virtualPeer") +} + +func (vp *virtualPeer) QuitSignal() <-chan struct{} { + panic("can't ask the QuitSignal from a virtualPeer") +} + +func (vp *virtualPeer) LocalFeatures() *lnwire.FeatureVector { + return lnwire.NewFeatureVector(nil, nil) +} + +func (vp *virtualPeer) RemoteFeatures() *lnwire.FeatureVector { + // TODO: When we implement MPP we have to declare that here + return lnwire.NewFeatureVector(nil, nil) +} diff --git a/lnrpc/virtualchannelsrpc/config_active.go b/lnrpc/virtualchannelsrpc/config_active.go new file mode 100644 index 00000000000..deffd354793 --- /dev/null +++ b/lnrpc/virtualchannelsrpc/config_active.go @@ -0,0 +1,24 @@ +package virtualchannelsrpc + +import ( + "github.com/lightningnetwork/lnd/htlcswitch" + "github.com/lightningnetwork/lnd/macaroons" +) + +// Config is the primary configuration struct for the 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 { + // NetworkDir is the main network directory wherein the rpc + // server will find the macaroon named DefaultVirtualChannelsMacFilename. + NetworkDir string + + // MacService is the main macaroon service that we'll use to handle + // authentication for the rpc server. + MacService *macaroons.Service + + // Switch is used to register new virtual channels + Switch *htlcswitch.Switch +} diff --git a/lnrpc/virtualchannelsrpc/driver.go b/lnrpc/virtualchannelsrpc/driver.go new file mode 100644 index 00000000000..8814b9d26c8 --- /dev/null +++ b/lnrpc/virtualchannelsrpc/driver.go @@ -0,0 +1,53 @@ +package virtualchannelsrpc + +import ( + "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) + } + + 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/virtualchannelsrpc/log.go b/lnrpc/virtualchannelsrpc/log.go new file mode 100644 index 00000000000..1dd7f6eb62a --- /dev/null +++ b/lnrpc/virtualchannelsrpc/log.go @@ -0,0 +1,45 @@ +package virtualchannelsrpc + +import ( + "github.com/btcsuite/btclog" + "github.com/lightningnetwork/lnd/build" +) + +// 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("VCRPC", 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/virtualchannelsrpc/virtualchannels.pb.go b/lnrpc/virtualchannelsrpc/virtualchannels.pb.go new file mode 100644 index 00000000000..8676bb4228f --- /dev/null +++ b/lnrpc/virtualchannelsrpc/virtualchannels.pb.go @@ -0,0 +1,764 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: virtualchannelsrpc/virtualchannels.proto + +package virtualchannelsrpc + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + 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 CreateVirtualChannelRequest struct { + NodePubKey []byte `protobuf:"bytes,1,opt,name=node_pub_key,json=nodePubKey,proto3" json:"node_pub_key,omitempty"` + ChannelId []byte `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateVirtualChannelRequest) Reset() { *m = CreateVirtualChannelRequest{} } +func (m *CreateVirtualChannelRequest) String() string { return proto.CompactTextString(m) } +func (*CreateVirtualChannelRequest) ProtoMessage() {} +func (*CreateVirtualChannelRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_67568afc06a5a11f, []int{0} +} + +func (m *CreateVirtualChannelRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateVirtualChannelRequest.Unmarshal(m, b) +} +func (m *CreateVirtualChannelRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateVirtualChannelRequest.Marshal(b, m, deterministic) +} +func (m *CreateVirtualChannelRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateVirtualChannelRequest.Merge(m, src) +} +func (m *CreateVirtualChannelRequest) XXX_Size() int { + return xxx_messageInfo_CreateVirtualChannelRequest.Size(m) +} +func (m *CreateVirtualChannelRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateVirtualChannelRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateVirtualChannelRequest proto.InternalMessageInfo + +func (m *CreateVirtualChannelRequest) GetNodePubKey() []byte { + if m != nil { + return m.NodePubKey + } + return nil +} + +func (m *CreateVirtualChannelRequest) GetChannelId() []byte { + if m != nil { + return m.ChannelId + } + return nil +} + +type CreateVirtualChannelResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateVirtualChannelResponse) Reset() { *m = CreateVirtualChannelResponse{} } +func (m *CreateVirtualChannelResponse) String() string { return proto.CompactTextString(m) } +func (*CreateVirtualChannelResponse) ProtoMessage() {} +func (*CreateVirtualChannelResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_67568afc06a5a11f, []int{1} +} + +func (m *CreateVirtualChannelResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateVirtualChannelResponse.Unmarshal(m, b) +} +func (m *CreateVirtualChannelResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateVirtualChannelResponse.Marshal(b, m, deterministic) +} +func (m *CreateVirtualChannelResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateVirtualChannelResponse.Merge(m, src) +} +func (m *CreateVirtualChannelResponse) XXX_Size() int { + return xxx_messageInfo_CreateVirtualChannelResponse.Size(m) +} +func (m *CreateVirtualChannelResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateVirtualChannelResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateVirtualChannelResponse proto.InternalMessageInfo + +type SubscribeVirtualForwardRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SubscribeVirtualForwardRequest) Reset() { *m = SubscribeVirtualForwardRequest{} } +func (m *SubscribeVirtualForwardRequest) String() string { return proto.CompactTextString(m) } +func (*SubscribeVirtualForwardRequest) ProtoMessage() {} +func (*SubscribeVirtualForwardRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_67568afc06a5a11f, []int{2} +} + +func (m *SubscribeVirtualForwardRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SubscribeVirtualForwardRequest.Unmarshal(m, b) +} +func (m *SubscribeVirtualForwardRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SubscribeVirtualForwardRequest.Marshal(b, m, deterministic) +} +func (m *SubscribeVirtualForwardRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SubscribeVirtualForwardRequest.Merge(m, src) +} +func (m *SubscribeVirtualForwardRequest) XXX_Size() int { + return xxx_messageInfo_SubscribeVirtualForwardRequest.Size(m) +} +func (m *SubscribeVirtualForwardRequest) XXX_DiscardUnknown() { + xxx_messageInfo_SubscribeVirtualForwardRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_SubscribeVirtualForwardRequest proto.InternalMessageInfo + +type VirtualForward struct { + ChannelId []byte `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + Htlc []byte `protobuf:"bytes,2,opt,name=htlc,proto3" json:"htlc,omitempty"` + Timeout int64 `protobuf:"varint,3,opt,name=timeout,proto3" json:"timeout,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *VirtualForward) Reset() { *m = VirtualForward{} } +func (m *VirtualForward) String() string { return proto.CompactTextString(m) } +func (*VirtualForward) ProtoMessage() {} +func (*VirtualForward) Descriptor() ([]byte, []int) { + return fileDescriptor_67568afc06a5a11f, []int{3} +} + +func (m *VirtualForward) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_VirtualForward.Unmarshal(m, b) +} +func (m *VirtualForward) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_VirtualForward.Marshal(b, m, deterministic) +} +func (m *VirtualForward) XXX_Merge(src proto.Message) { + xxx_messageInfo_VirtualForward.Merge(m, src) +} +func (m *VirtualForward) XXX_Size() int { + return xxx_messageInfo_VirtualForward.Size(m) +} +func (m *VirtualForward) XXX_DiscardUnknown() { + xxx_messageInfo_VirtualForward.DiscardUnknown(m) +} + +var xxx_messageInfo_VirtualForward proto.InternalMessageInfo + +func (m *VirtualForward) GetChannelId() []byte { + if m != nil { + return m.ChannelId + } + return nil +} + +func (m *VirtualForward) GetHtlc() []byte { + if m != nil { + return m.Htlc + } + return nil +} + +func (m *VirtualForward) GetTimeout() int64 { + if m != nil { + return m.Timeout + } + return 0 +} + +type SettleVirtualForwardRequest struct { + ChannelId []byte `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + Preimage []byte `protobuf:"bytes,2,opt,name=preimage,proto3" json:"preimage,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SettleVirtualForwardRequest) Reset() { *m = SettleVirtualForwardRequest{} } +func (m *SettleVirtualForwardRequest) String() string { return proto.CompactTextString(m) } +func (*SettleVirtualForwardRequest) ProtoMessage() {} +func (*SettleVirtualForwardRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_67568afc06a5a11f, []int{4} +} + +func (m *SettleVirtualForwardRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SettleVirtualForwardRequest.Unmarshal(m, b) +} +func (m *SettleVirtualForwardRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SettleVirtualForwardRequest.Marshal(b, m, deterministic) +} +func (m *SettleVirtualForwardRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SettleVirtualForwardRequest.Merge(m, src) +} +func (m *SettleVirtualForwardRequest) XXX_Size() int { + return xxx_messageInfo_SettleVirtualForwardRequest.Size(m) +} +func (m *SettleVirtualForwardRequest) XXX_DiscardUnknown() { + xxx_messageInfo_SettleVirtualForwardRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_SettleVirtualForwardRequest proto.InternalMessageInfo + +func (m *SettleVirtualForwardRequest) GetChannelId() []byte { + if m != nil { + return m.ChannelId + } + return nil +} + +func (m *SettleVirtualForwardRequest) GetPreimage() []byte { + if m != nil { + return m.Preimage + } + return nil +} + +type SettleVirtualForwardResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SettleVirtualForwardResponse) Reset() { *m = SettleVirtualForwardResponse{} } +func (m *SettleVirtualForwardResponse) String() string { return proto.CompactTextString(m) } +func (*SettleVirtualForwardResponse) ProtoMessage() {} +func (*SettleVirtualForwardResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_67568afc06a5a11f, []int{5} +} + +func (m *SettleVirtualForwardResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SettleVirtualForwardResponse.Unmarshal(m, b) +} +func (m *SettleVirtualForwardResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SettleVirtualForwardResponse.Marshal(b, m, deterministic) +} +func (m *SettleVirtualForwardResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_SettleVirtualForwardResponse.Merge(m, src) +} +func (m *SettleVirtualForwardResponse) XXX_Size() int { + return xxx_messageInfo_SettleVirtualForwardResponse.Size(m) +} +func (m *SettleVirtualForwardResponse) XXX_DiscardUnknown() { + xxx_messageInfo_SettleVirtualForwardResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_SettleVirtualForwardResponse proto.InternalMessageInfo + +type DeleteVirtualChannelRequest struct { + NodePubKey []byte `protobuf:"bytes,1,opt,name=node_pub_key,json=nodePubKey,proto3" json:"node_pub_key,omitempty"` + ChannelId []byte `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteVirtualChannelRequest) Reset() { *m = DeleteVirtualChannelRequest{} } +func (m *DeleteVirtualChannelRequest) String() string { return proto.CompactTextString(m) } +func (*DeleteVirtualChannelRequest) ProtoMessage() {} +func (*DeleteVirtualChannelRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_67568afc06a5a11f, []int{6} +} + +func (m *DeleteVirtualChannelRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteVirtualChannelRequest.Unmarshal(m, b) +} +func (m *DeleteVirtualChannelRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteVirtualChannelRequest.Marshal(b, m, deterministic) +} +func (m *DeleteVirtualChannelRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteVirtualChannelRequest.Merge(m, src) +} +func (m *DeleteVirtualChannelRequest) XXX_Size() int { + return xxx_messageInfo_DeleteVirtualChannelRequest.Size(m) +} +func (m *DeleteVirtualChannelRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteVirtualChannelRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteVirtualChannelRequest proto.InternalMessageInfo + +func (m *DeleteVirtualChannelRequest) GetNodePubKey() []byte { + if m != nil { + return m.NodePubKey + } + return nil +} + +func (m *DeleteVirtualChannelRequest) GetChannelId() []byte { + if m != nil { + return m.ChannelId + } + return nil +} + +type DeleteVirtualChannelResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteVirtualChannelResponse) Reset() { *m = DeleteVirtualChannelResponse{} } +func (m *DeleteVirtualChannelResponse) String() string { return proto.CompactTextString(m) } +func (*DeleteVirtualChannelResponse) ProtoMessage() {} +func (*DeleteVirtualChannelResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_67568afc06a5a11f, []int{7} +} + +func (m *DeleteVirtualChannelResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteVirtualChannelResponse.Unmarshal(m, b) +} +func (m *DeleteVirtualChannelResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteVirtualChannelResponse.Marshal(b, m, deterministic) +} +func (m *DeleteVirtualChannelResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteVirtualChannelResponse.Merge(m, src) +} +func (m *DeleteVirtualChannelResponse) XXX_Size() int { + return xxx_messageInfo_DeleteVirtualChannelResponse.Size(m) +} +func (m *DeleteVirtualChannelResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteVirtualChannelResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteVirtualChannelResponse proto.InternalMessageInfo + +type ListVirtualChannelsRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListVirtualChannelsRequest) Reset() { *m = ListVirtualChannelsRequest{} } +func (m *ListVirtualChannelsRequest) String() string { return proto.CompactTextString(m) } +func (*ListVirtualChannelsRequest) ProtoMessage() {} +func (*ListVirtualChannelsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_67568afc06a5a11f, []int{8} +} + +func (m *ListVirtualChannelsRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListVirtualChannelsRequest.Unmarshal(m, b) +} +func (m *ListVirtualChannelsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListVirtualChannelsRequest.Marshal(b, m, deterministic) +} +func (m *ListVirtualChannelsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListVirtualChannelsRequest.Merge(m, src) +} +func (m *ListVirtualChannelsRequest) XXX_Size() int { + return xxx_messageInfo_ListVirtualChannelsRequest.Size(m) +} +func (m *ListVirtualChannelsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListVirtualChannelsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ListVirtualChannelsRequest proto.InternalMessageInfo + +type ListVirtualChannelsResponse struct { + Channels []*VirtualChannel `protobuf:"bytes,1,rep,name=channels,proto3" json:"channels,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListVirtualChannelsResponse) Reset() { *m = ListVirtualChannelsResponse{} } +func (m *ListVirtualChannelsResponse) String() string { return proto.CompactTextString(m) } +func (*ListVirtualChannelsResponse) ProtoMessage() {} +func (*ListVirtualChannelsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_67568afc06a5a11f, []int{9} +} + +func (m *ListVirtualChannelsResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListVirtualChannelsResponse.Unmarshal(m, b) +} +func (m *ListVirtualChannelsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListVirtualChannelsResponse.Marshal(b, m, deterministic) +} +func (m *ListVirtualChannelsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListVirtualChannelsResponse.Merge(m, src) +} +func (m *ListVirtualChannelsResponse) XXX_Size() int { + return xxx_messageInfo_ListVirtualChannelsResponse.Size(m) +} +func (m *ListVirtualChannelsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListVirtualChannelsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ListVirtualChannelsResponse proto.InternalMessageInfo + +func (m *ListVirtualChannelsResponse) GetChannels() []*VirtualChannel { + if m != nil { + return m.Channels + } + return nil +} + +type VirtualChannel struct { + NodePubKey []byte `protobuf:"bytes,1,opt,name=node_pub_key,json=nodePubKey,proto3" json:"node_pub_key,omitempty"` + ChannelId []byte `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *VirtualChannel) Reset() { *m = VirtualChannel{} } +func (m *VirtualChannel) String() string { return proto.CompactTextString(m) } +func (*VirtualChannel) ProtoMessage() {} +func (*VirtualChannel) Descriptor() ([]byte, []int) { + return fileDescriptor_67568afc06a5a11f, []int{10} +} + +func (m *VirtualChannel) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_VirtualChannel.Unmarshal(m, b) +} +func (m *VirtualChannel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_VirtualChannel.Marshal(b, m, deterministic) +} +func (m *VirtualChannel) XXX_Merge(src proto.Message) { + xxx_messageInfo_VirtualChannel.Merge(m, src) +} +func (m *VirtualChannel) XXX_Size() int { + return xxx_messageInfo_VirtualChannel.Size(m) +} +func (m *VirtualChannel) XXX_DiscardUnknown() { + xxx_messageInfo_VirtualChannel.DiscardUnknown(m) +} + +var xxx_messageInfo_VirtualChannel proto.InternalMessageInfo + +func (m *VirtualChannel) GetNodePubKey() []byte { + if m != nil { + return m.NodePubKey + } + return nil +} + +func (m *VirtualChannel) GetChannelId() []byte { + if m != nil { + return m.ChannelId + } + return nil +} + +func init() { + proto.RegisterType((*CreateVirtualChannelRequest)(nil), "virtualchannelsrpc.CreateVirtualChannelRequest") + proto.RegisterType((*CreateVirtualChannelResponse)(nil), "virtualchannelsrpc.CreateVirtualChannelResponse") + proto.RegisterType((*SubscribeVirtualForwardRequest)(nil), "virtualchannelsrpc.SubscribeVirtualForwardRequest") + proto.RegisterType((*VirtualForward)(nil), "virtualchannelsrpc.VirtualForward") + proto.RegisterType((*SettleVirtualForwardRequest)(nil), "virtualchannelsrpc.SettleVirtualForwardRequest") + proto.RegisterType((*SettleVirtualForwardResponse)(nil), "virtualchannelsrpc.SettleVirtualForwardResponse") + proto.RegisterType((*DeleteVirtualChannelRequest)(nil), "virtualchannelsrpc.DeleteVirtualChannelRequest") + proto.RegisterType((*DeleteVirtualChannelResponse)(nil), "virtualchannelsrpc.DeleteVirtualChannelResponse") + proto.RegisterType((*ListVirtualChannelsRequest)(nil), "virtualchannelsrpc.ListVirtualChannelsRequest") + proto.RegisterType((*ListVirtualChannelsResponse)(nil), "virtualchannelsrpc.ListVirtualChannelsResponse") + proto.RegisterType((*VirtualChannel)(nil), "virtualchannelsrpc.VirtualChannel") +} + +func init() { + proto.RegisterFile("virtualchannelsrpc/virtualchannels.proto", fileDescriptor_67568afc06a5a11f) +} + +var fileDescriptor_67568afc06a5a11f = []byte{ + // 435 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0xdf, 0x6b, 0xd4, 0x40, + 0x10, 0xc7, 0x89, 0x57, 0xb4, 0x8e, 0x45, 0x61, 0x15, 0x0c, 0x49, 0x2d, 0x21, 0x4f, 0x79, 0x4a, + 0xca, 0xf9, 0x22, 0x3e, 0xf8, 0x60, 0x45, 0x10, 0x7d, 0xd0, 0x2b, 0x88, 0x08, 0xf6, 0xc8, 0x8f, + 0x21, 0x59, 0xba, 0xb7, 0x1b, 0x77, 0x37, 0x2d, 0xf7, 0x57, 0xfb, 0x2f, 0x48, 0x2e, 0x7b, 0x27, + 0x4d, 0xa7, 0xf1, 0x40, 0x7c, 0xcb, 0xee, 0x77, 0x76, 0xbe, 0x33, 0x93, 0xcf, 0x2e, 0x24, 0x57, + 0x5c, 0xdb, 0x2e, 0x17, 0x65, 0x93, 0x4b, 0x89, 0xc2, 0xe8, 0xb6, 0xcc, 0x46, 0x5b, 0x69, 0xab, + 0x95, 0x55, 0x8c, 0xdd, 0x8e, 0x8c, 0x2f, 0x20, 0x3c, 0xd3, 0x98, 0x5b, 0xfc, 0x3a, 0x68, 0x67, + 0x83, 0xb6, 0xc0, 0x9f, 0x1d, 0x1a, 0xcb, 0x22, 0x38, 0x92, 0xaa, 0xc2, 0x65, 0xdb, 0x15, 0xcb, + 0x4b, 0x5c, 0xfb, 0x5e, 0xe4, 0x25, 0x47, 0x0b, 0xe8, 0xf7, 0x3e, 0x77, 0xc5, 0x47, 0x5c, 0xb3, + 0x17, 0x00, 0x2e, 0xdf, 0x92, 0x57, 0xfe, 0xbd, 0x8d, 0xfe, 0xd0, 0xed, 0x7c, 0xa8, 0xe2, 0x13, + 0x38, 0xa6, 0xf3, 0x9b, 0x56, 0x49, 0x83, 0x71, 0x04, 0x27, 0xe7, 0x5d, 0x61, 0x4a, 0xcd, 0x8b, + 0x6d, 0xc8, 0x7b, 0xa5, 0xaf, 0x73, 0x5d, 0xb9, 0x12, 0xe2, 0x1f, 0xf0, 0xf8, 0xa6, 0x30, 0xb2, + 0xf4, 0x46, 0x96, 0x8c, 0xc1, 0x41, 0x63, 0x45, 0xe9, 0x6a, 0xd9, 0x7c, 0x33, 0x1f, 0x1e, 0x58, + 0xbe, 0x42, 0xd5, 0x59, 0x7f, 0x16, 0x79, 0xc9, 0x6c, 0xb1, 0x5d, 0xc6, 0xdf, 0x20, 0x3c, 0x47, + 0x6b, 0x05, 0xed, 0xfe, 0x37, 0xaf, 0x00, 0x0e, 0x5b, 0x8d, 0x7c, 0x95, 0xd7, 0xe8, 0xfc, 0x76, + 0xeb, 0xbe, 0x75, 0x3a, 0xb3, 0x6b, 0xfd, 0x02, 0xc2, 0x77, 0x28, 0xf0, 0x7f, 0x8e, 0x9e, 0xce, + 0xef, 0xfc, 0x8f, 0x21, 0xf8, 0xc4, 0x8d, 0xbd, 0xa9, 0x9a, 0x3f, 0x63, 0x0f, 0x49, 0x75, 0x38, + 0xcc, 0xde, 0xc0, 0xe1, 0x16, 0x23, 0xdf, 0x8b, 0x66, 0xc9, 0xa3, 0x79, 0x9c, 0xde, 0xc6, 0x2b, + 0x1d, 0x59, 0xef, 0xce, 0xc4, 0x5f, 0x76, 0x7f, 0xd5, 0x69, 0xff, 0xdc, 0xef, 0xfc, 0xd7, 0x01, + 0x3c, 0x19, 0x95, 0xcb, 0xd6, 0xf0, 0x8c, 0xc2, 0x8f, 0x65, 0x54, 0xb1, 0x13, 0x17, 0x21, 0x38, + 0xdd, 0xff, 0x80, 0x9b, 0x90, 0x81, 0xe7, 0x77, 0x90, 0xcd, 0xe6, 0x54, 0xb2, 0xe9, 0x6b, 0x10, + 0x4c, 0x8d, 0xd7, 0x85, 0x9e, 0x7a, 0x7d, 0xbf, 0x14, 0x73, 0x74, 0xbf, 0x13, 0xdc, 0xd3, 0xfd, + 0x4e, 0xe1, 0xdc, 0x5b, 0x53, 0xb8, 0xd1, 0xd6, 0x13, 0xe0, 0xd3, 0xd6, 0x53, 0x24, 0xb3, 0x2b, + 0x78, 0x4a, 0xb0, 0xca, 0x52, 0x2a, 0xd1, 0xdd, 0xc8, 0x07, 0xd9, 0xde, 0xf1, 0x83, 0xef, 0xdb, + 0xd7, 0xdf, 0x5f, 0xd5, 0xdc, 0x36, 0x5d, 0x91, 0x96, 0x6a, 0x95, 0x09, 0x5e, 0x37, 0x56, 0x72, + 0x59, 0x4b, 0xb4, 0xd7, 0x4a, 0x5f, 0x66, 0x42, 0x56, 0x99, 0x90, 0xc4, 0x7b, 0xac, 0xdb, 0xb2, + 0xb8, 0xbf, 0x79, 0x93, 0x5f, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x71, 0x8e, 0xff, 0xbf, + 0x05, 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 + +// VirtualChannelsClient is the client API for VirtualChannels service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type VirtualChannelsClient interface { + CreateVirtualChannel(ctx context.Context, in *CreateVirtualChannelRequest, opts ...grpc.CallOption) (*CreateVirtualChannelResponse, error) + SubscribeVirtualForward(ctx context.Context, in *SubscribeVirtualForwardRequest, opts ...grpc.CallOption) (VirtualChannels_SubscribeVirtualForwardClient, error) + SettleVirtualForward(ctx context.Context, in *SettleVirtualForwardRequest, opts ...grpc.CallOption) (*SettleVirtualForwardResponse, error) + DeleteVirtualChannel(ctx context.Context, in *DeleteVirtualChannelRequest, opts ...grpc.CallOption) (*DeleteVirtualChannelResponse, error) + ListVirtualChannels(ctx context.Context, in *ListVirtualChannelsRequest, opts ...grpc.CallOption) (*ListVirtualChannelsResponse, error) +} + +type virtualChannelsClient struct { + cc *grpc.ClientConn +} + +func NewVirtualChannelsClient(cc *grpc.ClientConn) VirtualChannelsClient { + return &virtualChannelsClient{cc} +} + +func (c *virtualChannelsClient) CreateVirtualChannel(ctx context.Context, in *CreateVirtualChannelRequest, opts ...grpc.CallOption) (*CreateVirtualChannelResponse, error) { + out := new(CreateVirtualChannelResponse) + err := c.cc.Invoke(ctx, "/virtualchannelsrpc.VirtualChannels/CreateVirtualChannel", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *virtualChannelsClient) SubscribeVirtualForward(ctx context.Context, in *SubscribeVirtualForwardRequest, opts ...grpc.CallOption) (VirtualChannels_SubscribeVirtualForwardClient, error) { + stream, err := c.cc.NewStream(ctx, &_VirtualChannels_serviceDesc.Streams[0], "/virtualchannelsrpc.VirtualChannels/SubscribeVirtualForward", opts...) + if err != nil { + return nil, err + } + x := &virtualChannelsSubscribeVirtualForwardClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type VirtualChannels_SubscribeVirtualForwardClient interface { + Recv() (*VirtualForward, error) + grpc.ClientStream +} + +type virtualChannelsSubscribeVirtualForwardClient struct { + grpc.ClientStream +} + +func (x *virtualChannelsSubscribeVirtualForwardClient) Recv() (*VirtualForward, error) { + m := new(VirtualForward) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *virtualChannelsClient) SettleVirtualForward(ctx context.Context, in *SettleVirtualForwardRequest, opts ...grpc.CallOption) (*SettleVirtualForwardResponse, error) { + out := new(SettleVirtualForwardResponse) + err := c.cc.Invoke(ctx, "/virtualchannelsrpc.VirtualChannels/SettleVirtualForward", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *virtualChannelsClient) DeleteVirtualChannel(ctx context.Context, in *DeleteVirtualChannelRequest, opts ...grpc.CallOption) (*DeleteVirtualChannelResponse, error) { + out := new(DeleteVirtualChannelResponse) + err := c.cc.Invoke(ctx, "/virtualchannelsrpc.VirtualChannels/DeleteVirtualChannel", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *virtualChannelsClient) ListVirtualChannels(ctx context.Context, in *ListVirtualChannelsRequest, opts ...grpc.CallOption) (*ListVirtualChannelsResponse, error) { + out := new(ListVirtualChannelsResponse) + err := c.cc.Invoke(ctx, "/virtualchannelsrpc.VirtualChannels/ListVirtualChannels", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// VirtualChannelsServer is the server API for VirtualChannels service. +type VirtualChannelsServer interface { + CreateVirtualChannel(context.Context, *CreateVirtualChannelRequest) (*CreateVirtualChannelResponse, error) + SubscribeVirtualForward(*SubscribeVirtualForwardRequest, VirtualChannels_SubscribeVirtualForwardServer) error + SettleVirtualForward(context.Context, *SettleVirtualForwardRequest) (*SettleVirtualForwardResponse, error) + DeleteVirtualChannel(context.Context, *DeleteVirtualChannelRequest) (*DeleteVirtualChannelResponse, error) + ListVirtualChannels(context.Context, *ListVirtualChannelsRequest) (*ListVirtualChannelsResponse, error) +} + +// UnimplementedVirtualChannelsServer can be embedded to have forward compatible implementations. +type UnimplementedVirtualChannelsServer struct { +} + +func (*UnimplementedVirtualChannelsServer) CreateVirtualChannel(ctx context.Context, req *CreateVirtualChannelRequest) (*CreateVirtualChannelResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateVirtualChannel not implemented") +} +func (*UnimplementedVirtualChannelsServer) SubscribeVirtualForward(req *SubscribeVirtualForwardRequest, srv VirtualChannels_SubscribeVirtualForwardServer) error { + return status.Errorf(codes.Unimplemented, "method SubscribeVirtualForward not implemented") +} +func (*UnimplementedVirtualChannelsServer) SettleVirtualForward(ctx context.Context, req *SettleVirtualForwardRequest) (*SettleVirtualForwardResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SettleVirtualForward not implemented") +} +func (*UnimplementedVirtualChannelsServer) DeleteVirtualChannel(ctx context.Context, req *DeleteVirtualChannelRequest) (*DeleteVirtualChannelResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteVirtualChannel not implemented") +} +func (*UnimplementedVirtualChannelsServer) ListVirtualChannels(ctx context.Context, req *ListVirtualChannelsRequest) (*ListVirtualChannelsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListVirtualChannels not implemented") +} + +func RegisterVirtualChannelsServer(s *grpc.Server, srv VirtualChannelsServer) { + s.RegisterService(&_VirtualChannels_serviceDesc, srv) +} + +func _VirtualChannels_CreateVirtualChannel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateVirtualChannelRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(VirtualChannelsServer).CreateVirtualChannel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/virtualchannelsrpc.VirtualChannels/CreateVirtualChannel", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(VirtualChannelsServer).CreateVirtualChannel(ctx, req.(*CreateVirtualChannelRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _VirtualChannels_SubscribeVirtualForward_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(SubscribeVirtualForwardRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(VirtualChannelsServer).SubscribeVirtualForward(m, &virtualChannelsSubscribeVirtualForwardServer{stream}) +} + +type VirtualChannels_SubscribeVirtualForwardServer interface { + Send(*VirtualForward) error + grpc.ServerStream +} + +type virtualChannelsSubscribeVirtualForwardServer struct { + grpc.ServerStream +} + +func (x *virtualChannelsSubscribeVirtualForwardServer) Send(m *VirtualForward) error { + return x.ServerStream.SendMsg(m) +} + +func _VirtualChannels_SettleVirtualForward_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SettleVirtualForwardRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(VirtualChannelsServer).SettleVirtualForward(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/virtualchannelsrpc.VirtualChannels/SettleVirtualForward", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(VirtualChannelsServer).SettleVirtualForward(ctx, req.(*SettleVirtualForwardRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _VirtualChannels_DeleteVirtualChannel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteVirtualChannelRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(VirtualChannelsServer).DeleteVirtualChannel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/virtualchannelsrpc.VirtualChannels/DeleteVirtualChannel", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(VirtualChannelsServer).DeleteVirtualChannel(ctx, req.(*DeleteVirtualChannelRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _VirtualChannels_ListVirtualChannels_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListVirtualChannelsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(VirtualChannelsServer).ListVirtualChannels(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/virtualchannelsrpc.VirtualChannels/ListVirtualChannels", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(VirtualChannelsServer).ListVirtualChannels(ctx, req.(*ListVirtualChannelsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _VirtualChannels_serviceDesc = grpc.ServiceDesc{ + ServiceName: "virtualchannelsrpc.VirtualChannels", + HandlerType: (*VirtualChannelsServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateVirtualChannel", + Handler: _VirtualChannels_CreateVirtualChannel_Handler, + }, + { + MethodName: "SettleVirtualForward", + Handler: _VirtualChannels_SettleVirtualForward_Handler, + }, + { + MethodName: "DeleteVirtualChannel", + Handler: _VirtualChannels_DeleteVirtualChannel_Handler, + }, + { + MethodName: "ListVirtualChannels", + Handler: _VirtualChannels_ListVirtualChannels_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "SubscribeVirtualForward", + Handler: _VirtualChannels_SubscribeVirtualForward_Handler, + ServerStreams: true, + }, + }, + Metadata: "virtualchannelsrpc/virtualchannels.proto", +} diff --git a/lnrpc/virtualchannelsrpc/virtualchannels.proto b/lnrpc/virtualchannelsrpc/virtualchannels.proto new file mode 100644 index 00000000000..89fe2268382 --- /dev/null +++ b/lnrpc/virtualchannelsrpc/virtualchannels.proto @@ -0,0 +1,54 @@ +syntax = "proto3"; + +package virtualchannelsrpc; + +option go_package = "github.com/lightningnetwork/lnd/lnrpc/virtualchannelsrpc"; + +// Invoices is a service that can be used to create, accept, settle and cancel +// invoices. +service VirtualChannels { + rpc CreateVirtualChannel (CreateVirtualChannelRequest) returns (CreateVirtualChannelResponse); + + rpc SubscribeVirtualForward (SubscribeVirtualForwardRequest) returns (stream VirtualForward); + + rpc SettleVirtualForward (SettleVirtualForwardRequest) returns (SettleVirtualForwardResponse); + + rpc DeleteVirtualChannel (DeleteVirtualChannelRequest) returns (DeleteVirtualChannelResponse); + + rpc ListVirtualChannels (ListVirtualChannelsRequest) returns (ListVirtualChannelsResponse); +} + +message CreateVirtualChannelRequest { + bytes node_pub_key = 1; + bytes channel_id = 2; +} +message CreateVirtualChannelResponse {} + +message SubscribeVirtualForwardRequest {} +message VirtualForward { + bytes channel_id = 1; + bytes htlc = 2; + int64 timeout = 3; +} + +message SettleVirtualForwardRequest { + bytes channel_id = 1; + bytes preimage = 2; +} +message SettleVirtualForwardResponse {} + +message DeleteVirtualChannelRequest { + bytes node_pub_key = 1; + bytes channel_id = 2; +} +message DeleteVirtualChannelResponse {} + +message ListVirtualChannelsRequest {} +message ListVirtualChannelsResponse { + repeated VirtualChannel channels = 1; +} + +message VirtualChannel { + bytes node_pub_key = 1; + bytes channel_id = 2; +} \ No newline at end of file diff --git a/lnrpc/virtualchannelsrpc/virtualchannels_server.go b/lnrpc/virtualchannelsrpc/virtualchannels_server.go new file mode 100644 index 00000000000..33d584fc717 --- /dev/null +++ b/lnrpc/virtualchannelsrpc/virtualchannels_server.go @@ -0,0 +1,331 @@ +package virtualchannelsrpc + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "google.golang.org/grpc" + "gopkg.in/macaroon-bakery.v2/bakery" + + "github.com/lightningnetwork/lnd/htlcswitch" + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnwire" +) + +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 recognize it as the name of our + // RPC service. + subServerName = "VirtualChannelsRPC" +) + +var ( + // macaroonOps are the set of capabilities that our minted macaroon (if + // it doesn't already exist) will have. + macaroonOps = []bakery.Op{ + { + Entity: "virtualchannels", + Action: "write", + }, + { + Entity: "virtualchannels", + Action: "read", + }, + } + + // macPermissions maps RPC calls to the permissions they require. + macPermissions = map[string][]bakery.Op{ + "/virtualchannelsrpc.VirtualChannels/CreateVirtualChannel": {{ + Entity: "virtualchannels", + Action: "write", + }}, + "/virtualchannelsrpc.VirtualChannels/SubscribeVirtualForward": {{ + Entity: "virtualchannels", + Action: "read", + }}, + "/virtualchannelsrpc.VirtualChannels/SettleVirtualForward": {{ + Entity: "virtualchannels", + Action: "write", + }}, + "/virtualchannelsrpc.VirtualChannels/DeleteVirtualChannel": {{ + Entity: "virtualchannels", + Action: "write", + }}, + "/virtualchannelsrpc.VirtualChannels/ListVirtualChannels": {{ + Entity: "virtualchannels", + Action: "read", + }}, + } + + // DefaultInvoicesMacFilename is the default name of the invoices + // macaroon that we expect to find via a file handle within the main + // configuration file in this package. + DefaultVirtualChannelsMacFilename = "virtualchannels.macaroon" +) + +type forward struct { + chanID lnwire.ChannelID + htlc []byte + timeout uint32 +} + +// Server is a sub-server of the main RPC server: the invoices RPC. This sub +// RPC server allows external callers to access the status of the invoices +// currently active within lnd, as well as configuring it at runtime. +type Server struct { + quit chan struct{} + cfg *Config + subscriptions []chan forward +} + +// A compile time check to ensure that Server fully implements the +// InvoicesServer gRPC service. +var _ VirtualChannelsServer = (*Server)(nil) + +// New returns a new instance of the invoicesrpc Invoices 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) (*Server, lnrpc.MacaroonPerms, error) { + // If the path of the invoices macaroon wasn't specified, then we'll + // assume that it's found at the default network directory. + macFilePath := filepath.Join( + cfg.NetworkDir, DefaultVirtualChannelsMacFilename, + ) + + // Now that we know the full path of the macaroon, we can + // check to see if we need to create it or not. + if !lnrpc.FileExists(macFilePath) && cfg.MacService != nil { + log.Infof("Baking macaroons for invoices RPC Server at: %v", + macFilePath) + + // At this point, we know that the invoices macaroon doesn't + // yet, exist, so we need to create it with the help of the + // main macaroon service. + invoicesMac, err := cfg.MacService.Oven.NewMacaroon( + context.Background(), bakery.LatestVersion, nil, + macaroonOps..., + ) + if err != nil { + return nil, nil, err + } + invoicesMacBytes, err := invoicesMac.M().MarshalBinary() + if err != nil { + return nil, nil, err + } + err = ioutil.WriteFile(macFilePath, invoicesMacBytes, 0644) + if err != nil { + os.Remove(macFilePath) + return nil, nil, err + } + } + + server := &Server{ + cfg: cfg, + quit: make(chan struct{}, 1), + } + + return server, macPermissions, nil +} + +// Start launches any helper goroutines required for the Server to function. +// +// NOTE: This is part of the lnrpc.SubServer interface. +func (s *Server) Start() error { + return nil +} + +// Stop signals any active goroutines for a graceful closure. +// +// NOTE: This is part of the lnrpc.SubServer interface. +func (s *Server) Stop() error { + close(s.quit) + + 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 (s *Server) 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 (s *Server) 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. + RegisterVirtualChannelsServer(grpcServer, s) + + log.Debugf("Virtual Channels RPC server successfully registered with root " + + "gRPC server") + + return nil +} + +func (s *Server) CreateVirtualChannel(ctx context.Context, request *CreateVirtualChannelRequest) (*CreateVirtualChannelResponse, error) { + + if len(request.NodePubKey) != 33 { + return nil, fmt.Errorf("failed to create virtual channel: node pub key must be 33 bytes") + } + + if len(request.ChannelId) != 32 { + return nil, fmt.Errorf("failed to create virtual channel: channel id must be 32 bytes") + } + + var pubKey [33]byte + copy(pubKey[:], request.NodePubKey[0:33]) + + var chanId [32]byte + copy(chanId[:], request.ChannelId[0:32]) + + // FIXME: When we have a virtual link registry, we should generate the short channel id there + // we would want to be sure that it never reaches an actual segwit block height to avoid matching with + // real existing channels + link := htlcswitch.NewVirtualLink( + pubKey, + chanId, + s.cfg.Switch.ForwardPackets, + s.cfg.Switch.CircuitModifier(), + s.acceptedHTLC) + err := s.cfg.Switch.AddLink(link) + if err != nil { + return nil, fmt.Errorf("failed to create virtual channel: %w", err) + } + + log.Errorf("Created new channel!") + + return &CreateVirtualChannelResponse{}, nil +} + +func (s *Server) acceptedHTLC(chanID lnwire.ChannelID, htlc lnwire.Message, timeout uint32) { + + var buf bytes.Buffer + if err := htlc.Encode(&buf, 0); err != nil { + panic(err) + } + + forward := forward{ + chanID: chanID, + htlc: buf.Bytes(), + timeout: timeout, + } + + // TODO: This feels like it needs a lock + for _, subscriber := range s.subscriptions { + subscriber <- forward + } + +} + +func (s *Server) SubscribeVirtualForward(request *SubscribeVirtualForwardRequest, + stream VirtualChannels_SubscribeVirtualForwardServer) error { + + forwards := make(chan forward) + // TODO: This feels like it needs a lock + s.subscriptions = append(s.subscriptions, forwards) + + for { + select { + case forward := <- forwards: + _ = forward + stream.Send(&VirtualForward{ + ChannelId: forward.chanID[:], + Htlc: forward.htlc, + Timeout: int64(forward.timeout), + }) + + case <-s.quit: + break + } + } +} + +func (s *Server) SettleVirtualForward(ctx context.Context, request *SettleVirtualForwardRequest) (*SettleVirtualForwardResponse, error) { + + if len(request.ChannelId) != 32 { + return nil, fmt.Errorf("failed to settle virtual forward: channel id must be 32 bytes") + } + + if len(request.Preimage) != lntypes.PreimageSize { + return nil, fmt.Errorf("failed to settle virtual forward: preimage size must be %v", lntypes.PreimageSize) + } + + var chanId [32]byte + copy(chanId[:], request.ChannelId[0:32]) + + link, err := s.cfg.Switch.GetLink(chanId) + if err != nil { + return nil, fmt.Errorf("failed to settle virtual forward: didnt find virtual channel: %w", err) + } + + virtualLink, ok := link.(htlcswitch.VirtualLink) + if !ok { + return nil, fmt.Errorf("failed to settle virtual forward: didnt find virtual channel") + } + + var preimage lntypes.Preimage + copy(preimage[:], request.Preimage[:lntypes.PreimageSize]) + + virtualLink.SettleHtlc(preimage) + + return &SettleVirtualForwardResponse{}, nil +} + +func (s *Server) DeleteVirtualChannel(context.Context, *DeleteVirtualChannelRequest) (*DeleteVirtualChannelResponse, error) { + panic("implement me") +} + +func (s *Server) ListVirtualChannels(context.Context, *ListVirtualChannelsRequest) (*ListVirtualChannelsResponse, error) { + panic("implement me") +} + +/* +// SubscribeSingleInvoice returns a uni-directional stream (server -> client) +// for notifying the client of state changes for a specified invoice. +func (s *Server) SubscribeSingleInvoice(req *SubscribeSingleInvoiceRequest, + updateStream Invoices_SubscribeSingleInvoiceServer) error { + + hash, err := lntypes.MakeHash(req.RHash) + if err != nil { + return err + } + + invoiceClient, err := s.cfg.InvoiceRegistry.SubscribeSingleInvoice(hash) + if err != nil { + return err + } + defer invoiceClient.Cancel() + + for { + select { + case newInvoice := <-invoiceClient.Updates: + rpcInvoice, err := CreateRPCInvoice( + newInvoice, s.cfg.ChainParams, + ) + if err != nil { + return err + } + + if err := updateStream.Send(rpcInvoice); err != nil { + return err + } + + case <-s.quit: + return nil + } + } +} +*/ diff --git a/subrpcserver_config.go b/subrpcserver_config.go index 31e8220b410..c30e960058b 100644 --- a/subrpcserver_config.go +++ b/subrpcserver_config.go @@ -15,6 +15,7 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/signrpc" + "github.com/lightningnetwork/lnd/lnrpc/virtualchannelsrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/watchtowerrpc" "github.com/lightningnetwork/lnd/lnrpc/wtclientrpc" @@ -72,6 +73,8 @@ type subRPCServerConfigs struct { // instance within lnd in order to add, remove, list registered client // towers, etc. WatchtowerClientRPC *wtclientrpc.Config `group:"wtclientrpc" namespace:"wtclientrpc"` + + VirtualChannelsRPC *virtualchannelsrpc.Config `group:"virtualchannelsrpc" namespace:"virtualchannelsrpc"` } // PopulateDependencies attempts to iterate through all the sub-server configs @@ -260,6 +263,19 @@ func (s *subRPCServerConfigs) PopulateDependencies(cc *chainControl, reflect.ValueOf(tcpResolver), ) + case *virtualchannelsrpc.Config: + subCfgValue := extractReflectValue(subCfg) + + subCfgValue.FieldByName("NetworkDir").Set( + reflect.ValueOf(networkDir), + ) + subCfgValue.FieldByName("MacService").Set( + reflect.ValueOf(macService), + ) + subCfgValue.FieldByName("Switch").Set( + reflect.ValueOf(htlcSwitch), + ) + default: return fmt.Errorf("unknown field: %v, %T", fieldName, cfg)