syntax = "proto3";
package tendermint.abci;

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

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

// This file is copied from http://github.com/tendermint/abci
// NOTE: When using custom types, mind the warnings.
// https://github.com/gogo/protobuf/blob/master/custom_types.md#warnings-and-issues

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

message Request {
  oneof value {
    RequestEcho               echo                 = 1;
    RequestFlush              flush                = 2;
    RequestInfo               info                 = 3;
    RequestInitChain          init_chain           = 4;
    RequestQuery              query                = 5;
    RequestBeginBlock         begin_block          = 6;
    RequestCheckTx            check_tx             = 7;
    RequestDeliverTx          deliver_tx           = 8;
    RequestEndBlock           end_block            = 9;
    RequestCommit             commit               = 10;
    RequestListSnapshots      list_snapshots       = 11;
    RequestOfferSnapshot      offer_snapshot       = 12;
    RequestLoadSnapshotChunk  load_snapshot_chunk  = 13;
    RequestApplySnapshotChunk apply_snapshot_chunk = 14;
  }
}

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;
  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;
}

message RequestBeginBlock {
  bytes                   hash                 = 1;
  tendermint.types.Header header               = 2 [(gogoproto.nullable) = false];
  LastCommitInfo          last_commit_info     = 3 [(gogoproto.nullable) = false];
  repeated Evidence       byzantine_validators = 4 [(gogoproto.nullable) = false];
}

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

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

message RequestDeliverTx {
  bytes tx = 1;
}

message RequestEndBlock {
  int64 height = 1;
}

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;
}

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

message Response {
  oneof value {
    ResponseException          exception            = 1;
    ResponseEcho               echo                 = 2;
    ResponseFlush              flush                = 3;
    ResponseInfo               info                 = 4;
    ResponseInitChain          init_chain           = 5;
    ResponseQuery              query                = 6;
    ResponseBeginBlock         begin_block          = 7;
    ResponseCheckTx            check_tx             = 8;
    ResponseDeliverTx          deliver_tx           = 9;
    ResponseEndBlock           end_block            = 10;
    ResponseCommit             commit               = 11;
    ResponseListSnapshots      list_snapshots       = 12;
    ResponseOfferSnapshot      offer_snapshot       = 13;
    ResponseLoadSnapshotChunk  load_snapshot_chunk  = 14;
    ResponseApplySnapshotChunk apply_snapshot_chunk = 15;
  }
}

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

message ResponseEcho {
  string message = 1;
}

message ResponseFlush {}

message ResponseInfo {
  string data = 1;

  // this is the software version of the application. TODO: remove?
  string version     = 2;
  uint64 app_version = 3;

  int64 last_block_height   = 4;
  bytes last_block_app_hash = 5;
}

message ResponseInitChain {
  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 ResponseBeginBlock {
  repeated Event events = 1
      [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"];
}

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;
}

message ResponseDeliverTx {
  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;
}

message ResponseEndBlock {
  repeated ValidatorUpdate validator_updates = 1
      [(gogoproto.nullable) = false];
  ConsensusParams consensus_param_updates = 2;
  repeated Event  events                  = 3
      [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"];
}

message ResponseCommit {
  // reserve 1
  bytes data          = 2;
  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
  }
}

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

// ConsensusParams contains all consensus-relevant parameters
// that can be adjusted by the abci app
message ConsensusParams {
  BlockParams                      block     = 1;
  tendermint.types.EvidenceParams  evidence  = 2;
  tendermint.types.ValidatorParams validator = 3;
  tendermint.types.VersionParams   version   = 4;
}

// BlockParams contains limits on the block size.
message BlockParams {
  // Note: must be greater than 0
  int64 max_bytes = 1;
  // Note: must be greater or equal to -1
  int64 max_gas = 2;
}

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

// Event allows application developers to attach additional information to
// ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx.
// 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 {
  bytes key   = 1;
  bytes value = 2;
  bool  index = 3;  // nondeterministic
}

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

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

// Validator
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
}

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

// VoteInfo
message VoteInfo {
  Validator validator         = 1 [(gogoproto.nullable) = false];
  bool      signed_last_block = 2;
}

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

message Evidence {
  EvidenceType 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
}

//----------------------------------------
// Service Definition

service ABCIApplication {
  rpc Echo(RequestEcho) returns (ResponseEcho);
  rpc Flush(RequestFlush) returns (ResponseFlush);
  rpc Info(RequestInfo) returns (ResponseInfo);
  rpc DeliverTx(RequestDeliverTx) returns (ResponseDeliverTx);
  rpc CheckTx(RequestCheckTx) returns (ResponseCheckTx);
  rpc Query(RequestQuery) returns (ResponseQuery);
  rpc Commit(RequestCommit) returns (ResponseCommit);
  rpc InitChain(RequestInitChain) returns (ResponseInitChain);
  rpc BeginBlock(RequestBeginBlock) returns (ResponseBeginBlock);
  rpc EndBlock(RequestEndBlock) returns (ResponseEndBlock);
  rpc ListSnapshots(RequestListSnapshots) returns (ResponseListSnapshots);
  rpc OfferSnapshot(RequestOfferSnapshot) returns (ResponseOfferSnapshot);
  rpc LoadSnapshotChunk(RequestLoadSnapshotChunk) returns (ResponseLoadSnapshotChunk);
  rpc ApplySnapshotChunk(RequestApplySnapshotChunk) returns (ResponseApplySnapshotChunk);
}
