syntax = "proto3";
package tendermint.abci;

option go_package = "github.com/cometbft/cometbft/abci/types";

// For more information on gogo.proto, see:
// https://github.com/cosmos/gogoproto/blob/master/extensions.md
import "tendermint/crypto/proof.proto";
import "tendermint/crypto/keys.proto";
import "tendermint/types/params.proto";
import "tendermint/types/validator.proto";
import "google/protobuf/timestamp.proto";
import "gogoproto/gogo.proto";

// NOTE: When using custom types, mind the warnings.
// https://github.com/cosmos/gogoproto/blob/master/custom_types.md#warnings-and-issues

service ABCI {
  rpc Echo(RequestEcho) returns (ResponseEcho);
  rpc Flush(RequestFlush) returns (ResponseFlush);
  rpc Info(RequestInfo) returns (ResponseInfo);
  rpc CheckTx(RequestCheckTx) returns (ResponseCheckTx);
  rpc Query(RequestQuery) returns (ResponseQuery);
  rpc Commit(RequestCommit) returns (ResponseCommit);
  rpc InitChain(RequestInitChain) returns (ResponseInitChain);
  rpc ListSnapshots(RequestListSnapshots) returns (ResponseListSnapshots);
  rpc OfferSnapshot(RequestOfferSnapshot) returns (ResponseOfferSnapshot);
  rpc LoadSnapshotChunk(RequestLoadSnapshotChunk) returns (ResponseLoadSnapshotChunk);
  rpc ApplySnapshotChunk(RequestApplySnapshotChunk) returns (ResponseApplySnapshotChunk);
  rpc PrepareProposal(RequestPrepareProposal) returns (ResponsePrepareProposal);
  rpc ProcessProposal(RequestProcessProposal) returns (ResponseProcessProposal);
  rpc ExtendVote(RequestExtendVote) returns (ResponseExtendVote);
  rpc VerifyVoteExtension(RequestVerifyVoteExtension) returns (ResponseVerifyVoteExtension);
  rpc FinalizeBlock(RequestFinalizeBlock) returns (ResponseFinalizeBlock);
}

//----------------------------------------
// Request types

message Request {
  oneof value {
    RequestEcho                echo                  = 1;
    RequestFlush               flush                 = 2;
    RequestInfo                info                  = 3;
    RequestInitChain           init_chain            = 5;
    RequestQuery               query                 = 6;
    RequestCheckTx             check_tx              = 8;
    RequestCommit              commit                = 11;
    RequestListSnapshots       list_snapshots        = 12;
    RequestOfferSnapshot       offer_snapshot        = 13;
    RequestLoadSnapshotChunk   load_snapshot_chunk   = 14;
    RequestApplySnapshotChunk  apply_snapshot_chunk  = 15;
    RequestPrepareProposal     prepare_proposal      = 16;
    RequestProcessProposal     process_proposal      = 17;
    RequestExtendVote          extend_vote           = 18;
    RequestVerifyVoteExtension verify_vote_extension = 19;
    RequestFinalizeBlock       finalize_block        = 20;
  }
  reserved 4, 7, 9, 10; // SetOption, BeginBlock, DeliverTx, EndBlock
}

message RequestEcho {
  string message = 1;
}

message RequestFlush {}

message RequestInfo {
  string version       = 1;
  uint64 block_version = 2;
  uint64 p2p_version   = 3;
  string abci_version  = 4;
}

message RequestInitChain {
  google.protobuf.Timestamp        time             = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
  string                           chain_id         = 2;
  tendermint.types.ConsensusParams consensus_params = 3;
  repeated ValidatorUpdate         validators       = 4 [(gogoproto.nullable) = false];
  bytes                            app_state_bytes  = 5;
  int64                            initial_height   = 6;
}

message RequestQuery {
  bytes  data   = 1;
  string path   = 2;
  int64  height = 3;
  bool   prove  = 4;
}

enum CheckTxType {
  NEW     = 0 [(gogoproto.enumvalue_customname) = "New"];
  RECHECK = 1 [(gogoproto.enumvalue_customname) = "Recheck"];
}

message RequestCheckTx {
  bytes       tx   = 1;
  CheckTxType type = 2;
}

message RequestCommit {}

// lists available snapshots
message RequestListSnapshots {}

