// Copyright 2025 Google LLC
//
// 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 google.cloud.universalledger.v1;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/cloud/universalledger/v1/query.proto";
import "google/cloud/universalledger/v1/types.proto";

option csharp_namespace = "Google.Cloud.UniversalLedger.V1";
option go_package = "cloud.google.com/go/universalledger/apiv1/universalledgerpb;universalledgerpb";
option java_multiple_files = true;
option java_outer_classname = "UniversalLedgerProto";
option java_package = "com.google.cloud.universalledger.v1";
option php_namespace = "Google\\Cloud\\UniversalLedger\\V1";
option ruby_package = "Google::Cloud::UniversalLedger::V1";

// A service for interacting with the Google Cloud Universal Ledger.
// Endpoints are pre-created and managed by Google and cannot
// be modified by users.
// The names of available endpoints will be provided in the public
// documentation.
// An endpoint is a regional resource within a Universal Ledger network.
// Requests sent to an endpoint may be routed to different validators in the
// given network within the given region.
service UniversalLedger {
  option (google.api.default_host) = "universalledger.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform";

  // Submits a transaction to the network.
  // The request is first validated for basic correctness. If validation fails,
  // the request will fail immediately.
  // If validation succeeds, this method returns only after the transaction has
  // been replicated across a majority of validators in the network, or until
  // the request fails.
  rpc SubmitTransaction(SubmitTransactionRequest)
      returns (SubmitTransactionResponse) {
    option (google.api.http) = {
      post: "/v1/{endpoint=projects/*/locations/*/endpoints/*}:submitTransaction"
      body: "*"
    };
    option (google.api.method_signature) =
        "endpoint,serialized_signed_transaction";
  }

  // Lists all endpoints for a given project and location.
  rpc ListEndpoints(ListEndpointsRequest) returns (ListEndpointsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*}/endpoints"
    };
    option (google.api.method_signature) = "parent";
  }

  // Gets the details of a specific endpoint.
  rpc GetEndpoint(GetEndpointRequest) returns (Endpoint) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/endpoints/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Submits an operational transaction to the network.
  // This method returns only after the transaction has been replicated across a
  // majority of validators in the network, or if the transaction fails.
  rpc SubmitOperationalTransaction(SubmitOperationalTransactionRequest)
      returns (SubmitOperationalTransactionResponse) {
    option (google.api.http) = {
      post: "/v1/{endpoint=projects/*/locations/*/endpoints/*}:submitOperationalTransaction"
      body: "*"
    };
    option (google.api.method_signature) =
        "endpoint,serialized_signed_operational_transaction";
  }

  // Queries the state of a transaction. This method can be called for any
  // transaction submitted to the network. The returned transaction details may
  // vary between calls, because an endpoint may route requests to different
  // validators within the network and region, and the validators may not be at
  // the same round ID at any given time.
  rpc QueryTransactionState(QueryTransactionStateRequest)
      returns (QueryTransactionStateResponse) {
    option (google.api.http) = {
      get: "/v1/{endpoint=projects/*/locations/*/endpoints/*}:queryTransactionState"
    };
    option (google.api.method_signature) = "endpoint,transaction_digest_hex";
  }

  // Queries all the information stored about an account in the network.
  // The returned account details may vary between calls, because an
  // endpoint may route requests to different validators within the network and
  // region, and the validators may not be at the same round ID at any given
  // time.
  rpc QueryAccount(QueryAccountRequest) returns (QueryAccountResponse) {
    option (google.api.http) = {
      get: "/v1/{endpoint=projects/*/locations/*/endpoints/*}:queryAccount"
    };
    option (google.api.method_signature) = "endpoint,account_id";
  }
}

// Represents a Universal Ledger endpoint.
message Endpoint {
  option (google.api.resource) = {
    type: "universalledger.googleapis.com/Endpoint"
    pattern: "projects/{project}/locations/{location}/endpoints/{endpoint}"
    plural: "endpoints"
    singular: "endpoint"
  };

  // Identifier. The resource name of the endpoint.
  // Format: `projects/{project}/locations/{location}/endpoints/{endpoint}`
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];
}

// Request message for ListEndpoints.
message ListEndpointsRequest {
  // Required. The parent, which owns this collection of endpoints.
  // Format: `projects/{project}/locations/{location}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "universalledger.googleapis.com/Endpoint"
    }
  ];

  // Optional. The maximum number of endpoints to return. The service may return
  // fewer than this value. If unspecified, at most 50 endpoints will be
  // returned. The maximum value is 1000; values above 1000 will be coerced to
  // 1000.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A page token, received from a previous `ListEndpoints` call.
  // Provide this to retrieve the subsequent page.
  string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Response message for ListEndpoints.
