// RPC-related types. Request messages, response messages, and dependant types.
//
// Clients are expected to build RequestMessages and wrap them in KaspadMessage. (see messages.proto)
//
// Having received a RequestMessage, (wrapped in a KaspadMessage) the RPC server will respond with a
// ResponseMessage (likewise wrapped in a KaspadMessage) respective to the original RequestMessage.
//
// **IMPORTANT:** This API is a work in progress and is subject to break between versions.
//
syntax = "proto3";
package protowire;

// RPCError represents a generic non-internal error.
//
// Receivers of any ResponseMessage are expected to check whether its error field is not null.
message RPCError{
  string message = 1;
}

message RpcBlock {
  RpcBlockHeader header = 1;
  repeated RpcTransaction transactions = 2;
  RpcBlockVerboseData verboseData = 3;
}

message RpcBlockHeader {
  uint32 version = 1;
  repeated RpcBlockLevelParents parents = 12;
  string hashMerkleRoot = 3;
  string acceptedIdMerkleRoot = 4;
  string utxoCommitment = 5;
  int64 timestamp = 6;
  uint32 bits = 7;
  uint64 nonce = 8;
  uint64 daaScore = 9;
  string blueWork = 10;
  string pruningPoint = 14;
  uint64 blueScore = 13;
}

message RpcBlockLevelParents {
  repeated string parentHashes = 1;
}

message RpcBlockVerboseData{
  string hash = 1;
  double difficulty = 11;
  string selectedParentHash = 13;
  repeated string transactionIds = 14;
  bool isHeaderOnly = 15;
  uint64 blueScore = 16;
  repeated string childrenHashes = 17;
  repeated string mergeSetBluesHashes = 18;
  repeated string mergeSetRedsHashes = 19;
  bool isChainBlock = 20;
}

message RpcTransaction {
  uint32 version = 1;
  repeated RpcTransactionInput inputs = 2;
  repeated RpcTransactionOutput outputs = 3;
  uint64 lockTime = 4;
  string subnetworkId = 5;
  uint64 gas = 6;
  string payload = 8;
  RpcTransactionVerboseData verboseData = 9;
  uint64 mass = 10;
}

message RpcTransactionInput {
  RpcOutpoint previousOutpoint = 1;
  string signatureScript = 2;
  uint64 sequence = 3;
  uint32 sigOpCount = 5;
  RpcTransactionInputVerboseData verboseData = 4;
}

message RpcScriptPublicKey {
  uint32 version = 1;
  string scriptPublicKey = 2;
}

message RpcTransactionOutput {
  uint64 amount = 1;
  RpcScriptPublicKey scriptPublicKey = 2;
  RpcTransactionOutputVerboseData verboseData = 3;
}

message RpcOutpoint {
  string transactionId = 1;
  uint32 index = 2;
}

message RpcUtxoEntry {
  uint64 amount = 1;
  RpcScriptPublicKey scriptPublicKey = 2;
  uint64 blockDaaScore = 3;
  bool isCoinbase = 4;
}

message RpcTransactionVerboseData{
  string transactionId = 1;
  string hash = 2;
  uint64 mass = 4;
  string blockHash = 12;
  uint64 blockTime = 14;
}

message RpcTransactionInputVerboseData{
}

message RpcTransactionOutputVerboseData{
  string scriptPublicKeyType = 5;
  string scriptPublicKeyAddress = 6;
}

enum RpcNotifyCommand {
  NOTIFY_START = 0;
  NOTIFY_STOP = 1;
}

// GetCurrentNetworkRequestMessage requests the network kaspad is currently running against.
//
// Possible networks are: Mainnet, Testnet, Simnet, Devnet
message GetCurrentNetworkRequestMessage{
}

message GetCurrentNetworkResponseMessage{
  string currentNetwork = 1;
  RPCError error = 1000;
}

// SubmitBlockRequestMessage requests to submit a block into the DAG.
// Blocks are generally expected to have been generated using the getBlockTemplate call.
//
// See: GetBlockTemplateRequestMessage
message SubmitBlockRequestMessage{
  RpcBlock block = 2;
  bool allowNonDAABlocks = 3;
}

