syntax = "proto3";
package tsoracle.v1;

service TsoService {
  rpc GetTs(GetTsRequest) returns (GetTsResponse);
}

message GetTsRequest {
  // Number of consecutive timestamps to allocate. Must be >= 1.
  uint32 count = 1;
}

message GetTsResponse {
  // 46-bit milliseconds-since-Unix-epoch component.
  uint64 physical_ms = 1;
  // 18-bit logical counter; the response covers logicals
  // [logical_start, logical_start + count - 1] at this physical_ms.
  uint32 logical_start = 2;
  // Number of consecutive timestamps allocated.
  uint32 count = 3;
  // Leader epoch that issued this grant, as a 128-bit value split into two
  // 64-bit halves (epoch_hi is the more significant half). Lexicographic
  // (epoch_hi, epoch_lo) order equals numeric order.
  uint64 epoch_hi = 4;
  uint64 epoch_lo = 5;
}

// Carried in the `tsoracle-leader-hint-bin` binary metadata trailer when the
// server returns FAILED_PRECONDITION from GetTs because it is not currently
// the leader.
message LeaderHint {
  optional string leader_endpoint = 1;
  // Leader epoch as a single nested message, so its presence implies both
  // halves: the hint either carries a complete epoch or none. Bundling the
  // halves makes a half-populated (corrupt) epoch unrepresentable on the
  // wire and in the generated Rust types.
  optional EpochWire leader_epoch = 2;
}

// The 128-bit leader epoch split into two 64-bit halves (`hi` is the more
// significant half), matching `GetTsResponse.epoch_hi`/`epoch_lo`.
// Lexicographic (hi, lo) order equals numeric order.
message EpochWire {
  uint64 hi = 1;
  uint64 lo = 2;
}
