// Copyright 2020 Prysmatic Labs.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";

package ethereum.eth.service;

import "google/api/annotations.proto";
import "google/protobuf/descriptor.proto";
import "google/protobuf/empty.proto";
import "proto/eth/ext/options.proto";

option csharp_namespace = "Ethereum.Eth.Service";
option go_package = "github.com/prysmaticlabs/prysm/v4/proto/eth/service";
option java_multiple_files = true;
option java_outer_classname = "KeyManagementServiceProto";
option java_package = "org.ethereum.eth.service";
option php_namespace = "Ethereum\\Eth\\Service";

// Validator Key Management Standard API
//
// The validator key management API is a set of endpoints to be used for keystore management in the validator client.
//
// This service is defined in the upstream Ethereum consensus APIs repository (beacon-apis/apis/keystores).
service KeyManagement {
  // ListKeystores for all keystores known to and decrypted by the keymanager.
  //
  // HTTP response status codes:
  //  - 200: Successful response
  //  - 401: Unauthorized
  //  - 403: Forbidden from accessing the resource
  //  - 500: Validator internal error
  rpc ListKeystores(google.protobuf.Empty) returns (ListKeystoresResponse) {
    option (google.api.http) = {
      get: "/internal/eth/v1/keystores"
    };
  }

  // ImportKeystores generated by the Eth2.0 deposit CLI tooling.
  // Users SHOULD send slashing_protection data associated with the imported
  // pubkeys. MUST follow the format defined in EIP-3076: Slashing Protection Interchange Format.
  //
  // HTTP response status codes:
  //  - 200: Successful response
  //  - 401: Unauthorized
  //  - 403: Forbidden from accessing the resource
  //  - 500: Validator internal error
  rpc ImportKeystores(ImportKeystoresRequest) returns (ImportKeystoresResponse) {
    option (google.api.http) = {
      post: "/internal/eth/v1/keystores",
      body: "*"
    };
  }

  // DeleteKeystores must delete all keystores from `request.pubkeys` that are known to the keymanager and exist
  // in its persistent storage. Additionally, DELETE must fetch the slashing protection data for the requested keys from
  // persistent storage, which must be retained (and not deleted) after the response has been sent. Therefore in the
  // case of two identical delete requests being made, both will have access to slashing protection data.
  // In a single atomic sequential operation the keymanager must:
  //
  //   1. Guarantee that key(s) can not produce any more signature; only then
  //   2. Delete key(s) and serialize its associated slashing protection data
  //
  // DELETE should never return a 404 response, even if all pubkeys from request.pubkeys have no extant keystores
  // nor slashing protection data.
  //
  // HTTP response status codes:
  //  - 200: Successful response
  //  - 401: Unauthorized
  //  - 403: Forbidden from accessing the resource
  //  - 500: Validator internal error
  rpc DeleteKeystores(DeleteKeystoresRequest) returns (DeleteKeystoresResponse) {
    option (google.api.http) = {
      delete: "/internal/eth/v1/keystores",
      body: "*"
    };
  }

  // ListRemoteKeys for all web3signer public validator keys known to the keymanager.
  //
  // HTTP response status codes:
  //  - 200: Successful response
  //  - 401: Unauthorized
  //  - 403: Forbidden from accessing the resource
  //  - 500: Validator internal error
  rpc ListRemoteKeys(google.protobuf.Empty) returns (ListRemoteKeysResponse) {
    option (google.api.http) = {
      get: "/internal/eth/v1/remotekeys"
    };
  }

  // ImportRemoteKeys imports and sets web3signer public validator keys in the keymanager.
  //
  // HTTP response status codes:
  //  - 200: Successful response
  //  - 401: Unauthorized
  //  - 403: Forbidden from accessing the resource
  //  - 500: Validator internal error
  rpc ImportRemoteKeys(ImportRemoteKeysRequest) returns (ImportRemoteKeysResponse) {
    option (google.api.http) = {
      post: "/internal/eth/v1/remotekeys",
      body: "*"
    };
  }


  // DeleteRemoteKeys removes web3signer public validator keys in the keymanager.
  //
  // HTTP response status codes:
  //  - 200: Successful response
  //  - 401: Unauthorized
  //  - 403: Forbidden from accessing the resource
  //  - 500: Validator internal error
  rpc DeleteRemoteKeys(DeleteRemoteKeysRequest) returns (DeleteRemoteKeysResponse) {
    option (google.api.http) = {
      delete: "/internal/eth/v1/remotekeys",
      body: "*"
    };
  }

  // ListFeeRecipientByPubkey returns the hex encoded fee recipient address for the given pubkey.
  //
  // HTTP response status codes:
  //  - 200: Successful response
  //  - 401: Unauthorized
  //  - 403: Forbidden from accessing the resource
  //  - 500: Validator internal error
  rpc ListFeeRecipientByPubkey(PubkeyRequest) returns (GetFeeRecipientByPubkeyResponse) {
    option (google.api.http) = {
      get: "/internal/eth/v1/validator/{pubkey}/feerecipient"
    };
  }

  // SetFeeRecipientByPubkey sets the fee recipient for the specific public key, overrides the existing one.
  //
  // HTTP response status codes:
  //  - 202: Successful response
  //  - 401: Unauthorized
  //  - 403: Forbidden from accessing the resource
  //  - 500: Validator internal error
  rpc SetFeeRecipientByPubkey(SetFeeRecipientByPubkeyRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/internal/eth/v1/validator/{pubkey}/feerecipient",
      body: "*"
    };
  }

  // DeleteFeeRecipientByPubkey deletes the current settings on the fee recipient and replaces with the default fallback fee recipient.
  //
  // HTTP response status codes:
  //  - 204: No Content
  //  - 401: Unauthorized
  //  - 403: Forbidden from accessing the resource
  //  - 500: Validator internal error
  rpc DeleteFeeRecipientByPubkey(PubkeyRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/internal/eth/v1/validator/{pubkey}/feerecipient",
      body: "*"
    };
  }

  // GetGasLimit returns the execution gas limit for an individual validator.
  //
  // HTTP response status codes:
  //  - 400: Bad request
  //  - 401: Unauthorized
  //  - 403: Forbidden
  //  - 500: Validator internal error
  rpc GetGasLimit(PubkeyRequest) returns (GetGasLimitResponse) {
    option (google.api.http) = {
      get: "/internal/eth/v1/validator/{pubkey}/gas_limit"
    };
  }

  // SetGasLimit sets the gas limit for the specific public key, overrides the existing one.
  //
  // Spec page: https://ethereum.github.io/keymanager-APIs/#/Gas%20Limit/SetGasLimit
  // 
  // HTTP response status codes:
  //  - 202: Successful response
  //  - 400: Bad request
  //  - 401: Unauthorized
  //  - 403: Forbidden from accessing the resource
  //  - 404: Path not found
  //  - 500: Validator internal error
  rpc SetGasLimit(SetGasLimitRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/internal/eth/v1/validator/{pubkey}/gas_limit",
      body: "*"
    };
  }

  // DeleteGasLimit deletes the gas limit for the specific public key.
  //
  // Spec page: https://ethereum.github.io/keymanager-APIs/#/Gas%20Limit/DeleteGasLimit
  //
  // HTTP response status codes:
  //  - 204: Successfully removed the gas limit or there was no gas limit set for the requested pubkey.
  //  - 400: Bad request, malformed request
  //  - 401: Unauthorized, no token is found.
  //  - 403: A gas limit was found but cannot be removed. This may be because the gas limit was in configuration files that cannot be updated.
  //  - 404: The key was not found on the server, nothing to delete.
  //  - 500: Validator internal error
  rpc DeleteGasLimit(DeleteGasLimitRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/internal/eth/v1/validator/{pubkey}/gas_limit",
      body: "*"
    };
  }

  // SetVoluntaryExit creates a signed voluntary exit message and returns a VoluntaryExit object.
  //
  //  Spec page: https://ethereum.github.io/keymanager-APIs/?urls.primaryName=dev#/Voluntary%20Exit/signVoluntaryExit
  //
  // HTTP response status codes:
  //  - 200: Successfully created and signed voluntary exit
  //  - 400: Bad request, malformed request
  //  - 401: Unauthorized, no token is found.
  //  - 403: Forbidden, a token is found but is invalid
  //  - 404: Path not found
  //  - 500: Validator internal error
  rpc SetVoluntaryExit(SetVoluntaryExitRequest) returns (SetVoluntaryExitResponse) {
    option (google.api.http) = {
      post: "/internal/eth/v1/validator/{pubkey}/voluntary_exit",
      body: "*"
    };
  }

}