// offers a snapshot to the application
message RequestOfferSnapshot {
  Snapshot snapshot = 1; // snapshot offered by peers
  bytes    app_hash = 2; // light client-verified app hash for snapshot height
}

// loads a snapshot chunk
message RequestLoadSnapshotChunk {
  uint64 height = 1;
  uint32 format = 2;
  uint32 chunk  = 3;
}

// Applies a snapshot chunk
message RequestApplySnapshotChunk {
  uint32 index  = 1;
  bytes  chunk  = 2;
  string sender = 3;
}

message RequestPrepareProposal {
  // the modified transactions cannot exceed this size.
  int64 max_tx_bytes = 1;
  // txs is an array of transactions that will be included in a block,
  // sent to the app for possible modifications.
  repeated bytes            txs                  = 2;
  ExtendedCommitInfo        local_last_commit    = 3 [(gogoproto.nullable) = false];
  repeated Misbehavior      misbehavior          = 4 [(gogoproto.nullable) = false];
  int64                     height               = 5;
  google.protobuf.Timestamp time                 = 6 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
  bytes                     next_validators_hash = 7;
  // address of the public key of the validator proposing the block.
  bytes proposer_address = 8;
}

message RequestProcessProposal {
  repeated bytes       txs                  = 1;
  CommitInfo           proposed_last_commit = 2 [(gogoproto.nullable) = false];
  repeated Misbehavior misbehavior          = 3 [(gogoproto.nullable) = false];
  // hash is the merkle root hash of the fields of the proposed block.
  bytes                     hash                 = 4;
  int64                     height               = 5;
  google.protobuf.Timestamp time                 = 6 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
  bytes                     next_validators_hash = 7;
  // address of the public key of the original proposer of the block.
  bytes proposer_address = 8;
}

// Extends a vote with application-injected data
message RequestExtendVote {
  // the hash of the block that this vote may be referring to
  bytes hash = 1;
  // the height of the extended vote
  int64 height = 2;
  // info of the block that this vote may be referring to
  google.protobuf.Timestamp time                 = 3 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
  repeated bytes            txs                  = 4;
  CommitInfo                proposed_last_commit = 5 [(gogoproto.nullable) = false];
  repeated Misbehavior      misbehavior          = 6 [(gogoproto.nullable) = false];
  bytes                     next_validators_hash = 7;
  // address of the public key of the original proposer of the block.
  bytes proposer_address = 8;
}

// Verify the vote extension
message RequestVerifyVoteExtension {
  // the hash of the block that this received vote corresponds to
  bytes hash = 1;
  // the validator that signed the vote extension
  bytes validator_address = 2;
  int64 height            = 3;
  bytes vote_extension    = 4;
}

message RequestFinalizeBlock {
  repeated bytes       txs                 = 1;
  CommitInfo           decided_last_commit = 2 [(gogoproto.nullable) = false];
  repeated Misbehavior misbehavior         = 3 [(gogoproto.nullable) = false];
  // hash is the merkle root hash of the fields of the decided block.
  bytes                     hash                 = 4;
  int64                     height               = 5;
  google.protobuf.Timestamp time                 = 6 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
  bytes                     next_validators_hash = 7;
  // proposer_address is the address of the public key of the original proposer of the block.
  bytes proposer_address = 8;
}

//----------------------------------------
// Response types

message Response {
  oneof value {
    ResponseException           exception             = 1;
    ResponseEcho                echo                  = 2;
    ResponseFlush               flush                 = 3;
    ResponseInfo                info                  = 4;
    ResponseInitChain           init_chain            = 6;
    ResponseQuery               query                 = 7;
    ResponseCheckTx             check_tx              = 9;
    ResponseCommit              commit                = 12;
    ResponseListSnapshots       list_snapshots        = 13;
    ResponseOfferSnapshot       offer_snapshot        = 14;
    ResponseLoadSnapshotChunk   load_snapshot_chunk   = 15;
    ResponseApplySnapshotChunk  apply_snapshot_chunk  = 16;
    ResponsePrepareProposal     prepare_proposal      = 17;
    ResponseProcessProposal     process_proposal      = 18;
    ResponseExtendVote          extend_vote           = 19;
    ResponseVerifyVoteExtension verify_vote_extension = 20;
    ResponseFinalizeBlock       finalize_block        = 21;
  }
  reserved 5, 8, 10, 11; // SetOption, BeginBlock, DeliverTx, EndBlock
}

