协议与接口

September 7, 2019 · View on GitHub

目录

基础信息

模块

下面描述的模块对应着golang的模块,和目录名一致。

模块描述
cmd各程序的入口
core挖矿、共识的核心模块
crypto密钥管理,密钥和ID的映射关系定义
db数据持久化存储
p2p节点发现、节点连接,为上层协议提供抽象接口
rpc对外提供的HTTP查询接口
serialize定义各类可序列化和反序列化的数据,用于存储、网络协议
utils杂项

参数

参数描述
主网ID1-
块大小1MB-
出块时间 90秒 -
证据大小 约 150~700 Bytes上传的哈希描述会影响大小,最多可填140个字符
哈希长度 32 Bytes一律使用sha256
最低的出块POW E81000000x100000 << (0xE8 - 24),低于这个值时取这个值
最低的证据POWEE1000000x100000 << (0xEE - 24),低于这个值的证据不会被打包入块
难度调整参考区块数量20调整系数为 (前20个块出块时间 * 0.9 + 当前距离上一个块时间 * 0.1) / 20个块预期时间
账户ID-账户压缩公钥的base32编码(不填充)

数据格式与协议

下文只对数据格式和协议作用做基本的描述,不深入讨论细节。

P2P发现

具体格式参考源码注释 /serialize/discover/discover.go

类型描述
Ping1心跳探测
Pong2Ping应答
GetNeighbours3获取邻居节点请求
Neighbours4GetNeighbours应答,或主动推送邻居节点
  • 每个节点维护着邻居表
  • 定期向邻居发送Ping测试对端存活,长期未收到Pong响应会剔除相应节点
  • 定期向邻居发送GetNeighbours请求,将Neighbours相应中带的节点加入到自己的邻居表

握手

具体格式参考源码注释 /serialize/handshake/handshake.go

Request类型

字段 字段含义 
Version握手协议版本
ChainID链ID
CodeVersion代码版本
NodeType节点类型
PubKey请求方公钥
SessionKey请求方会话公钥
Sig签名

Response类型

字段 字段含义 
Version握手协议版本
Accept是否接受
CodeVersion代码版本
NodeType节点类型
SessionKey响应方会话公钥
Sig签名
  • 使用椭圆曲线secp256k1进行签名和密钥协商
  • 使用sha512做KDF,结果前32位为会话密钥,接下来的12位做随机值
  • 使用AES-256-GCM进行后续的加密通信

coreProtocol

具体格式参考源码注释 /serialize/cp/cp.go

数据结构

数据描述
Evidence表示证据的结构,做pow时基于该格式的序列化结果进行
BlockHeader表示区块头,做pow时基于该格式的序列化结果进行
Block区块,是上述两者的组合,用于网络传输

协议

类型描述
SyncReq1同步请求,节点会带上当前最新的区块哈希
SyncResp2SyncReq响应,如果发现对端区块不是最新,会返回最新区块哈希以及两者间的高度差
BlockRequest3根据SyncResp生成区块请求,期待获取某个区块哈希间的所有块
BlockResponse4BlockRequest响应,可生成多个响应,每次最大携带16个区块
BlockBroadcast5区块广播
EvidenceBroadcast6证据广播
  • 节点起来后会发送SyncReq,根据响应生成BlockRequest拉取区块,直到所有的SyncResp都告知已经最新时才停止初始化同步
  • 当进行着区块拉取时,不会再发同步请求,因此对BlockResponse有超时限制,目前期待每个块的网络传输时延为5s
  • 运行期间节点也会定时向网络查询最新信息
  • 当节点第一次收到广播后会广播给其他节点并记录下广播内容,下次收到同样广播时不再进行处理

HTTP接口

anti996 运行期间会监听本地端口(默认23666)提供HTTP服务,client 的部分功能是基于这些接口实现的。

基本规则

规则描述
URL/版本号/业务/操作,如 /v1/block/query-via-range 表示通过高度范围查询区块
方法只有GET和POST
编码UTF-8
返回值 见下文

返回值

HTTP请求正常时都返回200,并附带以下格式的应答:

{
    "code":0,
    "msg":"",
    "data":""
}
字段描述
code返回码,成功返回0,失败返回1,请求参数有误返回2
msg返回的消息,当code为1时不为空
data每个接口返回的响应数据,对应下文有返回数据的接口里的data字段

证据

上传证据

POST /v1/evidence/upload

请求结构

# data数组中的每一项均表示一条证据
{
    "data": [
        {
            "version": 1,
            "hash": "xxxx",
            "description": "xxxx",
            "public_key": "xxxx",
            "sigature": "xxxx",
            "nonce": 10000
        }
    ]
}
字段描述
version证据版本,当前均为1
hash证据摘要,十六进制编码
description证据的描述,不超过140个字符,可为空
public_key证据持有者公钥,十六进制编码
sigature签名信息,十六进制编码
nonce随机值,需按照3.3节的Evidence序列化格式进行POW得出

响应结构

上传未签名的证据

请求节点为你进行POW并签名,确保节点所持私钥是自己的私钥。

POST /v1/evidence/upload-raw

请求结构

# data数组中的每一项均表示一条证据
{
   "evds":[
      {
         "hash":"xxx",
         "description":"yyy"
      }
   ]
}
字段描述
hash证据摘要,十六进制编码
description对证据的描述,不超过140个字符,可为空

响应结构

查询证据

POST /v1/evidence/query

请求结构

# data数组中每一项表示一条证据的哈希
{
    "hash":["xxxx", "xxxx", "xxxx"]
}
字段描述
hash需要查询的证据的哈希值集合,哈希值使用十六进制编码

响应结构 data数组中每一项均表示一条证据

{
    "data": [
        {
            "version": 1,
            "hash": "xxxx",
            "description": "xxxx",
            "public_key": "xxxx",
            "sigature": "xxxx",
            "nonce": 10000,
            "height": 10000,
            "block_hash": "xxxx",
            "time": 123456,
        }
    ]
}
字段描述
version证据版本
hash证据摘要,十六进制编码
description证据的描述
public_key证据持有者公钥,十六进制编码
sigature签名信息,十六进制编码
nonce随机值
height所在区块高度
block_hash所在区块的哈希值,十六进制编码
time所在区块的时间,1970/1/1至今的秒数

区块

区块查询的返回结构如下所示,其中data数组中的每一项表示一个区块,evds数组中的每一项表示该区块包含的证据信息。下面小节不再赘述该结构。

{
    "data":[
        {
            "version": 1,
            "time": 123456,
            "nonce": 10000,
            "target": 10000,
            "last_hash": "xxxx",
            "miner": "xxxx",
            "evidence_root": "xxxx",
            "height": 100,
            "hash": "xxxx",
            "evds":[
                {
                    "hash":"xxxx",
                    "owner":"xxxx"
                }
            ]
        }
    ]
}
区块字段描述
version区块版本
time所在区块的时间,1970/1/1至今的秒数
nonce随机值
target难度
last_hash上一个块的哈希值,十六进制编码
miner挖出该块的矿工公钥,十六进制编码
evidence_root证据的默克树根,十六进制编码
height区块高度
hash区块的哈希值,十六进制编码
证据字段描述
hash证据的哈希值,十六进制编码
owner所有者公钥,十六进制编码

通过高度范围查询区块

GET /v1/block/query-via-range?range=...

请求参数格式 描述
x指定某个高度x
x,y,z指定多个高度,逗号分隔
x-y从高度x至y,如1-100表示查询高度1-100的区块,如果超出范围,则只返回范围内的区块
-1最新的区块

通过哈希查询区块

GET /v1/block/query-via-hash?hash=...

请求参数格式 描述
x指定某个哈希值查询,需要十六进制编码
x,y,z指定多个哈希值查询,需要十六进制编码

账户

通过ID查询账户

GET /v1/account/query?id=...

请求参数格式 描述
x用户ID,压缩公钥的base32编码(不填充)

返回结构

{
    "data":{
        "evidence":["xxx","yyy","zzz"],
        "score":0
    }
}
字段描述
evidence该账户所持的证据哈希,十六进制编码
score该账户的挖矿得分,没挖出一个块计1分(该数据并不存在链上,只从链上统计而得)