message SubmitBlockResponseMessage{
  enum RejectReason {
    NONE = 0;
    BLOCK_INVALID = 1;
    IS_IN_IBD = 2;
  }
  RejectReason rejectReason = 1;
  RPCError error = 1000;
}

// GetBlockTemplateRequestMessage requests a current block template.
// Callers are expected to solve the block template and submit it using the submitBlock call
//
// See: SubmitBlockRequestMessage
message GetBlockTemplateRequestMessage{
  // Which kaspa address should the coinbase block reward transaction pay into
  string payAddress = 1;
  string extraData = 2;
}

message GetBlockTemplateResponseMessage{
  RpcBlock block = 3;

  // Whether kaspad thinks that it's synced.
  // Callers are discouraged (but not forbidden) from solving blocks when kaspad is not synced.
  // That is because when kaspad isn't in sync with the rest of the network there's a high
  // chance the block will never be accepted, thus the solving effort would have been wasted.
  bool isSynced = 2;

  RPCError error = 1000;
}

// NotifyBlockAddedRequestMessage registers this connection for blockAdded notifications.
//
// See: BlockAddedNotificationMessage
message NotifyBlockAddedRequestMessage{
  RpcNotifyCommand command = 101;
}

message NotifyBlockAddedResponseMessage{
  RPCError error = 1000;
}

// BlockAddedNotificationMessage is sent whenever a blocks has been added (NOT accepted)
// into the DAG.
//
// See: NotifyBlockAddedRequestMessage
message BlockAddedNotificationMessage{
  RpcBlock block = 3;
}

// GetPeerAddressesRequestMessage requests the list of known kaspad addresses in the
// current network. (mainnet, testnet, etc.)
message GetPeerAddressesRequestMessage{
}

message GetPeerAddressesResponseMessage{
  repeated GetPeerAddressesKnownAddressMessage addresses = 1;
  repeated GetPeerAddressesKnownAddressMessage bannedAddresses = 2;
  RPCError error = 1000;
}

message GetPeerAddressesKnownAddressMessage {
  string Addr = 1;
}

// GetSinkRequestMessage requests the hash of the current virtual's
// selected parent.
message GetSinkRequestMessage{
}

message GetSinkResponseMessage{
  string sink = 1;
  RPCError error = 1000;
}

// GetMempoolEntryRequestMessage requests information about a specific transaction
// in the mempool.
message GetMempoolEntryRequestMessage{
  // The transaction's TransactionID.
  string txId = 1;
  bool includeOrphanPool = 2;
  bool filterTransactionPool = 3;
}

message GetMempoolEntryResponseMessage{
  RpcMempoolEntry entry = 1;

  RPCError error = 1000;
}

// GetMempoolEntriesRequestMessage requests information about all the transactions
// currently in the mempool.
message GetMempoolEntriesRequestMessage{
  bool includeOrphanPool = 1;
  bool filterTransactionPool = 2;
}

message GetMempoolEntriesResponseMessage{
  repeated RpcMempoolEntry entries = 1;

  RPCError error = 1000;
}

message RpcMempoolEntry{
  uint64 fee = 1;
  RpcTransaction transaction = 3;
  bool isOrphan = 4;
}

// GetConnectedPeerInfoRequestMessage requests information about all the p2p peers
// currently connected to this kaspad.
message GetConnectedPeerInfoRequestMessage{
}

message GetConnectedPeerInfoResponseMessage{
  repeated GetConnectedPeerInfoMessage infos = 1;
  RPCError error = 1000;
}

message GetConnectedPeerInfoMessage{
  string id = 1;
  string address = 2;

  // How long did the last ping/pong exchange take
  int64 lastPingDuration = 3;

  // Whether this kaspad initiated the connection
  bool isOutbound = 6;
  int64 timeOffset = 7;
  string userAgent = 8;

  // The protocol version that this peer claims to support
  uint32 advertisedProtocolVersion = 9;

  // The timestamp of when this peer connected to this kaspad
  int64 timeConnected = 10;

  // Whether this peer is the IBD peer (if IBD is running)
  bool isIbdPeer = 11;
}

// AddPeerRequestMessage adds a peer to kaspad's outgoing connection list.
// This will, in most cases, result in kaspad connecting to said peer.
message AddPeerRequestMessage{
  string address = 1;

  // Whether to keep attempting to connect to this peer after disconnection
  bool isPermanent = 2;
}

