// Unified specification of the internal store gRPC APIs.
syntax = "proto3";
package store;

import "google/protobuf/empty.proto";
import "types/account.proto";
import "types/blockchain.proto";
import "types/transaction.proto";
import "types/note.proto";
import "types/primitives.proto";
import "rpc.proto";

// RPC STORE API
// ================================================================================================

// Store API for the RPC component
service Rpc {
    // Returns the status info.
    rpc Status(google.protobuf.Empty) returns (rpc.StoreStatus) {}

    // Returns a Sparse Merkle Tree opening proof for each requested nullifier
    //
    // Each proof demonstrates either:
    // - **Inclusion**: Nullifier exists in the tree (note was consumed)
    // - **Non-inclusion**: Nullifier does not exist (note was not consumed)
    //
    // The `leaf` field indicates the status:
    // - `empty_leaf_index`: Non-inclusion proof
    // - `single` or `multiple`: Inclusion proof if the nullifier key is present
    //
    // Verify proofs against the nullifier tree root in the latest block header.
    rpc CheckNullifiers(rpc.NullifierList) returns (rpc.CheckNullifiersResponse) {}

    // Returns the latest details the specified account.
    rpc GetAccount(rpc.AccountRequest) returns (rpc.AccountResponse) {}

    // Returns raw block data for the specified block number.
    rpc GetBlockByNumber(blockchain.BlockNumber) returns (blockchain.MaybeBlock) {}

    // Retrieves block header by given block number. Optionally, it also returns the MMR path
    // and current chain length to authenticate the block's inclusion.
    rpc GetBlockHeaderByNumber(rpc.BlockHeaderByNumberRequest) returns (rpc.BlockHeaderByNumberResponse) {}

    // Returns a list of committed notes matching the provided note IDs.
    rpc GetNotesById(note.NoteIdList) returns (note.CommittedNoteList) {}

    // Returns the script for a note by its root.
    rpc GetNoteScriptByRoot(note.NoteRoot) returns (rpc.MaybeNoteScript) {}

    // Returns a list of nullifiers that match the specified prefixes and are recorded in the node.
    //
    // Note that only 16-bit prefixes are supported at this time.
    rpc SyncNullifiers(rpc.SyncNullifiersRequest) returns (rpc.SyncNullifiersResponse) {}

    // Returns info which can be used by the requester to sync up to the tip of chain for the notes they are interested in.
    //
    // requester specifies the `note_tags` they are interested in, and the block height from which to search for new for
    // matching notes for. The request will then return the next block containing any note matching the provided tags.
    //
    // The response includes each note's metadata and inclusion proof.
    //
    // A basic note sync can be implemented by repeatedly requesting the previous response's block until reaching the
    // tip of the chain.
    rpc SyncNotes(rpc.SyncNotesRequest) returns (rpc.SyncNotesResponse) {}

    // Returns info which can be used by the requester to sync up to the latest state of the chain
    // for the objects (accounts, notes, nullifiers) the requester is interested in.
    //
    // This request returns the next block containing requested data. It also returns `chain_tip`
    // which is the latest block number in the chain. requester is expected to repeat these requests
    // in a loop until `response.block_header.block_num == response.chain_tip`, at which point
    // the requester is fully synchronized with the chain.
    //
    // Each request also returns info about new notes, nullifiers etc. created. It also returns
    // Chain MMR delta that can be used to update the state of Chain MMR. This includes both chain
    // MMR peaks and chain MMR nodes.
    //
    // For preserving some degree of privacy, note tags and nullifiers filters contain only high
    // part of hashes. Thus, returned data contains excessive notes and nullifiers, requester can make
    // additional filtering of that data on its side.
    rpc SyncState(rpc.SyncStateRequest) returns (rpc.SyncStateResponse) {}

    // Returns account vault updates for specified account within a block range.
    rpc SyncAccountVault(rpc.SyncAccountVaultRequest) returns (rpc.SyncAccountVaultResponse) {}

    // Returns storage map updates for specified account and storage slots within a block range.
    rpc SyncAccountStorageMaps(rpc.SyncAccountStorageMapsRequest) returns (rpc.SyncAccountStorageMapsResponse) {}

    // Returns transactions records for specific accounts within a block range.
    rpc SyncTransactions(rpc.SyncTransactionsRequest) returns (rpc.SyncTransactionsResponse) {}
}

