syntax = "proto3";

import "transaction.proto";
import "common.proto";
import "blockchain.proto";

package types;
option go_package = "github.com/33cn/chain33/types";

service p2pgservice {
    //广播交易
    rpc BroadCastTx(P2PTx) returns (Reply) {}
    //广播区块
    rpc BroadCastBlock(P2PBlock) returns (Reply) {}

    // PING
    rpc Ping(P2PPing) returns (P2PPong) {}

    //获取地址
    rpc GetAddr(P2PGetAddr) returns (P2PAddr) {}

    rpc GetAddrList(P2PGetAddr) returns (P2PAddrList) {}

    //版本
    rpc Version(P2PVersion) returns (P2PVerAck) {}
    //获取p2p协议的版本号
    rpc Version2(P2PVersion) returns (P2PVersion) {}
    //获取软件的版本号
    rpc SoftVersion(P2PPing) returns (Reply) {}
    //获取区块，最高200
    rpc GetBlocks(P2PGetBlocks) returns (P2PInv) {}

    //获取mempool
    rpc GetMemPool(P2PGetMempool) returns (P2PInv) {}

    //获取数据
    rpc GetData(P2PGetData) returns (stream InvDatas) {}

    //获取头部
    rpc GetHeaders(P2PGetHeaders) returns (P2PHeaders) {}

    //获取 peerinfo
    rpc GetPeerInfo(P2PGetPeerInfo) returns (P2PPeerInfo) {}

    // grpc server 读客户端发送来的数据
    rpc ServerStreamRead(stream BroadCastData) returns (ReqNil) {}

    // grpc server 发送数据给客户端
    rpc ServerStreamSend(P2PPing) returns (stream BroadCastData) {}

    // grpc 收集inpeers
    rpc CollectInPeers(P2PPing) returns (PeerList) {}
    rpc CollectInPeers2(P2PPing) returns (PeersReply) {}
}

/**
 * 请求获取远程节点的节点信息
 */
message P2PGetPeerInfo {
    /// p2p版本
    int32 version = 1;
}

/**
 * 节点信息
 */
message P2PPeerInfo {
    ///节点的IP地址
    string addr = 1;
    ///节点的外网端口
    int32 port = 2;
    ///节点的名称
    string name = 3;
    /// mempool 的大小
    int32 mempoolSize = 4;
    ///节点当前高度头部数据
    Header header = 5;
}

/**
 * p2p节点间发送版本数据结构
 */
message P2PVersion {
    ///当前版本
    int32 version = 1;
    ///服务类型
    int64 service = 2;
    ///时间戳
    int64 timestamp = 3;
    ///数据包的目的地址
    string addrRecv = 4;
    ///数据发送的源地址
    string addrFrom = 5;
    ///随机数
    int64 nonce = 6;
    ///用户代理
    string userAgent = 7;
    ///当前节点的高度
    int64 startHeight = 8;
}

/**
 * P2P 版本返回
 */
message P2PVerAck {
    int32 version = 1;
    int64 service = 2;
    int64 nonce   = 3;
}

/**
 * P2P 心跳包
 */
message P2PPing {
    ///随机数
    int64 nonce = 1;
    ///节点的外网地址
    string addr = 2;
    ///节点的外网端口
    int32 port = 3;
    //签名
    Signature sign = 4;
}

/**
 * 心跳返回包
 */
message P2PPong {
    int64 nonce = 1;
}

/**
 * 获取对方节点所连接的其他节点地址的请求包
 */
message P2PGetAddr {
    int64 nonce = 1;
}

/**
 * 返回请求地址列表的社保
 */
message P2PAddr {
    int64 nonce = 1;
    ///对方节点返回的其他节点信息
    repeated string addrlist = 2;
}
/**
 * 返回包括地址以及响应地址高度的列表信息
 **/

message P2PAddrList {
    int64    nonce                = 1;
    repeated P2PPeerInfo peerinfo = 2;
}

/**
 * 节点外网信息
 */
message P2PExternalInfo {
    ///节点的外网地址
    string addr = 1;
    //节点是否在外网
    bool isoutside = 2;
}