message AddPeerResponseMessage{
  RPCError error = 1000;
}

// SubmitTransactionRequestMessage submits a transaction to the mempool
message SubmitTransactionRequestMessage{
  RpcTransaction transaction = 1;
  bool allowOrphan = 2;
}

message SubmitTransactionResponseMessage{
  // The transaction ID of the submitted transaction
  string transactionId = 1;

  RPCError error = 1000;
}

// NotifyVirtualChainChangedRequestMessage registers this connection for virtualChainChanged notifications.
//
// See: VirtualChainChangedNotificationMessage
message NotifyVirtualChainChangedRequestMessage{
  bool includeAcceptedTransactionIds = 1;
  RpcNotifyCommand command = 101;
}

message NotifyVirtualChainChangedResponseMessage{
  RPCError error = 1000;
}

// VirtualChainChangedNotificationMessage is sent whenever the DAG's selected parent
// chain had changed.
//
// See: NotifyVirtualChainChangedRequestMessage
message VirtualChainChangedNotificationMessage{
  // The chain blocks that were removed, in high-to-low order
  repeated string removedChainBlockHashes = 1;

  // The chain blocks that were added, in low-to-high order
  repeated string addedChainBlockHashes = 3;

  // Will be filled only if `includeAcceptedTransactionIds = true` in the notify request.
  repeated RpcAcceptedTransactionIds acceptedTransactionIds = 2;
}

// GetBlockRequestMessage requests information about a specific block
message GetBlockRequestMessage{
  // The hash of the requested block
  string hash = 1;

  // Whether to include transaction data in the response
  bool includeTransactions = 3;
}

message GetBlockResponseMessage{
  RpcBlock block = 3;
  RPCError error = 1000;
}

// GetSubnetworkRequestMessage requests information about a specific subnetwork
//
// Currently unimplemented
message GetSubnetworkRequestMessage{
  string subnetworkId = 1;
}

message GetSubnetworkResponseMessage{
  uint64 gasLimit = 1;
  RPCError error = 1000;
}

// GetVirtualChainFromBlockRequestMessage requests the virtual selected
// parent chain from some startHash to this kaspad's current virtual
message GetVirtualChainFromBlockRequestMessage{
  string startHash = 1;
  bool includeAcceptedTransactionIds = 2;
}

message RpcAcceptedTransactionIds{
  string acceptingBlockHash = 1;
  repeated string acceptedTransactionIds = 2;
}

message GetVirtualChainFromBlockResponseMessage{
  // The chain blocks that were removed, in high-to-low order
  repeated string removedChainBlockHashes = 1;

  // The chain blocks that were added, in low-to-high order
  repeated string addedChainBlockHashes = 3;

  // The transactions accepted by each block in addedChainBlockHashes.
  // Will be filled only if `includeAcceptedTransactionIds = true` in the request.
  repeated RpcAcceptedTransactionIds acceptedTransactionIds = 2;

  RPCError error = 1000;
}

// GetBlocksRequestMessage requests blocks between a certain block lowHash up to this
// kaspad's current virtual.
message GetBlocksRequestMessage{
  string lowHash = 1;
  bool includeBlocks = 2;
  bool includeTransactions = 3;
}

message GetBlocksResponseMessage{
  repeated string blockHashes = 4;
  repeated RpcBlock blocks = 3;
  RPCError error = 1000;
}

// GetBlockCountRequestMessage requests the current number of blocks in this kaspad.
// Note that this number may decrease as pruning occurs.
message GetBlockCountRequestMessage{
}

message GetBlockCountResponseMessage{
  uint64 blockCount = 1;
  uint64 headerCount = 2;
  RPCError error = 1000;
}

// GetBlockDagInfoRequestMessage requests general information about the current state
// of this kaspad's DAG.
message GetBlockDagInfoRequestMessage{
}

message GetBlockDagInfoResponseMessage{
  string networkName = 1;
  uint64 blockCount = 2;
  uint64 headerCount = 3;
  repeated string tipHashes = 4;
  double difficulty = 5;
  int64 pastMedianTime = 6;
  repeated string virtualParentHashes = 7;
  string pruningPointHash = 8;
  uint64 virtualDaaScore = 9;
  string sink = 10;
  RPCError error = 1000;
}