// BLOCK PRODUCER STORE API
// ================================================================================================

// Store API for the BlockProducer component
service BlockProducer {
    // Applies changes of a new block to the DB and in-memory data structures.
    rpc ApplyBlock(blockchain.Block) returns (google.protobuf.Empty) {}

    // Retrieves block header by given block number. Optionally, it also returns the MMR path
    // and current chain length to authenticate the block's inclusion.
    rpc GetBlockHeaderByNumber(rpc.BlockHeaderByNumberRequest) returns (rpc.BlockHeaderByNumberResponse) {}

    // Returns data required to prove the next block.
    rpc GetBlockInputs(BlockInputsRequest) returns (BlockInputs) {}

    // Returns the inputs for a transaction batch.
    rpc GetBatchInputs(BatchInputsRequest) returns (BatchInputs) {}

    // Returns data required to validate a new transaction.
    rpc GetTransactionInputs(TransactionInputsRequest) returns (TransactionInputs) {}
}

// GET BLOCK INPUTS
// ================================================================================================

// Returns data required to prove the next block.
message BlockInputsRequest {
    // IDs of all accounts updated in the proposed block for which to retrieve account witnesses.
    repeated account.AccountId account_ids = 1;

    // Nullifiers of all notes consumed by the block for which to retrieve witnesses.
    //
    // Due to note erasure it will generally not be possible to know the exact set of nullifiers
    // a block will create, unless we pre-execute note erasure. So in practice, this set of
    // nullifiers will be the set of nullifiers of all proven batches in the block, which is a
    // superset of the nullifiers the block may create.
    //
    // However, if it is known that a certain note will be erased, it would not be necessary to
    // provide a nullifier witness for it.
    repeated primitives.Digest nullifiers = 2;

    // Array of note IDs for which to retrieve note inclusion proofs, **if they exist in the store**.
    repeated primitives.Digest unauthenticated_notes = 3;

    // Array of block numbers referenced by all batches in the block.
    repeated fixed32 reference_blocks = 4;
}

// Represents the result of getting block inputs.
message BlockInputs {
    // A nullifier returned as a response to the `GetBlockInputs`.
    message NullifierWitness {
        // The nullifier.
        primitives.Digest nullifier = 1;

        // The SMT proof to verify the nullifier's inclusion in the nullifier tree.
        primitives.SmtOpening opening = 2;
    }
    // The latest block header.
    blockchain.BlockHeader latest_block_header = 1;

    // Proof of each requested unauthenticated note's inclusion in a block, **if it existed in
    // the store**.
    repeated note.NoteInclusionInBlockProof unauthenticated_note_proofs = 2;

    // The serialized chain MMR which includes proofs for all blocks referenced by the
    // above note inclusion proofs as well as proofs for inclusion of the requested blocks
    // referenced by the batches in the block.
    bytes partial_block_chain = 3;

    // The state commitments of the requested accounts and their authentication paths.
    repeated account.AccountWitness account_witnesses = 4;

    // The requested nullifiers and their authentication paths.
    repeated NullifierWitness nullifier_witnesses = 5;
}

// GET BATCH INPUTS
// ================================================================================================

// Returns the inputs for a transaction batch.
message BatchInputsRequest {
  // List of unauthenticated note commitments to be queried from the database.
  repeated primitives.Digest note_commitments = 1;
  // Set of block numbers referenced by transactions.
  repeated fixed32 reference_blocks = 2;
}

// Represents the result of getting batch inputs.
message BatchInputs {
    // The block header that the transaction batch should reference.
    blockchain.BlockHeader batch_reference_block_header = 1;

    // Proof of each _found_ unauthenticated note's inclusion in a block.
    repeated note.NoteInclusionInBlockProof note_proofs = 2;

    // The serialized chain MMR which includes proofs for all blocks referenced by the
    // above note inclusion proofs as well as proofs for inclusion of the blocks referenced
    // by the transactions in the batch.
    bytes partial_block_chain = 3;
}

