syntax = "proto3";

package vm;

import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "io/prometheus/client/metrics.proto";

option go_package = "github.com/ava-labs/avalanchego/proto/pb/vm";

// ref. https://pkg.go.dev/github.com/ava-labs/avalanchego/snow/engine/snowman/block
// ref. https://pkg.go.dev/github.com/ava-labs/avalanchego/snow/consensus/snowman#Block
service VM {
  // ChainVM
  //
  // Initialize this VM.
  rpc Initialize(InitializeRequest) returns (InitializeResponse);
  // SetState communicates to VM its next state it starts
  rpc SetState(SetStateRequest) returns (SetStateResponse);
  // Shutdown is called when the node is shutting down.
  rpc Shutdown(google.protobuf.Empty) returns (google.protobuf.Empty);
  // Creates the HTTP handlers for custom chain network calls.
  rpc CreateHandlers(google.protobuf.Empty) returns (CreateHandlersResponse);
  // Creates the HTTP handlers for custom VM network calls.
  //
  // Note: RPC Chain VM Factory will start a new instance of the VM in a
  // seperate process which will populate the static handlers. After this
  // process is created other processes will be created to populate blockchains,
  // but they will not have the static handlers be called again.
  rpc CreateStaticHandlers(google.protobuf.Empty) returns (CreateStaticHandlersResponse);
  rpc Connected(ConnectedRequest) returns (google.protobuf.Empty);
  rpc Disconnected(DisconnectedRequest) returns (google.protobuf.Empty);
  // Attempt to create a new block from data contained in the VM.
  rpc BuildBlock(BuildBlockRequest) returns (BuildBlockResponse);
  // Attempt to create a block from a stream of bytes.
  rpc ParseBlock(ParseBlockRequest) returns (ParseBlockResponse);
  // Attempt to load a block.
  rpc GetBlock(GetBlockRequest) returns (GetBlockResponse);
  // Notify the VM of the currently preferred block.
  rpc SetPreference(SetPreferenceRequest) returns (google.protobuf.Empty);
  // Attempt to verify the health of the VM.
  rpc Health(google.protobuf.Empty) returns (HealthResponse);
  // Version returns the version of the VM.
  rpc Version(google.protobuf.Empty) returns (VersionResponse);
  // Notify this engine of a request for data from [nodeID].
  rpc AppRequest(AppRequestMsg) returns (google.protobuf.Empty);
  // Notify this engine that an AppRequest message it sent to [nodeID] with
  // request ID [requestID] failed.
  rpc AppRequestFailed(AppRequestFailedMsg) returns (google.protobuf.Empty);
  // Notify this engine of a response to the AppRequest message it sent to
  // [nodeID] with request ID [requestID].
  rpc AppResponse(AppResponseMsg) returns (google.protobuf.Empty);
  // Notify this engine of a gossip message from [nodeID].
  rpc AppGossip(AppGossipMsg) returns (google.protobuf.Empty);
  // Attempts to gather metrics from a VM.
  rpc Gather(google.protobuf.Empty) returns (GatherResponse);
  rpc CrossChainAppRequest(CrossChainAppRequestMsg) returns (google.protobuf.Empty);
  rpc CrossChainAppRequestFailed(CrossChainAppRequestFailedMsg) returns (google.protobuf.Empty);
  rpc CrossChainAppResponse(CrossChainAppResponseMsg) returns (google.protobuf.Empty);

  // BatchedChainVM
  rpc GetAncestors(GetAncestorsRequest) returns (GetAncestorsResponse);
  rpc BatchedParseBlock(BatchedParseBlockRequest) returns (BatchedParseBlockResponse);

  // HeightIndexedChainVM
  rpc VerifyHeightIndex(google.protobuf.Empty) returns (VerifyHeightIndexResponse);
  rpc GetBlockIDAtHeight(GetBlockIDAtHeightRequest) returns (GetBlockIDAtHeightResponse);

  // StateSyncableVM
  //
  // StateSyncEnabled indicates whether the state sync is enabled for this VM.
  rpc StateSyncEnabled(google.protobuf.Empty) returns (StateSyncEnabledResponse);
  // GetOngoingSyncStateSummary returns an in-progress state summary if it exists.
  rpc GetOngoingSyncStateSummary(google.protobuf.Empty) returns (GetOngoingSyncStateSummaryResponse);
  // GetLastStateSummary returns the latest state summary.
  rpc GetLastStateSummary(google.protobuf.Empty) returns (GetLastStateSummaryResponse);
  // ParseStateSummary parses a state summary out of [summaryBytes].
  rpc ParseStateSummary(ParseStateSummaryRequest) returns (ParseStateSummaryResponse);
  // GetStateSummary retrieves the state summary that was generated at height
  // [summaryHeight].
  rpc GetStateSummary(GetStateSummaryRequest) returns (GetStateSummaryResponse);

  // Block
  rpc BlockVerify(BlockVerifyRequest) returns (BlockVerifyResponse);
  rpc BlockAccept(BlockAcceptRequest) returns (google.protobuf.Empty);
  rpc BlockReject(BlockRejectRequest) returns (google.protobuf.Empty);

  // StateSummary
  rpc StateSummaryAccept(StateSummaryAcceptRequest) returns (StateSummaryAcceptResponse);
}