message ListEndpointsResponse {
  // The endpoints for the given project and location.
  repeated Endpoint endpoints = 1;

  // A token, which can be sent as `page_token` to retrieve the next page.
  // If this field is omitted, there are no subsequent pages.
  string next_page_token = 2;
}

// Request message for GetEndpoint.
message GetEndpointRequest {
  // Required. The name of the endpoint to retrieve.
  // Format: `projects/{project}/locations/{location}/endpoints/{endpoint}`
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "universalledger.googleapis.com/Endpoint"
    }
  ];
}

// Request message for QueryAccount.
message QueryAccountRequest {
  // Required. The endpoint to serve the request.
  // Format: `projects/{project}/locations/{location}/endpoints/{endpoint}`
  // The location is a region.
  string endpoint = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The account ID to get information about.
  string account_id = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. The ID of the execution round (similar to block "height") at
  // which to request data. The returned account information will be accurate
  // for the world state at this execution round. If unspecified, uses the
  // latest finalized round as known by the serving validator.
  //
  // The method does not block to wait for the absolute latest state across the
  // entire network. Instead, it returns the state as known by the contacted
  // validator, ensuring low latency and high availability. The state at a
  // given round ID is always consistent and canonical.
  int64 round_id = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Response message for QueryAccount.
message QueryAccountResponse {
  // The account information, along with the height at which it was obtained.
  Account account = 1;
}

// Request message for SubmitTransaction.
message SubmitTransactionRequest {
  // Required. The endpoint to submit the transaction to.
  // Format: `projects/{project}/locations/{location}/endpoints/{endpoint}`
  // The location is a region.
  string endpoint = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. A protobuf serialized
  // [SignedTransaction][google.cloud.universalledger.v1.SignedTransaction] to
  // submit to the Universal Ledger network. Using a serialized format ensures
  // that all validators can compute the same hash for the transaction,
  // regardless of the machine or environment where the transaction was
  // serialized.
  bytes serialized_signed_transaction = 2
      [(google.api.field_behavior) = REQUIRED];
}

// Response message for SubmitTransaction.
message SubmitTransactionResponse {
  // Hex encoded SHA-256 hash of the `serialized_signed_transaction` that
  // uniquely identifies the submitted transaction.
  // This ID is provided so that a client can track the transaction without
  // needing to implement the hashing logic itself. The ID can be directly
  // used in subsequent API calls, for example to query the transaction state.
  string transaction_digest_hex = 1;
}

// Request message for SubmitOperationalTransaction.
message SubmitOperationalTransactionRequest {
  // Required. The endpoint to serve the request.
  // Format: `projects/{project}/locations/{location}/endpoints/{endpoint}`
  // The location is a region.
  string endpoint = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. A protobuf serialized
  // [SignedTransaction][google.cloud.universalledger.v1.SignedTransaction] to
  // submit to the network. The enclosed client transaction must be an
  // operational transaction, and the sender must be the platform operator.
  // Having the fully serialized transaction allows all validators
  // to compute the same hash without assuming any format for the serialized
  // transaction.
  bytes serialized_signed_operational_transaction = 2
      [(google.api.field_behavior) = REQUIRED];
}

// Response message for SubmitOperationalTransaction.
message SubmitOperationalTransactionResponse {
  // Hex encoded SHA-256 hash of the `serialized_signed_operational_transaction`
  // that uniquely identifies the submitted operational transaction.
  // This ID is provided so that a client can track the transaction without
  // needing to implement the hashing logic itself. The ID can be directly
  // used in subsequent API calls, for example to query the transaction state.
  string transaction_digest_hex = 1;
}

// Request message for QueryTransactionState.
message QueryTransactionStateRequest {
  // Required. The endpoint to serve the request.
  // Format: `projects/{project}/locations/{location}/endpoints/{endpoint}`
  // The location is a region.
  string endpoint = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The transaction digest to get the state of.
  string transaction_digest_hex = 2 [(google.api.field_behavior) = REQUIRED];
}

// Response message for QueryTransactionState.
message QueryTransactionStateResponse {
  // One entry per each known submission of the transaction to the validator
  // handling the request.
  repeated TransactionAttempt transaction_attempts = 1;
}