message ResolveFinalityConflictRequestMessage{
  string finalityBlockHash = 1;
}

message ResolveFinalityConflictResponseMessage{
  RPCError error = 1000;
}

message NotifyFinalityConflictRequestMessage{
  RpcNotifyCommand command = 101;
}

message NotifyFinalityConflictResponseMessage{
  RPCError error = 1000;
}

message FinalityConflictNotificationMessage{
  string violatingBlockHash = 1;
}

message FinalityConflictResolvedNotificationMessage{
  string finalityBlockHash = 1;
}

// ShutdownRequestMessage shuts down this kaspad.
message ShutdownRequestMessage{
}

message ShutdownResponseMessage{
  RPCError error = 1000;
}

// GetHeadersRequestMessage requests headers between the given startHash and the
// current virtual, up to the given limit.
message GetHeadersRequestMessage{
  string startHash = 1;
  uint64 limit = 2;
  bool isAscending = 3;
}

message GetHeadersResponseMessage{
  repeated string headers = 1;
  RPCError error = 1000;
}

// NotifyUtxosChangedRequestMessage registers this connection for utxoChanged notifications
// for the given addresses.
//
// This call is only available when this kaspad was started with `--utxoindex`
//
// See: UtxosChangedNotificationMessage
message NotifyUtxosChangedRequestMessage {
  // UTXOs addresses to start/stop getting notified about
  // Leave empty to start/stop all updates
  repeated string addresses = 1;
  RpcNotifyCommand command = 101;
}

message NotifyUtxosChangedResponseMessage {
  RPCError error = 1000;
}

// UtxosChangedNotificationMessage is sent whenever the UTXO index had been updated.
//
// See: NotifyUtxosChangedRequestMessage
message UtxosChangedNotificationMessage {
  repeated RpcUtxosByAddressesEntry added = 1;
  repeated RpcUtxosByAddressesEntry removed = 2;
}

message RpcUtxosByAddressesEntry {
  string address = 1;
  RpcOutpoint outpoint = 2;
  RpcUtxoEntry utxoEntry = 3;
}

// StopNotifyingUtxosChangedRequestMessage unregisters this connection for utxoChanged notifications
// for the given addresses.
//
// This call is only available when this kaspad was started with `--utxoindex`
//
// See: UtxosChangedNotificationMessage
//
// This message only exists for backward compatibility reason with kaspad and is deprecated.
// Use instead UtxosChangedNotificationMessage with command = NOTIFY_STOP.
message StopNotifyingUtxosChangedRequestMessage {
  repeated string addresses = 1;
}

message StopNotifyingUtxosChangedResponseMessage {
  RPCError error = 1000;
}

// GetUtxosByAddressesRequestMessage requests all current UTXOs for the given kaspad addresses
//
// This call is only available when this kaspad was started with `--utxoindex`
message GetUtxosByAddressesRequestMessage {
  repeated string addresses = 1;
}

message GetUtxosByAddressesResponseMessage {
  repeated RpcUtxosByAddressesEntry entries = 1;

  RPCError error = 1000;
}

// GetBalanceByAddressRequest returns the total balance in unspent transactions towards a given address
// 
// This call is only available when this kaspad was started with `--utxoindex`
message GetBalanceByAddressRequestMessage {
  string address = 1;
}

message GetBalanceByAddressResponseMessage {
  uint64 balance = 1;

  RPCError error = 1000;
}

message GetBalancesByAddressesRequestMessage {
  repeated string addresses = 1;
}

message RpcBalancesByAddressesEntry{
  string address = 1;
  uint64 balance = 2;

  RPCError error = 1000;
}

message GetBalancesByAddressesResponseMessage {
  repeated RpcBalancesByAddressesEntry entries = 1;

  RPCError error = 1000;
}

// GetSinkBlueScoreRequestMessage requests the blue score of the current selected parent
// of the virtual block.
message GetSinkBlueScoreRequestMessage {
}

message GetSinkBlueScoreResponseMessage {
  uint64 blueScore = 1;

  RPCError error = 1000;
}