message ListKeystoresResponse {
  message Keystore {
    bytes validating_pubkey = 1;
    string derivation_path = 2;
  }
  repeated Keystore data = 1;
}

message ImportKeystoresRequest {
  repeated string keystores = 1;
  repeated string passwords = 2;
  string slashing_protection = 3;
}

message ImportKeystoresResponse {
  repeated ImportedKeystoreStatus data = 1;
}

message DeleteKeystoresRequest {
  repeated bytes pubkeys = 1;
}

message DeleteKeystoresResponse {
  repeated DeletedKeystoreStatus data = 1;
  string slashing_protection = 2;
}

message ImportedKeystoreStatus {
  enum Status {
    IMPORTED = 0;
    DUPLICATE = 1;
    ERROR = 2;
  }
  Status status = 1;
  string message = 2;
}

message DeletedKeystoreStatus {
  enum Status {
    DELETED = 0;
    NOT_FOUND = 1;
    NOT_ACTIVE = 2;
    ERROR = 3;
  }
  Status status = 1;
  string message = 2;
}


message ListRemoteKeysResponse {
  message Keystore {
    bytes pubkey = 1;
    string url = 2;
    bool readonly = 3;
  }
  repeated Keystore data = 1;
}

message ImportRemoteKeysRequest {
  message Keystore {
    bytes pubkey = 1;
    string url = 2;
  }
  repeated Keystore remote_keys = 1;
}

