ByteBall交易单元校验过程
相比于在单链结构中,在DAG中对交易单元要更加复杂,不仅需要检查交易单元的格式是否正确、交易单元是否发生双花、交易单元是否违反DAG构建规则,还需要对交易单元中承载的应用进行检查(比如支付、投票、认证等)。当钱包构造新的交易单元或者接收到到网络上的交易单元时,需要对其进行校验。
检查过程中,ByteBall采用一个全局变量objValidationState
来保存检查的结果,包括的内容有:
objValidationState = {
bUnsigned, // 是否完整签名标志
sequence, // 交易单元的检查结果,包括'good', 'temp-bad', 'final-bad'
last_ball_mci, // last_ball的MCI
max_known_mci, // 目前已知最大的MCI
max_parent_limci, // 父结点中最大的LIMCI
witnessed_level, // 见证级别
best_parent_unit, // 最优父结点
unit_hash_to_sign, // 用于签名的单元hash
bAdvancedLastStableMci, // last_ball是否发生更新
bHasBasePayment, // 是否具有支付消息
bHasPoll, // 是否具有投票消息
bHasDataFeed, // 是否具有数据消息
bHasProfile, // 是否具有认证消息
bHasDefinitionTemplate, // 是否具有地址定义模板
bHasAssetDefinition, // 是否具有资产定义消息
bPrivate, // 是否为隐私资产支付
bDefiningPrivateAsset, // 是否定义隐私资产
src_coin, // 用于固定面额的隐私资产
assocHasAssetAttestors, // 是否有资产认证者
arrSkiplistBalls, // 对应skiplist_units的ball
arrAddressesWithForkedPath, // 发生交易冲突的地址列表
arrConflictingUnits, // 与当前交易单元冲突的交易单元列表
arrAdditionalQueries, // 需要进一步执行的数据更新操作
arrDoubleSpendInputs, // 是否有双花输入
arrInputKeys, // 花费证明列表
arrDefinitionChangeFlags // 签名地址定义是否发生变化
}
在进行校验之前,还需要把该交易单元涉及到的所有地址进行锁定,待交易单元检查完成后进行解锁。
校验完成后的几种处理方式包括:
ifUnitError
:交易单元数据发生错误ifJointError
:连接点数据发生错误ifTransientError
:临时性错误,花费未确认的交易(已取消)ifNeedHashTree
:需要同步最新数据ifNeedParentUnits
:缺失父结点数据ifOk
:校验结果正确,返回objValidationState
ifOkUnsigned
:对于未签名完整的单元校验结果正确
校验过程主要包含以下几个步骤:
检查交易单元基本格式
- 检查交易单元hash长度,根据交易单元重新计算hash并与数据中记录的hash比对;
- 检查连接点
objJoint
数据的字段是否完整,连接点包括三种类型:- 普通的交易单元
unit
:已签名的交易单元; - 未完整签名的交易单元
unit
+unsigned
:没有完整签名的交易单元,比如多签名情况下只有一方签名的交易单元; - 稳定的交易单元
unit
+ball
+skiplist_units
:已达到稳定状态的交易单元,需要验证其是否真的达到稳定状态;
- 普通的交易单元
- 检查连接点
objJoint
中交易单元objUnit
的数据内容,根据其中是否有具体内容分为:- 包含
content_hash
:该交易单元是不连续的(nonserial)且其内容被省略,要求具有字段unit
+version
+alt
+timestamp
+authors
+witness_list_unit
+witnesses
+content_hash
+parent_units
+last_ball
+last_ball_unit
,且它只能出现在稳定的交易单元中,即objJoint
中必须包含ball
字段; - 不包含
content_hash
,仅包含普通的消息:要求具有字段unit
+version
+alt
+timestamp
+authors
+messages
+witness_list_unit
+witnesses
+earned_headers_commission_receipients
+last_ball
+last_ball_unit
+parent_units
+headers_commission
+payload_commission
,并对headers_commission
和payload_commission
的数值以及messages
的大小进行检查
- 包含
- 检查交易单元中的
version
、alt
、authors
、parent_units
、last_ball
、last_ball_unit
; - 检查
witness_list_unit
以及witnesses
是否同时出现; - 对于轻节点而言,在上述基本检查后,只需要再对
timestamp
进行检查即可。此外,轻节点不接受不提供任何证据的稳定交易单元。
检查重复性checkDuplicate
在数据库表units
中搜索是否已有相同的交易单元。
检查headers激励接收者validateHeadersCommissionRecipients
当交易单元涉及的author
大于1个时,必须明确earned_headers_commission_recipients
。earned_headers_commission_recipients
中的地址必须按升序排列,并且分配比例之和为100。
检查Hash树validateHashTree
当objJoint
中包含ball
时,即该交易单元为稳定的,需要检查Hash树是否已经有该交易单元。
子结点变成ball
时,其父结点也必须是ball
,ball
的计算包括4个部分:
var objBall = {
unit: unit,
parent_balls: arrParentBalls,
skiplist_balls: arrSkiplistBalls,
is_nonserial: bNonserial
}
对上述对象进行Base64Hash得到ball
。通过上述过程,需要检查objJoint
中的ball
是否正确。
hash_tree_balls
在Catch Up过程中使用,表中前一个ball
是后一个ball
的last_ball
。
检查父单元validateParents
检查规则:
- 每个结点的父结点最多16个;
- 检查每个父结点的信息是否已知;
- 如果父结点个数超过1个,则
- 父结点需按照字母排序
- 父结点之间不存在包含关系
- 父结点不能包含相同的地址
- 检查
last_ball_unit
是否满足要求,从父结点的视角来看last_ball_unit
必须达到稳定且位于主链上; - 当前结点的
last_ball_mci
应大于等于其父结点中最大的last_ball_mci
检查跳跃列表validateSkiplist
检查规则:
- 跳跃列表中的单元按照字母排序
- 跳跃列表中的单元必须在主链上,且达到稳定
- 跳跃列表中的单元MCI必须被10整除
允许跳跃列表中的单元暂时没有达到稳定,当它达到稳定时,还需要再做进一步的检查
检查见证人列表validateWitnesses
每个交易单元可以通过两种方式给出见证人:
- 通过引用
witness_list_unit
,与witness_list_unit
具有相同的见证人列表,witness_list_unit
必须达到稳定且位于last_ball
之后; - 直接给出见证人列表,见证人必须按序排列,并且见证人至少发出一个已经稳定的交易单元。
对于交易单元的见证人列表,需要进行如下检查:
- 要求从该交易单元出发到达
last_ball_unit
的主链上的所有结点对应的见证人列表witnesses
差别不超过一个; - 要求见证人的定义中没有引用其它的地址;
- 要求该交易单元的见证级别
witnessed_level
不小于父结点。
检查签名地址validateAuthors
对于交易单元的签名地址,需要检查如下条件:
- 每个交易单元的签名地址数不超过16个;
- 签名地址之间按序排列;
- 交易单元签名地址数据最多包含3个字段:
address
,authentifiers
,definition
; - 获取签名地址的定义,并根据定义检查签名;
- 检查相同地址发出来的交易单元是否连续(即相同地址发出的交易单元都可以连通);
- 检查地址定义修改所在单元是否达到稳定;
- 检查地址定义所在交易单元是否达到稳定;
- 检查地址定义是否发生重复。
检查消息内容validateMessages
消息中允许包含的字段包括:
objMessage = {
'app',
'payload_hash',
'payload_location', // 消息内容位置,包括'inline', 'uri', 'none'
'payload',
'payload_uri',
'payload_uri_hash',
'spend_proofs': [{ // 隐私资产的花费证明列表
'spend_prrof',
'address'
}]
}
当payload_location='none'
时,不允许包含payload
、payload_uri
及payload_uri_hash
。当payload_location='uri'
时,不允许包含payload
;否则,不允许包含payload_uri
及payload_uri_hash
。当payload_location='inline'
时,不允许包含spend_proofs
。
payment
:支付消息,最重要的是检查是否发送双花;text
:文本消息;address_definition_change
:地址定义修改消息,payload
包含definition_chash
和address
;poll
:发起投票消息,payload
包含question
及choices
;vote
:响应投票消息,payload
包含unit
及choice
;data_feed
:数据订阅消息,payload
包含数据内容;profile
:用户简介消息;data
:数据消息;definition_template
:发布地址定义模板消息;attestation
:认证消息;asset
:资产声明消息;asset_attestors
:资产发布者消息。
其中,address_definition_change
、data_feed
、definition_template
、asset
、asset_attestors
、attestation
、poll
、vote
这些类型的消息的payload_location
必须为inline
。
文章目录
版权所有。发布者:Alan During,转载请注明出处:https://bbfans.org/2018/10/27/byteball-unit-validation/