// GET TRANSACTION INPUTS
// ================================================================================================

// Returns data required to validate a new transaction.
message TransactionInputsRequest {
    // ID of the account against which a transaction is executed.
    account.AccountId account_id = 1;
    // Set of nullifiers consumed by this transaction.
    repeated primitives.Digest nullifiers = 2;
    // Set of unauthenticated note commitments to check for existence on-chain.
    //
    // These are notes which were not on-chain at the state the transaction was proven,
    // but could by now be present.
    repeated primitives.Digest unauthenticated_notes = 3;
}

// Represents the result of getting transaction inputs.
message TransactionInputs {
    // An account returned as a response to the `GetTransactionInputs`.
    message AccountTransactionInputRecord {
        // The account ID.
        account.AccountId account_id = 1;

        // The latest account commitment, zero commitment if the account doesn't exist.
        primitives.Digest account_commitment = 2;
    }

    // A nullifier returned as a response to the `GetTransactionInputs`.
    message NullifierTransactionInputRecord {
        // The nullifier ID.
        primitives.Digest nullifier = 1;

        // The block at which the nullifier has been consumed, zero if not consumed.
        fixed32 block_num = 2;
    }

    // Account state proof.
    AccountTransactionInputRecord account_state = 1;

    // List of nullifiers that have been consumed.
    repeated NullifierTransactionInputRecord nullifiers = 2;

    // List of unauthenticated notes that were not found in the database.
    repeated primitives.Digest found_unauthenticated_notes = 3;

    // The node's current block height.
    fixed32 block_height = 4;

    // Whether the account ID prefix is unique. Only relevant for account creation requests.
    optional bool new_account_id_prefix_is_unique = 5; // TODO: Replace this with an error. When a general error message exists.
}

// NTX BUILDER STORE API
// ================================================================================================

// Store API for the network transaction builder component
service NtxBuilder {
    // Retrieves block header by given block number. Optionally, it also returns the MMR path
    // and current chain length to authenticate the block's inclusion.
    rpc GetBlockHeaderByNumber(rpc.BlockHeaderByNumberRequest) returns (rpc.BlockHeaderByNumberResponse) {}

    // Returns a paginated list of unconsumed network notes.
    rpc GetUnconsumedNetworkNotes(UnconsumedNetworkNotesRequest) returns (UnconsumedNetworkNotes) {}

    // Returns the block header at the chain tip, as well as the MMR peaks corresponding to this
    // header for executing network transactions. If the block number is not provided, the latest
    // header and peaks will be retrieved.
    rpc GetCurrentBlockchainData(blockchain.MaybeBlockNumber) returns (CurrentBlockchainData) {}

    // Returns the latest state of a network account with the specified account ID.
    rpc GetNetworkAccountDetailsById(account.AccountId) returns (MaybeAccountDetails) {}

    // Returns a list of all network account ids.
    rpc GetNetworkAccountIds(rpc.BlockRange) returns (NetworkAccountIdList) {}

    // Returns the latest details of the specified account.
    rpc GetAccount(rpc.AccountRequest) returns (rpc.AccountResponse) {}

    // Returns the script for a note by its root.
    rpc GetNoteScriptByRoot(note.NoteRoot) returns (rpc.MaybeNoteScript) {}

    // Returns vault asset witnesses for the specified account.
    rpc GetVaultAssetWitnesses(VaultAssetWitnessesRequest) returns (VaultAssetWitnessesResponse) {}

    // Returns a storage map witness for the specified account and storage map entry.
    rpc GetStorageMapWitness(StorageMapWitnessRequest) returns (StorageMapWitnessResponse) {}
}

// GET NETWORK ACCOUNT DETAILS BY ID
// ================================================================================================

// Represents the result of getting network account details by ID.
message MaybeAccountDetails {
    // Account details.
    optional account.AccountDetails details = 1;
}