// NotifySinkBlueScoreChangedRequestMessage registers this connection for
// sinkBlueScoreChanged notifications.
//
// See: SinkBlueScoreChangedNotificationMessage
message NotifySinkBlueScoreChangedRequestMessage {
  RpcNotifyCommand command = 101;
}

message NotifySinkBlueScoreChangedResponseMessage {
  RPCError error = 1000;
}

// SinkBlueScoreChangedNotificationMessage is sent whenever the blue score
// of the virtual's selected parent changes.
//
// See NotifySinkBlueScoreChangedRequestMessage
message SinkBlueScoreChangedNotificationMessage {
  uint64 sinkBlueScore = 1;
}

// NotifyVirtualDaaScoreChangedRequestMessage registers this connection for
// virtualDaaScoreChanged notifications.
//
// See: VirtualDaaScoreChangedNotificationMessage
message NotifyVirtualDaaScoreChangedRequestMessage {
  RpcNotifyCommand command = 101;
}

message NotifyVirtualDaaScoreChangedResponseMessage {
  RPCError error = 1000;
}

// VirtualDaaScoreChangedNotificationMessage is sent whenever the DAA score
// of the virtual changes.
//
// See NotifyVirtualDaaScoreChangedRequestMessage
message VirtualDaaScoreChangedNotificationMessage {
  uint64 virtualDaaScore = 1;
}

// NotifyPruningPointUtxoSetOverrideRequestMessage registers this connection for
// pruning point UTXO set override notifications.
//
// This call is only available when this kaspad was started with `--utxoindex`
//
// See: NotifyPruningPointUtxoSetOverrideResponseMessage
message NotifyPruningPointUtxoSetOverrideRequestMessage {
  RpcNotifyCommand command = 101;
}


message NotifyPruningPointUtxoSetOverrideResponseMessage {
  RPCError error = 1000;
}

// PruningPointUtxoSetOverrideNotificationMessage is sent whenever the UTXO index
// resets due to pruning point change via IBD.
//
// See NotifyPruningPointUtxoSetOverrideRequestMessage
message PruningPointUtxoSetOverrideNotificationMessage {
}

// StopNotifyingPruningPointUtxoSetOverrideRequestMessage unregisters this connection for
// pruning point UTXO set override notifications.
//
// This call is only available when this kaspad was started with `--utxoindex`
//
// See: PruningPointUtxoSetOverrideNotificationMessage
//
// This message only exists for backward compatibility reason with kaspad and is deprecated.
// Use instead NotifyPruningPointUtxoSetOverrideRequestMessage with command = NOTIFY_STOP.
message StopNotifyingPruningPointUtxoSetOverrideRequestMessage {
}

message StopNotifyingPruningPointUtxoSetOverrideResponseMessage {
  RPCError error = 1000;
}

// BanRequestMessage bans the given ip.
message BanRequestMessage{
  string ip = 1;
}

message BanResponseMessage{
  RPCError error = 1000;
}

// UnbanRequestMessage unbans the given ip.
message UnbanRequestMessage{
  string ip = 1;
}

message UnbanResponseMessage{
  RPCError error = 1000;
}

// GetInfoRequestMessage returns info about the node.
message GetInfoRequestMessage{
}

message GetInfoResponseMessage{
  string p2pId = 1;
  uint64 mempoolSize = 2;
  string serverVersion = 3;
  bool isUtxoIndexed = 4;
  bool isSynced = 5;
  bool hasNotifyCommand = 11;
  bool hasMessageId = 12;
  RPCError error = 1000;
}

message EstimateNetworkHashesPerSecondRequestMessage{
  uint32 windowSize = 1;
  string startHash = 2;
}

message EstimateNetworkHashesPerSecondResponseMessage{
  uint64 networkHashesPerSecond = 1;
  RPCError error = 1000;
}

// NotifyNewBlockTemplateRequestMessage registers this connection for
// NewBlockTemplate notifications.
//
// See: NewBlockTemplateNotificationMessage
message NotifyNewBlockTemplateRequestMessage {
  RpcNotifyCommand command = 101;
}

message NotifyNewBlockTemplateResponseMessage {
  RPCError error = 1000;
}