// nondeterministic
message ResponseException {
  string error = 1;
}

message ResponseEcho {
  string message = 1;
}

message ResponseFlush {}

message ResponseInfo {
  string data = 1;

  string version     = 2;
  uint64 app_version = 3;

  int64 last_block_height   = 4;
  bytes last_block_app_hash = 5;
}

message ResponseInitChain {
  tendermint.types.ConsensusParams consensus_params = 1;
  repeated ValidatorUpdate         validators       = 2 [(gogoproto.nullable) = false];
  bytes                            app_hash         = 3;
}

message ResponseQuery {
  uint32 code = 1;
  // bytes data = 2; // use "value" instead.
  string                     log       = 3; // nondeterministic
  string                     info      = 4; // nondeterministic
  int64                      index     = 5;
  bytes                      key       = 6;
  bytes                      value     = 7;
  tendermint.crypto.ProofOps proof_ops = 8;
  int64                      height    = 9;
  string                     codespace = 10;
}

message ResponseCheckTx {
  uint32         code       = 1;
  bytes          data       = 2;
  string         log        = 3; // nondeterministic
  string         info       = 4; // nondeterministic
  int64          gas_wanted = 5 [json_name = "gas_wanted"];
  int64          gas_used   = 6 [json_name = "gas_used"];
  repeated Event events     = 7 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"];
  string         codespace  = 8;

  // These reserved fields were used until v0.37 by the priority mempool (now
  // removed).
  reserved 9 to 11;
  reserved "sender", "priority", "mempool_error";
}

message ResponseCommit {
  reserved 1, 2; // data was previously returned here
  int64 retain_height = 3;
}

message ResponseListSnapshots {
  repeated Snapshot snapshots = 1;
}

message ResponseOfferSnapshot {
  Result result = 1;

  enum Result {
    UNKNOWN       = 0; // Unknown result, abort all snapshot restoration
    ACCEPT        = 1; // Snapshot accepted, apply chunks
    ABORT         = 2; // Abort all snapshot restoration
    REJECT        = 3; // Reject this specific snapshot, try others
    REJECT_FORMAT = 4; // Reject all snapshots of this format, try others
    REJECT_SENDER = 5; // Reject all snapshots from the sender(s), try others
  }
}

message ResponseLoadSnapshotChunk {
  bytes chunk = 1;
}

message ResponseApplySnapshotChunk {
  Result          result         = 1;
  repeated uint32 refetch_chunks = 2; // Chunks to refetch and reapply
  repeated string reject_senders = 3; // Chunk senders to reject and ban

  enum Result {
    UNKNOWN         = 0; // Unknown result, abort all snapshot restoration
    ACCEPT          = 1; // Chunk successfully accepted
    ABORT           = 2; // Abort all snapshot restoration
    RETRY           = 3; // Retry chunk (combine with refetch and reject)
    RETRY_SNAPSHOT  = 4; // Retry snapshot (combine with refetch and reject)
    REJECT_SNAPSHOT = 5; // Reject this snapshot, try others
  }
}

message ResponsePrepareProposal {
  repeated bytes txs = 1;
}

message ResponseProcessProposal {
  ProposalStatus status = 1;

  enum ProposalStatus {
    UNKNOWN = 0;
    ACCEPT  = 1;
    REJECT  = 2;
  }
}

message ResponseExtendVote {
  bytes vote_extension = 1;
}

message ResponseVerifyVoteExtension {
  VerifyStatus status = 1;

  enum VerifyStatus {
    UNKNOWN = 0;
    ACCEPT  = 1;
    // Rejecting the vote extension will reject the entire precommit by the sender.
    // Incorrectly implementing this thus has liveness implications as it may affect
    // CometBFT's ability to receive 2/3+ valid votes to finalize the block.
    // Honest nodes should never be rejected.
    REJECT = 2;
  }
}

message ResponseFinalizeBlock {
  // set of block events emmitted as part of executing the block
  repeated Event events = 1 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"];
  // the result of executing each transaction including the events
  // the particular transction emitted. This should match the order
  // of the transactions delivered in the block itself
  repeated ExecTxResult tx_results = 2;
  // a list of updates to the validator set. These will reflect the validator set at current height + 2.
  repeated ValidatorUpdate validator_updates = 3 [(gogoproto.nullable) = false];
  // updates to the consensus params, if any.
  tendermint.types.ConsensusParams consensus_param_updates = 4;
  // app_hash is the hash of the applications' state which is used to confirm that execution of the transactions was
  // deterministic. It is up to the application to decide which algorithm to use.
  bytes app_hash = 5;
}