message ImportRemoteKeysResponse {
  repeated ImportedRemoteKeysStatus data = 1;
}

message DeleteRemoteKeysRequest {
  repeated bytes pubkeys = 1;
}

message DeleteRemoteKeysResponse {
  repeated DeletedRemoteKeysStatus data = 1;
}

message ImportedRemoteKeysStatus {
  enum Status {
    UNKNOWN = 0;
    IMPORTED = 1;
    DUPLICATE = 2;
    ERROR = 3;
  }
  Status status = 1;
  string message = 2;
}

message DeletedRemoteKeysStatus {
  enum Status {
    NOT_FOUND = 0;
    DELETED = 1;
    ERROR = 3; // skips 2 to match Delete KeyStore status which has error = 3.
  }
  Status status = 1;
  string message = 2;
}


message PubkeyRequest {
  bytes pubkey = 1;
}

message GetFeeRecipientByPubkeyResponse {
  message FeeRecipient {
    bytes pubkey = 1;
    bytes ethaddress = 2;
  }
  FeeRecipient data = 1;
}

message SetFeeRecipientByPubkeyRequest {
  bytes pubkey = 1;
  bytes ethaddress = 2;
}

message GetGasLimitResponse {
  message GasLimit {
    bytes pubkey = 1;
    uint64 gas_limit = 2;
  }
  GasLimit data = 1;
}

message SetGasLimitRequest {
  bytes pubkey = 1;
  uint64 gas_limit = 2;
}

message DeleteGasLimitRequest {
  bytes pubkey = 1;
}

message SetVoluntaryExitRequest {
  bytes pubkey = 1 [(ethereum.eth.ext.ssz_size) = "48"];
  uint64 epoch = 2 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives.Epoch"];
}

message SetVoluntaryExitResponse {
  message SignedVoluntaryExit {
    message VoluntaryExit {
      uint64 epoch = 1 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives.Epoch"];
      uint64 validator_index = 2 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives.ValidatorIndex"];
    }
    VoluntaryExit message = 1;
    bytes signature = 2;
  }
  SignedVoluntaryExit data = 1;
}