enum State {
  STATE_UNSPECIFIED = 0;
  STATE_STATE_SYNCING = 1;
  STATE_BOOTSTRAPPING = 2;
  STATE_NORMAL_OP = 3;
}

enum Status {
  STATUS_UNSPECIFIED = 0;
  STATUS_PROCESSING = 1;
  STATUS_REJECTED = 2;
  STATUS_ACCEPTED = 3;
}

enum Error {
  // ERROR_UNSPECIFIED is used to indicate that no error occurred.
  ERROR_UNSPECIFIED = 0;
  ERROR_CLOSED = 1;
  ERROR_NOT_FOUND = 2;
  ERROR_HEIGHT_INDEX_NOT_IMPLEMENTED = 3;
  ERROR_HEIGHT_INDEX_INCOMPLETE = 4;
  ERROR_STATE_SYNC_NOT_IMPLEMENTED = 5;
}

message InitializeRequest {
  uint32 network_id = 1;
  bytes subnet_id = 2;
  bytes chain_id = 3;
  bytes node_id = 4;
  // public_key is the BLS public key that would correspond with any signatures
  // produced by the warp messaging signer
  bytes public_key = 5;
  bytes x_chain_id = 6;
  bytes c_chain_id = 7;
  bytes avax_asset_id = 8;
  string chain_data_dir = 9;
  bytes genesis_bytes = 10;
  bytes upgrade_bytes = 11;
  bytes config_bytes = 12;
  repeated VersionedDBServer db_servers = 13;
  // server_addr is the address of the gRPC server which serves
  // the messenger, keystore, shared memory, blockchain alias,
  // subnet alias, and appSender services
  string server_addr = 14;
}

message InitializeResponse {
  bytes last_accepted_id = 1;
  bytes last_accepted_parent_id = 2;
  uint64 height = 3;
  bytes bytes = 4;
  google.protobuf.Timestamp timestamp = 5;
}

message VersionedDBServer {
  string version = 1;
  // server_addr is the address of the gRPC server which serves the
  // Database service
  string server_addr = 2;
}

message SetStateRequest {
  State state = 1;
}

message SetStateResponse {
  bytes last_accepted_id = 1;
  bytes last_accepted_parent_id = 2;
  uint64 height = 3;
  bytes bytes = 4;
  google.protobuf.Timestamp timestamp = 5;
}

message CreateHandlersResponse {
  repeated Handler handlers = 1;
}

message CreateStaticHandlersResponse {
  repeated Handler handlers = 1;
}

message Handler {
  string prefix = 1;
  uint32 lock_options = 2;
  // server_addr is the address of the gRPC server which serves the
  // HTTP service
  string server_addr = 3;
}

message BuildBlockRequest {
  optional uint64 p_chain_height = 1;
}

// Note: The status of a freshly built block is assumed to be Processing.
message BuildBlockResponse {
  bytes id = 1;
  bytes parent_id = 2;
  bytes bytes = 3;
  uint64 height = 4;
  google.protobuf.Timestamp timestamp = 5;
  bool verify_with_context = 6;
}

message ParseBlockRequest {
  bytes bytes = 1;
}

message ParseBlockResponse {
  bytes id = 1;
  bytes parent_id = 2;
  Status status = 3;
  uint64 height = 4;
  google.protobuf.Timestamp timestamp = 5;
  bool verify_with_context = 6;
}

message GetBlockRequest {
  bytes id = 1;
}