// NewBlockTemplateNotificationMessage is sent whenever a new updated block template is
// available for miners.
//
// See NotifyNewBlockTemplateRequestMessage
message NewBlockTemplateNotificationMessage {
}

message RpcMempoolEntryByAddress{
  string address = 1;
  repeated RpcMempoolEntry sending = 2;
  repeated RpcMempoolEntry receiving = 3;
}

message GetMempoolEntriesByAddressesRequestMessage{
  repeated string addresses = 1;
  bool includeOrphanPool = 2;
  bool filterTransactionPool = 3;
}

message  GetMempoolEntriesByAddressesResponseMessage{
  repeated RpcMempoolEntryByAddress entries = 1;

  RPCError error = 1000;
}

message GetCoinSupplyRequestMessage{
}

message GetCoinSupplyResponseMessage{
  uint64 maxSompi = 1; // note: this is a hard coded maxSupply, actual maxSupply is expected to deviate by upto -5%, but cannot be measured exactly.
  uint64 circulatingSompi = 2;

  RPCError error = 1000;
}

message PingRequestMessage{
}

message PingResponseMessage{
  RPCError error = 1000;
}

message ProcessMetrics{
  uint64 residentSetSize = 1;
  uint64 virtualMemorySize = 2;
  uint32 coreNum = 3;
  float cpuUsage = 4;
  uint32 fdNum = 5;
  uint64 diskIoReadBytes = 6;
  uint64 diskIoWriteBytes = 7;
  float diskIoReadPerSec = 8;
  float diskIoWritePerSec = 9;
}

message ConnectionMetrics {
  uint32 borshLiveConnections = 31;
  uint64 borshConnectionAttempts = 32;
  uint64 borshHandshakeFailures = 33;

  uint32 jsonLiveConnections = 41;
  uint64 jsonConnectionAttempts = 42;
  uint64 jsonHandshakeFailures = 43;
  
  uint32 activePeers = 51;
}

message BandwidthMetrics {
  uint64 borshBytesTx = 61;
  uint64 borshBytesRx = 62;
  uint64 jsonBytesTx = 63;
  uint64 jsonBytesRx = 64;
  uint64 grpcP2pBytesTx = 65;
  uint64 grpcP2pBytesRx = 66;
  uint64 grpcUserBytesTx = 67;
  uint64 grpcUserBytesRx = 68;
}

message ConsensusMetrics{
  uint64 blocksSubmitted = 1;
  uint64 headerCounts = 2;
  uint64 depCounts = 3;
  uint64 bodyCounts = 4;
  uint64 txsCounts = 5;
  uint64 chainBlockCounts = 6;
  uint64 massCounts = 7;
  
  uint64 blockCount = 11;
  uint64 headerCount = 12;
  uint64 mempoolSize = 13;
  uint32 tipHashesCount = 14;
  double difficulty = 15;
  uint64 pastMedianTime = 16;
  uint32 virtualParentHashesCount = 17;
  uint64 virtualDaaScore = 18;
}

message GetMetricsRequestMessage{
  bool processMetrics = 1;
  bool connectionMetrics = 2;
  bool bandwidthMetrics = 3;
  bool consensusMetrics = 4;
}

message GetMetricsResponseMessage{
  uint64 serverTime = 1;
  ProcessMetrics processMetrics = 11;
  ConnectionMetrics connectionMetrics = 12;
  BandwidthMetrics bandwidthMetrics = 13;
  ConsensusMetrics consensusMetrics = 14;
  RPCError error = 1000;
}

message GetServerInfoRequestMessage{
}

message GetServerInfoResponseMessage{
  repeated uint32 rpcApiVersion = 1; // Expecting exactly 4 elements
  string serverVersion = 2;
  string networkId = 3;
  bool hasUtxoIndex = 4;
  bool isSynced = 5;
  uint64 virtualDaaScore = 6;
  RPCError error = 1000;
}

message GetSyncStatusRequestMessage{
}

message GetSyncStatusResponseMessage{
  bool isSynced = 1;
  RPCError error = 1000;
}

message GetDaaScoreTimestampEstimateRequestMessage {
        repeated uint64 daa_scores = 1;
}

message GetDaaScoreTimestampEstimateResponseMessage{
        repeated uint64 timestamps = 1;
        RPCError error = 1000;
}