/**
 * 获取区间区块
 */
message P2PGetBlocks {
    int32 version     = 1;
    int64 startHeight = 2;
    int64 endHeight   = 3;
}

/**
 * 获取mempool
 */
message P2PGetMempool {
    int32 version = 1;
}

message P2PInv {
    repeated Inventory invs = 1;
}

// ty=MSG_TX MSG_BLOCK
message Inventory {
    //类型，数据类型，MSG_TX MSG_BLOCK
    int32 ty = 1;
    ///哈希
    bytes hash = 2;
    //高度
    int64 height = 3;
}

/**
 * 通过invs 下载数据
 */
message P2PGetData {
    /// p2p版本
    int32 version = 1;
    /// invs 数组
    repeated Inventory invs = 2;
}

//
message P2PRoute {
    int32 TTL = 1;
}

/**
 * p2p 发送交易协议
 */
message P2PTx {
    Transaction tx    = 1;
    P2PRoute    route = 2;
}

/**
 * p2p 发送区块协议
 */
message P2PBlock {
    Block block = 1;
}

/**
 * p2p 轻量级区块, 广播交易短哈希列表
 */
message LightBlock {

    int64       size          = 1;
    Header      header        = 2;
    Transaction minerTx       = 3;
    repeated string sTxHashes = 4;
}

// 轻量级交易广播
message LightTx {
    bytes    txHash = 1;
    P2PRoute route  = 2;
}

// 请求完整交易数据
message P2PTxReq {
    bytes txHash = 1;
}

// 请求区块内交易数据
message P2PBlockTxReq {
    string   blockHash       = 1;
    repeated int32 txIndices = 2;
}

// 区块交易数据返回
message P2PBlockTxReply {
    string   blockHash       = 1;
    repeated int32 txIndices = 2;
    repeated Transaction txs = 3;
}

/* 节点收到区块或交易hash,
 * 当在本地不存在时,需要请求重发完整交易或区块
 * 采用统一结构减少消息类型
 */
message P2PQueryData {
    oneof value {
        P2PTxReq      txReq      = 1;
        P2PBlockTxReq blockTxReq = 2;
    }
}
/**
 * p2p 协议和软件版本
 */
message Versions {
    int32  p2pversion  = 1;
    string softversion = 2;
    string peername    = 3;
}

/**
 * p2p 广播数据协议
 */
message BroadCastData {
    oneof value {
        P2PTx           tx       = 1;
        P2PBlock        block    = 2;
        P2PPing         ping     = 3;
        Versions        version  = 4;
        LightTx         ltTx     = 5;
        LightBlock      ltBlock  = 6;
        P2PQueryData    query    = 7;
        P2PBlockTxReply blockRep = 8;
    }
}

/**
 * p2p 获取区块区间头部信息协议
 */
message P2PGetHeaders {
    int32 version     = 1;
    int64 startHeight = 2;
    int64 endHeight   = 3;
}

/**
 * p2p 区块头传输协议
 */
message P2PHeaders {
    repeated Header headers = 1;
}

/**
 * inv 请求协议
 */
message InvData {
    oneof value {
        Transaction tx    = 1;
        Block       block = 2;
    }
    int32 ty = 3;
}

/**
 * inv 返回数据
 */
message InvDatas {
    repeated InvData items = 1;
}

/**
 * peer 信息
 */
message Peer {
    string addr        = 1;
    int32  port        = 2;
    string name        = 3;
    bool   self        = 4;
    int32  mempoolSize = 5;
    Header header      = 6;
}

/**
 * peer 列表
 */
message PeerList {
    repeated Peer peers = 1;
}

/**
 *当前节点的网络信息
 */
message NodeNetInfo {
    string externaladdr = 1;
    string localaddr    = 2;
    bool   service      = 3;
    int32  outbounds    = 4;
    int32  inbounds     = 5;
}

/**
 * p2p节点扫描返回的结构数据
 */

message PeersReply {
    repeated PeersInfo peers = 1;
}

message PeersInfo {
    string name        = 1;
    string ip          = 2;
    int32  port        = 3;
    string softversion = 4;
    int32  p2pversion  = 5;
}
