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
}