//----------------------------------------
// Misc.

message CommitInfo {
  int32             round = 1;
  repeated VoteInfo votes = 2 [(gogoproto.nullable) = false];
}

// ExtendedCommitInfo is similar to CommitInfo except that it is only used in
// the PrepareProposal request such that CometBFT can provide vote extensions
// to the application.
message ExtendedCommitInfo {
  // The round at which the block proposer decided in the previous height.
  int32 round = 1;
  // List of validators' addresses in the last validator set with their voting
  // information, including vote extensions.
  repeated ExtendedVoteInfo votes = 2 [(gogoproto.nullable) = false];
}

// Event allows application developers to attach additional information to
// ResponseFinalizeBlock and ResponseCheckTx.
// Later, transactions may be queried using these events.
message Event {
  string                  type       = 1;
  repeated EventAttribute attributes = 2 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "attributes,omitempty"];
}

// EventAttribute is a single key-value pair, associated with an event.
message EventAttribute {
  string key   = 1;
  string value = 2;
  bool   index = 3; // nondeterministic
}

// ExecTxResult contains results of executing one individual transaction.
//
// * Its structure is equivalent to #ResponseDeliverTx which will be deprecated/deleted
message ExecTxResult {
  uint32         code       = 1;
  bytes          data       = 2;
  string         log        = 3; // nondeterministic
  string         info       = 4; // nondeterministic
  int64          gas_wanted = 5 [json_name = "gas_wanted"];
  int64          gas_used   = 6 [json_name = "gas_used"];
  repeated Event events     = 7
      [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; // nondeterministic
  string codespace = 8;
}

// TxResult contains results of executing the transaction.
//
// One usage is indexing transaction results.
message TxResult {
  int64        height = 1;
  uint32       index  = 2;
  bytes        tx     = 3;
  ExecTxResult result = 4 [(gogoproto.nullable) = false];
}

//----------------------------------------
// Blockchain Types

message Validator {
  bytes address = 1; // The first 20 bytes of SHA256(public key)
  // PubKey pub_key = 2 [(gogoproto.nullable)=false];
  int64 power = 3; // The voting power
}

message ValidatorUpdate {
  tendermint.crypto.PublicKey pub_key = 1 [(gogoproto.nullable) = false];
  int64                       power   = 2;
}

message VoteInfo {
  Validator                    validator     = 1 [(gogoproto.nullable) = false];
  tendermint.types.BlockIDFlag block_id_flag = 3;

  reserved 2; // signed_last_block
}

message ExtendedVoteInfo {
  // The validator that sent the vote.
  Validator validator = 1 [(gogoproto.nullable) = false];
  // Non-deterministic extension provided by the sending validator's application.
  bytes vote_extension = 3;
  // Vote extension signature created by CometBFT
  bytes extension_signature = 4;
  // block_id_flag indicates whether the validator voted for a block, nil, or did not vote at all
  tendermint.types.BlockIDFlag block_id_flag = 5;

  reserved 2; // signed_last_block
}

enum MisbehaviorType {
  UNKNOWN             = 0;
  DUPLICATE_VOTE      = 1;
  LIGHT_CLIENT_ATTACK = 2;
}

message Misbehavior {
  MisbehaviorType type = 1;
  // The offending validator
  Validator validator = 2 [(gogoproto.nullable) = false];
  // The height when the offense occurred
  int64 height = 3;
  // The corresponding time where the offense occurred
  google.protobuf.Timestamp time = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
  // Total voting power of the validator set in case the ABCI application does
  // not store historical validators.
  // https://github.com/tendermint/tendermint/issues/4581
  int64 total_voting_power = 5;
}

//----------------------------------------
// State Sync Types

message Snapshot {
  uint64 height   = 1; // The height at which the snapshot was taken
  uint32 format   = 2; // The application-specific snapshot format
  uint32 chunks   = 3; // Number of chunks in the snapshot
  bytes  hash     = 4; // Arbitrary snapshot hash, equal only if identical
  bytes  metadata = 5; // Arbitrary application metadata
}
