Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

NEO网络协议

宠着祖宗
160 0 0
网络协议) O2 k* F  n, D6 H8 N1 P
在网络结构上,NEO 采用点对点网络结构,并使用 TCP 协议进行通讯。/ p5 ~* K- j: E: o4 B0 R
网络中存在两种节点类型,分别是普通节点和共识节点。普通节点可以广播、接收和转发交易、区块等,而共识节点可以创建区块。
' F  r6 }2 a9 p! C7 Y# mNEO 的网络协议规范与比特币的协议大致类似,但在区块、交易等的数据结构上有很大的不同。
" Z- K" W. H' Q" f4 H约定
6 I2 Z% E9 C& l) _字节序
4 C) E- S: P2 FNEO 系统中所有的整数类型都是采用小端序 (Little Endian) 编码,只有 IP 地址和端口号采用大端序 (Big Endian) 编码。
# T4 y  j. s4 ]3 N1 c7 a9 V# Q散列. u" D0 e6 ~( F) ]( @* o8 Z
NEO 系统中会用到 2 种不同的散列函数:SHA256 和 RIPEMD160。前者用于生成较长的散列值,而后者用于生成较短的散列值。通常生成一个对象的散列值时,会运用两次散列函数,例如要生成区块或交易的散列时,会计算两次 SHA256;生成合约地址时,会先计算脚本的 SHA256 散列,然后再计算上一个散列的 RIPEMD160 散列。" E$ J4 B1 ^% |) s# D. p1 ?
此外,区块中还会用到一种散列树 (Merkle Tree) 的结构,它将每一笔交易的散列两两相接后再计算一次散列,并重复以上过程直到只剩下一个根散列 (Merkle Root)。9 g. l( H; z) }, V9 k3 O9 ~+ D
变长类型
( e% P; R1 x$ S! I0 z1 U, Rvarint:变长整数,可以根据表达的值进行编码以节省空间。
: {. U: g9 f. {& m( K
长度格式
0xffffffff90xff + uint64
& C% p8 v% s2 d
varstr:变长字符串,由一个变长整数后接字符串构成。字符串采用 UTF8 编码。
6 ^! {9 G1 x+ O% Q! n
尺寸字段数据类型说明
?lengthvarint字符串的长度,以字节为单位
lengthstringuint8[length]字符串本身

- O5 C4 }+ P( Q5 v, @0 A8 ~array:数组,由一个变长整数后接元素序列构成。! r2 `/ s! W) S
定点数
1 s/ B; v5 r# r' j) J, ]NEO 系统中的金额、价格等数据,统一采用 64 位定点数,小数部分精确到 10-8,可表示的范围是:[-263/108, +263/108)) `& c/ _$ [# g: U( W
数据结构  ^+ o+ s4 T  H% w, T$ l
区块链1 a- E/ Y1 I- ^4 F0 W( }
区块链是一种逻辑结构,它以单向链表的形式将区块串联起来,用于存放全网的交易、资产等数据。
9 O% W8 y+ c/ K. g1 `. u区块
% o5 K3 s0 G1 S4 ?  z; I
尺寸字段数据类型说明
4Versionuint32区块版本,目前为 0
32PrevBlockuint256前一个区块的散列值
32MerkleRootuint256交易列表的根散列
4Timestampuint32时间戳
4Indexuint32区块高度(区块索引) = 区块数量 - 1
8ConsensusDatauint64共识数据(共识节点生成的伪随机数)
20NextConsensusuint160下一个区块的记账合约的散列值
1-uint8固定为 1
?Scriptscript用于验证该区块的脚本
?*?Transactionstx[]交易列表
  w; v. X8 I; z/ g9 L# l
在计算区块散列时,并不会把整个区块都计算在内,而是只计算区块头的前 7 个字段:Version, PrevBlock, MerkleRoot, Timestamp, Height, Nonce, NextMiner。由于 MerkleRoot 已经包含了所有交易的散列值,因此修改交易也会改变区块的散列值。
4 T+ F/ Q7 v# E2 {9 S, w& h区块头的数据结构如下:8 l1 x5 n+ U" Y& S- c1 H) L2 W7 w2 O
尺寸字段数据类型说明
4Versionuint32区块版本,目前为 0
32PrevBlockuint256前一个区块的散列值
32MerkleRootuint256交易列表的根散列
4Timestampuint32时间戳
4Indexuint32区块高度(区块索引) = 区块数量 - 1
8ConsensusDatauint64共识数据(共识节点生成的伪随机数)
20NextConsensusuint160下一个区块的记账合约的散列值
1-uint8固定为 1
?Scriptscript用于验证该区块的脚本
1-uint8固定为 0
' D# i+ ~% G; m$ o
每个区块的时间戳必须晚于前一个区块的时间戳,一般两个区块的时间戳相差 15 秒左右,但是也允许出现不精确的情况。区块的高度值必须恰好等于前一个区块的高度值加一。1 W7 U' c5 i1 u5 Q1 n2 `
交易; A( P& b7 i( a  J
尺寸字段数据类型说明
1Typeuint8交易类型
1Versionuint8交易版本,目前为 0
?--特定于交易类型的数据
?*?Attributestx_attr[]该交易所具备的额外特性
34*?Inputstx_in[]输入
60*?Outputstx_out[]输出
?*?Scriptsscript[]用于验证该交易的脚本列表
8 K: y( o8 }/ e  I" C+ C8 C
NEO 系统中的一切事务都以交易为单位进行记录。交易有以下几种类型:' M; Y) S( ?$ i8 h2 q
名称系统费用说明
0x00MinerTransaction0用于分配字节费的交易
0x01IssueTransaction500|0用于分发资产的交易
0x02ClaimTransaction0用于分配 NeoGas 的交易
0x20EnrollmentTransaction1000(已弃用) 用于报名成为共识候选人的特殊交易
0x40RegisterTransaction10000|0(已弃用) 用于资产登记的交易
0x80ContractTransaction0合约交易,这是最常用的一种交易
0xd0PublishTransaction500*n(已弃用)智能合约发布的特殊交易
0xd1InvocationTransaction0调用智能合约的特殊交易
- J6 Z2 F* ]) F  }9 o
每一种类型的交易除了具有交易的公共字段之外,还会具有自己的专属字段。关于不同类型交易的专属字段,下文会有详细说明。. ^4 e; ?! w' k
MinerTransaction8 o8 c% f6 W  g6 [
尺寸字段数据类型说明
---交易的公共字段
4Nonceuint32随机数
---交易的公共字段
. Z8 P6 @' x- e. y) j) E
每一个区块的第一笔交易必然是 MinerTransaction。它用于将当前区块中所有的交易手续费奖励给记账人。6 r5 p' t, U+ y" ^" J. N# t
交易中的随机数用于防止出现散列冲突。' R6 V" v4 X! x% i* v  F* A! F4 b
IssueTransaction
, x$ t/ J* N% I! E- Y资产发行交易没有额外的特殊字段。
6 `4 N6 I% c$ K  \& w( c资产管理员可以通过资产发行交易,将已经登记过的资产在 NEO 区块链上制造出来,并发送到任意地址。$ v. a& e: |" ^& ?$ a- {+ m! @) D
特别的,如果发行的资产是 NEO,那么这笔交易将可以免费发送。3 {1 y6 c) K' C
ClaimTransaction5 b+ B; X2 v; n
尺寸字段数据类型说明
---交易的公共字段
34*?Claimstx_in[]用于分配的 NEO
---交易的公共字段
$ R6 `6 b9 d. n! M0 `" B! N  ^
EnrollmentTransaction
1 O+ U" Y5 r; r8 ?  `! o" U7 W* p. _) R# g) e
[!Warning]
7 ~; d  R% l6 U2 W! \  m已弃用,已被智能合约的 Neo.Blockchain.RegisterValidator 所替代。- i5 m1 k% {! E; X0 o
8 V( G- s! H8 f1 ?+ A' Z& E" `
查看 替代的 .NET 智能合约框架2 C3 q+ d$ q4 I, E  Q
查看 替代智能合约 API - o' O0 i' ~' x0 O9 {
RegisterTransaction
/ B& b  e# R3 ]& K1 `+ t* {
6 O; G% k! d- Q[!Warning]3 R6 g9 [& _6 q8 p# X1 j
已弃用,已被智能合约的 Neo.Blockchain.CreateAsset 所替代。
" `! ^- G& p6 ?( e
( o6 l4 K$ g! B
查看 替代的 .NET 智能合约框架
, e0 _- R" O! y6 C5 y% h查看 替代智能合约 API   o2 e' r3 D! v' q& r. f5 F
ContractTransaction
8 _  M9 N/ `6 W/ Y2 w# g+ _; v( N合约交易没有任何特殊的地方。. ?7 U% s1 ~! f9 p+ e0 I$ _1 I
PublishTransaction& L% E1 w$ c" a$ v0 r1 p8 H

, B1 A  d$ ^6 w& }* M0 Y# G[!Warning]
8 ^& a% C+ Q) T2 |& e已弃用,已被智能合约的 Neo.Blockchain.CreateContract 所替代。
+ u' Q6 ]/ L# n4 m

& ]7 X) M! x* @% N+ H. H  t% \查看 替代的 .NET 智能合约框架
  o( J2 y" i) `+ h$ }" y查看 替代智能合约 API ' E- Z, Q5 f% s" `; {. }7 j
InvocationTransaction
/ E; v) A2 X+ d# r
尺寸字段数据类型说明
---交易的公共字段
?Scriptuint8[]所调用的智能合约的脚本
8Gasint64运行所调用的智能合约需要的费用
---交易的公共字段

- b' D/ J8 h; Q+ Z5 E交易特性& L+ R, ]  M$ C4 ?
尺寸字段数据类型说明
1Usageuint8用途
0|1lengthuint8数据长度(特定情况下会省略)
lengthDatauint8[length]特定于用途的外部数据
: A' x0 M5 _+ G) r0 O) c, O
有时候交易中会需要包含一些供外部使用的数据,这些数据将统一被放置在交易特性字段中。
- u8 Q" n% w7 B( I1 }, x7 H: e每个交易特性可以有不同的用途:
2 u2 t8 `0 I& B8 e5 }4 M: j7 }
名称说明
0x00ContractHash外部合同的散列值
0x02-0x03ECDH02-ECDH03用于 ECDH 密钥交换的公钥
0x20Script用于对交易进行额外的验证
0x30Vote用于投票选出记账人
0x81DescriptionUrl外部介绍信息地址
0x90Description简短的介绍信息
0xa1-0xafHash1-Hash15用于存放自定义的散列值
0xf0-0xffRemark-Remark15备注

9 ?1 g9 x/ h' |# W" G  v/ H, W对于 ContractHash,ECDH 系列,Vote,Hash 系列,数据长度固定为 32 字节,length 字段省略;
: x! E2 p- m: H: X- I对于 Script,数据长度固定为 20 字节,存放地址;
3 Z) p7 G9 ?1 w# C% t对于 DescriptionUrl,必须明确给出数据长度,且长度不能超过 255 字节;
" p6 a' i2 ?2 O7 c' W( _对于 Description 和 Remark 系列,必须明确给出数据长度, 且长度不能超过 65535 字节。
; e. M* c' `8 h# g$ p0 p$ E2 c+ B4 v交易输入
" P6 n9 `: \9 l( u. m/ p
尺寸字段数据类型说明
32PrevHashuint256引用交易的散列值
2PrevIndexuint16引用交易输出的索引
3 }9 N- z7 i; U$ C; [
交易输出
, }- h& K7 ]- T8 i* ?  t# \
尺寸字段数据类型说明
32AssetIduint256资产编号
8Valueint64金额
20ScriptHashuint160收款地址

! v6 B8 X$ ?6 p每个交易中最多只能包含 65536 个输出。
. ?, ]! \+ |& _$ y- Y4 d0 c6 k验证脚本* u7 X' o+ A7 u
尺寸字段数据类型说明
?StackScriptuint8[]栈脚本代码
?RedeemScriptuint8[]合约脚本代码
, a' R/ D8 d1 }. `8 o# _
栈脚本中只能包含压栈操作指令,用于向合约脚本传递参数(如签名等)。脚本解释器会先执行栈脚本代码,然后执行合约脚本代码。
4 A3 L' T, A3 E+ N' V/ p在一笔交易中,合约脚本代码的散列值必须与交易输出中的一致,这是验证的一部分。关于脚本执行的过程,后文会详细阐述。
, F! A* z/ ^: l, Y网络消息
7 x/ E3 Q# m1 g# M( B0 b所有的网络消息都通过以下消息结构来发送:8 `; N5 p& C* X! y. W( V; g
尺寸字段数据类型说明
4Magicuint32协议标识号
12Commandchar[12]命令
4lengthuint32Payload 的长度
4Checksumuint32校验和
lengthPayloaduint8[length]消息内容

+ z3 a9 [5 N% P% u$ Z4 |8 i& V已定义的 Magic 值:. {9 p2 ^9 I  v+ f# U/ v
说明
0x00746e41正式网
0x74746e41测试网
, m& N; @7 O" A( j
Command 采用 utf8 编码,长度为 12 字节,多余部分用 0 填充。7 S( A! R/ B( P" @) S7 g
Checksum 是 Payload 两次 SHA256 散列后的前 4 个字节。! O; Q" }, M( K/ ^
Payload 根据不同的命令有不同的详细格式,见下文。
! m7 w( I' I& p5 I! \version+ J' f5 r9 l: y4 c
尺寸字段数据类型说明
4Versionuint32协议版本,目前为 0
8Servicesuint64节点提供的服务,目前为 1
4Timestampuint32当前时间
2Portuint16监听的端口,如果不监听则为 0
4Nonceuint32用于区分相同公网 IP 的节点
?UserAgentvarstr客户端标识
4StartHeightuint32区块链高度
1Relaybool是否接收并转发
$ {2 @9 S) W* g, S7 c/ {! J
一个节点收到连接请求时,它立即宣告其版本。在通信双方都得到对方版本之前,不会有其他通信。
4 ~: j& g) R/ n* h  q- h+ }: Lverack6 `- }) Y9 X5 u; M
节点收到 version 消息后,立刻回复一个 verack 作为应答。: p( P4 U5 Q% x! K+ o2 T
此消息没有 payload。1 |" \$ P3 H) n- I  A
getaddr
6 U6 f. S4 I( z" M5 {向一个节点请求一批新的活动节点,以增加自身的连接数。! d  k1 i4 E* l& F. H; C# B
此消息没有 payload。
, `9 [& s* B/ O+ {% W' C8 Caddr
4 c/ D- U' I1 L0 |* a# j
尺寸字段数据类型说明
30*?AddressListnet_addr[]网络上其他节点的地址
1 C) c8 h! G8 f5 H/ d' T+ e) ^3 E
节点收到 getaddr 消息后,返回一个 addr 消息作为应答,提供网络上已知节点的信息。
8 s. Z* {! B7 E, O0 u4 S1 qgetheaders
# r2 {! [3 H2 X# L" j/ n5 c) M
尺寸字段数据类型说明
32*?HashStartuint256[]节点已知的最新 block 散列
32HashStopuint256请求的最后一个 block 的散列
2 H' x  ~* }3 n% K
向一个节点请求包含编号 HashStart 到 HashStop 的至多 2000 个 block 的 header 包。要获取之后的 block 散列,需要重新发送 getheaders 消息。这个消息用于快速下载不包含相关交易的 blockchain。
% z$ O' [$ P* H# I5 f4 Hheaders# e, U; d; f1 c5 n9 Q7 ]; i7 E  t
尺寸字段数据类型说明
?*?Headersheader[]区块头
0 @/ R3 o& r' ]- w4 g1 U$ k
节点收到 getheaders 消息后,返回一个 headers 消息作为应答,提供请求的区块头。
. Q- _2 }% T' w* m/ igetblocks9 M- L9 l$ O  @  I; `3 V9 B, J% J
尺寸字段数据类型说明
32*?HashStartuint256[]节点已知的最新 block 散列
32HashStopuint256请求的最后一个 block 的散列
, S8 x" A4 D. F+ [8 V6 ^! O
向一个节点请求包含编号从 HashStart 到 HashStop 的 block 列表的 inv 消息。若 HashStart 到 HashStop 的 block 数超过 500,则在 500 处截止。欲获取后面的 block 散列,需要重新发送 getblocks 消息。2 n+ Z' {+ }7 `) ?1 I) f1 v7 l. N/ I
inv" v5 [& R2 ~' o/ l9 c! S/ ^2 j
尺寸字段数据类型说明
1Typeuint8清单类型
32*?Hashesuint256[]清单
  x# L3 s" U& G, ?+ o8 ]% J
节点通过此消息可以广播它拥有的对象信息。这个消息可以主动发送,也可以用于应答 getbloks 消息。
6 z2 s( K8 {2 f5 m* q1 _+ {清单类型有以下几种:  Q  N6 Q, J$ \1 M
名称说明
0x01TX交易
0x02Block区块
0xe0Consensus共识数据

; x7 V0 ]( r# pgetdata6 [. A/ N/ a5 ^0 {# C, l* l
尺寸字段数据类型说明
1Typeuint8清单类型
32*?Hashesuint256[]清单
2 p8 n- H9 @; h  }% S. p6 X0 c/ e: m
向一个节点请求指定的对象,它通常在接收到 inv 包并滤去已知元素后发送。
! R0 p, s1 W8 k/ P: h4 yblock
4 x3 z: z: y7 u  A" `* f" @1 A
尺寸字段数据类型说明
?Blockblock区块
9 G) D& \; r1 e4 f
向一个节点发送一个区块,用于响应请求数据的 getdata 消息。2 f; B9 U2 Y' ?
tx# A8 R. @9 V4 f: ], \" h0 W
尺寸字段数据类型说明
?Transactiontx交易

0 _1 x, G% h6 Z, x7 @8 r, X7 k& F向一个节点发送一笔交易,用于响应请求数据的 getdata 消息。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

宠着祖宗 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1