// Apibara DNA server V2
syntax = "proto3";

package dna.v2.stream;

import "google/protobuf/duration.proto";

service DnaStream {
  // Stream data from the server.
  rpc StreamData(StreamDataRequest) returns (stream StreamDataResponse);
  // Get DNA server status.
  rpc Status(StatusRequest) returns (StatusResponse);
}

// A cursor over the stream content.
message Cursor {
  // Key used for ordering messages in the stream.
  //
  // This is usually the block or slot number.
  uint64 order_key = 1;
  // Key used to discriminate branches in the stream.
  //
  // This is usually the hash of the block.
  bytes unique_key = 2;
}

// Request for the `Status` method.
message StatusRequest {}

// Response for the `Status` method.
message StatusResponse {
  // The current head of the chain.
  Cursor current_head = 1;
  // The last cursor that was ingested by the node.
  Cursor last_ingested = 2;
  // The finalized block.
  Cursor finalized = 3;
  // The first block available.
  Cursor starting = 4;
}

// Request data to be streamed.
message StreamDataRequest {
  // Cursor to start streaming from.
  //
  // If not specified, starts from the genesis block.
  // Use the data's message `end_cursor` field to resume streaming.
  optional Cursor starting_cursor = 1;
  // Return data with the specified finality.
  //
  // If not specified, defaults to `DATA_FINALITY_ACCEPTED`.
  optional DataFinality finality = 2;
  // Filters used to generate data.
  repeated bytes filter = 3;
  // Heartbeat interval.
  //
  // Value must be between 10 and 60 seconds.
  // If not specified, defaults to 30 seconds.
  optional google.protobuf.Duration heartbeat_interval = 4;
}

// Contains a piece of streamed data.
message StreamDataResponse {
  oneof message {
    Data data = 1;
    Invalidate invalidate = 2;
    Finalize finalize = 3;
    Heartbeat heartbeat = 4;
    SystemMessage system_message = 5;
  }
}

// Invalidate data after the given cursor.
message Invalidate {
  // The cursor of the new chain's head.
  //
  // All data after this cursor should be considered invalid.
  Cursor cursor = 1;
  // List of blocks that were removed from the chain.
  repeated Cursor removed = 2;
}

// Move the finalized block forward.
message Finalize {
  // The cursor of the new finalized block.
  //
  // All data before this cursor cannot be invalidated.
  Cursor cursor = 1;
}

// A single block of data.
//
// If the request specified multiple filters, the `data` field will contain the
// data for each filter in the same order as the filters were specified in the
// request.
// If no data is available for a filter, the corresponding data field will be
// empty.
message Data {
  // Cursor that generated this block of data.
  optional Cursor cursor = 1;
  // Block cursor. Use this cursor to resume the stream.
  Cursor end_cursor = 2;
  // The finality status of the block.
  DataFinality finality = 3;
  // The block data.
  //
  // This message contains chain-specific data serialized using protobuf.
  repeated bytes data = 4;
  // The production mode of the block.
  DataProduction production = 5;
}

// Sent to clients to check if stream is still connected.
message Heartbeat {}

// Message from the server to the client.
message SystemMessage {
  oneof output {
    // Output to stdout.
    string stdout = 1;
    // Output to stderr.
    string stderr = 2;
  }
}

// Data finality.
enum DataFinality {
  DATA_FINALITY_UNKNOWN = 0;
  // Data was received, but is not part of the canonical chain yet.
  DATA_FINALITY_PENDING = 1;
  // Data is now part of the canonical chain, but could still be invalidated.
  DATA_FINALITY_ACCEPTED = 2;
  // Data is finalized and cannot be invalidated.
  DATA_FINALITY_FINALIZED = 3;
}

// Data production mode.
enum DataProduction {
  DATA_PRODUCTION_UNKNOWN = 0;
  // Data is for a backfilled block.
  DATA_PRODUCTION_BACKFILL = 1;
  // Data is for a live block.
  DATA_PRODUCTION_LIVE = 2;
}
