// Distributed under the MIT software license, see the accompanying
// file LICENSE or http://www.opensource.org/licenses/mit-license.php.

syntax = "proto3";

package qrl;

// TODO: Avoid using timestamp until the github issue is fixed
// import "google/protobuf/timestamp.proto";
message Timestamp
{
    int64 seconds = 1;
    int32 nanos = 2;
}

////////////////////////////
////////////////////////////
////////////////////////////
//////     API       ///////
////////////////////////////
////////////////////////////
////////////////////////////

// This service describes the P2P API
service P2PNode
{
    rpc Ping (PingReq) returns (PongResp) { }
    rpc GetKnownPeers (GetKnownPeersReq) returns (GetKnownPeersResp);
}

// This service describes the Public API used by clients (wallet/cli/etc)
service PublicAPI
{
    rpc GetNodeState (GetNodeStateReq) returns (GetNodeStateResp);
    rpc GetStats (GetStatsReq) returns (GetStatsResp);
    rpc GetKnownPeers (GetKnownPeersReq) returns (GetKnownPeersResp);
    rpc GetAddressState (GetAddressStateReq) returns (GetAddressStateResp);
    rpc GetObject(GetObjectReq) returns (GetObjectResp);

    rpc GetLatestData(GetLatestDataReq) returns (GetLatestDataResp);

    rpc TransferCoins (TransferCoinsReq) returns (TransferCoinsResp);
    rpc PushTransaction (PushTransactionReq) returns (PushTransactionResp);
}

// This is a place holder for testing/instrumentation APIs
service AdminAPI
{
}

////////////////////////////
////////////////////////////
////////////////////////////
//    Request/Response    //
////////////////////////////
////////////////////////////
////////////////////////////

message PingReq {
    string name = 1;
}
message PongResp {
    string message = 1;
}
message GetKnownPeersReq {
}
message GetKnownPeersResp {
    KnownPeers known_peers = 1;
}

////////////////////////////
////////////////////////////
////////////////////////////
////////////////////////////
////////////////////////////
////////////////////////////
////////////////////////////

message GetStatsReq { }
message GetStatsResp {
    NodeInfo node_info = 1;
    uint64 epoch = 2;
    uint64 uptime_network = 3;

    uint64 stakers_count = 4;
    uint64 block_last_reward = 5;
    uint64 block_time_mean = 6;
    uint64 block_time_sd = 7;

    uint64 coins_total_supply = 8;
    uint64 coins_emitted = 9;
    uint64 coins_atstake = 10;
}

message GetNodeStateReq { }
message GetNodeStateResp {
    NodeInfo info = 1;
}

message GetAddressStateReq {    string address = 1; }
message GetAddressStateResp {
    AddressState state = 1;
}

message GetObjectReq {  bytes query = 1;    }
message GetObjectResp {
    bool found = 1;
    oneof result {
        AddressState address_state = 2;
        Transaction transaction = 3;
        Block block = 4;
    }
}

message GetLatestDataReq { }
message GetLatestDataResp {
    repeated Block blocks = 1;
    repeated Transaction transactions = 2;
    repeated Transaction transactions_unconfirmed = 3;
}

message TransferCoinsReq {
    bytes address_from = 1;
    bytes address_to = 2;
    uint64 amount = 3; // IMPORTANT: These should be expressed in Shor
    uint64 fee = 4; // IMPORTANT: These should be expressed in Shor
    bytes xmss_pk = 5;
    uint64 xmss_ots_index = 6;
}
message TransferCoinsResp {
    Transaction transaction_unsigned = 1;
}

message PushTransactionReq {    Transaction transaction_signed = 1;     }
message PushTransactionResp {
    string some_response = 1;
}

////////////////////////////
////////////////////////////
////////////////////////////
//         Content        //
////////////////////////////
////////////////////////////
////////////////////////////

message NodeInfo
{
    enum State {
        UNKNOWN = 0;
        UNSYNCED = 1;
        SYNCING = 2;
        SYNCED = 3;
        FORKED = 4;
    }

    string version = 1;
    State  state = 2;
    uint32 num_connections = 3;
    uint32 num_known_peers = 4;
    uint64 uptime = 5;                  // Uptime in seconds
    uint64 block_height = 6;
    bytes  block_last_hash = 7;
    bool   stake_enabled = 8;
    string network_id = 9;
}

message WalletStore {
    repeated Wallet wallets = 1;
}

message Wallet {
    string address = 1;
    string mnemonic = 2;
    int32 xmss_index = 3;
}

message KnownPeers {
    repeated Peer peers = 1;
}

message Peer {
    string ip = 1;
}

message AddressState {
    //    int64 range = [                                   -9223372036854775808 to 9223372036854775807 ]
    //    QRL coins = 105M - 10^-8 = 104999999.99999999 =>     10499999999999999

    string address = 1;
    uint64 balance = 2;
    uint64 nonce = 3;                           // FIXME: Discuss. 32 or 64 bits?
    repeated bytes pubhashes = 4;
    repeated Transaction transactions = 5;      // FIXME: Add stake information. Probably a reference to another obj
}

message BlockHeader {
    // Header
    uint64 block_number = 1;
    uint64 epoch = 2;
    Timestamp timestamp = 3; // FIXME: Temporary

    bytes hash_header = 4;
    bytes hash_header_prev = 5;

    uint64 reward_block = 6;
    uint64 reward_fee = 7;

    bytes merkle_root = 8;
    bytes hash_reveal = 9;
    bytes stake_selector = 10;
}

message Block {
    BlockHeader header = 1;
    repeated Transaction transactions = 2;
    repeated Transaction dup_transactions = 3; // TODO: Review this
}

message BlockMetaDataList {
    repeated BlockMetaData block_number_hashes = 1;
}

message BlockMetaData {
    uint64 block_number = 1;
    bytes hash_header = 2;
}

message MR {
    bytes hash = 1;
    string type = 2;
    bytes stake_selector = 3;
    uint64 block_number = 4;
    bytes prev_headerhash = 5;
    bytes reveal_hash = 6;
}

message Transaction {
    enum Type {
        UNKNOWN = 0;
        TRANSFER = 1;
        STAKE = 2;
        DESTAKE = 3;
        COINBASE = 4;
        LATTICE = 5;
        DUPLICATE = 6;
    }

    Type type = 1;

    uint64 nonce = 2;
    bytes addr_from = 3;
    bytes public_key = 4;
    bytes transaction_hash = 5;
    uint32 ots_key = 6;
    bytes signature = 7;

    oneof transactionType {
        Transfer transfer = 8;
        Stake stake = 9;
        CoinBase coinbase = 10;
        LatticePublicKey latticePK = 11;
        Duplicate duplicate = 12;
    }

    //////////
    message Transfer {
        bytes addr_to = 1;
        uint64 amount = 2;
        uint64 fee = 3;
    }

    message Stake {
        uint64 balance = 1;
        uint64 activation_blocknumber = 2;
        uint64 finalized_blocknumber = 3;
        bytes finalized_headerhash = 4;
        bytes slavePK = 5;
        bytes hash = 7;
    }

    message Destake {
    }

    message CoinBase {
        bytes addr_to = 1;
        uint64 amount = 2;
    }

    message LatticePublicKey {
        bytes pk_kyber = 1;
        bytes pk_tesla = 2;
    }

    message Duplicate {
        uint64 block_number = 1;
        uint64 prev_header_hash = 2;
        bytes coinbase1_hhash = 3;
        bytes coinbase2_hhash = 4;
        Transaction coinbase1 = 5;
        Transaction coinbase2 = 6;
    }

}