// GET UNCONSUMED NETWORK NOTES
// ================================================================================================

// Returns a paginated list of unconsumed network notes for an account.
//
// Notes created or consumed after the specified block are excluded from the result.
message UnconsumedNetworkNotesRequest {
    // This should be null on the first call, and set to the response token until the response token
    // is null, at which point all data has been fetched.
    //
    // Note that this token is only valid if used with the same parameters.
     optional uint64 page_token = 1;

     // Number of notes to retrieve per page.
     uint64 page_size = 2;

     // The full account ID to filter notes by.
     account.AccountId account_id = 3;

     // The block number to filter the returned notes by.
     //
     // Notes that are created or consumed after this block are excluded from the result.
     fixed32 block_num = 4;
}

// Represents the result of getting the unconsumed network notes.
message UnconsumedNetworkNotes {
    // An opaque pagination token.
    //
    // Use this in your next request to get the next
    // set of data.
    //
    // Will be null once there is no more data remaining.
    optional uint64 next_token = 1;

    // The list of unconsumed network notes.
    repeated note.NetworkNote notes = 2;
}

// GET NETWORK ACCOUNTS
// ================================================================================================

// Represents the result of getting the network account ids.
message NetworkAccountIdList {
  // Pagination information.
  rpc.PaginationInfo pagination_info = 1;

  // The list of network account ids.
  repeated account.AccountId account_ids = 2;
}

// GET CURRENT BLOCKCHAIN DATA
// ================================================================================================

// Current blockchain data based on the requested block number.
message CurrentBlockchainData {
    // Commitments that represent the current state according to the MMR.
    repeated primitives.Digest current_peaks = 1;
    // Current block header.
    optional blockchain.BlockHeader current_block_header = 2;
}

// GET VAULT ASSET WITNESSES
// ================================================================================================

// Request for vault asset witnesses for a specific account.
message VaultAssetWitnessesRequest {
    // The account ID for which to retrieve vault asset witnesses.
    account.AccountId account_id = 1;

    // Set of asset vault keys to retrieve witnesses for.
    repeated primitives.Digest vault_keys = 2;

    // The witnesses returned correspond to the account state at the specified block number.
    //
    // Optional block number. If not provided, uses the latest state.
    //
    // The specified block number should be relatively near the chain tip else an error will be
    // returned.
    optional fixed32 block_num = 3;
}

// Response containing vault asset witnesses.
message VaultAssetWitnessesResponse {
    // A vault asset witness containing the asset and its proof.
    message VaultAssetWitness {
        // The SMT opening proof for the asset's inclusion in the vault.
        primitives.SmtOpening proof = 1;
    }

    // Block number at which the witnesses were generated.
    //
    // The witnesses returned corresponds to the account state at the specified block number.
    fixed32 block_num = 1;

    // List of asset witnesses.
    repeated VaultAssetWitness asset_witnesses = 2;
}

// GET STORAGE MAP WITNESS
// ================================================================================================

// Request for a storage map witness for a specific account and storage slot.
message StorageMapWitnessRequest {
    // The account ID for which to retrieve the storage map witness.
    account.AccountId account_id = 1;

    // The raw, user-provided storage map key for which to retrieve the witness.
    primitives.Digest map_key = 2;

    // Optional block number. If not provided, uses the latest state.
    //
    // The witness returned corresponds to the account state at the specified block number.
    //
    // The specified block number should be relatively near the chain tip else an error will be
    // returned.
    optional fixed32 block_num = 3;

    // The storage slot name for the map.
    string slot_name = 4;
}

// Response containing a storage map witness.
message StorageMapWitnessResponse {
    // Storage map witness data.
    message StorageWitness {
        // The raw, user-provided storage map key.
        primitives.Digest key = 1;

        // The SMT opening proof for the key-value pair.
        primitives.SmtOpening proof = 3;
    }

    // The storage map witness.
    StorageWitness witness = 1;

    // Block number at which the witness was generated.
    fixed32 block_num = 2;
}