message GetBlockResponse {
  bytes parent_id = 1;
  bytes bytes = 2;
  Status status = 3;
  uint64 height = 4;
  google.protobuf.Timestamp timestamp = 5;
  // used to propagate database.ErrNotFound through RPC
  Error err = 6;
  bool verify_with_context = 7;
}

message SetPreferenceRequest {
  bytes id = 1;
}

message BlockVerifyRequest {
  bytes bytes = 1;

  // If set, the VM server casts the block to a [block.WithVerifyContext] and
  // calls [VerifyWithContext] instead of [Verify].
  optional uint64 p_chain_height = 2;
}

message BlockVerifyResponse {
  google.protobuf.Timestamp timestamp = 1;
}

message BlockAcceptRequest {
  bytes id = 1;
}

message BlockRejectRequest {
  bytes id = 1;
}

message HealthResponse {
  bytes details = 1;
}

message VersionResponse {
  string version = 1;
}

message AppRequestMsg {
  // The node that sent us this request
  bytes node_id = 1;
  // The ID of this request
  uint32 request_id = 2;
  // deadline for this request
  google.protobuf.Timestamp deadline = 3;
  // The request body
  bytes request = 4;
}

message AppRequestFailedMsg {
  // The node that we failed to get a response from
  bytes node_id = 1;
  // The ID of the request we sent and didn't get a response to
  uint32 request_id = 2;
}

message AppResponseMsg {
  // The node that we got a response from
  bytes node_id = 1;
  // Request ID of request that this is in response to
  uint32 request_id = 2;
  // The response body
  bytes response = 3;
}

message AppGossipMsg {
  // The node that sent us a gossip message
  bytes node_id = 1;
  // The message body
  bytes msg = 2;
}

message CrossChainAppRequestMsg {
  // The chain that sent us this request
  bytes chain_id = 1;
  // The ID of this request
  uint32 request_id = 2;
  // deadline for this request
  google.protobuf.Timestamp deadline = 3;
  // The request body
  bytes request = 4;
}

message CrossChainAppRequestFailedMsg {
  // The chain that we failed to get a response from
  bytes chain_id = 1;
  // The ID of the request we sent and didn't get a response to
  uint32 request_id = 2;
}

message CrossChainAppResponseMsg {
  // The chain that we got a response from
  bytes chain_id = 1;
  // Request ID of request that this is in response to
  uint32 request_id = 2;
  // The response body
  bytes response = 3;
}

message ConnectedRequest {
  bytes node_id = 1;
  string version = 2;
}

message DisconnectedRequest {
  bytes node_id = 1;
}

message GetAncestorsRequest {
  bytes blk_id = 1;
  int32 max_blocks_num = 2;
  int32 max_blocks_size = 3;
  int64 max_blocks_retrival_time = 4;
}

message GetAncestorsResponse {
  repeated bytes blks_bytes = 1;
}

message BatchedParseBlockRequest {
  repeated bytes request = 1;
}

message BatchedParseBlockResponse {
  repeated ParseBlockResponse response = 1;
}

message VerifyHeightIndexResponse {
  Error err = 1;
}

message GetBlockIDAtHeightRequest {
  uint64 height = 1;
}

message GetBlockIDAtHeightResponse {
  bytes blk_id = 1;
  Error err = 2;
}

message GatherResponse {
  repeated io.prometheus.client.MetricFamily metric_families = 1;
}

message StateSyncEnabledResponse {
  bool enabled = 1;
  Error err = 2;
}

message GetOngoingSyncStateSummaryResponse {
  bytes id = 1;
  uint64 height = 2;
  bytes bytes = 3;
  Error err = 4;
}

message GetLastStateSummaryResponse {
  bytes id = 1;
  uint64 height = 2;
  bytes bytes = 3;
  Error err = 4;
}

message ParseStateSummaryRequest {
  bytes bytes = 1;
}

message ParseStateSummaryResponse {
  bytes id = 1;
  uint64 height = 2;
  Error err = 3;
}

message GetStateSummaryRequest {
  uint64 height = 1;
}

message GetStateSummaryResponse {
  bytes id = 1;
  bytes bytes = 2;
  Error err = 3;
}

message StateSummaryAcceptRequest {
  bytes bytes = 1;
}

message StateSummaryAcceptResponse {
  enum Mode {
    MODE_UNSPECIFIED = 0;
    MODE_SKIPPED = 1;
    MODE_STATIC = 2;
    MODE_DYNAMIC = 3;
  }
  Mode mode = 1;
  Error err = 2;
}
