From e0b25cdb5ae0995ac22feb6354e9ac50e93805b4 Mon Sep 17 00:00:00 2001 From: Peter Neuroth Date: Tue, 4 Mar 2025 16:50:34 +0100 Subject: [PATCH 1/4] protos: Format scheduler.proto Signed-off-by: Peter Neuroth --- .../.resources/proto/glclient/scheduler.proto | 749 +++++++++--------- libs/proto/glclient/scheduler.proto | 749 +++++++++--------- 2 files changed, 748 insertions(+), 750 deletions(-) diff --git a/libs/gl-client/.resources/proto/glclient/scheduler.proto b/libs/gl-client/.resources/proto/glclient/scheduler.proto index 3bb15f32e..57e7137c3 100644 --- a/libs/gl-client/.resources/proto/glclient/scheduler.proto +++ b/libs/gl-client/.resources/proto/glclient/scheduler.proto @@ -37,170 +37,170 @@ import "glclient/greenlight.proto"; // to use the node-specific mTLS keypair. // service Scheduler { - // A user may register a new node with greenlight by providing - // some basic metadata and proving that they have access to - // the corresponding private key (see challenge-response - // mechanism below). This means that in order to register a - // new node the user must have access to the corresponding - // private keys to prove ownership, and prevent users from - // just registering arbitrary node_ids without actually - // knowing the corresponding secrets. - // - // Upon successful registration an mTLS certificate and - // private key are returned. These can be used to authenticate - // future connections to the scheduler or the node. - // - // Each node may be registered once, any later attempt will - // result in an error being returned. If the user lost its - // credentials it can make use of the Recover RPC method to - // recover the credentials. Notice that this also means that - // the same node_id cannot be reused for different networks. - rpc Register(RegistrationRequest) returns (RegistrationResponse) {} - - // Should a user have lost its credentials (mTLS keypair) for - // any reason, they may regain access to their node using the - // Recover RPC method. Similar to the initial registration the - // caller needs to authenticate the call by proving access to - // the node's secret. This also uses the challenge-response - // mechanism. - // - // Upon success a newly generated mTLS certificate and private - // key are returned, allowing the user to authenticate going - // forward. Existing keypairs are not revoked, in order to - // avoid locking out other authenticated applications. - rpc Recover(RecoveryRequest) returns (RecoveryResponse) {} - - // Challenges are one-time values issued by the server, used - // to authenticate a user/device against the server. A user or - // device can authenticate to the server by signing the - // challenge and returning the signed message as part of the - // request that is to be authenticated. - // - // Challenges may not be reused, and are bound to the scope - // they have been issued for. Attempting to reuse a challenge - // or use a challenge with a different scope will result in an - // error being returned. - rpc GetChallenge(ChallengeRequest) returns (ChallengeResponse) {} - - // Scheduling takes a previously registered node, locates a - // free slot in greenlight's infrastructure and allocates it - // to run the node. The node then goes through the startup - // sequence, synchronizing with the blockchain, and finally - // binding its grpc interface (see Node service below) to a - // public IP address and port. Access is authenticated via the - // mTLS keypair the user received from registering or - // recovering the node. - // - // Upon success a NodeInfoResponse containing the grpc - // connection details and some metadata is returned. The - // application must use the grpc details and its node-specific - // mTLS keypair to interact with the node directly. - rpc Schedule(ScheduleRequest) returns (NodeInfoResponse) {} - - // Much like `Schedule` this call is used to retrieve the - // metadata and grpc details of a node. Unlike the other call - // however it is passive, and will not result in the node - // being scheduled if it isn't already running. This can be - // used to check if a node is already scheduled, or to wait - // for it to be scheduled (e.g., if the caller is an `hsmd` - // that signs off on changes, but doesn't want to keep the - // node itself scheduled). - rpc GetNodeInfo(NodeInfoRequest) returns (NodeInfoResponse) {} - - // The signer may want to trigger an upgrade of the node - // before waiting for the node to be scheduled. This ensures - // that the signer version is in sync with the node - // version. The scheduler may decide to defer upgrading if the - // protocols are compatible. Please do not use this directly, - // rather use the Signer in the client library to trigger this - // automatically when required. Posting an incomplete or - // non-functional UpgradeRequest may result in unschedulable - // nodes. - rpc MaybeUpgrade(UpgradeRequest) returns (UpgradeResponse) {} - - // This call is used to fetch a list of invite codes associated - // with the node id of the client. These invite codes can be used - // for further registration of new nodes. - rpc ListInviteCodes(ListInviteCodesRequest) returns (ListInviteCodesResponse) {} - - // Exporting a node allows users to take control of their node - // - // This method initiates the node export on Greenlight, - // allowing users to offboard from GL into their own - // infrastructure. After calling this method the node will no - // longer be schedulable on Greenlight, since it is never safe - // to assume there haven't been changes in the node's state - // (see CLN Backups documentation for details). `ExportNode` - // marks the node as `Exporting`, then generates an encryption - // secret which is then used to encrypt a database - // backup. This encrypted database backup is then made - // accessible through an HTTP server, and a link to it is - // returned as a response to `ExportNode`. After the export - // completes the node is marked as `Exported`. The encryption - // key can then be derived using the signer, using ECDH, - // allowing only users with the node secret to decrypt it. - // - // `ExportNode` is idempotent and may be called multiple - // times, without causing the node to be re-exported multiple - // times, should the call or the download be interrupted. DO - // NOT import the backup multiple times into your - // infrastructure, as that can lead to dataloss (old state - // being replayed) and loss of funds (see CLN Backups - // documentation for more information) - rpc ExportNode(ExportNodeRequest) returns (ExportNodeResponse) {} - - rpc AddOutgoingWebhook(AddOutgoingWebhookRequest) returns (AddOutgoingWebhookResponse) {} - - rpc ListOutgoingWebhooks(ListOutgoingWebhooksRequest) returns (ListOutgoingWebhooksResponse) {} - - rpc DeleteWebhooks(DeleteOutgoingWebhooksRequest) returns (greenlight.Empty) {} - - rpc RotateOutgoingWebhookSecret(RotateOutgoingWebhookSecretRequest) returns (WebhookSecretResponse) {} - - // Attaches a Signer via a bidirectional stream to the scheduler. - // This is a communication channel between greenlight and the signing - // device that is used for requests that are not part of the node api. - // - // The stream is used to hand out the ApprovePairingRequests that - // the signer answers with a ApprovePairingResponse. - rpc SignerRequestsStream(stream SignerResponse) returns (stream SignerRequest) {}; -}; + // A user may register a new node with greenlight by providing + // some basic metadata and proving that they have access to + // the corresponding private key (see challenge-response + // mechanism below). This means that in order to register a + // new node the user must have access to the corresponding + // private keys to prove ownership, and prevent users from + // just registering arbitrary node_ids without actually + // knowing the corresponding secrets. + // + // Upon successful registration an mTLS certificate and + // private key are returned. These can be used to authenticate + // future connections to the scheduler or the node. + // + // Each node may be registered once, any later attempt will + // result in an error being returned. If the user lost its + // credentials it can make use of the Recover RPC method to + // recover the credentials. Notice that this also means that + // the same node_id cannot be reused for different networks. + rpc Register(RegistrationRequest) returns (RegistrationResponse) {} + + // Should a user have lost its credentials (mTLS keypair) for + // any reason, they may regain access to their node using the + // Recover RPC method. Similar to the initial registration the + // caller needs to authenticate the call by proving access to + // the node's secret. This also uses the challenge-response + // mechanism. + // + // Upon success a newly generated mTLS certificate and private + // key are returned, allowing the user to authenticate going + // forward. Existing keypairs are not revoked, in order to + // avoid locking out other authenticated applications. + rpc Recover(RecoveryRequest) returns (RecoveryResponse) {} + + // Challenges are one-time values issued by the server, used + // to authenticate a user/device against the server. A user or + // device can authenticate to the server by signing the + // challenge and returning the signed message as part of the + // request that is to be authenticated. + // + // Challenges may not be reused, and are bound to the scope + // they have been issued for. Attempting to reuse a challenge + // or use a challenge with a different scope will result in an + // error being returned. + rpc GetChallenge(ChallengeRequest) returns (ChallengeResponse) {} + + // Scheduling takes a previously registered node, locates a + // free slot in greenlight's infrastructure and allocates it + // to run the node. The node then goes through the startup + // sequence, synchronizing with the blockchain, and finally + // binding its grpc interface (see Node service below) to a + // public IP address and port. Access is authenticated via the + // mTLS keypair the user received from registering or + // recovering the node. + // + // Upon success a NodeInfoResponse containing the grpc + // connection details and some metadata is returned. The + // application must use the grpc details and its node-specific + // mTLS keypair to interact with the node directly. + rpc Schedule(ScheduleRequest) returns (NodeInfoResponse) {} + + // Much like `Schedule` this call is used to retrieve the + // metadata and grpc details of a node. Unlike the other call + // however it is passive, and will not result in the node + // being scheduled if it isn't already running. This can be + // used to check if a node is already scheduled, or to wait + // for it to be scheduled (e.g., if the caller is an `hsmd` + // that signs off on changes, but doesn't want to keep the + // node itself scheduled). + rpc GetNodeInfo(NodeInfoRequest) returns (NodeInfoResponse) {} + + // The signer may want to trigger an upgrade of the node + // before waiting for the node to be scheduled. This ensures + // that the signer version is in sync with the node + // version. The scheduler may decide to defer upgrading if the + // protocols are compatible. Please do not use this directly, + // rather use the Signer in the client library to trigger this + // automatically when required. Posting an incomplete or + // non-functional UpgradeRequest may result in unschedulable + // nodes. + rpc MaybeUpgrade(UpgradeRequest) returns (UpgradeResponse) {} + + // This call is used to fetch a list of invite codes associated + // with the node id of the client. These invite codes can be used + // for further registration of new nodes. + rpc ListInviteCodes(ListInviteCodesRequest) returns (ListInviteCodesResponse) {} + + // Exporting a node allows users to take control of their node + // + // This method initiates the node export on Greenlight, + // allowing users to offboard from GL into their own + // infrastructure. After calling this method the node will no + // longer be schedulable on Greenlight, since it is never safe + // to assume there haven't been changes in the node's state + // (see CLN Backups documentation for details). `ExportNode` + // marks the node as `Exporting`, then generates an encryption + // secret which is then used to encrypt a database + // backup. This encrypted database backup is then made + // accessible through an HTTP server, and a link to it is + // returned as a response to `ExportNode`. After the export + // completes the node is marked as `Exported`. The encryption + // key can then be derived using the signer, using ECDH, + // allowing only users with the node secret to decrypt it. + // + // `ExportNode` is idempotent and may be called multiple + // times, without causing the node to be re-exported multiple + // times, should the call or the download be interrupted. DO + // NOT import the backup multiple times into your + // infrastructure, as that can lead to dataloss (old state + // being replayed) and loss of funds (see CLN Backups + // documentation for more information) + rpc ExportNode(ExportNodeRequest) returns (ExportNodeResponse) {} + + rpc AddOutgoingWebhook(AddOutgoingWebhookRequest) returns (AddOutgoingWebhookResponse) {} + + rpc ListOutgoingWebhooks(ListOutgoingWebhooksRequest) returns (ListOutgoingWebhooksResponse) {} + + rpc DeleteWebhooks(DeleteOutgoingWebhooksRequest) returns (greenlight.Empty) {} + + rpc RotateOutgoingWebhookSecret(RotateOutgoingWebhookSecretRequest) returns (WebhookSecretResponse) {} + + // Attaches a Signer via a bidirectional stream to the scheduler. + // This is a communication channel between greenlight and the signing + // device that is used for requests that are not part of the node api. + // + // The stream is used to hand out the ApprovePairingRequests that + // the signer answers with a ApprovePairingResponse. + rpc SignerRequestsStream(stream SignerResponse) returns (stream SignerRequest) {} +} message AddOutgoingWebhookRequest { - bytes node_id = 1; - string uri = 2; + bytes node_id = 1; + string uri = 2; } message AddOutgoingWebhookResponse { - int64 id = 1; - string secret = 2; + int64 id = 1; + string secret = 2; } message ListOutgoingWebhooksRequest { - bytes node_id = 1; + bytes node_id = 1; } message Webhook { - int64 id = 1; - string uri = 2; + int64 id = 1; + string uri = 2; } message ListOutgoingWebhooksResponse { - repeated Webhook outgoing_webhooks = 1; + repeated Webhook outgoing_webhooks = 1; } message DeleteOutgoingWebhooksRequest { - bytes node_id = 1; - repeated int64 ids = 2; + bytes node_id = 1; + repeated int64 ids = 2; } message RotateOutgoingWebhookSecretRequest { - bytes node_id = 1; - int64 webhook_id = 2; + bytes node_id = 1; + int64 webhook_id = 2; } message WebhookSecretResponse { - string secret = 1; + string secret = 1; } // A service to collect debugging information from clients. @@ -212,112 +212,112 @@ service Debug { // to debug these false negatives, hence why we report rejections, // so we can investigate the validity of the rejection, and to // fine-tine the signer's ruleset. - rpc ReportSignerRejection(SignerRejection) returns (greenlight.Empty) {} + rpc ReportSignerRejection(SignerRejection) returns (greenlight.Empty) {} } // A service to pair signer-less clients with an existing signer. service Pairing { - // Initiates a new Pairing Sessions. This is called by the new - // device that wants to request a pairing from an existing device. - // The session lifetime is bound to the stream so closing the - // stream destroys the session. - rpc PairDevice(PairDeviceRequest) returns (PairDeviceResponse) {} - - // Returns the pairing related data that belongs to a pairing - // session. This is meant to be called from a device that can - // approve a pairing request, we sometimes call it "old device". - rpc GetPairingData(GetPairingDataRequest) returns (GetPairingDataResponse) {} - - // Approves a pairing request. The ApprovePairingRequest is - // forwarded to a signer for further processing. - rpc ApprovePairing(ApprovePairingRequest) returns (greenlight.Empty) {} + // Initiates a new Pairing Sessions. This is called by the new + // device that wants to request a pairing from an existing device. + // The session lifetime is bound to the stream so closing the + // stream destroys the session. + rpc PairDevice(PairDeviceRequest) returns (PairDeviceResponse) {} + + // Returns the pairing related data that belongs to a pairing + // session. This is meant to be called from a device that can + // approve a pairing request, we sometimes call it "old device". + rpc GetPairingData(GetPairingDataRequest) returns (GetPairingDataResponse) {} + + // Approves a pairing request. The ApprovePairingRequest is + // forwarded to a signer for further processing. + rpc ApprovePairing(ApprovePairingRequest) returns (greenlight.Empty) {} } message ChallengeRequest { - ChallengeScope scope = 1; - bytes node_id = 2; -}; + ChallengeScope scope = 1; + bytes node_id = 2; +} message ChallengeResponse { - bytes challenge = 1; -}; + bytes challenge = 1; +} // Operation is the challenge associated with? enum ChallengeScope { - REGISTER = 0; - RECOVER = 1; + REGISTER = 0; + RECOVER = 1; } message RegistrationRequest { - // 33 bytes node public key. - bytes node_id = 1; - - // DEPRECATED: The `init_msg` subsumes this field - bytes bip32_key = 2; - - // Which network is this node going to run on? Options are - // bitcoin, testnet, and regtest. - string network = 4; - - // An previously unused challenge as retrieved from - // `Scheduler.GetChallenge() with `scope=REGISTER`. In - // combination with the `signature` below this is used to - // authenticate the caller and ensure the caller has access to - // the secret keys corresponding to the `node_id`. - bytes challenge = 5; - - // A signature for the `challenge` signed by the secret key - // corresponding to the `node_id`. Please refer to the - // documentation of `Scheduler.GetChallenge()` for details on - // how to create this signature. - bytes signature = 6; - - // The signer_proto is required in order to determine which - // version the node should run. If these don't match the - // signer may not be able to sign incoming requests. - string signer_proto = 7; - - // The fuil init message returned by the `libhsmd`, this - // supersedes the bip32_key field which was a misnomer. Notice - // that this includes the prefix 0x006F which is the message - // type. - bytes init_msg = 8; - - // The certificate signing request that will be signed by the - // greenlight backend. Notice that this must have the valid - // CN corresponding to the node_id e.g. /users/{node_id} set. - bytes csr = 9; - - // An optional invite code. We may want to throttle the - // registration rate. Therefore we might check that a registration - // request has a valid invite code. - string invite_code = 10; - - // Messages stashed at the scheduler to allow signerless - // startups. - repeated StartupMessage startupmsgs = 3; -}; + // 33 bytes node public key. + bytes node_id = 1; + + // DEPRECATED: The `init_msg` subsumes this field + bytes bip32_key = 2; + + // Which network is this node going to run on? Options are + // bitcoin, testnet, and regtest. + string network = 4; + + // An previously unused challenge as retrieved from + // `Scheduler.GetChallenge() with `scope=REGISTER`. In + // combination with the `signature` below this is used to + // authenticate the caller and ensure the caller has access to + // the secret keys corresponding to the `node_id`. + bytes challenge = 5; + + // A signature for the `challenge` signed by the secret key + // corresponding to the `node_id`. Please refer to the + // documentation of `Scheduler.GetChallenge()` for details on + // how to create this signature. + bytes signature = 6; + + // The signer_proto is required in order to determine which + // version the node should run. If these don't match the + // signer may not be able to sign incoming requests. + string signer_proto = 7; + + // The fuil init message returned by the `libhsmd`, this + // supersedes the bip32_key field which was a misnomer. Notice + // that this includes the prefix 0x006F which is the message + // type. + bytes init_msg = 8; + + // The certificate signing request that will be signed by the + // greenlight backend. Notice that this must have the valid + // CN corresponding to the node_id e.g. /users/{node_id} set. + bytes csr = 9; + + // An optional invite code. We may want to throttle the + // registration rate. Therefore we might check that a registration + // request has a valid invite code. + string invite_code = 10; + + // Messages stashed at the scheduler to allow signerless + // startups. + repeated StartupMessage startupmsgs = 3; +} message RegistrationResponse { - // Upon registering the user receives back the signed certificate that - // belongs to the certificate signing request the that was sent in the - // registration request, so they can authenticate themselves in the future. - string device_cert = 1; - - // The private key that was used to create the certificate with. This key - // is used to sign the requests to the node. - string device_key = 2; - - // A master rune that is returned if the device that is registered has its - // own signer. The signer is necessary as the response is intercepted on the - // client side and appends the rune to the registratrion response. - string rune = 3; - - // Creds contains a serialized version of the device_cert, the device_key - // and the rune that are used to authenticate a device at the backend, - // and to authorize a request at the signer. - bytes creds = 4; -}; + // Upon registering the user receives back the signed certificate that + // belongs to the certificate signing request the that was sent in the + // registration request, so they can authenticate themselves in the future. + string device_cert = 1; + + // The private key that was used to create the certificate with. This key + // is used to sign the requests to the node. + string device_key = 2; + + // A master rune that is returned if the device that is registered has its + // own signer. The signer is necessary as the response is intercepted on the + // client side and appends the rune to the registratrion response. + string rune = 3; + + // Creds contains a serialized version of the device_cert, the device_key + // and the rune that are used to authenticate a device at the backend, + // and to authorize a request at the signer. + bytes creds = 4; +} // Ask the scheduler to schedule the node to be run on an available nodelet. // @@ -325,68 +325,67 @@ message RegistrationResponse { // like to see if a nodelet is currently taking care of this node, or // wait for one to start please use the message ScheduleRequest { - bytes node_id = 1; -}; + bytes node_id = 1; +} // Discovery request asking the scheduler if a nodelet is currently assigned // the specified node_id, or wait for one to be assigned. If `wait` is set to // `true` the scheduler will keep the request pending until a nodelet is // assigned. message NodeInfoRequest { - bytes node_id = 1; - bool wait = 2; -}; + bytes node_id = 1; + bool wait = 2; +} message NodeInfoResponse { - bytes node_id = 1; - string grpc_uri = 2; - uint64 session_id = 3; -}; - + bytes node_id = 1; + string grpc_uri = 2; + uint64 session_id = 3; +} message RecoveryRequest { - bytes challenge = 1; - bytes signature = 2; - bytes node_id = 3; - // The certificate signing request that will be signed by the - // greenlight backend. Notice that this must have the valid - // CN corresponding to the node_id e.g. /users/{node_id} set. - bytes csr = 9; -}; + bytes challenge = 1; + bytes signature = 2; + bytes node_id = 3; + // The certificate signing request that will be signed by the + // greenlight backend. Notice that this must have the valid + // CN corresponding to the node_id e.g. /users/{node_id} set. + bytes csr = 9; +} message RecoveryResponse { - string device_cert = 1; - string device_key = 2; - - // A master rune that is returned if the device that is registered has its - // own signer. The signer is necessary as the response is intercepted on the - // client side and appends the rune to the registratrion response. - string rune = 3; - - // Creds contains a serialized version of the device_cert, the device_key - // and the rune that are used to authenticate a device at the backend, - // and to authorize a request at the signer. - bytes creds = 4; -}; + string device_cert = 1; + string device_key = 2; + + // A master rune that is returned if the device that is registered has its + // own signer. The signer is necessary as the response is intercepted on the + // client side and appends the rune to the registratrion response. + string rune = 3; + + // Creds contains a serialized version of the device_cert, the device_key + // and the rune that are used to authenticate a device at the backend, + // and to authorize a request at the signer. + bytes creds = 4; +} message UpgradeRequest { - // The version of the signer, i.e., the maximum version of the - // protocol that this signer can understand. - string signer_version = 1; - - // The new initmsg matching the above version. Necessary to - // schedule the node without a signer present. - // Deprecated: Replaced by the more generic `startupmsgs` - bytes initmsg = 2 [deprecated = true]; - - // Messages stashed at the scheduler to allow signerless startups. - repeated StartupMessage startupmsgs = 3; -}; + // The version of the signer, i.e., the maximum version of the + // protocol that this signer can understand. + string signer_version = 1; + + // The new initmsg matching the above version. Necessary to + // schedule the node without a signer present. + // Deprecated: Replaced by the more generic `startupmsgs` + bytes initmsg = 2 [deprecated = true]; + + // Messages stashed at the scheduler to allow signerless startups. + repeated StartupMessage startupmsgs = 3; +} message UpgradeResponse { - // The version of the node before the upgrade request has been - // processed. - string old_version = 1; -}; + // The version of the node before the upgrade request has been + // processed. + string old_version = 1; +} // A message that we know will be requested by `lightningd` at // startup, and that we stash a response to on the scheduler. This @@ -398,24 +397,24 @@ message StartupMessage { bytes response = 2; } -message ListInviteCodesRequest {}; +message ListInviteCodesRequest {} message ListInviteCodesResponse { - repeated InviteCode invite_code_list = 1; -}; + repeated InviteCode invite_code_list = 1; +} message InviteCode { - string code = 1; - bool is_redeemed = 2; -}; + string code = 1; + bool is_redeemed = 2; +} // Empty message for now, node identity is extracted from the mTLS // certificate used to authenticate against the Scheduler. message ExportNodeRequest {} message ExportNodeResponse { - // URL where the encrypted backup can be retrieved from. - string url = 1; + // URL where the encrypted backup can be retrieved from. + string url = 1; } message SignerRejection { @@ -427,123 +426,123 @@ message SignerRejection { } message PairDeviceRequest { - // The tls public key of the new device. - string device_id = 1; - - // The certificate signing request that will be signed by the - // greenlight backend if the pairing succeeds. Notice that the CN - // here is irrelevant. - bytes csr = 2; - - // The name of the device that will be part of the tls certificate - // subjects CN field: CN=/users//. - string device_name = 3; - - // A human readable description of the device, this can be a - // purpose or something similar. Can be used to display to the - // user on the old device. - string description = 4; - - // A set of restrictions that the new devices requests for the - // rune. This might in the future get upgraded for easier naming. - string restrictions = 5; + // The tls public key of the new device. + string device_id = 1; + + // The certificate signing request that will be signed by the + // greenlight backend if the pairing succeeds. Notice that the CN + // here is irrelevant. + bytes csr = 2; + + // The name of the device that will be part of the tls certificate + // subjects CN field: CN=/users//. + string device_name = 3; + + // A human readable description of the device, this can be a + // purpose or something similar. Can be used to display to the + // user on the old device. + string description = 4; + + // A set of restrictions that the new devices requests for the + // rune. This might in the future get upgraded for easier naming. + string restrictions = 5; } message PairDeviceResponse { - // device_id is the public key of the new device used for the - // tls cert. - string device_id = 1; - - // Upon a pairing request, the device receives back the signed certificate - // that belongs to the certificate signing request the that was sent with - // the pairing request, so they can authenticate themselves in the future. - string device_cert = 2; - - // The private key that was used to create the certificate with. This key - // is used to sign the requests to the node. - string device_key = 3; - - // A rune that is returned if the device that is created by the signer that - // the device pairs to. - string rune = 4; - - // Creds contains a serialized version of the device certificate, the device - // key and the rune that are used to authenticate a device at the backend, - // and to authorize a request at the signer. - bytes creds = 5; + // device_id is the public key of the new device used for the + // tls cert. + string device_id = 1; + + // Upon a pairing request, the device receives back the signed certificate + // that belongs to the certificate signing request the that was sent with + // the pairing request, so they can authenticate themselves in the future. + string device_cert = 2; + + // The private key that was used to create the certificate with. This key + // is used to sign the requests to the node. + string device_key = 3; + + // A rune that is returned if the device that is created by the signer that + // the device pairs to. + string rune = 4; + + // Creds contains a serialized version of the device certificate, the device + // key and the rune that are used to authenticate a device at the backend, + // and to authorize a request at the signer. + bytes creds = 5; } message GetPairingDataRequest { - // The device_id that the client got from the qr-code. - string device_id = 1; + // The device_id that the client got from the qr-code. + string device_id = 1; } message GetPairingDataResponse { - string device_id = 1; + string device_id = 1; - // The certificate signing request that will be signed by the - // greenlight backend if the pairing succeeds. Notice that the CN - // here is irrelevant. - bytes csr = 2; + // The certificate signing request that will be signed by the + // greenlight backend if the pairing succeeds. Notice that the CN + // here is irrelevant. + bytes csr = 2; - // The name of the device that will be part of the tls certificate - // subjects CN field: CN=/users//. - string device_name = 3; + // The name of the device that will be part of the tls certificate + // subjects CN field: CN=/users//. + string device_name = 3; - // A human readable description of the device, this can be a - // purpose or something similar. Can be used to display to the - // user on the old device. - string description = 4; + // A human readable description of the device, this can be a + // purpose or something similar. Can be used to display to the + // user on the old device. + string description = 4; - // A set of restrictions that the new devices requests for the - // rune. This might in the future get upgraded for easier naming. - string restrictions = 5; + // A set of restrictions that the new devices requests for the + // rune. This might in the future get upgraded for easier naming. + string restrictions = 5; } message ApprovePairingRequest { - string device_id = 1; + string device_id = 1; + + // The time that the old device approved the pairing request. This + // is used by the signer to restrict the duration an approval + // request is valid. + uint64 timestamp = 2; + + // The name of the device that will be part of the tls certificate + // subjects CN field: CN=/users//. + string device_name = 3; - // The time that the old device approved the pairing request. This - // is used by the signer to restrict the duration an approval - // request is valid. - uint64 timestamp = 2; + // The restrictions need a pubkey set. + string restrictions = 4; - // The name of the device that will be part of the tls certificate - // subjects CN field: CN=/users//. - string device_name = 3; - - // The restrictions need a pubkey set. - string restrictions = 4; + // The signature of the above to ensure data integrity. + bytes sig = 5; - // The signature of the above to ensure data integrity. - bytes sig = 5; - - // The public key corresponding to the private key that was used - // to sign the request and that is part of the rune; - bytes pubkey = 6; + // The public key corresponding to the private key that was used + // to sign the request and that is part of the rune; + bytes pubkey = 6; - // The rune of the old device with a pubkey field corresponding to - // the signature above. Used to authorize the approval request. - string rune = 7; + // The rune of the old device with a pubkey field corresponding to + // the signature above. Used to authorize the approval request. + string rune = 7; } message ApprovePairingResponse { - string device_id = 1; - bytes node_id = 2; - string rune =3; + string device_id = 1; + bytes node_id = 2; + string rune = 3; } message SignerRequest { - uint32 request_id = 1; - oneof request { - ApprovePairingRequest approve_pairing = 2; - } + uint32 request_id = 1; + oneof request { + ApprovePairingRequest approve_pairing = 2; + } } message SignerResponse { - uint32 request_id = 1; - oneof response { - greenlight.Empty empty = 2; - ApprovePairingResponse approve_pairing = 3; - } + uint32 request_id = 1; + oneof response { + greenlight.Empty empty = 2; + ApprovePairingResponse approve_pairing = 3; + } } diff --git a/libs/proto/glclient/scheduler.proto b/libs/proto/glclient/scheduler.proto index 3bb15f32e..57e7137c3 100644 --- a/libs/proto/glclient/scheduler.proto +++ b/libs/proto/glclient/scheduler.proto @@ -37,170 +37,170 @@ import "glclient/greenlight.proto"; // to use the node-specific mTLS keypair. // service Scheduler { - // A user may register a new node with greenlight by providing - // some basic metadata and proving that they have access to - // the corresponding private key (see challenge-response - // mechanism below). This means that in order to register a - // new node the user must have access to the corresponding - // private keys to prove ownership, and prevent users from - // just registering arbitrary node_ids without actually - // knowing the corresponding secrets. - // - // Upon successful registration an mTLS certificate and - // private key are returned. These can be used to authenticate - // future connections to the scheduler or the node. - // - // Each node may be registered once, any later attempt will - // result in an error being returned. If the user lost its - // credentials it can make use of the Recover RPC method to - // recover the credentials. Notice that this also means that - // the same node_id cannot be reused for different networks. - rpc Register(RegistrationRequest) returns (RegistrationResponse) {} - - // Should a user have lost its credentials (mTLS keypair) for - // any reason, they may regain access to their node using the - // Recover RPC method. Similar to the initial registration the - // caller needs to authenticate the call by proving access to - // the node's secret. This also uses the challenge-response - // mechanism. - // - // Upon success a newly generated mTLS certificate and private - // key are returned, allowing the user to authenticate going - // forward. Existing keypairs are not revoked, in order to - // avoid locking out other authenticated applications. - rpc Recover(RecoveryRequest) returns (RecoveryResponse) {} - - // Challenges are one-time values issued by the server, used - // to authenticate a user/device against the server. A user or - // device can authenticate to the server by signing the - // challenge and returning the signed message as part of the - // request that is to be authenticated. - // - // Challenges may not be reused, and are bound to the scope - // they have been issued for. Attempting to reuse a challenge - // or use a challenge with a different scope will result in an - // error being returned. - rpc GetChallenge(ChallengeRequest) returns (ChallengeResponse) {} - - // Scheduling takes a previously registered node, locates a - // free slot in greenlight's infrastructure and allocates it - // to run the node. The node then goes through the startup - // sequence, synchronizing with the blockchain, and finally - // binding its grpc interface (see Node service below) to a - // public IP address and port. Access is authenticated via the - // mTLS keypair the user received from registering or - // recovering the node. - // - // Upon success a NodeInfoResponse containing the grpc - // connection details and some metadata is returned. The - // application must use the grpc details and its node-specific - // mTLS keypair to interact with the node directly. - rpc Schedule(ScheduleRequest) returns (NodeInfoResponse) {} - - // Much like `Schedule` this call is used to retrieve the - // metadata and grpc details of a node. Unlike the other call - // however it is passive, and will not result in the node - // being scheduled if it isn't already running. This can be - // used to check if a node is already scheduled, or to wait - // for it to be scheduled (e.g., if the caller is an `hsmd` - // that signs off on changes, but doesn't want to keep the - // node itself scheduled). - rpc GetNodeInfo(NodeInfoRequest) returns (NodeInfoResponse) {} - - // The signer may want to trigger an upgrade of the node - // before waiting for the node to be scheduled. This ensures - // that the signer version is in sync with the node - // version. The scheduler may decide to defer upgrading if the - // protocols are compatible. Please do not use this directly, - // rather use the Signer in the client library to trigger this - // automatically when required. Posting an incomplete or - // non-functional UpgradeRequest may result in unschedulable - // nodes. - rpc MaybeUpgrade(UpgradeRequest) returns (UpgradeResponse) {} - - // This call is used to fetch a list of invite codes associated - // with the node id of the client. These invite codes can be used - // for further registration of new nodes. - rpc ListInviteCodes(ListInviteCodesRequest) returns (ListInviteCodesResponse) {} - - // Exporting a node allows users to take control of their node - // - // This method initiates the node export on Greenlight, - // allowing users to offboard from GL into their own - // infrastructure. After calling this method the node will no - // longer be schedulable on Greenlight, since it is never safe - // to assume there haven't been changes in the node's state - // (see CLN Backups documentation for details). `ExportNode` - // marks the node as `Exporting`, then generates an encryption - // secret which is then used to encrypt a database - // backup. This encrypted database backup is then made - // accessible through an HTTP server, and a link to it is - // returned as a response to `ExportNode`. After the export - // completes the node is marked as `Exported`. The encryption - // key can then be derived using the signer, using ECDH, - // allowing only users with the node secret to decrypt it. - // - // `ExportNode` is idempotent and may be called multiple - // times, without causing the node to be re-exported multiple - // times, should the call or the download be interrupted. DO - // NOT import the backup multiple times into your - // infrastructure, as that can lead to dataloss (old state - // being replayed) and loss of funds (see CLN Backups - // documentation for more information) - rpc ExportNode(ExportNodeRequest) returns (ExportNodeResponse) {} - - rpc AddOutgoingWebhook(AddOutgoingWebhookRequest) returns (AddOutgoingWebhookResponse) {} - - rpc ListOutgoingWebhooks(ListOutgoingWebhooksRequest) returns (ListOutgoingWebhooksResponse) {} - - rpc DeleteWebhooks(DeleteOutgoingWebhooksRequest) returns (greenlight.Empty) {} - - rpc RotateOutgoingWebhookSecret(RotateOutgoingWebhookSecretRequest) returns (WebhookSecretResponse) {} - - // Attaches a Signer via a bidirectional stream to the scheduler. - // This is a communication channel between greenlight and the signing - // device that is used for requests that are not part of the node api. - // - // The stream is used to hand out the ApprovePairingRequests that - // the signer answers with a ApprovePairingResponse. - rpc SignerRequestsStream(stream SignerResponse) returns (stream SignerRequest) {}; -}; + // A user may register a new node with greenlight by providing + // some basic metadata and proving that they have access to + // the corresponding private key (see challenge-response + // mechanism below). This means that in order to register a + // new node the user must have access to the corresponding + // private keys to prove ownership, and prevent users from + // just registering arbitrary node_ids without actually + // knowing the corresponding secrets. + // + // Upon successful registration an mTLS certificate and + // private key are returned. These can be used to authenticate + // future connections to the scheduler or the node. + // + // Each node may be registered once, any later attempt will + // result in an error being returned. If the user lost its + // credentials it can make use of the Recover RPC method to + // recover the credentials. Notice that this also means that + // the same node_id cannot be reused for different networks. + rpc Register(RegistrationRequest) returns (RegistrationResponse) {} + + // Should a user have lost its credentials (mTLS keypair) for + // any reason, they may regain access to their node using the + // Recover RPC method. Similar to the initial registration the + // caller needs to authenticate the call by proving access to + // the node's secret. This also uses the challenge-response + // mechanism. + // + // Upon success a newly generated mTLS certificate and private + // key are returned, allowing the user to authenticate going + // forward. Existing keypairs are not revoked, in order to + // avoid locking out other authenticated applications. + rpc Recover(RecoveryRequest) returns (RecoveryResponse) {} + + // Challenges are one-time values issued by the server, used + // to authenticate a user/device against the server. A user or + // device can authenticate to the server by signing the + // challenge and returning the signed message as part of the + // request that is to be authenticated. + // + // Challenges may not be reused, and are bound to the scope + // they have been issued for. Attempting to reuse a challenge + // or use a challenge with a different scope will result in an + // error being returned. + rpc GetChallenge(ChallengeRequest) returns (ChallengeResponse) {} + + // Scheduling takes a previously registered node, locates a + // free slot in greenlight's infrastructure and allocates it + // to run the node. The node then goes through the startup + // sequence, synchronizing with the blockchain, and finally + // binding its grpc interface (see Node service below) to a + // public IP address and port. Access is authenticated via the + // mTLS keypair the user received from registering or + // recovering the node. + // + // Upon success a NodeInfoResponse containing the grpc + // connection details and some metadata is returned. The + // application must use the grpc details and its node-specific + // mTLS keypair to interact with the node directly. + rpc Schedule(ScheduleRequest) returns (NodeInfoResponse) {} + + // Much like `Schedule` this call is used to retrieve the + // metadata and grpc details of a node. Unlike the other call + // however it is passive, and will not result in the node + // being scheduled if it isn't already running. This can be + // used to check if a node is already scheduled, or to wait + // for it to be scheduled (e.g., if the caller is an `hsmd` + // that signs off on changes, but doesn't want to keep the + // node itself scheduled). + rpc GetNodeInfo(NodeInfoRequest) returns (NodeInfoResponse) {} + + // The signer may want to trigger an upgrade of the node + // before waiting for the node to be scheduled. This ensures + // that the signer version is in sync with the node + // version. The scheduler may decide to defer upgrading if the + // protocols are compatible. Please do not use this directly, + // rather use the Signer in the client library to trigger this + // automatically when required. Posting an incomplete or + // non-functional UpgradeRequest may result in unschedulable + // nodes. + rpc MaybeUpgrade(UpgradeRequest) returns (UpgradeResponse) {} + + // This call is used to fetch a list of invite codes associated + // with the node id of the client. These invite codes can be used + // for further registration of new nodes. + rpc ListInviteCodes(ListInviteCodesRequest) returns (ListInviteCodesResponse) {} + + // Exporting a node allows users to take control of their node + // + // This method initiates the node export on Greenlight, + // allowing users to offboard from GL into their own + // infrastructure. After calling this method the node will no + // longer be schedulable on Greenlight, since it is never safe + // to assume there haven't been changes in the node's state + // (see CLN Backups documentation for details). `ExportNode` + // marks the node as `Exporting`, then generates an encryption + // secret which is then used to encrypt a database + // backup. This encrypted database backup is then made + // accessible through an HTTP server, and a link to it is + // returned as a response to `ExportNode`. After the export + // completes the node is marked as `Exported`. The encryption + // key can then be derived using the signer, using ECDH, + // allowing only users with the node secret to decrypt it. + // + // `ExportNode` is idempotent and may be called multiple + // times, without causing the node to be re-exported multiple + // times, should the call or the download be interrupted. DO + // NOT import the backup multiple times into your + // infrastructure, as that can lead to dataloss (old state + // being replayed) and loss of funds (see CLN Backups + // documentation for more information) + rpc ExportNode(ExportNodeRequest) returns (ExportNodeResponse) {} + + rpc AddOutgoingWebhook(AddOutgoingWebhookRequest) returns (AddOutgoingWebhookResponse) {} + + rpc ListOutgoingWebhooks(ListOutgoingWebhooksRequest) returns (ListOutgoingWebhooksResponse) {} + + rpc DeleteWebhooks(DeleteOutgoingWebhooksRequest) returns (greenlight.Empty) {} + + rpc RotateOutgoingWebhookSecret(RotateOutgoingWebhookSecretRequest) returns (WebhookSecretResponse) {} + + // Attaches a Signer via a bidirectional stream to the scheduler. + // This is a communication channel between greenlight and the signing + // device that is used for requests that are not part of the node api. + // + // The stream is used to hand out the ApprovePairingRequests that + // the signer answers with a ApprovePairingResponse. + rpc SignerRequestsStream(stream SignerResponse) returns (stream SignerRequest) {} +} message AddOutgoingWebhookRequest { - bytes node_id = 1; - string uri = 2; + bytes node_id = 1; + string uri = 2; } message AddOutgoingWebhookResponse { - int64 id = 1; - string secret = 2; + int64 id = 1; + string secret = 2; } message ListOutgoingWebhooksRequest { - bytes node_id = 1; + bytes node_id = 1; } message Webhook { - int64 id = 1; - string uri = 2; + int64 id = 1; + string uri = 2; } message ListOutgoingWebhooksResponse { - repeated Webhook outgoing_webhooks = 1; + repeated Webhook outgoing_webhooks = 1; } message DeleteOutgoingWebhooksRequest { - bytes node_id = 1; - repeated int64 ids = 2; + bytes node_id = 1; + repeated int64 ids = 2; } message RotateOutgoingWebhookSecretRequest { - bytes node_id = 1; - int64 webhook_id = 2; + bytes node_id = 1; + int64 webhook_id = 2; } message WebhookSecretResponse { - string secret = 1; + string secret = 1; } // A service to collect debugging information from clients. @@ -212,112 +212,112 @@ service Debug { // to debug these false negatives, hence why we report rejections, // so we can investigate the validity of the rejection, and to // fine-tine the signer's ruleset. - rpc ReportSignerRejection(SignerRejection) returns (greenlight.Empty) {} + rpc ReportSignerRejection(SignerRejection) returns (greenlight.Empty) {} } // A service to pair signer-less clients with an existing signer. service Pairing { - // Initiates a new Pairing Sessions. This is called by the new - // device that wants to request a pairing from an existing device. - // The session lifetime is bound to the stream so closing the - // stream destroys the session. - rpc PairDevice(PairDeviceRequest) returns (PairDeviceResponse) {} - - // Returns the pairing related data that belongs to a pairing - // session. This is meant to be called from a device that can - // approve a pairing request, we sometimes call it "old device". - rpc GetPairingData(GetPairingDataRequest) returns (GetPairingDataResponse) {} - - // Approves a pairing request. The ApprovePairingRequest is - // forwarded to a signer for further processing. - rpc ApprovePairing(ApprovePairingRequest) returns (greenlight.Empty) {} + // Initiates a new Pairing Sessions. This is called by the new + // device that wants to request a pairing from an existing device. + // The session lifetime is bound to the stream so closing the + // stream destroys the session. + rpc PairDevice(PairDeviceRequest) returns (PairDeviceResponse) {} + + // Returns the pairing related data that belongs to a pairing + // session. This is meant to be called from a device that can + // approve a pairing request, we sometimes call it "old device". + rpc GetPairingData(GetPairingDataRequest) returns (GetPairingDataResponse) {} + + // Approves a pairing request. The ApprovePairingRequest is + // forwarded to a signer for further processing. + rpc ApprovePairing(ApprovePairingRequest) returns (greenlight.Empty) {} } message ChallengeRequest { - ChallengeScope scope = 1; - bytes node_id = 2; -}; + ChallengeScope scope = 1; + bytes node_id = 2; +} message ChallengeResponse { - bytes challenge = 1; -}; + bytes challenge = 1; +} // Operation is the challenge associated with? enum ChallengeScope { - REGISTER = 0; - RECOVER = 1; + REGISTER = 0; + RECOVER = 1; } message RegistrationRequest { - // 33 bytes node public key. - bytes node_id = 1; - - // DEPRECATED: The `init_msg` subsumes this field - bytes bip32_key = 2; - - // Which network is this node going to run on? Options are - // bitcoin, testnet, and regtest. - string network = 4; - - // An previously unused challenge as retrieved from - // `Scheduler.GetChallenge() with `scope=REGISTER`. In - // combination with the `signature` below this is used to - // authenticate the caller and ensure the caller has access to - // the secret keys corresponding to the `node_id`. - bytes challenge = 5; - - // A signature for the `challenge` signed by the secret key - // corresponding to the `node_id`. Please refer to the - // documentation of `Scheduler.GetChallenge()` for details on - // how to create this signature. - bytes signature = 6; - - // The signer_proto is required in order to determine which - // version the node should run. If these don't match the - // signer may not be able to sign incoming requests. - string signer_proto = 7; - - // The fuil init message returned by the `libhsmd`, this - // supersedes the bip32_key field which was a misnomer. Notice - // that this includes the prefix 0x006F which is the message - // type. - bytes init_msg = 8; - - // The certificate signing request that will be signed by the - // greenlight backend. Notice that this must have the valid - // CN corresponding to the node_id e.g. /users/{node_id} set. - bytes csr = 9; - - // An optional invite code. We may want to throttle the - // registration rate. Therefore we might check that a registration - // request has a valid invite code. - string invite_code = 10; - - // Messages stashed at the scheduler to allow signerless - // startups. - repeated StartupMessage startupmsgs = 3; -}; + // 33 bytes node public key. + bytes node_id = 1; + + // DEPRECATED: The `init_msg` subsumes this field + bytes bip32_key = 2; + + // Which network is this node going to run on? Options are + // bitcoin, testnet, and regtest. + string network = 4; + + // An previously unused challenge as retrieved from + // `Scheduler.GetChallenge() with `scope=REGISTER`. In + // combination with the `signature` below this is used to + // authenticate the caller and ensure the caller has access to + // the secret keys corresponding to the `node_id`. + bytes challenge = 5; + + // A signature for the `challenge` signed by the secret key + // corresponding to the `node_id`. Please refer to the + // documentation of `Scheduler.GetChallenge()` for details on + // how to create this signature. + bytes signature = 6; + + // The signer_proto is required in order to determine which + // version the node should run. If these don't match the + // signer may not be able to sign incoming requests. + string signer_proto = 7; + + // The fuil init message returned by the `libhsmd`, this + // supersedes the bip32_key field which was a misnomer. Notice + // that this includes the prefix 0x006F which is the message + // type. + bytes init_msg = 8; + + // The certificate signing request that will be signed by the + // greenlight backend. Notice that this must have the valid + // CN corresponding to the node_id e.g. /users/{node_id} set. + bytes csr = 9; + + // An optional invite code. We may want to throttle the + // registration rate. Therefore we might check that a registration + // request has a valid invite code. + string invite_code = 10; + + // Messages stashed at the scheduler to allow signerless + // startups. + repeated StartupMessage startupmsgs = 3; +} message RegistrationResponse { - // Upon registering the user receives back the signed certificate that - // belongs to the certificate signing request the that was sent in the - // registration request, so they can authenticate themselves in the future. - string device_cert = 1; - - // The private key that was used to create the certificate with. This key - // is used to sign the requests to the node. - string device_key = 2; - - // A master rune that is returned if the device that is registered has its - // own signer. The signer is necessary as the response is intercepted on the - // client side and appends the rune to the registratrion response. - string rune = 3; - - // Creds contains a serialized version of the device_cert, the device_key - // and the rune that are used to authenticate a device at the backend, - // and to authorize a request at the signer. - bytes creds = 4; -}; + // Upon registering the user receives back the signed certificate that + // belongs to the certificate signing request the that was sent in the + // registration request, so they can authenticate themselves in the future. + string device_cert = 1; + + // The private key that was used to create the certificate with. This key + // is used to sign the requests to the node. + string device_key = 2; + + // A master rune that is returned if the device that is registered has its + // own signer. The signer is necessary as the response is intercepted on the + // client side and appends the rune to the registratrion response. + string rune = 3; + + // Creds contains a serialized version of the device_cert, the device_key + // and the rune that are used to authenticate a device at the backend, + // and to authorize a request at the signer. + bytes creds = 4; +} // Ask the scheduler to schedule the node to be run on an available nodelet. // @@ -325,68 +325,67 @@ message RegistrationResponse { // like to see if a nodelet is currently taking care of this node, or // wait for one to start please use the message ScheduleRequest { - bytes node_id = 1; -}; + bytes node_id = 1; +} // Discovery request asking the scheduler if a nodelet is currently assigned // the specified node_id, or wait for one to be assigned. If `wait` is set to // `true` the scheduler will keep the request pending until a nodelet is // assigned. message NodeInfoRequest { - bytes node_id = 1; - bool wait = 2; -}; + bytes node_id = 1; + bool wait = 2; +} message NodeInfoResponse { - bytes node_id = 1; - string grpc_uri = 2; - uint64 session_id = 3; -}; - + bytes node_id = 1; + string grpc_uri = 2; + uint64 session_id = 3; +} message RecoveryRequest { - bytes challenge = 1; - bytes signature = 2; - bytes node_id = 3; - // The certificate signing request that will be signed by the - // greenlight backend. Notice that this must have the valid - // CN corresponding to the node_id e.g. /users/{node_id} set. - bytes csr = 9; -}; + bytes challenge = 1; + bytes signature = 2; + bytes node_id = 3; + // The certificate signing request that will be signed by the + // greenlight backend. Notice that this must have the valid + // CN corresponding to the node_id e.g. /users/{node_id} set. + bytes csr = 9; +} message RecoveryResponse { - string device_cert = 1; - string device_key = 2; - - // A master rune that is returned if the device that is registered has its - // own signer. The signer is necessary as the response is intercepted on the - // client side and appends the rune to the registratrion response. - string rune = 3; - - // Creds contains a serialized version of the device_cert, the device_key - // and the rune that are used to authenticate a device at the backend, - // and to authorize a request at the signer. - bytes creds = 4; -}; + string device_cert = 1; + string device_key = 2; + + // A master rune that is returned if the device that is registered has its + // own signer. The signer is necessary as the response is intercepted on the + // client side and appends the rune to the registratrion response. + string rune = 3; + + // Creds contains a serialized version of the device_cert, the device_key + // and the rune that are used to authenticate a device at the backend, + // and to authorize a request at the signer. + bytes creds = 4; +} message UpgradeRequest { - // The version of the signer, i.e., the maximum version of the - // protocol that this signer can understand. - string signer_version = 1; - - // The new initmsg matching the above version. Necessary to - // schedule the node without a signer present. - // Deprecated: Replaced by the more generic `startupmsgs` - bytes initmsg = 2 [deprecated = true]; - - // Messages stashed at the scheduler to allow signerless startups. - repeated StartupMessage startupmsgs = 3; -}; + // The version of the signer, i.e., the maximum version of the + // protocol that this signer can understand. + string signer_version = 1; + + // The new initmsg matching the above version. Necessary to + // schedule the node without a signer present. + // Deprecated: Replaced by the more generic `startupmsgs` + bytes initmsg = 2 [deprecated = true]; + + // Messages stashed at the scheduler to allow signerless startups. + repeated StartupMessage startupmsgs = 3; +} message UpgradeResponse { - // The version of the node before the upgrade request has been - // processed. - string old_version = 1; -}; + // The version of the node before the upgrade request has been + // processed. + string old_version = 1; +} // A message that we know will be requested by `lightningd` at // startup, and that we stash a response to on the scheduler. This @@ -398,24 +397,24 @@ message StartupMessage { bytes response = 2; } -message ListInviteCodesRequest {}; +message ListInviteCodesRequest {} message ListInviteCodesResponse { - repeated InviteCode invite_code_list = 1; -}; + repeated InviteCode invite_code_list = 1; +} message InviteCode { - string code = 1; - bool is_redeemed = 2; -}; + string code = 1; + bool is_redeemed = 2; +} // Empty message for now, node identity is extracted from the mTLS // certificate used to authenticate against the Scheduler. message ExportNodeRequest {} message ExportNodeResponse { - // URL where the encrypted backup can be retrieved from. - string url = 1; + // URL where the encrypted backup can be retrieved from. + string url = 1; } message SignerRejection { @@ -427,123 +426,123 @@ message SignerRejection { } message PairDeviceRequest { - // The tls public key of the new device. - string device_id = 1; - - // The certificate signing request that will be signed by the - // greenlight backend if the pairing succeeds. Notice that the CN - // here is irrelevant. - bytes csr = 2; - - // The name of the device that will be part of the tls certificate - // subjects CN field: CN=/users//. - string device_name = 3; - - // A human readable description of the device, this can be a - // purpose or something similar. Can be used to display to the - // user on the old device. - string description = 4; - - // A set of restrictions that the new devices requests for the - // rune. This might in the future get upgraded for easier naming. - string restrictions = 5; + // The tls public key of the new device. + string device_id = 1; + + // The certificate signing request that will be signed by the + // greenlight backend if the pairing succeeds. Notice that the CN + // here is irrelevant. + bytes csr = 2; + + // The name of the device that will be part of the tls certificate + // subjects CN field: CN=/users//. + string device_name = 3; + + // A human readable description of the device, this can be a + // purpose or something similar. Can be used to display to the + // user on the old device. + string description = 4; + + // A set of restrictions that the new devices requests for the + // rune. This might in the future get upgraded for easier naming. + string restrictions = 5; } message PairDeviceResponse { - // device_id is the public key of the new device used for the - // tls cert. - string device_id = 1; - - // Upon a pairing request, the device receives back the signed certificate - // that belongs to the certificate signing request the that was sent with - // the pairing request, so they can authenticate themselves in the future. - string device_cert = 2; - - // The private key that was used to create the certificate with. This key - // is used to sign the requests to the node. - string device_key = 3; - - // A rune that is returned if the device that is created by the signer that - // the device pairs to. - string rune = 4; - - // Creds contains a serialized version of the device certificate, the device - // key and the rune that are used to authenticate a device at the backend, - // and to authorize a request at the signer. - bytes creds = 5; + // device_id is the public key of the new device used for the + // tls cert. + string device_id = 1; + + // Upon a pairing request, the device receives back the signed certificate + // that belongs to the certificate signing request the that was sent with + // the pairing request, so they can authenticate themselves in the future. + string device_cert = 2; + + // The private key that was used to create the certificate with. This key + // is used to sign the requests to the node. + string device_key = 3; + + // A rune that is returned if the device that is created by the signer that + // the device pairs to. + string rune = 4; + + // Creds contains a serialized version of the device certificate, the device + // key and the rune that are used to authenticate a device at the backend, + // and to authorize a request at the signer. + bytes creds = 5; } message GetPairingDataRequest { - // The device_id that the client got from the qr-code. - string device_id = 1; + // The device_id that the client got from the qr-code. + string device_id = 1; } message GetPairingDataResponse { - string device_id = 1; + string device_id = 1; - // The certificate signing request that will be signed by the - // greenlight backend if the pairing succeeds. Notice that the CN - // here is irrelevant. - bytes csr = 2; + // The certificate signing request that will be signed by the + // greenlight backend if the pairing succeeds. Notice that the CN + // here is irrelevant. + bytes csr = 2; - // The name of the device that will be part of the tls certificate - // subjects CN field: CN=/users//. - string device_name = 3; + // The name of the device that will be part of the tls certificate + // subjects CN field: CN=/users//. + string device_name = 3; - // A human readable description of the device, this can be a - // purpose or something similar. Can be used to display to the - // user on the old device. - string description = 4; + // A human readable description of the device, this can be a + // purpose or something similar. Can be used to display to the + // user on the old device. + string description = 4; - // A set of restrictions that the new devices requests for the - // rune. This might in the future get upgraded for easier naming. - string restrictions = 5; + // A set of restrictions that the new devices requests for the + // rune. This might in the future get upgraded for easier naming. + string restrictions = 5; } message ApprovePairingRequest { - string device_id = 1; + string device_id = 1; + + // The time that the old device approved the pairing request. This + // is used by the signer to restrict the duration an approval + // request is valid. + uint64 timestamp = 2; + + // The name of the device that will be part of the tls certificate + // subjects CN field: CN=/users//. + string device_name = 3; - // The time that the old device approved the pairing request. This - // is used by the signer to restrict the duration an approval - // request is valid. - uint64 timestamp = 2; + // The restrictions need a pubkey set. + string restrictions = 4; - // The name of the device that will be part of the tls certificate - // subjects CN field: CN=/users//. - string device_name = 3; - - // The restrictions need a pubkey set. - string restrictions = 4; + // The signature of the above to ensure data integrity. + bytes sig = 5; - // The signature of the above to ensure data integrity. - bytes sig = 5; - - // The public key corresponding to the private key that was used - // to sign the request and that is part of the rune; - bytes pubkey = 6; + // The public key corresponding to the private key that was used + // to sign the request and that is part of the rune; + bytes pubkey = 6; - // The rune of the old device with a pubkey field corresponding to - // the signature above. Used to authorize the approval request. - string rune = 7; + // The rune of the old device with a pubkey field corresponding to + // the signature above. Used to authorize the approval request. + string rune = 7; } message ApprovePairingResponse { - string device_id = 1; - bytes node_id = 2; - string rune =3; + string device_id = 1; + bytes node_id = 2; + string rune = 3; } message SignerRequest { - uint32 request_id = 1; - oneof request { - ApprovePairingRequest approve_pairing = 2; - } + uint32 request_id = 1; + oneof request { + ApprovePairingRequest approve_pairing = 2; + } } message SignerResponse { - uint32 request_id = 1; - oneof response { - greenlight.Empty empty = 2; - ApprovePairingResponse approve_pairing = 3; - } + uint32 request_id = 1; + oneof response { + greenlight.Empty empty = 2; + ApprovePairingResponse approve_pairing = 3; + } } From c5d52e7a3820d3a36171715de94bb0f4e42e06de Mon Sep 17 00:00:00 2001 From: Peter Neuroth Date: Tue, 4 Mar 2025 17:58:17 +0100 Subject: [PATCH 2/4] gl-testing: Use uv in Makefile Changed the invocation of the proto compilation to use `uv` instead of the system's python env. Signed-off-by: Peter Neuroth --- Makefile | 2 +- libs/gl-client-py/Makefile | 6 +++--- libs/gl-client-py/pyproject.toml | 1 + libs/gl-testing/Makefile | 5 ++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index d0bd7763d..5e6c347d8 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,7 @@ gen: ${GENALL} build-self: ensure-docker cargo build --all - uv sync --package gl-client --extra dev + uv sync --package gl-client --dev check-all: check-rs check-self check-py check-testing-py diff --git a/libs/gl-client-py/Makefile b/libs/gl-client-py/Makefile index c1a120ee3..e74407653 100644 --- a/libs/gl-client-py/Makefile +++ b/libs/gl-client-py/Makefile @@ -35,9 +35,9 @@ ${PYPROTOS}: pygrpc pygrpc: ${PROTOSRC} cp ${PYDIR}/../proto/glclient/scheduler.proto ${PYDIR}/glclient/ cp ${PYDIR}/../proto/glclient/greenlight.proto ${PYDIR}/glclient/ - cd ${PYDIR}; poetry install - cd ${PYDIR}; poetry run python -m grpc_tools.protoc ${PYPROTOC_OPTS} glclient/scheduler.proto - cd ${PYDIR}; poetry run python -m grpc_tools.protoc ${PYPROTOC_OPTS} glclient/greenlight.proto + cd ${PYDIR}; uv sync + cd ${PYDIR}; uv run python3 -m grpc_tools.protoc ${PYPROTOC_OPTS} glclient/scheduler.proto + cd ${PYDIR}; uv run python3 -m grpc_tools.protoc ${PYPROTOC_OPTS} glclient/greenlight.proto check-py: #uv run --all-packages mypy ${PYDIR}/glclient diff --git a/libs/gl-client-py/pyproject.toml b/libs/gl-client-py/pyproject.toml index 121549ae2..3f326d355 100644 --- a/libs/gl-client-py/pyproject.toml +++ b/libs/gl-client-py/pyproject.toml @@ -21,6 +21,7 @@ dev = [ "grpcio>=1.67", "maturin>=1", "mypy>=1.14.1", + "mypy-protobuf>=3.0", "protobuf>=4", "pyln-grpc-proto>=0.1.2", "types-protobuf>=5.29.1.20241207", diff --git a/libs/gl-testing/Makefile b/libs/gl-testing/Makefile index 1f6b6d5d5..4fbc3653d 100644 --- a/libs/gl-testing/Makefile +++ b/libs/gl-testing/Makefile @@ -19,11 +19,10 @@ GENALL += ${GEN_TESTING} ${TESTINGDIR}/gltesting/scheduler_grpc.py: testgrpc check-testing-py: - #cd ${TESTINGDIR}; mypy gltesting - cd ${TESTINGDIR}; poetry install --with=dev; poetry run pytest tests -n 4 -vvv + cd ${TESTINGDIR}; uv run pytest tests -n 4 -vvv testgrpc: ${REPO_ROOT}/libs/proto/glclient/scheduler.proto - python -m grpc_tools.protoc ${TESTPROTOC_OPTS} glclient/scheduler.proto + uv run python3 -m grpc_tools.protoc ${TESTPROTOC_OPTS} glclient/scheduler.proto mv ${TESTINGDIR}/gltesting/glclient/scheduler_grpc.py ${TESTINGDIR}/gltesting/scheduler_grpc.py rm -rf ${TESTINGDIR}/gltesting/glclient From 93dd5a2ca1031e1d31317bd333fb5baec9a1c019 Mon Sep 17 00:00:00 2001 From: Peter Neuroth Date: Tue, 4 Mar 2025 16:58:23 +0100 Subject: [PATCH 3/4] gl-scheduler: Add LSP discovery for mocking We need to add some LSP discovery service to the scheduler in order to provide some mocks for cln-application. Signed-off-by: Peter Neuroth --- libs/gl-client-py/glclient/scheduler.proto | 859 ++++++++++-------- libs/gl-client-py/glclient/scheduler_pb2.py | 54 +- libs/gl-client-py/glclient/scheduler_pb2.pyi | 302 +++++- .../glclient/scheduler_pb2_grpc.py | 134 ++- .../glclient/scheduler_pb2_grpc.pyi | 70 +- libs/gl-testing/gltesting/scheduler.py | 13 +- libs/gl-testing/gltesting/scheduler_grpc.py | 57 ++ libs/proto/glclient/scheduler.proto | 110 +++ 8 files changed, 1189 insertions(+), 410 deletions(-) diff --git a/libs/gl-client-py/glclient/scheduler.proto b/libs/gl-client-py/glclient/scheduler.proto index 3bb15f32e..5ac956585 100644 --- a/libs/gl-client-py/glclient/scheduler.proto +++ b/libs/gl-client-py/glclient/scheduler.proto @@ -37,170 +37,170 @@ import "glclient/greenlight.proto"; // to use the node-specific mTLS keypair. // service Scheduler { - // A user may register a new node with greenlight by providing - // some basic metadata and proving that they have access to - // the corresponding private key (see challenge-response - // mechanism below). This means that in order to register a - // new node the user must have access to the corresponding - // private keys to prove ownership, and prevent users from - // just registering arbitrary node_ids without actually - // knowing the corresponding secrets. - // - // Upon successful registration an mTLS certificate and - // private key are returned. These can be used to authenticate - // future connections to the scheduler or the node. - // - // Each node may be registered once, any later attempt will - // result in an error being returned. If the user lost its - // credentials it can make use of the Recover RPC method to - // recover the credentials. Notice that this also means that - // the same node_id cannot be reused for different networks. - rpc Register(RegistrationRequest) returns (RegistrationResponse) {} - - // Should a user have lost its credentials (mTLS keypair) for - // any reason, they may regain access to their node using the - // Recover RPC method. Similar to the initial registration the - // caller needs to authenticate the call by proving access to - // the node's secret. This also uses the challenge-response - // mechanism. - // - // Upon success a newly generated mTLS certificate and private - // key are returned, allowing the user to authenticate going - // forward. Existing keypairs are not revoked, in order to - // avoid locking out other authenticated applications. - rpc Recover(RecoveryRequest) returns (RecoveryResponse) {} - - // Challenges are one-time values issued by the server, used - // to authenticate a user/device against the server. A user or - // device can authenticate to the server by signing the - // challenge and returning the signed message as part of the - // request that is to be authenticated. - // - // Challenges may not be reused, and are bound to the scope - // they have been issued for. Attempting to reuse a challenge - // or use a challenge with a different scope will result in an - // error being returned. - rpc GetChallenge(ChallengeRequest) returns (ChallengeResponse) {} - - // Scheduling takes a previously registered node, locates a - // free slot in greenlight's infrastructure and allocates it - // to run the node. The node then goes through the startup - // sequence, synchronizing with the blockchain, and finally - // binding its grpc interface (see Node service below) to a - // public IP address and port. Access is authenticated via the - // mTLS keypair the user received from registering or - // recovering the node. - // - // Upon success a NodeInfoResponse containing the grpc - // connection details and some metadata is returned. The - // application must use the grpc details and its node-specific - // mTLS keypair to interact with the node directly. - rpc Schedule(ScheduleRequest) returns (NodeInfoResponse) {} - - // Much like `Schedule` this call is used to retrieve the - // metadata and grpc details of a node. Unlike the other call - // however it is passive, and will not result in the node - // being scheduled if it isn't already running. This can be - // used to check if a node is already scheduled, or to wait - // for it to be scheduled (e.g., if the caller is an `hsmd` - // that signs off on changes, but doesn't want to keep the - // node itself scheduled). - rpc GetNodeInfo(NodeInfoRequest) returns (NodeInfoResponse) {} - - // The signer may want to trigger an upgrade of the node - // before waiting for the node to be scheduled. This ensures - // that the signer version is in sync with the node - // version. The scheduler may decide to defer upgrading if the - // protocols are compatible. Please do not use this directly, - // rather use the Signer in the client library to trigger this - // automatically when required. Posting an incomplete or - // non-functional UpgradeRequest may result in unschedulable - // nodes. - rpc MaybeUpgrade(UpgradeRequest) returns (UpgradeResponse) {} - - // This call is used to fetch a list of invite codes associated - // with the node id of the client. These invite codes can be used - // for further registration of new nodes. - rpc ListInviteCodes(ListInviteCodesRequest) returns (ListInviteCodesResponse) {} - - // Exporting a node allows users to take control of their node - // - // This method initiates the node export on Greenlight, - // allowing users to offboard from GL into their own - // infrastructure. After calling this method the node will no - // longer be schedulable on Greenlight, since it is never safe - // to assume there haven't been changes in the node's state - // (see CLN Backups documentation for details). `ExportNode` - // marks the node as `Exporting`, then generates an encryption - // secret which is then used to encrypt a database - // backup. This encrypted database backup is then made - // accessible through an HTTP server, and a link to it is - // returned as a response to `ExportNode`. After the export - // completes the node is marked as `Exported`. The encryption - // key can then be derived using the signer, using ECDH, - // allowing only users with the node secret to decrypt it. - // - // `ExportNode` is idempotent and may be called multiple - // times, without causing the node to be re-exported multiple - // times, should the call or the download be interrupted. DO - // NOT import the backup multiple times into your - // infrastructure, as that can lead to dataloss (old state - // being replayed) and loss of funds (see CLN Backups - // documentation for more information) - rpc ExportNode(ExportNodeRequest) returns (ExportNodeResponse) {} - - rpc AddOutgoingWebhook(AddOutgoingWebhookRequest) returns (AddOutgoingWebhookResponse) {} - - rpc ListOutgoingWebhooks(ListOutgoingWebhooksRequest) returns (ListOutgoingWebhooksResponse) {} - - rpc DeleteWebhooks(DeleteOutgoingWebhooksRequest) returns (greenlight.Empty) {} - - rpc RotateOutgoingWebhookSecret(RotateOutgoingWebhookSecretRequest) returns (WebhookSecretResponse) {} - - // Attaches a Signer via a bidirectional stream to the scheduler. - // This is a communication channel between greenlight and the signing - // device that is used for requests that are not part of the node api. - // - // The stream is used to hand out the ApprovePairingRequests that - // the signer answers with a ApprovePairingResponse. - rpc SignerRequestsStream(stream SignerResponse) returns (stream SignerRequest) {}; -}; + // A user may register a new node with greenlight by providing + // some basic metadata and proving that they have access to + // the corresponding private key (see challenge-response + // mechanism below). This means that in order to register a + // new node the user must have access to the corresponding + // private keys to prove ownership, and prevent users from + // just registering arbitrary node_ids without actually + // knowing the corresponding secrets. + // + // Upon successful registration an mTLS certificate and + // private key are returned. These can be used to authenticate + // future connections to the scheduler or the node. + // + // Each node may be registered once, any later attempt will + // result in an error being returned. If the user lost its + // credentials it can make use of the Recover RPC method to + // recover the credentials. Notice that this also means that + // the same node_id cannot be reused for different networks. + rpc Register(RegistrationRequest) returns (RegistrationResponse) {} + + // Should a user have lost its credentials (mTLS keypair) for + // any reason, they may regain access to their node using the + // Recover RPC method. Similar to the initial registration the + // caller needs to authenticate the call by proving access to + // the node's secret. This also uses the challenge-response + // mechanism. + // + // Upon success a newly generated mTLS certificate and private + // key are returned, allowing the user to authenticate going + // forward. Existing keypairs are not revoked, in order to + // avoid locking out other authenticated applications. + rpc Recover(RecoveryRequest) returns (RecoveryResponse) {} + + // Challenges are one-time values issued by the server, used + // to authenticate a user/device against the server. A user or + // device can authenticate to the server by signing the + // challenge and returning the signed message as part of the + // request that is to be authenticated. + // + // Challenges may not be reused, and are bound to the scope + // they have been issued for. Attempting to reuse a challenge + // or use a challenge with a different scope will result in an + // error being returned. + rpc GetChallenge(ChallengeRequest) returns (ChallengeResponse) {} + + // Scheduling takes a previously registered node, locates a + // free slot in greenlight's infrastructure and allocates it + // to run the node. The node then goes through the startup + // sequence, synchronizing with the blockchain, and finally + // binding its grpc interface (see Node service below) to a + // public IP address and port. Access is authenticated via the + // mTLS keypair the user received from registering or + // recovering the node. + // + // Upon success a NodeInfoResponse containing the grpc + // connection details and some metadata is returned. The + // application must use the grpc details and its node-specific + // mTLS keypair to interact with the node directly. + rpc Schedule(ScheduleRequest) returns (NodeInfoResponse) {} + + // Much like `Schedule` this call is used to retrieve the + // metadata and grpc details of a node. Unlike the other call + // however it is passive, and will not result in the node + // being scheduled if it isn't already running. This can be + // used to check if a node is already scheduled, or to wait + // for it to be scheduled (e.g., if the caller is an `hsmd` + // that signs off on changes, but doesn't want to keep the + // node itself scheduled). + rpc GetNodeInfo(NodeInfoRequest) returns (NodeInfoResponse) {} + + // The signer may want to trigger an upgrade of the node + // before waiting for the node to be scheduled. This ensures + // that the signer version is in sync with the node + // version. The scheduler may decide to defer upgrading if the + // protocols are compatible. Please do not use this directly, + // rather use the Signer in the client library to trigger this + // automatically when required. Posting an incomplete or + // non-functional UpgradeRequest may result in unschedulable + // nodes. + rpc MaybeUpgrade(UpgradeRequest) returns (UpgradeResponse) {} + + // This call is used to fetch a list of invite codes associated + // with the node id of the client. These invite codes can be used + // for further registration of new nodes. + rpc ListInviteCodes(ListInviteCodesRequest) returns (ListInviteCodesResponse) {} + + // Exporting a node allows users to take control of their node + // + // This method initiates the node export on Greenlight, + // allowing users to offboard from GL into their own + // infrastructure. After calling this method the node will no + // longer be schedulable on Greenlight, since it is never safe + // to assume there haven't been changes in the node's state + // (see CLN Backups documentation for details). `ExportNode` + // marks the node as `Exporting`, then generates an encryption + // secret which is then used to encrypt a database + // backup. This encrypted database backup is then made + // accessible through an HTTP server, and a link to it is + // returned as a response to `ExportNode`. After the export + // completes the node is marked as `Exported`. The encryption + // key can then be derived using the signer, using ECDH, + // allowing only users with the node secret to decrypt it. + // + // `ExportNode` is idempotent and may be called multiple + // times, without causing the node to be re-exported multiple + // times, should the call or the download be interrupted. DO + // NOT import the backup multiple times into your + // infrastructure, as that can lead to dataloss (old state + // being replayed) and loss of funds (see CLN Backups + // documentation for more information) + rpc ExportNode(ExportNodeRequest) returns (ExportNodeResponse) {} + + rpc AddOutgoingWebhook(AddOutgoingWebhookRequest) returns (AddOutgoingWebhookResponse) {} + + rpc ListOutgoingWebhooks(ListOutgoingWebhooksRequest) returns (ListOutgoingWebhooksResponse) {} + + rpc DeleteWebhooks(DeleteOutgoingWebhooksRequest) returns (greenlight.Empty) {} + + rpc RotateOutgoingWebhookSecret(RotateOutgoingWebhookSecretRequest) returns (WebhookSecretResponse) {} + + // Attaches a Signer via a bidirectional stream to the scheduler. + // This is a communication channel between greenlight and the signing + // device that is used for requests that are not part of the node api. + // + // The stream is used to hand out the ApprovePairingRequests that + // the signer answers with a ApprovePairingResponse. + rpc SignerRequestsStream(stream SignerResponse) returns (stream SignerRequest) {} +} message AddOutgoingWebhookRequest { - bytes node_id = 1; - string uri = 2; + bytes node_id = 1; + string uri = 2; } message AddOutgoingWebhookResponse { - int64 id = 1; - string secret = 2; + int64 id = 1; + string secret = 2; } message ListOutgoingWebhooksRequest { - bytes node_id = 1; + bytes node_id = 1; } message Webhook { - int64 id = 1; - string uri = 2; + int64 id = 1; + string uri = 2; } message ListOutgoingWebhooksResponse { - repeated Webhook outgoing_webhooks = 1; + repeated Webhook outgoing_webhooks = 1; } message DeleteOutgoingWebhooksRequest { - bytes node_id = 1; - repeated int64 ids = 2; + bytes node_id = 1; + repeated int64 ids = 2; } message RotateOutgoingWebhookSecretRequest { - bytes node_id = 1; - int64 webhook_id = 2; + bytes node_id = 1; + int64 webhook_id = 2; } message WebhookSecretResponse { - string secret = 1; + string secret = 1; } // A service to collect debugging information from clients. @@ -212,112 +212,112 @@ service Debug { // to debug these false negatives, hence why we report rejections, // so we can investigate the validity of the rejection, and to // fine-tine the signer's ruleset. - rpc ReportSignerRejection(SignerRejection) returns (greenlight.Empty) {} + rpc ReportSignerRejection(SignerRejection) returns (greenlight.Empty) {} } // A service to pair signer-less clients with an existing signer. service Pairing { - // Initiates a new Pairing Sessions. This is called by the new - // device that wants to request a pairing from an existing device. - // The session lifetime is bound to the stream so closing the - // stream destroys the session. - rpc PairDevice(PairDeviceRequest) returns (PairDeviceResponse) {} - - // Returns the pairing related data that belongs to a pairing - // session. This is meant to be called from a device that can - // approve a pairing request, we sometimes call it "old device". - rpc GetPairingData(GetPairingDataRequest) returns (GetPairingDataResponse) {} - - // Approves a pairing request. The ApprovePairingRequest is - // forwarded to a signer for further processing. - rpc ApprovePairing(ApprovePairingRequest) returns (greenlight.Empty) {} + // Initiates a new Pairing Sessions. This is called by the new + // device that wants to request a pairing from an existing device. + // The session lifetime is bound to the stream so closing the + // stream destroys the session. + rpc PairDevice(PairDeviceRequest) returns (PairDeviceResponse) {} + + // Returns the pairing related data that belongs to a pairing + // session. This is meant to be called from a device that can + // approve a pairing request, we sometimes call it "old device". + rpc GetPairingData(GetPairingDataRequest) returns (GetPairingDataResponse) {} + + // Approves a pairing request. The ApprovePairingRequest is + // forwarded to a signer for further processing. + rpc ApprovePairing(ApprovePairingRequest) returns (greenlight.Empty) {} } message ChallengeRequest { - ChallengeScope scope = 1; - bytes node_id = 2; -}; + ChallengeScope scope = 1; + bytes node_id = 2; +} message ChallengeResponse { - bytes challenge = 1; -}; + bytes challenge = 1; +} // Operation is the challenge associated with? enum ChallengeScope { - REGISTER = 0; - RECOVER = 1; + REGISTER = 0; + RECOVER = 1; } message RegistrationRequest { - // 33 bytes node public key. - bytes node_id = 1; - - // DEPRECATED: The `init_msg` subsumes this field - bytes bip32_key = 2; - - // Which network is this node going to run on? Options are - // bitcoin, testnet, and regtest. - string network = 4; - - // An previously unused challenge as retrieved from - // `Scheduler.GetChallenge() with `scope=REGISTER`. In - // combination with the `signature` below this is used to - // authenticate the caller and ensure the caller has access to - // the secret keys corresponding to the `node_id`. - bytes challenge = 5; - - // A signature for the `challenge` signed by the secret key - // corresponding to the `node_id`. Please refer to the - // documentation of `Scheduler.GetChallenge()` for details on - // how to create this signature. - bytes signature = 6; - - // The signer_proto is required in order to determine which - // version the node should run. If these don't match the - // signer may not be able to sign incoming requests. - string signer_proto = 7; - - // The fuil init message returned by the `libhsmd`, this - // supersedes the bip32_key field which was a misnomer. Notice - // that this includes the prefix 0x006F which is the message - // type. - bytes init_msg = 8; - - // The certificate signing request that will be signed by the - // greenlight backend. Notice that this must have the valid - // CN corresponding to the node_id e.g. /users/{node_id} set. - bytes csr = 9; - - // An optional invite code. We may want to throttle the - // registration rate. Therefore we might check that a registration - // request has a valid invite code. - string invite_code = 10; - - // Messages stashed at the scheduler to allow signerless - // startups. - repeated StartupMessage startupmsgs = 3; -}; + // 33 bytes node public key. + bytes node_id = 1; + + // DEPRECATED: The `init_msg` subsumes this field + bytes bip32_key = 2; + + // Which network is this node going to run on? Options are + // bitcoin, testnet, and regtest. + string network = 4; + + // An previously unused challenge as retrieved from + // `Scheduler.GetChallenge() with `scope=REGISTER`. In + // combination with the `signature` below this is used to + // authenticate the caller and ensure the caller has access to + // the secret keys corresponding to the `node_id`. + bytes challenge = 5; + + // A signature for the `challenge` signed by the secret key + // corresponding to the `node_id`. Please refer to the + // documentation of `Scheduler.GetChallenge()` for details on + // how to create this signature. + bytes signature = 6; + + // The signer_proto is required in order to determine which + // version the node should run. If these don't match the + // signer may not be able to sign incoming requests. + string signer_proto = 7; + + // The fuil init message returned by the `libhsmd`, this + // supersedes the bip32_key field which was a misnomer. Notice + // that this includes the prefix 0x006F which is the message + // type. + bytes init_msg = 8; + + // The certificate signing request that will be signed by the + // greenlight backend. Notice that this must have the valid + // CN corresponding to the node_id e.g. /users/{node_id} set. + bytes csr = 9; + + // An optional invite code. We may want to throttle the + // registration rate. Therefore we might check that a registration + // request has a valid invite code. + string invite_code = 10; + + // Messages stashed at the scheduler to allow signerless + // startups. + repeated StartupMessage startupmsgs = 3; +} message RegistrationResponse { - // Upon registering the user receives back the signed certificate that - // belongs to the certificate signing request the that was sent in the - // registration request, so they can authenticate themselves in the future. - string device_cert = 1; - - // The private key that was used to create the certificate with. This key - // is used to sign the requests to the node. - string device_key = 2; - - // A master rune that is returned if the device that is registered has its - // own signer. The signer is necessary as the response is intercepted on the - // client side and appends the rune to the registratrion response. - string rune = 3; - - // Creds contains a serialized version of the device_cert, the device_key - // and the rune that are used to authenticate a device at the backend, - // and to authorize a request at the signer. - bytes creds = 4; -}; + // Upon registering the user receives back the signed certificate that + // belongs to the certificate signing request the that was sent in the + // registration request, so they can authenticate themselves in the future. + string device_cert = 1; + + // The private key that was used to create the certificate with. This key + // is used to sign the requests to the node. + string device_key = 2; + + // A master rune that is returned if the device that is registered has its + // own signer. The signer is necessary as the response is intercepted on the + // client side and appends the rune to the registratrion response. + string rune = 3; + + // Creds contains a serialized version of the device_cert, the device_key + // and the rune that are used to authenticate a device at the backend, + // and to authorize a request at the signer. + bytes creds = 4; +} // Ask the scheduler to schedule the node to be run on an available nodelet. // @@ -325,68 +325,67 @@ message RegistrationResponse { // like to see if a nodelet is currently taking care of this node, or // wait for one to start please use the message ScheduleRequest { - bytes node_id = 1; -}; + bytes node_id = 1; +} // Discovery request asking the scheduler if a nodelet is currently assigned // the specified node_id, or wait for one to be assigned. If `wait` is set to // `true` the scheduler will keep the request pending until a nodelet is // assigned. message NodeInfoRequest { - bytes node_id = 1; - bool wait = 2; -}; + bytes node_id = 1; + bool wait = 2; +} message NodeInfoResponse { - bytes node_id = 1; - string grpc_uri = 2; - uint64 session_id = 3; -}; - + bytes node_id = 1; + string grpc_uri = 2; + uint64 session_id = 3; +} message RecoveryRequest { - bytes challenge = 1; - bytes signature = 2; - bytes node_id = 3; - // The certificate signing request that will be signed by the - // greenlight backend. Notice that this must have the valid - // CN corresponding to the node_id e.g. /users/{node_id} set. - bytes csr = 9; -}; + bytes challenge = 1; + bytes signature = 2; + bytes node_id = 3; + // The certificate signing request that will be signed by the + // greenlight backend. Notice that this must have the valid + // CN corresponding to the node_id e.g. /users/{node_id} set. + bytes csr = 9; +} message RecoveryResponse { - string device_cert = 1; - string device_key = 2; - - // A master rune that is returned if the device that is registered has its - // own signer. The signer is necessary as the response is intercepted on the - // client side and appends the rune to the registratrion response. - string rune = 3; - - // Creds contains a serialized version of the device_cert, the device_key - // and the rune that are used to authenticate a device at the backend, - // and to authorize a request at the signer. - bytes creds = 4; -}; + string device_cert = 1; + string device_key = 2; + + // A master rune that is returned if the device that is registered has its + // own signer. The signer is necessary as the response is intercepted on the + // client side and appends the rune to the registratrion response. + string rune = 3; + + // Creds contains a serialized version of the device_cert, the device_key + // and the rune that are used to authenticate a device at the backend, + // and to authorize a request at the signer. + bytes creds = 4; +} message UpgradeRequest { - // The version of the signer, i.e., the maximum version of the - // protocol that this signer can understand. - string signer_version = 1; - - // The new initmsg matching the above version. Necessary to - // schedule the node without a signer present. - // Deprecated: Replaced by the more generic `startupmsgs` - bytes initmsg = 2 [deprecated = true]; - - // Messages stashed at the scheduler to allow signerless startups. - repeated StartupMessage startupmsgs = 3; -}; + // The version of the signer, i.e., the maximum version of the + // protocol that this signer can understand. + string signer_version = 1; + + // The new initmsg matching the above version. Necessary to + // schedule the node without a signer present. + // Deprecated: Replaced by the more generic `startupmsgs` + bytes initmsg = 2 [deprecated = true]; + + // Messages stashed at the scheduler to allow signerless startups. + repeated StartupMessage startupmsgs = 3; +} message UpgradeResponse { - // The version of the node before the upgrade request has been - // processed. - string old_version = 1; -}; + // The version of the node before the upgrade request has been + // processed. + string old_version = 1; +} // A message that we know will be requested by `lightningd` at // startup, and that we stash a response to on the scheduler. This @@ -398,24 +397,24 @@ message StartupMessage { bytes response = 2; } -message ListInviteCodesRequest {}; +message ListInviteCodesRequest {} message ListInviteCodesResponse { - repeated InviteCode invite_code_list = 1; -}; + repeated InviteCode invite_code_list = 1; +} message InviteCode { - string code = 1; - bool is_redeemed = 2; -}; + string code = 1; + bool is_redeemed = 2; +} // Empty message for now, node identity is extracted from the mTLS // certificate used to authenticate against the Scheduler. message ExportNodeRequest {} message ExportNodeResponse { - // URL where the encrypted backup can be retrieved from. - string url = 1; + // URL where the encrypted backup can be retrieved from. + string url = 1; } message SignerRejection { @@ -427,123 +426,233 @@ message SignerRejection { } message PairDeviceRequest { - // The tls public key of the new device. - string device_id = 1; - - // The certificate signing request that will be signed by the - // greenlight backend if the pairing succeeds. Notice that the CN - // here is irrelevant. - bytes csr = 2; - - // The name of the device that will be part of the tls certificate - // subjects CN field: CN=/users//. - string device_name = 3; - - // A human readable description of the device, this can be a - // purpose or something similar. Can be used to display to the - // user on the old device. - string description = 4; - - // A set of restrictions that the new devices requests for the - // rune. This might in the future get upgraded for easier naming. - string restrictions = 5; + // The tls public key of the new device. + string device_id = 1; + + // The certificate signing request that will be signed by the + // greenlight backend if the pairing succeeds. Notice that the CN + // here is irrelevant. + bytes csr = 2; + + // The name of the device that will be part of the tls certificate + // subjects CN field: CN=/users//. + string device_name = 3; + + // A human readable description of the device, this can be a + // purpose or something similar. Can be used to display to the + // user on the old device. + string description = 4; + + // A set of restrictions that the new devices requests for the + // rune. This might in the future get upgraded for easier naming. + string restrictions = 5; } message PairDeviceResponse { - // device_id is the public key of the new device used for the - // tls cert. - string device_id = 1; - - // Upon a pairing request, the device receives back the signed certificate - // that belongs to the certificate signing request the that was sent with - // the pairing request, so they can authenticate themselves in the future. - string device_cert = 2; - - // The private key that was used to create the certificate with. This key - // is used to sign the requests to the node. - string device_key = 3; - - // A rune that is returned if the device that is created by the signer that - // the device pairs to. - string rune = 4; - - // Creds contains a serialized version of the device certificate, the device - // key and the rune that are used to authenticate a device at the backend, - // and to authorize a request at the signer. - bytes creds = 5; + // device_id is the public key of the new device used for the + // tls cert. + string device_id = 1; + + // Upon a pairing request, the device receives back the signed certificate + // that belongs to the certificate signing request the that was sent with + // the pairing request, so they can authenticate themselves in the future. + string device_cert = 2; + + // The private key that was used to create the certificate with. This key + // is used to sign the requests to the node. + string device_key = 3; + + // A rune that is returned if the device that is created by the signer that + // the device pairs to. + string rune = 4; + + // Creds contains a serialized version of the device certificate, the device + // key and the rune that are used to authenticate a device at the backend, + // and to authorize a request at the signer. + bytes creds = 5; } message GetPairingDataRequest { - // The device_id that the client got from the qr-code. - string device_id = 1; + // The device_id that the client got from the qr-code. + string device_id = 1; } message GetPairingDataResponse { - string device_id = 1; + string device_id = 1; - // The certificate signing request that will be signed by the - // greenlight backend if the pairing succeeds. Notice that the CN - // here is irrelevant. - bytes csr = 2; + // The certificate signing request that will be signed by the + // greenlight backend if the pairing succeeds. Notice that the CN + // here is irrelevant. + bytes csr = 2; - // The name of the device that will be part of the tls certificate - // subjects CN field: CN=/users//. - string device_name = 3; + // The name of the device that will be part of the tls certificate + // subjects CN field: CN=/users//. + string device_name = 3; - // A human readable description of the device, this can be a - // purpose or something similar. Can be used to display to the - // user on the old device. - string description = 4; + // A human readable description of the device, this can be a + // purpose or something similar. Can be used to display to the + // user on the old device. + string description = 4; - // A set of restrictions that the new devices requests for the - // rune. This might in the future get upgraded for easier naming. - string restrictions = 5; + // A set of restrictions that the new devices requests for the + // rune. This might in the future get upgraded for easier naming. + string restrictions = 5; } message ApprovePairingRequest { - string device_id = 1; + string device_id = 1; + + // The time that the old device approved the pairing request. This + // is used by the signer to restrict the duration an approval + // request is valid. + uint64 timestamp = 2; - // The time that the old device approved the pairing request. This - // is used by the signer to restrict the duration an approval - // request is valid. - uint64 timestamp = 2; + // The name of the device that will be part of the tls certificate + // subjects CN field: CN=/users//. + string device_name = 3; - // The name of the device that will be part of the tls certificate - // subjects CN field: CN=/users//. - string device_name = 3; - - // The restrictions need a pubkey set. - string restrictions = 4; + // The restrictions need a pubkey set. + string restrictions = 4; - // The signature of the above to ensure data integrity. - bytes sig = 5; - - // The public key corresponding to the private key that was used - // to sign the request and that is part of the rune; - bytes pubkey = 6; + // The signature of the above to ensure data integrity. + bytes sig = 5; - // The rune of the old device with a pubkey field corresponding to - // the signature above. Used to authorize the approval request. - string rune = 7; + // The public key corresponding to the private key that was used + // to sign the request and that is part of the rune; + bytes pubkey = 6; + + // The rune of the old device with a pubkey field corresponding to + // the signature above. Used to authorize the approval request. + string rune = 7; } message ApprovePairingResponse { - string device_id = 1; - bytes node_id = 2; - string rune =3; + string device_id = 1; + bytes node_id = 2; + string rune = 3; } message SignerRequest { - uint32 request_id = 1; - oneof request { - ApprovePairingRequest approve_pairing = 2; - } + uint32 request_id = 1; + oneof request { + ApprovePairingRequest approve_pairing = 2; + } } message SignerResponse { - uint32 request_id = 1; - oneof response { - greenlight.Empty empty = 2; - ApprovePairingResponse approve_pairing = 3; - } + uint32 request_id = 1; + oneof response { + greenlight.Empty empty = 2; + ApprovePairingResponse approve_pairing = 3; + } +} + +message ListLspsRequest {} + +message ListLspsResponse { + // A map that maps the public keys of known LSPs to the information we have + // about them. + map lsps = 1; +} + +message Lsp { + // An object that contains the supported protocols with additional + // information about the LSPs conditions. + repeated int32 protocols = 1; +} + +message GetLspInfoRequest { + // The public key of the LSP of interest. + string public_key = 1; +} + +message GetLspInfoResponse { + // The public key of the LSP. + string public_key = 1; + // Infos about the supported protocols. + LspProtocols protocols = 2; +} + +message LspProtocols { + // Optional information relating to the lsps1 protocol. Is only present if + // the LSP supports the protocol. + Lsps1Info lsps1 = 1; + // Optional information relating to the lsps2 protocol. Is only present if + // the LSP supports the protocol. + Lsps2Info lsps2 = 2; +} + +message Lsps1Info { + // The smallest number of confirmations needed for the LSP to accept a + // channel as confirmed and sends `channel_ready` (see bolt02). + uint32 min_required_channel_confirmations = 1; + // The smallest number of blocks in which the LSP can confirm the funding + // transaction. + uint32 min_funding_confirms_within_blocks = 2; + // Is true if the LSP supports zeroreserve on the channel. + bool supports_zero_channel_reserve = 3; + // Is the maximum number of blocks a channel can be leased for. + uint32 max_channel_expiry_blocks = 4; + // The minimum amount in satoshis that a client must request. + uint64 min_initial_client_balance_sat = 5; + // The maximum amount in satoshis that a client must request. + uint64 max_initial_client_balance_sat = 6; + // The minimum amount in satoshis that the LSP will provide to the channel. + uint64 min_initial_lsp_balance_sat = 7; + // The maximum amount in satoshis that the LSP will provide to the channel. + uint64 max_initial_lsp_balance_sat = 8; + // The minimum channel size the LSP accepts. + uint64 min_channel_balance_sat = 9; + // The maximum channel size the LSP accepts. + uint64 max_channel_balance_sat = 10; +} + +message Lsps2Info { + // The LSP may return an empty array in which case, the client currently + // cannot use JIT channels with this LSP. + repeated Lsps2OpeningFeeParams opening_fee_params_menu = 1; +} + +message Lsps2OpeningFeeParams { + // The minimum fee to be paid by the client to the LSP. + uint64 min_fee_msat = 1; + // A parts-per-million number that describes how many millisatoshis to charge + // for every 1 million millisatoshis of payment size for the first payment. If + // the proportional fee is less than than `min_fee_msat`, then `min_fee_msat` + // is paid instead of the proportional times payment size divided by 1 + // million. + uint32 proportional = 2; + // Is a datetime (as an ISO8601 string) up to which this specific + // `opening_fee_params` is valid, and also serves as the timeout for the JIT + // Channel flow, if this particular object is selected. + string valid_until = 3; + // Is a number of blocks that the LSP promises it will keep the channel alive + // without closing, after confirmation. + uint32 min_lifetime = 4; + // Is a maximum number of blocks that the client is allowed to set its + // `to_self_pay_delay` parameter. + uint32 max_client_to_self_delay = 5; + // Is the minimum payment size, inclusive. Is the amount in millisatoshis that + // the payer is guaranteed to be able to send to the client, not including the + // forwarding fees of nodes along the way. + uint64 min_payment_size_msat = 6; + // Is the maximum payment size, inclusive. Is the amount in millisatoshis that + // the payer is guaranteed to be able to send to the client, not including the + // forwarding fees of nodes along the way. + uint64 max_payment_size_msat = 7; + // An arbitrary LSP-genereated string that proves to the LSP that it has + // promised a specific `opening_fee_params`. + string promise = 8; +} + +// A service to explore lsps compatible LSP's +service Lsps { + // Returns a structured list of all available Lsps. An Lsp is a + // Lightning Service Provider, providing an API as described in blips + // 50, 51 and 52 https://github.com/lightning/blips. From cln: + // `lsps-listlsps`. + rpc ListLsps(ListLspsRequest) returns (ListLspsResponse) {} + + // Returns detailed information about a LSP. From cln: `lsps-lspinfo`. + rpc GetLspInfo(GetLspInfoRequest) returns (GetLspInfoResponse) {} } diff --git a/libs/gl-client-py/glclient/scheduler_pb2.py b/libs/gl-client-py/glclient/scheduler_pb2.py index 1b05456f6..df8c60620 100644 --- a/libs/gl-client-py/glclient/scheduler_pb2.py +++ b/libs/gl-client-py/glclient/scheduler_pb2.py @@ -1,12 +1,22 @@ # -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE # source: glclient/scheduler.proto -# Protobuf Python Version: 5.26.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version from google.protobuf import symbol_database as _symbol_database from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 29, + 0, + '', + 'glclient/scheduler.proto' +) # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() @@ -15,7 +25,7 @@ from glclient import greenlight_pb2 as glclient_dot_greenlight__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18glclient/scheduler.proto\x12\tscheduler\x1a\x19glclient/greenlight.proto\"9\n\x19\x41\x64\x64OutgoingWebhookRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x0b\n\x03uri\x18\x02 \x01(\t\"8\n\x1a\x41\x64\x64OutgoingWebhookResponse\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0e\n\x06secret\x18\x02 \x01(\t\".\n\x1bListOutgoingWebhooksRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\"\"\n\x07Webhook\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0b\n\x03uri\x18\x02 \x01(\t\"M\n\x1cListOutgoingWebhooksResponse\x12-\n\x11outgoing_webhooks\x18\x01 \x03(\x0b\x32\x12.scheduler.Webhook\"=\n\x1d\x44\x65leteOutgoingWebhooksRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x0b\n\x03ids\x18\x02 \x03(\x03\"I\n\"RotateOutgoingWebhookSecretRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x12\n\nwebhook_id\x18\x02 \x01(\x03\"\'\n\x15WebhookSecretResponse\x12\x0e\n\x06secret\x18\x01 \x01(\t\"M\n\x10\x43hallengeRequest\x12(\n\x05scope\x18\x01 \x01(\x0e\x32\x19.scheduler.ChallengeScope\x12\x0f\n\x07node_id\x18\x02 \x01(\x0c\"&\n\x11\x43hallengeResponse\x12\x11\n\tchallenge\x18\x01 \x01(\x0c\"\xea\x01\n\x13RegistrationRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x11\n\tbip32_key\x18\x02 \x01(\x0c\x12\x0f\n\x07network\x18\x04 \x01(\t\x12\x11\n\tchallenge\x18\x05 \x01(\x0c\x12\x11\n\tsignature\x18\x06 \x01(\x0c\x12\x14\n\x0csigner_proto\x18\x07 \x01(\t\x12\x10\n\x08init_msg\x18\x08 \x01(\x0c\x12\x0b\n\x03\x63sr\x18\t \x01(\x0c\x12\x13\n\x0binvite_code\x18\n \x01(\t\x12.\n\x0bstartupmsgs\x18\x03 \x03(\x0b\x32\x19.scheduler.StartupMessage\"\\\n\x14RegistrationResponse\x12\x13\n\x0b\x64\x65vice_cert\x18\x01 \x01(\t\x12\x12\n\ndevice_key\x18\x02 \x01(\t\x12\x0c\n\x04rune\x18\x03 \x01(\t\x12\r\n\x05\x63reds\x18\x04 \x01(\x0c\"\"\n\x0fScheduleRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\"0\n\x0fNodeInfoRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x0c\n\x04wait\x18\x02 \x01(\x08\"I\n\x10NodeInfoResponse\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x10\n\x08grpc_uri\x18\x02 \x01(\t\x12\x12\n\nsession_id\x18\x03 \x01(\x04\"U\n\x0fRecoveryRequest\x12\x11\n\tchallenge\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07node_id\x18\x03 \x01(\x0c\x12\x0b\n\x03\x63sr\x18\t \x01(\x0c\"X\n\x10RecoveryResponse\x12\x13\n\x0b\x64\x65vice_cert\x18\x01 \x01(\t\x12\x12\n\ndevice_key\x18\x02 \x01(\t\x12\x0c\n\x04rune\x18\x03 \x01(\t\x12\r\n\x05\x63reds\x18\x04 \x01(\x0c\"m\n\x0eUpgradeRequest\x12\x16\n\x0esigner_version\x18\x01 \x01(\t\x12\x13\n\x07initmsg\x18\x02 \x01(\x0c\x42\x02\x18\x01\x12.\n\x0bstartupmsgs\x18\x03 \x03(\x0b\x32\x19.scheduler.StartupMessage\"&\n\x0fUpgradeResponse\x12\x13\n\x0bold_version\x18\x01 \x01(\t\"3\n\x0eStartupMessage\x12\x0f\n\x07request\x18\x01 \x01(\x0c\x12\x10\n\x08response\x18\x02 \x01(\x0c\"\x18\n\x16ListInviteCodesRequest\"J\n\x17ListInviteCodesResponse\x12/\n\x10invite_code_list\x18\x01 \x03(\x0b\x32\x15.scheduler.InviteCode\"/\n\nInviteCode\x12\x0c\n\x04\x63ode\x18\x01 \x01(\t\x12\x13\n\x0bis_redeemed\x18\x02 \x01(\x08\"\x13\n\x11\x45xportNodeRequest\"!\n\x12\x45xportNodeResponse\x12\x0b\n\x03url\x18\x01 \x01(\t\"m\n\x0fSignerRejection\x12\x0b\n\x03msg\x18\x01 \x01(\t\x12\'\n\x07request\x18\x02 \x01(\x0b\x32\x16.greenlight.HsmRequest\x12\x13\n\x0bgit_version\x18\x03 \x01(\t\x12\x0f\n\x07node_id\x18\x04 \x01(\x0c\"s\n\x11PairDeviceRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x0b\n\x03\x63sr\x18\x02 \x01(\x0c\x12\x13\n\x0b\x64\x65vice_name\x18\x03 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x04 \x01(\t\x12\x14\n\x0crestrictions\x18\x05 \x01(\t\"m\n\x12PairDeviceResponse\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_cert\x18\x02 \x01(\t\x12\x12\n\ndevice_key\x18\x03 \x01(\t\x12\x0c\n\x04rune\x18\x04 \x01(\t\x12\r\n\x05\x63reds\x18\x05 \x01(\x0c\"*\n\x15GetPairingDataRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\t\"x\n\x16GetPairingDataResponse\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x0b\n\x03\x63sr\x18\x02 \x01(\x0c\x12\x13\n\x0b\x64\x65vice_name\x18\x03 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x04 \x01(\t\x12\x14\n\x0crestrictions\x18\x05 \x01(\t\"\x93\x01\n\x15\x41pprovePairingRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x11\n\ttimestamp\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x65vice_name\x18\x03 \x01(\t\x12\x14\n\x0crestrictions\x18\x04 \x01(\t\x12\x0b\n\x03sig\x18\x05 \x01(\x0c\x12\x0e\n\x06pubkey\x18\x06 \x01(\x0c\x12\x0c\n\x04rune\x18\x07 \x01(\t\"J\n\x16\x41pprovePairingResponse\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x0c\x12\x0c\n\x04rune\x18\x03 \x01(\t\"k\n\rSignerRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\r\x12;\n\x0f\x61pprove_pairing\x18\x02 \x01(\x0b\x32 .scheduler.ApprovePairingRequestH\x00\x42\t\n\x07request\"\x92\x01\n\x0eSignerResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\r\x12\"\n\x05\x65mpty\x18\x02 \x01(\x0b\x32\x11.greenlight.EmptyH\x00\x12<\n\x0f\x61pprove_pairing\x18\x03 \x01(\x0b\x32!.scheduler.ApprovePairingResponseH\x00\x42\n\n\x08response*+\n\x0e\x43hallengeScope\x12\x0c\n\x08REGISTER\x10\x00\x12\x0b\n\x07RECOVER\x10\x01\x32\xd6\x08\n\tScheduler\x12M\n\x08Register\x12\x1e.scheduler.RegistrationRequest\x1a\x1f.scheduler.RegistrationResponse\"\x00\x12\x44\n\x07Recover\x12\x1a.scheduler.RecoveryRequest\x1a\x1b.scheduler.RecoveryResponse\"\x00\x12K\n\x0cGetChallenge\x12\x1b.scheduler.ChallengeRequest\x1a\x1c.scheduler.ChallengeResponse\"\x00\x12\x45\n\x08Schedule\x12\x1a.scheduler.ScheduleRequest\x1a\x1b.scheduler.NodeInfoResponse\"\x00\x12H\n\x0bGetNodeInfo\x12\x1a.scheduler.NodeInfoRequest\x1a\x1b.scheduler.NodeInfoResponse\"\x00\x12G\n\x0cMaybeUpgrade\x12\x19.scheduler.UpgradeRequest\x1a\x1a.scheduler.UpgradeResponse\"\x00\x12Z\n\x0fListInviteCodes\x12!.scheduler.ListInviteCodesRequest\x1a\".scheduler.ListInviteCodesResponse\"\x00\x12K\n\nExportNode\x12\x1c.scheduler.ExportNodeRequest\x1a\x1d.scheduler.ExportNodeResponse\"\x00\x12\x63\n\x12\x41\x64\x64OutgoingWebhook\x12$.scheduler.AddOutgoingWebhookRequest\x1a%.scheduler.AddOutgoingWebhookResponse\"\x00\x12i\n\x14ListOutgoingWebhooks\x12&.scheduler.ListOutgoingWebhooksRequest\x1a\'.scheduler.ListOutgoingWebhooksResponse\"\x00\x12O\n\x0e\x44\x65leteWebhooks\x12(.scheduler.DeleteOutgoingWebhooksRequest\x1a\x11.greenlight.Empty\"\x00\x12p\n\x1bRotateOutgoingWebhookSecret\x12-.scheduler.RotateOutgoingWebhookSecretRequest\x1a .scheduler.WebhookSecretResponse\"\x00\x12Q\n\x14SignerRequestsStream\x12\x19.scheduler.SignerResponse\x1a\x18.scheduler.SignerRequest\"\x00(\x01\x30\x01\x32Q\n\x05\x44\x65\x62ug\x12H\n\x15ReportSignerRejection\x12\x1a.scheduler.SignerRejection\x1a\x11.greenlight.Empty\"\x00\x32\xf8\x01\n\x07Pairing\x12K\n\nPairDevice\x12\x1c.scheduler.PairDeviceRequest\x1a\x1d.scheduler.PairDeviceResponse\"\x00\x12W\n\x0eGetPairingData\x12 .scheduler.GetPairingDataRequest\x1a!.scheduler.GetPairingDataResponse\"\x00\x12G\n\x0e\x41pprovePairing\x12 .scheduler.ApprovePairingRequest\x1a\x11.greenlight.Empty\"\x00\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18glclient/scheduler.proto\x12\tscheduler\x1a\x19glclient/greenlight.proto\"9\n\x19\x41\x64\x64OutgoingWebhookRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x0b\n\x03uri\x18\x02 \x01(\t\"8\n\x1a\x41\x64\x64OutgoingWebhookResponse\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0e\n\x06secret\x18\x02 \x01(\t\".\n\x1bListOutgoingWebhooksRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\"\"\n\x07Webhook\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0b\n\x03uri\x18\x02 \x01(\t\"M\n\x1cListOutgoingWebhooksResponse\x12-\n\x11outgoing_webhooks\x18\x01 \x03(\x0b\x32\x12.scheduler.Webhook\"=\n\x1d\x44\x65leteOutgoingWebhooksRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x0b\n\x03ids\x18\x02 \x03(\x03\"I\n\"RotateOutgoingWebhookSecretRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x12\n\nwebhook_id\x18\x02 \x01(\x03\"\'\n\x15WebhookSecretResponse\x12\x0e\n\x06secret\x18\x01 \x01(\t\"M\n\x10\x43hallengeRequest\x12(\n\x05scope\x18\x01 \x01(\x0e\x32\x19.scheduler.ChallengeScope\x12\x0f\n\x07node_id\x18\x02 \x01(\x0c\"&\n\x11\x43hallengeResponse\x12\x11\n\tchallenge\x18\x01 \x01(\x0c\"\xea\x01\n\x13RegistrationRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x11\n\tbip32_key\x18\x02 \x01(\x0c\x12\x0f\n\x07network\x18\x04 \x01(\t\x12\x11\n\tchallenge\x18\x05 \x01(\x0c\x12\x11\n\tsignature\x18\x06 \x01(\x0c\x12\x14\n\x0csigner_proto\x18\x07 \x01(\t\x12\x10\n\x08init_msg\x18\x08 \x01(\x0c\x12\x0b\n\x03\x63sr\x18\t \x01(\x0c\x12\x13\n\x0binvite_code\x18\n \x01(\t\x12.\n\x0bstartupmsgs\x18\x03 \x03(\x0b\x32\x19.scheduler.StartupMessage\"\\\n\x14RegistrationResponse\x12\x13\n\x0b\x64\x65vice_cert\x18\x01 \x01(\t\x12\x12\n\ndevice_key\x18\x02 \x01(\t\x12\x0c\n\x04rune\x18\x03 \x01(\t\x12\r\n\x05\x63reds\x18\x04 \x01(\x0c\"\"\n\x0fScheduleRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\"0\n\x0fNodeInfoRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x0c\n\x04wait\x18\x02 \x01(\x08\"I\n\x10NodeInfoResponse\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x10\n\x08grpc_uri\x18\x02 \x01(\t\x12\x12\n\nsession_id\x18\x03 \x01(\x04\"U\n\x0fRecoveryRequest\x12\x11\n\tchallenge\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07node_id\x18\x03 \x01(\x0c\x12\x0b\n\x03\x63sr\x18\t \x01(\x0c\"X\n\x10RecoveryResponse\x12\x13\n\x0b\x64\x65vice_cert\x18\x01 \x01(\t\x12\x12\n\ndevice_key\x18\x02 \x01(\t\x12\x0c\n\x04rune\x18\x03 \x01(\t\x12\r\n\x05\x63reds\x18\x04 \x01(\x0c\"m\n\x0eUpgradeRequest\x12\x16\n\x0esigner_version\x18\x01 \x01(\t\x12\x13\n\x07initmsg\x18\x02 \x01(\x0c\x42\x02\x18\x01\x12.\n\x0bstartupmsgs\x18\x03 \x03(\x0b\x32\x19.scheduler.StartupMessage\"&\n\x0fUpgradeResponse\x12\x13\n\x0bold_version\x18\x01 \x01(\t\"3\n\x0eStartupMessage\x12\x0f\n\x07request\x18\x01 \x01(\x0c\x12\x10\n\x08response\x18\x02 \x01(\x0c\"\x18\n\x16ListInviteCodesRequest\"J\n\x17ListInviteCodesResponse\x12/\n\x10invite_code_list\x18\x01 \x03(\x0b\x32\x15.scheduler.InviteCode\"/\n\nInviteCode\x12\x0c\n\x04\x63ode\x18\x01 \x01(\t\x12\x13\n\x0bis_redeemed\x18\x02 \x01(\x08\"\x13\n\x11\x45xportNodeRequest\"!\n\x12\x45xportNodeResponse\x12\x0b\n\x03url\x18\x01 \x01(\t\"m\n\x0fSignerRejection\x12\x0b\n\x03msg\x18\x01 \x01(\t\x12\'\n\x07request\x18\x02 \x01(\x0b\x32\x16.greenlight.HsmRequest\x12\x13\n\x0bgit_version\x18\x03 \x01(\t\x12\x0f\n\x07node_id\x18\x04 \x01(\x0c\"s\n\x11PairDeviceRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x0b\n\x03\x63sr\x18\x02 \x01(\x0c\x12\x13\n\x0b\x64\x65vice_name\x18\x03 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x04 \x01(\t\x12\x14\n\x0crestrictions\x18\x05 \x01(\t\"m\n\x12PairDeviceResponse\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_cert\x18\x02 \x01(\t\x12\x12\n\ndevice_key\x18\x03 \x01(\t\x12\x0c\n\x04rune\x18\x04 \x01(\t\x12\r\n\x05\x63reds\x18\x05 \x01(\x0c\"*\n\x15GetPairingDataRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\t\"x\n\x16GetPairingDataResponse\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x0b\n\x03\x63sr\x18\x02 \x01(\x0c\x12\x13\n\x0b\x64\x65vice_name\x18\x03 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x04 \x01(\t\x12\x14\n\x0crestrictions\x18\x05 \x01(\t\"\x93\x01\n\x15\x41pprovePairingRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x11\n\ttimestamp\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x65vice_name\x18\x03 \x01(\t\x12\x14\n\x0crestrictions\x18\x04 \x01(\t\x12\x0b\n\x03sig\x18\x05 \x01(\x0c\x12\x0e\n\x06pubkey\x18\x06 \x01(\x0c\x12\x0c\n\x04rune\x18\x07 \x01(\t\"J\n\x16\x41pprovePairingResponse\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x0c\x12\x0c\n\x04rune\x18\x03 \x01(\t\"k\n\rSignerRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\r\x12;\n\x0f\x61pprove_pairing\x18\x02 \x01(\x0b\x32 .scheduler.ApprovePairingRequestH\x00\x42\t\n\x07request\"\x92\x01\n\x0eSignerResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\r\x12\"\n\x05\x65mpty\x18\x02 \x01(\x0b\x32\x11.greenlight.EmptyH\x00\x12<\n\x0f\x61pprove_pairing\x18\x03 \x01(\x0b\x32!.scheduler.ApprovePairingResponseH\x00\x42\n\n\x08response\"\x11\n\x0fListLspsRequest\"\x84\x01\n\x10ListLspsResponse\x12\x33\n\x04lsps\x18\x01 \x03(\x0b\x32%.scheduler.ListLspsResponse.LspsEntry\x1a;\n\tLspsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1d\n\x05value\x18\x02 \x01(\x0b\x32\x0e.scheduler.Lsp:\x02\x38\x01\"\x18\n\x03Lsp\x12\x11\n\tprotocols\x18\x01 \x03(\x05\"\'\n\x11GetLspInfoRequest\x12\x12\n\npublic_key\x18\x01 \x01(\t\"T\n\x12GetLspInfoResponse\x12\x12\n\npublic_key\x18\x01 \x01(\t\x12*\n\tprotocols\x18\x02 \x01(\x0b\x32\x17.scheduler.LspProtocols\"X\n\x0cLspProtocols\x12#\n\x05lsps1\x18\x01 \x01(\x0b\x32\x14.scheduler.Lsps1Info\x12#\n\x05lsps2\x18\x02 \x01(\x0b\x32\x14.scheduler.Lsps2Info\"\x89\x03\n\tLsps1Info\x12*\n\"min_required_channel_confirmations\x18\x01 \x01(\r\x12*\n\"min_funding_confirms_within_blocks\x18\x02 \x01(\r\x12%\n\x1dsupports_zero_channel_reserve\x18\x03 \x01(\x08\x12!\n\x19max_channel_expiry_blocks\x18\x04 \x01(\r\x12&\n\x1emin_initial_client_balance_sat\x18\x05 \x01(\x04\x12&\n\x1emax_initial_client_balance_sat\x18\x06 \x01(\x04\x12#\n\x1bmin_initial_lsp_balance_sat\x18\x07 \x01(\x04\x12#\n\x1bmax_initial_lsp_balance_sat\x18\x08 \x01(\x04\x12\x1f\n\x17min_channel_balance_sat\x18\t \x01(\x04\x12\x1f\n\x17max_channel_balance_sat\x18\n \x01(\x04\"N\n\tLsps2Info\x12\x41\n\x17opening_fee_params_menu\x18\x01 \x03(\x0b\x32 .scheduler.Lsps2OpeningFeeParams\"\xdf\x01\n\x15Lsps2OpeningFeeParams\x12\x14\n\x0cmin_fee_msat\x18\x01 \x01(\x04\x12\x14\n\x0cproportional\x18\x02 \x01(\r\x12\x13\n\x0bvalid_until\x18\x03 \x01(\t\x12\x14\n\x0cmin_lifetime\x18\x04 \x01(\r\x12 \n\x18max_client_to_self_delay\x18\x05 \x01(\r\x12\x1d\n\x15min_payment_size_msat\x18\x06 \x01(\x04\x12\x1d\n\x15max_payment_size_msat\x18\x07 \x01(\x04\x12\x0f\n\x07promise\x18\x08 \x01(\t*+\n\x0e\x43hallengeScope\x12\x0c\n\x08REGISTER\x10\x00\x12\x0b\n\x07RECOVER\x10\x01\x32\xd6\x08\n\tScheduler\x12M\n\x08Register\x12\x1e.scheduler.RegistrationRequest\x1a\x1f.scheduler.RegistrationResponse\"\x00\x12\x44\n\x07Recover\x12\x1a.scheduler.RecoveryRequest\x1a\x1b.scheduler.RecoveryResponse\"\x00\x12K\n\x0cGetChallenge\x12\x1b.scheduler.ChallengeRequest\x1a\x1c.scheduler.ChallengeResponse\"\x00\x12\x45\n\x08Schedule\x12\x1a.scheduler.ScheduleRequest\x1a\x1b.scheduler.NodeInfoResponse\"\x00\x12H\n\x0bGetNodeInfo\x12\x1a.scheduler.NodeInfoRequest\x1a\x1b.scheduler.NodeInfoResponse\"\x00\x12G\n\x0cMaybeUpgrade\x12\x19.scheduler.UpgradeRequest\x1a\x1a.scheduler.UpgradeResponse\"\x00\x12Z\n\x0fListInviteCodes\x12!.scheduler.ListInviteCodesRequest\x1a\".scheduler.ListInviteCodesResponse\"\x00\x12K\n\nExportNode\x12\x1c.scheduler.ExportNodeRequest\x1a\x1d.scheduler.ExportNodeResponse\"\x00\x12\x63\n\x12\x41\x64\x64OutgoingWebhook\x12$.scheduler.AddOutgoingWebhookRequest\x1a%.scheduler.AddOutgoingWebhookResponse\"\x00\x12i\n\x14ListOutgoingWebhooks\x12&.scheduler.ListOutgoingWebhooksRequest\x1a\'.scheduler.ListOutgoingWebhooksResponse\"\x00\x12O\n\x0e\x44\x65leteWebhooks\x12(.scheduler.DeleteOutgoingWebhooksRequest\x1a\x11.greenlight.Empty\"\x00\x12p\n\x1bRotateOutgoingWebhookSecret\x12-.scheduler.RotateOutgoingWebhookSecretRequest\x1a .scheduler.WebhookSecretResponse\"\x00\x12Q\n\x14SignerRequestsStream\x12\x19.scheduler.SignerResponse\x1a\x18.scheduler.SignerRequest\"\x00(\x01\x30\x01\x32Q\n\x05\x44\x65\x62ug\x12H\n\x15ReportSignerRejection\x12\x1a.scheduler.SignerRejection\x1a\x11.greenlight.Empty\"\x00\x32\xf8\x01\n\x07Pairing\x12K\n\nPairDevice\x12\x1c.scheduler.PairDeviceRequest\x1a\x1d.scheduler.PairDeviceResponse\"\x00\x12W\n\x0eGetPairingData\x12 .scheduler.GetPairingDataRequest\x1a!.scheduler.GetPairingDataResponse\"\x00\x12G\n\x0e\x41pprovePairing\x12 .scheduler.ApprovePairingRequest\x1a\x11.greenlight.Empty\"\x00\x32\x9a\x01\n\x04Lsps\x12\x45\n\x08ListLsps\x12\x1a.scheduler.ListLspsRequest\x1a\x1b.scheduler.ListLspsResponse\"\x00\x12K\n\nGetLspInfo\x12\x1c.scheduler.GetLspInfoRequest\x1a\x1d.scheduler.GetLspInfoResponse\"\x00\x62\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -24,8 +34,10 @@ DESCRIPTOR._loaded_options = None _globals['_UPGRADEREQUEST'].fields_by_name['initmsg']._loaded_options = None _globals['_UPGRADEREQUEST'].fields_by_name['initmsg']._serialized_options = b'\030\001' - _globals['_CHALLENGESCOPE']._serialized_start=2713 - _globals['_CHALLENGESCOPE']._serialized_end=2756 + _globals['_LISTLSPSRESPONSE_LSPSENTRY']._loaded_options = None + _globals['_LISTLSPSRESPONSE_LSPSENTRY']._serialized_options = b'8\001' + _globals['_CHALLENGESCOPE']._serialized_start=3812 + _globals['_CHALLENGESCOPE']._serialized_end=3855 _globals['_ADDOUTGOINGWEBHOOKREQUEST']._serialized_start=66 _globals['_ADDOUTGOINGWEBHOOKREQUEST']._serialized_end=123 _globals['_ADDOUTGOINGWEBHOOKRESPONSE']._serialized_start=125 @@ -94,10 +106,32 @@ _globals['_SIGNERREQUEST']._serialized_end=2562 _globals['_SIGNERRESPONSE']._serialized_start=2565 _globals['_SIGNERRESPONSE']._serialized_end=2711 - _globals['_SCHEDULER']._serialized_start=2759 - _globals['_SCHEDULER']._serialized_end=3869 - _globals['_DEBUG']._serialized_start=3871 - _globals['_DEBUG']._serialized_end=3952 - _globals['_PAIRING']._serialized_start=3955 - _globals['_PAIRING']._serialized_end=4203 + _globals['_LISTLSPSREQUEST']._serialized_start=2713 + _globals['_LISTLSPSREQUEST']._serialized_end=2730 + _globals['_LISTLSPSRESPONSE']._serialized_start=2733 + _globals['_LISTLSPSRESPONSE']._serialized_end=2865 + _globals['_LISTLSPSRESPONSE_LSPSENTRY']._serialized_start=2806 + _globals['_LISTLSPSRESPONSE_LSPSENTRY']._serialized_end=2865 + _globals['_LSP']._serialized_start=2867 + _globals['_LSP']._serialized_end=2891 + _globals['_GETLSPINFOREQUEST']._serialized_start=2893 + _globals['_GETLSPINFOREQUEST']._serialized_end=2932 + _globals['_GETLSPINFORESPONSE']._serialized_start=2934 + _globals['_GETLSPINFORESPONSE']._serialized_end=3018 + _globals['_LSPPROTOCOLS']._serialized_start=3020 + _globals['_LSPPROTOCOLS']._serialized_end=3108 + _globals['_LSPS1INFO']._serialized_start=3111 + _globals['_LSPS1INFO']._serialized_end=3504 + _globals['_LSPS2INFO']._serialized_start=3506 + _globals['_LSPS2INFO']._serialized_end=3584 + _globals['_LSPS2OPENINGFEEPARAMS']._serialized_start=3587 + _globals['_LSPS2OPENINGFEEPARAMS']._serialized_end=3810 + _globals['_SCHEDULER']._serialized_start=3858 + _globals['_SCHEDULER']._serialized_end=4968 + _globals['_DEBUG']._serialized_start=4970 + _globals['_DEBUG']._serialized_end=5051 + _globals['_PAIRING']._serialized_start=5054 + _globals['_PAIRING']._serialized_end=5302 + _globals['_LSPS']._serialized_start=5305 + _globals['_LSPS']._serialized_end=5459 # @@protoc_insertion_point(module_scope) diff --git a/libs/gl-client-py/glclient/scheduler_pb2.pyi b/libs/gl-client-py/glclient/scheduler_pb2.pyi index aac68c5d0..a6b114fca 100644 --- a/libs/gl-client-py/glclient/scheduler_pb2.pyi +++ b/libs/gl-client-py/glclient/scheduler_pb2.pyi @@ -309,8 +309,8 @@ class RegistrationResponse(google.protobuf.message.Message): client side and appends the rune to the registratrion response. """ creds: builtins.bytes - """Creds contains a serialized version of the device_cert, the device_key - and the rune that are used to authenticate a device at the backend, + """Creds contains a serialized version of the device_cert, the device_key + and the rune that are used to authenticate a device at the backend, and to authorize a request at the signer. """ def __init__( @@ -436,8 +436,8 @@ class RecoveryResponse(google.protobuf.message.Message): client side and appends the rune to the registratrion response. """ creds: builtins.bytes - """Creds contains a serialized version of the device_cert, the device_key - and the rune that are used to authenticate a device at the backend, + """Creds contains a serialized version of the device_cert, the device_key + and the rune that are used to authenticate a device at the backend, and to authorize a request at the signer. """ def __init__( @@ -648,12 +648,12 @@ class PairDeviceRequest(google.protobuf.message.Message): subjects CN field: CN=/users//. """ description: builtins.str - """A human readable description of the device, this can be a - purpose or something similar. Can be used to display to the + """A human readable description of the device, this can be a + purpose or something similar. Can be used to display to the user on the old device. """ restrictions: builtins.str - """A set of restrictions that the new devices requests for the + """A set of restrictions that the new devices requests for the rune. This might in the future get upgraded for easier naming. """ def __init__( @@ -696,8 +696,8 @@ class PairDeviceResponse(google.protobuf.message.Message): the device pairs to. """ creds: builtins.bytes - """Creds contains a serialized version of the device certificate, the device - key and the rune that are used to authenticate a device at the backend, + """Creds contains a serialized version of the device certificate, the device + key and the rune that are used to authenticate a device at the backend, and to authorize a request at the signer. """ def __init__( @@ -749,12 +749,12 @@ class GetPairingDataResponse(google.protobuf.message.Message): subjects CN field: CN=/users//. """ description: builtins.str - """A human readable description of the device, this can be a - purpose or something similar. Can be used to display to the + """A human readable description of the device, this can be a + purpose or something similar. Can be used to display to the user on the old device. """ restrictions: builtins.str - """A set of restrictions that the new devices requests for the + """A set of restrictions that the new devices requests for the rune. This might in the future get upgraded for easier naming. """ def __init__( @@ -796,7 +796,7 @@ class ApprovePairingRequest(google.protobuf.message.Message): sig: builtins.bytes """The signature of the above to ensure data integrity.""" pubkey: builtins.bytes - """The public key corresponding to the private key that was used + """The public key corresponding to the private key that was used to sign the request and that is part of the rune; """ rune: builtins.str @@ -884,3 +884,279 @@ class SignerResponse(google.protobuf.message.Message): def WhichOneof(self, oneof_group: typing.Literal["response", b"response"]) -> typing.Literal["empty", "approve_pairing"] | None: ... global___SignerResponse = SignerResponse + +@typing.final +class ListLspsRequest(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + def __init__( + self, + ) -> None: ... + +global___ListLspsRequest = ListLspsRequest + +@typing.final +class ListLspsResponse(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + @typing.final + class LspsEntry(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + KEY_FIELD_NUMBER: builtins.int + VALUE_FIELD_NUMBER: builtins.int + key: builtins.str + @property + def value(self) -> global___Lsp: ... + def __init__( + self, + *, + key: builtins.str = ..., + value: global___Lsp | None = ..., + ) -> None: ... + def HasField(self, field_name: typing.Literal["value", b"value"]) -> builtins.bool: ... + def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ... + + LSPS_FIELD_NUMBER: builtins.int + @property + def lsps(self) -> google.protobuf.internal.containers.MessageMap[builtins.str, global___Lsp]: + """A map that maps the public keys of known LSPs to the information we have + about them. + """ + + def __init__( + self, + *, + lsps: collections.abc.Mapping[builtins.str, global___Lsp] | None = ..., + ) -> None: ... + def ClearField(self, field_name: typing.Literal["lsps", b"lsps"]) -> None: ... + +global___ListLspsResponse = ListLspsResponse + +@typing.final +class Lsp(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + PROTOCOLS_FIELD_NUMBER: builtins.int + @property + def protocols(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: + """An object that contains the supported protocols with additional + information about the LSPs conditions. + """ + + def __init__( + self, + *, + protocols: collections.abc.Iterable[builtins.int] | None = ..., + ) -> None: ... + def ClearField(self, field_name: typing.Literal["protocols", b"protocols"]) -> None: ... + +global___Lsp = Lsp + +@typing.final +class GetLspInfoRequest(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + PUBLIC_KEY_FIELD_NUMBER: builtins.int + public_key: builtins.str + """The public key of the LSP of interest.""" + def __init__( + self, + *, + public_key: builtins.str = ..., + ) -> None: ... + def ClearField(self, field_name: typing.Literal["public_key", b"public_key"]) -> None: ... + +global___GetLspInfoRequest = GetLspInfoRequest + +@typing.final +class GetLspInfoResponse(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + PUBLIC_KEY_FIELD_NUMBER: builtins.int + PROTOCOLS_FIELD_NUMBER: builtins.int + public_key: builtins.str + """The public key of the LSP.""" + @property + def protocols(self) -> global___LspProtocols: + """Infos about the supported protocols.""" + + def __init__( + self, + *, + public_key: builtins.str = ..., + protocols: global___LspProtocols | None = ..., + ) -> None: ... + def HasField(self, field_name: typing.Literal["protocols", b"protocols"]) -> builtins.bool: ... + def ClearField(self, field_name: typing.Literal["protocols", b"protocols", "public_key", b"public_key"]) -> None: ... + +global___GetLspInfoResponse = GetLspInfoResponse + +@typing.final +class LspProtocols(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + LSPS1_FIELD_NUMBER: builtins.int + LSPS2_FIELD_NUMBER: builtins.int + @property + def lsps1(self) -> global___Lsps1Info: + """Optional information relating to the lsps1 protocol. Is only present if + the LSP supports the protocol. + """ + + @property + def lsps2(self) -> global___Lsps2Info: + """Optional information relating to the lsps2 protocol. Is only present if + the LSP supports the protocol. + """ + + def __init__( + self, + *, + lsps1: global___Lsps1Info | None = ..., + lsps2: global___Lsps2Info | None = ..., + ) -> None: ... + def HasField(self, field_name: typing.Literal["lsps1", b"lsps1", "lsps2", b"lsps2"]) -> builtins.bool: ... + def ClearField(self, field_name: typing.Literal["lsps1", b"lsps1", "lsps2", b"lsps2"]) -> None: ... + +global___LspProtocols = LspProtocols + +@typing.final +class Lsps1Info(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + MIN_REQUIRED_CHANNEL_CONFIRMATIONS_FIELD_NUMBER: builtins.int + MIN_FUNDING_CONFIRMS_WITHIN_BLOCKS_FIELD_NUMBER: builtins.int + SUPPORTS_ZERO_CHANNEL_RESERVE_FIELD_NUMBER: builtins.int + MAX_CHANNEL_EXPIRY_BLOCKS_FIELD_NUMBER: builtins.int + MIN_INITIAL_CLIENT_BALANCE_SAT_FIELD_NUMBER: builtins.int + MAX_INITIAL_CLIENT_BALANCE_SAT_FIELD_NUMBER: builtins.int + MIN_INITIAL_LSP_BALANCE_SAT_FIELD_NUMBER: builtins.int + MAX_INITIAL_LSP_BALANCE_SAT_FIELD_NUMBER: builtins.int + MIN_CHANNEL_BALANCE_SAT_FIELD_NUMBER: builtins.int + MAX_CHANNEL_BALANCE_SAT_FIELD_NUMBER: builtins.int + min_required_channel_confirmations: builtins.int + """The smallest number of confirmations needed for the LSP to accept a + channel as confirmed and sends `channel_ready` (see bolt02). + """ + min_funding_confirms_within_blocks: builtins.int + """The smallest number of blocks in which the LSP can confirm the funding + transaction. + """ + supports_zero_channel_reserve: builtins.bool + """Is true if the LSP supports zeroreserve on the channel.""" + max_channel_expiry_blocks: builtins.int + """Is the maximum number of blocks a channel can be leased for.""" + min_initial_client_balance_sat: builtins.int + """The minimum amount in satoshis that a client must request.""" + max_initial_client_balance_sat: builtins.int + """The maximum amount in satoshis that a client must request.""" + min_initial_lsp_balance_sat: builtins.int + """The minimum amount in satoshis that the LSP will provide to the channel.""" + max_initial_lsp_balance_sat: builtins.int + """The maximum amount in satoshis that the LSP will provide to the channel.""" + min_channel_balance_sat: builtins.int + """The minimum channel size the LSP accepts.""" + max_channel_balance_sat: builtins.int + """The maximum channel size the LSP accepts.""" + def __init__( + self, + *, + min_required_channel_confirmations: builtins.int = ..., + min_funding_confirms_within_blocks: builtins.int = ..., + supports_zero_channel_reserve: builtins.bool = ..., + max_channel_expiry_blocks: builtins.int = ..., + min_initial_client_balance_sat: builtins.int = ..., + max_initial_client_balance_sat: builtins.int = ..., + min_initial_lsp_balance_sat: builtins.int = ..., + max_initial_lsp_balance_sat: builtins.int = ..., + min_channel_balance_sat: builtins.int = ..., + max_channel_balance_sat: builtins.int = ..., + ) -> None: ... + def ClearField(self, field_name: typing.Literal["max_channel_balance_sat", b"max_channel_balance_sat", "max_channel_expiry_blocks", b"max_channel_expiry_blocks", "max_initial_client_balance_sat", b"max_initial_client_balance_sat", "max_initial_lsp_balance_sat", b"max_initial_lsp_balance_sat", "min_channel_balance_sat", b"min_channel_balance_sat", "min_funding_confirms_within_blocks", b"min_funding_confirms_within_blocks", "min_initial_client_balance_sat", b"min_initial_client_balance_sat", "min_initial_lsp_balance_sat", b"min_initial_lsp_balance_sat", "min_required_channel_confirmations", b"min_required_channel_confirmations", "supports_zero_channel_reserve", b"supports_zero_channel_reserve"]) -> None: ... + +global___Lsps1Info = Lsps1Info + +@typing.final +class Lsps2Info(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + OPENING_FEE_PARAMS_MENU_FIELD_NUMBER: builtins.int + @property + def opening_fee_params_menu(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Lsps2OpeningFeeParams]: + """The LSP may return an empty array in which case, the client currently + cannot use JIT channels with this LSP. + """ + + def __init__( + self, + *, + opening_fee_params_menu: collections.abc.Iterable[global___Lsps2OpeningFeeParams] | None = ..., + ) -> None: ... + def ClearField(self, field_name: typing.Literal["opening_fee_params_menu", b"opening_fee_params_menu"]) -> None: ... + +global___Lsps2Info = Lsps2Info + +@typing.final +class Lsps2OpeningFeeParams(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + MIN_FEE_MSAT_FIELD_NUMBER: builtins.int + PROPORTIONAL_FIELD_NUMBER: builtins.int + VALID_UNTIL_FIELD_NUMBER: builtins.int + MIN_LIFETIME_FIELD_NUMBER: builtins.int + MAX_CLIENT_TO_SELF_DELAY_FIELD_NUMBER: builtins.int + MIN_PAYMENT_SIZE_MSAT_FIELD_NUMBER: builtins.int + MAX_PAYMENT_SIZE_MSAT_FIELD_NUMBER: builtins.int + PROMISE_FIELD_NUMBER: builtins.int + min_fee_msat: builtins.int + """The minimum fee to be paid by the client to the LSP.""" + proportional: builtins.int + """A parts-per-million number that describes how many millisatoshis to charge + for every 1 million millisatoshis of payment size for the first payment. If + the proportional fee is less than than `min_fee_msat`, then `min_fee_msat` + is paid instead of the proportional times payment size divided by 1 + million. + """ + valid_until: builtins.str + """Is a datetime (as an ISO8601 string) up to which this specific + `opening_fee_params` is valid, and also serves as the timeout for the JIT + Channel flow, if this particular object is selected. + """ + min_lifetime: builtins.int + """Is a number of blocks that the LSP promises it will keep the channel alive + without closing, after confirmation. + """ + max_client_to_self_delay: builtins.int + """Is a maximum number of blocks that the client is allowed to set its + `to_self_pay_delay` parameter. + """ + min_payment_size_msat: builtins.int + """Is the minimum payment size, inclusive. Is the amount in millisatoshis that + the payer is guaranteed to be able to send to the client, not including the + forwarding fees of nodes along the way. + """ + max_payment_size_msat: builtins.int + """Is the maximum payment size, inclusive. Is the amount in millisatoshis that + the payer is guaranteed to be able to send to the client, not including the + forwarding fees of nodes along the way. + """ + promise: builtins.str + """An arbitrary LSP-genereated string that proves to the LSP that it has + promised a specific `opening_fee_params`. + """ + def __init__( + self, + *, + min_fee_msat: builtins.int = ..., + proportional: builtins.int = ..., + valid_until: builtins.str = ..., + min_lifetime: builtins.int = ..., + max_client_to_self_delay: builtins.int = ..., + min_payment_size_msat: builtins.int = ..., + max_payment_size_msat: builtins.int = ..., + promise: builtins.str = ..., + ) -> None: ... + def ClearField(self, field_name: typing.Literal["max_client_to_self_delay", b"max_client_to_self_delay", "max_payment_size_msat", b"max_payment_size_msat", "min_fee_msat", b"min_fee_msat", "min_lifetime", b"min_lifetime", "min_payment_size_msat", b"min_payment_size_msat", "promise", b"promise", "proportional", b"proportional", "valid_until", b"valid_until"]) -> None: ... + +global___Lsps2OpeningFeeParams = Lsps2OpeningFeeParams diff --git a/libs/gl-client-py/glclient/scheduler_pb2_grpc.py b/libs/gl-client-py/glclient/scheduler_pb2_grpc.py index 7f57a4540..9fdd9ec91 100644 --- a/libs/gl-client-py/glclient/scheduler_pb2_grpc.py +++ b/libs/gl-client-py/glclient/scheduler_pb2_grpc.py @@ -6,10 +6,8 @@ from glclient import greenlight_pb2 as glclient_dot_greenlight__pb2 from glclient import scheduler_pb2 as glclient_dot_scheduler__pb2 -GRPC_GENERATED_VERSION = '1.64.1' +GRPC_GENERATED_VERSION = '1.70.0' GRPC_VERSION = grpc.__version__ -EXPECTED_ERROR_RELEASE = '1.65.0' -SCHEDULED_RELEASE_DATE = 'June 25, 2024' _version_not_supported = False try: @@ -19,15 +17,12 @@ _version_not_supported = True if _version_not_supported: - warnings.warn( + raise RuntimeError( f'The grpc package installed is at version {GRPC_VERSION},' + f' but the generated code in glclient/scheduler_pb2_grpc.py depends on' + f' grpcio>={GRPC_GENERATED_VERSION}.' + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' - + f' This warning will become an error in {EXPECTED_ERROR_RELEASE},' - + f' scheduled for release on {SCHEDULED_RELEASE_DATE}.', - RuntimeWarning ) @@ -345,7 +340,7 @@ def RotateOutgoingWebhookSecret(self, request, context): raise NotImplementedError('Method not implemented!') def SignerRequestsStream(self, request_iterator, context): - """Attaches a Signer via a bidirectional stream to the scheduler. + """Attaches a Signer via a bidirectional stream to the scheduler. This is a communication channel between greenlight and the signing device that is used for requests that are not part of the node api. @@ -1070,3 +1065,126 @@ def ApprovePairing(request, timeout, metadata, _registered_method=True) + + +class LspsStub(object): + """A service to explore lsps compatible LSP's + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.ListLsps = channel.unary_unary( + '/scheduler.Lsps/ListLsps', + request_serializer=glclient_dot_scheduler__pb2.ListLspsRequest.SerializeToString, + response_deserializer=glclient_dot_scheduler__pb2.ListLspsResponse.FromString, + _registered_method=True) + self.GetLspInfo = channel.unary_unary( + '/scheduler.Lsps/GetLspInfo', + request_serializer=glclient_dot_scheduler__pb2.GetLspInfoRequest.SerializeToString, + response_deserializer=glclient_dot_scheduler__pb2.GetLspInfoResponse.FromString, + _registered_method=True) + + +class LspsServicer(object): + """A service to explore lsps compatible LSP's + """ + + def ListLsps(self, request, context): + """Returns a structured list of all available Lsps. An Lsp is a + Lightning Service Provider, providing an API as described in blips + 50, 51 and 52 https://github.com/lightning/blips. From cln: + `lsps-listlsps`. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetLspInfo(self, request, context): + """Returns detailed information about a LSP. From cln: `lsps-lspinfo`. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_LspsServicer_to_server(servicer, server): + rpc_method_handlers = { + 'ListLsps': grpc.unary_unary_rpc_method_handler( + servicer.ListLsps, + request_deserializer=glclient_dot_scheduler__pb2.ListLspsRequest.FromString, + response_serializer=glclient_dot_scheduler__pb2.ListLspsResponse.SerializeToString, + ), + 'GetLspInfo': grpc.unary_unary_rpc_method_handler( + servicer.GetLspInfo, + request_deserializer=glclient_dot_scheduler__pb2.GetLspInfoRequest.FromString, + response_serializer=glclient_dot_scheduler__pb2.GetLspInfoResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'scheduler.Lsps', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('scheduler.Lsps', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class Lsps(object): + """A service to explore lsps compatible LSP's + """ + + @staticmethod + def ListLsps(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/scheduler.Lsps/ListLsps', + glclient_dot_scheduler__pb2.ListLspsRequest.SerializeToString, + glclient_dot_scheduler__pb2.ListLspsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetLspInfo(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/scheduler.Lsps/GetLspInfo', + glclient_dot_scheduler__pb2.GetLspInfoRequest.SerializeToString, + glclient_dot_scheduler__pb2.GetLspInfoResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/libs/gl-client-py/glclient/scheduler_pb2_grpc.pyi b/libs/gl-client-py/glclient/scheduler_pb2_grpc.pyi index 1e19a1758..40a89b66a 100644 --- a/libs/gl-client-py/glclient/scheduler_pb2_grpc.pyi +++ b/libs/gl-client-py/glclient/scheduler_pb2_grpc.pyi @@ -222,7 +222,7 @@ class SchedulerStub: glclient.scheduler_pb2.SignerResponse, glclient.scheduler_pb2.SignerRequest, ] - """Attaches a Signer via a bidirectional stream to the scheduler. + """Attaches a Signer via a bidirectional stream to the scheduler. This is a communication channel between greenlight and the signing device that is used for requests that are not part of the node api. @@ -433,7 +433,7 @@ class SchedulerAsyncStub: glclient.scheduler_pb2.SignerResponse, glclient.scheduler_pb2.SignerRequest, ] - """Attaches a Signer via a bidirectional stream to the scheduler. + """Attaches a Signer via a bidirectional stream to the scheduler. This is a communication channel between greenlight and the signing device that is used for requests that are not part of the node api. @@ -670,7 +670,7 @@ class SchedulerServicer(metaclass=abc.ABCMeta): request_iterator: _MaybeAsyncIterator[glclient.scheduler_pb2.SignerResponse], context: _ServicerContext, ) -> typing.Union[collections.abc.Iterator[glclient.scheduler_pb2.SignerRequest], collections.abc.AsyncIterator[glclient.scheduler_pb2.SignerRequest]]: - """Attaches a Signer via a bidirectional stream to the scheduler. + """Attaches a Signer via a bidirectional stream to the scheduler. This is a communication channel between greenlight and the signing device that is used for requests that are not part of the node api. @@ -831,3 +831,67 @@ class PairingServicer(metaclass=abc.ABCMeta): """ def add_PairingServicer_to_server(servicer: PairingServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ... + +class LspsStub: + """A service to explore lsps compatible LSP's""" + + def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ... + ListLsps: grpc.UnaryUnaryMultiCallable[ + glclient.scheduler_pb2.ListLspsRequest, + glclient.scheduler_pb2.ListLspsResponse, + ] + """Returns a structured list of all available Lsps. An Lsp is a + Lightning Service Provider, providing an API as described in blips + 50, 51 and 52 https://github.com/lightning/blips. From cln: + `lsps-listlsps`. + """ + + GetLspInfo: grpc.UnaryUnaryMultiCallable[ + glclient.scheduler_pb2.GetLspInfoRequest, + glclient.scheduler_pb2.GetLspInfoResponse, + ] + """Returns detailed information about a LSP. From cln: `lsps-lspinfo`.""" + +class LspsAsyncStub: + """A service to explore lsps compatible LSP's""" + + ListLsps: grpc.aio.UnaryUnaryMultiCallable[ + glclient.scheduler_pb2.ListLspsRequest, + glclient.scheduler_pb2.ListLspsResponse, + ] + """Returns a structured list of all available Lsps. An Lsp is a + Lightning Service Provider, providing an API as described in blips + 50, 51 and 52 https://github.com/lightning/blips. From cln: + `lsps-listlsps`. + """ + + GetLspInfo: grpc.aio.UnaryUnaryMultiCallable[ + glclient.scheduler_pb2.GetLspInfoRequest, + glclient.scheduler_pb2.GetLspInfoResponse, + ] + """Returns detailed information about a LSP. From cln: `lsps-lspinfo`.""" + +class LspsServicer(metaclass=abc.ABCMeta): + """A service to explore lsps compatible LSP's""" + + @abc.abstractmethod + def ListLsps( + self, + request: glclient.scheduler_pb2.ListLspsRequest, + context: _ServicerContext, + ) -> typing.Union[glclient.scheduler_pb2.ListLspsResponse, collections.abc.Awaitable[glclient.scheduler_pb2.ListLspsResponse]]: + """Returns a structured list of all available Lsps. An Lsp is a + Lightning Service Provider, providing an API as described in blips + 50, 51 and 52 https://github.com/lightning/blips. From cln: + `lsps-listlsps`. + """ + + @abc.abstractmethod + def GetLspInfo( + self, + request: glclient.scheduler_pb2.GetLspInfoRequest, + context: _ServicerContext, + ) -> typing.Union[glclient.scheduler_pb2.GetLspInfoResponse, collections.abc.Awaitable[glclient.scheduler_pb2.GetLspInfoResponse]]: + """Returns detailed information about a LSP. From cln: `lsps-lspinfo`.""" + +def add_LspsServicer_to_server(servicer: LspsServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ... diff --git a/libs/gl-testing/gltesting/scheduler.py b/libs/gl-testing/gltesting/scheduler.py index 1f4645229..fd77a5e5d 100644 --- a/libs/gl-testing/gltesting/scheduler.py +++ b/libs/gl-testing/gltesting/scheduler.py @@ -91,10 +91,10 @@ def __init__( self.received_invite_code = None self.debugger = DebugServicer() self.webhooks = [] - self.pairings = PairingServicer() self.pairing_tx_in, self.pairing_rx_in = anyio.create_memory_object_stream() self.pairing_tx_out, self.paring_rx_out = anyio.create_memory_object_stream() self.pairings = PairingServicer(stream_out=self.pairing_tx_in, stream_in=self.paring_rx_out) + self.lsps = LspsServicer() if node_directory is not None: self.node_directory = node_directory @@ -119,6 +119,7 @@ def start(self): self.server.add_service(self.service) self.server.add_service(self.debugger.service) self.server.add_service(self.pairings.service) + self.server.add_service(self.lsps.service) threading.Thread(target=anyio.run, args=(self.run,), daemon=True).start() logging.info(f"Scheduler started on port {self.grpc_port}") @@ -468,5 +469,15 @@ async def ApprovePairing(self, req): await self.stream_out.send(req) return greenlightpb.Empty() +class LspsServicer(schedgrpc.LspsServicer): + """Mocks LSP discovery for the scheduler""" + def __init__(self): + pass + + async def ListLsps(self, _req: schedpb.ListLspsRequest): + return schedpb.ListLspsResponse() + + async def GetLspInfo(self, _req: schedpb.GetLspInfoRequest): + return schedpb.GetLspInfoResponse() Scheduler = AsyncScheduler diff --git a/libs/gl-testing/gltesting/scheduler_grpc.py b/libs/gl-testing/gltesting/scheduler_grpc.py index d3220e865..42741819f 100644 --- a/libs/gl-testing/gltesting/scheduler_grpc.py +++ b/libs/gl-testing/gltesting/scheduler_grpc.py @@ -391,4 +391,61 @@ def __init__(self, channel): glclient_dot_scheduler__pb2.ApprovePairingRequest, glclient_dot_greenlight__pb2.Empty, ) + ) + + +class LspsServicer(purerpc.Servicer): + async def ListLsps(self, input_message): + raise NotImplementedError() + + async def GetLspInfo(self, input_message): + raise NotImplementedError() + + @property + def service(self) -> purerpc.Service: + service_obj = purerpc.Service( + "scheduler.Lsps" + ) + service_obj.add_method( + "ListLsps", + self.ListLsps, + purerpc.RPCSignature( + purerpc.Cardinality.UNARY_UNARY, + glclient_dot_scheduler__pb2.ListLspsRequest, + glclient_dot_scheduler__pb2.ListLspsResponse, + ) + ) + service_obj.add_method( + "GetLspInfo", + self.GetLspInfo, + purerpc.RPCSignature( + purerpc.Cardinality.UNARY_UNARY, + glclient_dot_scheduler__pb2.GetLspInfoRequest, + glclient_dot_scheduler__pb2.GetLspInfoResponse, + ) + ) + return service_obj + + +class LspsStub: + def __init__(self, channel): + self._client = purerpc.Client( + "scheduler.Lsps", + channel + ) + self.ListLsps = self._client.get_method_stub( + "ListLsps", + purerpc.RPCSignature( + purerpc.Cardinality.UNARY_UNARY, + glclient_dot_scheduler__pb2.ListLspsRequest, + glclient_dot_scheduler__pb2.ListLspsResponse, + ) + ) + self.GetLspInfo = self._client.get_method_stub( + "GetLspInfo", + purerpc.RPCSignature( + purerpc.Cardinality.UNARY_UNARY, + glclient_dot_scheduler__pb2.GetLspInfoRequest, + glclient_dot_scheduler__pb2.GetLspInfoResponse, + ) ) \ No newline at end of file diff --git a/libs/proto/glclient/scheduler.proto b/libs/proto/glclient/scheduler.proto index 57e7137c3..5ac956585 100644 --- a/libs/proto/glclient/scheduler.proto +++ b/libs/proto/glclient/scheduler.proto @@ -546,3 +546,113 @@ message SignerResponse { ApprovePairingResponse approve_pairing = 3; } } + +message ListLspsRequest {} + +message ListLspsResponse { + // A map that maps the public keys of known LSPs to the information we have + // about them. + map lsps = 1; +} + +message Lsp { + // An object that contains the supported protocols with additional + // information about the LSPs conditions. + repeated int32 protocols = 1; +} + +message GetLspInfoRequest { + // The public key of the LSP of interest. + string public_key = 1; +} + +message GetLspInfoResponse { + // The public key of the LSP. + string public_key = 1; + // Infos about the supported protocols. + LspProtocols protocols = 2; +} + +message LspProtocols { + // Optional information relating to the lsps1 protocol. Is only present if + // the LSP supports the protocol. + Lsps1Info lsps1 = 1; + // Optional information relating to the lsps2 protocol. Is only present if + // the LSP supports the protocol. + Lsps2Info lsps2 = 2; +} + +message Lsps1Info { + // The smallest number of confirmations needed for the LSP to accept a + // channel as confirmed and sends `channel_ready` (see bolt02). + uint32 min_required_channel_confirmations = 1; + // The smallest number of blocks in which the LSP can confirm the funding + // transaction. + uint32 min_funding_confirms_within_blocks = 2; + // Is true if the LSP supports zeroreserve on the channel. + bool supports_zero_channel_reserve = 3; + // Is the maximum number of blocks a channel can be leased for. + uint32 max_channel_expiry_blocks = 4; + // The minimum amount in satoshis that a client must request. + uint64 min_initial_client_balance_sat = 5; + // The maximum amount in satoshis that a client must request. + uint64 max_initial_client_balance_sat = 6; + // The minimum amount in satoshis that the LSP will provide to the channel. + uint64 min_initial_lsp_balance_sat = 7; + // The maximum amount in satoshis that the LSP will provide to the channel. + uint64 max_initial_lsp_balance_sat = 8; + // The minimum channel size the LSP accepts. + uint64 min_channel_balance_sat = 9; + // The maximum channel size the LSP accepts. + uint64 max_channel_balance_sat = 10; +} + +message Lsps2Info { + // The LSP may return an empty array in which case, the client currently + // cannot use JIT channels with this LSP. + repeated Lsps2OpeningFeeParams opening_fee_params_menu = 1; +} + +message Lsps2OpeningFeeParams { + // The minimum fee to be paid by the client to the LSP. + uint64 min_fee_msat = 1; + // A parts-per-million number that describes how many millisatoshis to charge + // for every 1 million millisatoshis of payment size for the first payment. If + // the proportional fee is less than than `min_fee_msat`, then `min_fee_msat` + // is paid instead of the proportional times payment size divided by 1 + // million. + uint32 proportional = 2; + // Is a datetime (as an ISO8601 string) up to which this specific + // `opening_fee_params` is valid, and also serves as the timeout for the JIT + // Channel flow, if this particular object is selected. + string valid_until = 3; + // Is a number of blocks that the LSP promises it will keep the channel alive + // without closing, after confirmation. + uint32 min_lifetime = 4; + // Is a maximum number of blocks that the client is allowed to set its + // `to_self_pay_delay` parameter. + uint32 max_client_to_self_delay = 5; + // Is the minimum payment size, inclusive. Is the amount in millisatoshis that + // the payer is guaranteed to be able to send to the client, not including the + // forwarding fees of nodes along the way. + uint64 min_payment_size_msat = 6; + // Is the maximum payment size, inclusive. Is the amount in millisatoshis that + // the payer is guaranteed to be able to send to the client, not including the + // forwarding fees of nodes along the way. + uint64 max_payment_size_msat = 7; + // An arbitrary LSP-genereated string that proves to the LSP that it has + // promised a specific `opening_fee_params`. + string promise = 8; +} + +// A service to explore lsps compatible LSP's +service Lsps { + // Returns a structured list of all available Lsps. An Lsp is a + // Lightning Service Provider, providing an API as described in blips + // 50, 51 and 52 https://github.com/lightning/blips. From cln: + // `lsps-listlsps`. + rpc ListLsps(ListLspsRequest) returns (ListLspsResponse) {} + + // Returns detailed information about a LSP. From cln: `lsps-lspinfo`. + rpc GetLspInfo(GetLspInfoRequest) returns (GetLspInfoResponse) {} +} From 634b2a46498497ef0554a686c9544d96523a1a41 Mon Sep 17 00:00:00 2001 From: Peter Neuroth Date: Wed, 5 Mar 2025 20:15:49 +0100 Subject: [PATCH 4/4] gl-testing: Add lsp mocks Signed-off-by: Peter Neuroth --- libs/gl-testing/gltesting/scheduler.py | 89 ++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/libs/gl-testing/gltesting/scheduler.py b/libs/gl-testing/gltesting/scheduler.py index fd77a5e5d..0000df6e1 100644 --- a/libs/gl-testing/gltesting/scheduler.py +++ b/libs/gl-testing/gltesting/scheduler.py @@ -472,12 +472,93 @@ async def ApprovePairing(self, req): class LspsServicer(schedgrpc.LspsServicer): """Mocks LSP discovery for the scheduler""" def __init__(self): - pass + self.lsps = { + "02ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff": schedpb.LspProtocols( + lsps1=schedpb.Lsps1Info( + min_required_channel_confirmations=3, + min_funding_confirms_within_blocks=6, + supports_zero_channel_reserve=False, + max_channel_expiry_blocks=144, + min_initial_client_balance_sat=0, + max_initial_client_balance_sat=1000000, + min_initial_lsp_balance_sat=50000, + max_initial_lsp_balance_sat=1000000, + min_channel_balance_sat=50000, + max_channel_balance_sat=2000000, + ), + lsps2=schedpb.Lsps2Info( + opening_fee_params_menu=[ + schedpb.Lsps2OpeningFeeParams( + min_fee_msat=5000000, + proportional=2500, + valid_until="2025-12-31T23:59:59Z", + min_lifetime=1000, + max_client_to_self_delay=2016, + min_payment_size_msat=1000000, + max_payment_size_msat=1000000000, + promise="sample-promise-25d3fa", + ), + schedpb.Lsps2OpeningFeeParams( + min_fee_msat=2000000, + proportional=5500, + valid_until="2025-12-31T23:59:59Z", + min_lifetime=100, + max_client_to_self_delay=2016, + min_payment_size_msat=1000000, + max_payment_size_msat=1000000000, + promise="sample-promise-ffb6da", + ), + ], + ), + ), + "02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": schedpb.LspProtocols( + lsps1=schedpb.Lsps1Info( + min_required_channel_confirmations=6, + min_funding_confirms_within_blocks=10, + supports_zero_channel_reserve=True, + max_channel_expiry_blocks=1000, + min_initial_client_balance_sat=0, + max_initial_client_balance_sat=1000000, + min_initial_lsp_balance_sat=50000, + max_initial_lsp_balance_sat=1000000, + min_channel_balance_sat=50000, + max_channel_balance_sat=2000000, + ), + lsps2=schedpb.Lsps2Info( + opening_fee_params_menu=[ + schedpb.Lsps2OpeningFeeParams( + min_fee_msat=3000000, + proportional=1500, + valid_until="2025-12-31T23:59:59Z", + min_lifetime=500, + max_client_to_self_delay=2016, + min_payment_size_msat=1000000, + max_payment_size_msat=1000000000, + promise="sample-promise-ababab", + ), + ], + ), + ), + "020000000000000000000000000000000000000000000000000000000000000000": schedpb.LspProtocols(), + } async def ListLsps(self, _req: schedpb.ListLspsRequest): - return schedpb.ListLspsResponse() + response = schedpb.ListLspsResponse(lsps={ + "02ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff": schedpb.Lsp(protocols=[1,2]), + "02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": schedpb.Lsp(protocols=[2,1]), + "020000000000000000000000000000000000000000000000000000000000000000": schedpb.Lsp() + }) - async def GetLspInfo(self, _req: schedpb.GetLspInfoRequest): - return schedpb.GetLspInfoResponse() + return response + + async def GetLspInfo(self, req: schedpb.GetLspInfoRequest): + response = schedpb.GetLspInfoResponse() + protocols = self.lsps[req.public_key] + if protocols is not None: + response = schedpb.GetLspInfoResponse( + public_key=req.public_key, + protocols=protocols, + ) + return response Scheduler = AsyncScheduler