1. 字节雪球爱好者社区首页
  2. 基本原理

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     // 签名地址定义是否发生变化
}

在进行校验之前,还需要把该交易单元涉及到的所有地址进行锁定,待交易单元检查完成后进行解锁。

校验完成后的几种处理方式包括:

  1. ifUnitError:交易单元数据发生错误
  2. ifJointError:连接点数据发生错误
  3. ifTransientError:临时性错误,花费未确认的交易(已取消)
  4. ifNeedHashTree:需要同步最新数据
  5. ifNeedParentUnits:缺失父结点数据
  6. ifOk:校验结果正确,返回objValidationState
  7. ifOkUnsigned:对于未签名完整的单元校验结果正确

校验过程主要包含以下几个步骤:

检查交易单元基本格式

  1. 检查交易单元hash长度,根据交易单元重新计算hash并与数据中记录的hash比对;
  2. 检查连接点objJoint数据的字段是否完整,连接点包括三种类型:
    • 普通的交易单元unit:已签名的交易单元;
    • 未完整签名的交易单元unit+unsigned:没有完整签名的交易单元,比如多签名情况下只有一方签名的交易单元;
    • 稳定的交易单元unit+ball+skiplist_units:已达到稳定状态的交易单元,需要验证其是否真的达到稳定状态;
  3. 检查连接点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_commissionpayload_commission的数值以及messages的大小进行检查
  4. 检查交易单元中的versionaltauthorsparent_unitslast_balllast_ball_unit
  5. 检查witness_list_unit以及witnesses是否同时出现;
  6. 对于轻节点而言,在上述基本检查后,只需要再对timestamp进行检查即可。此外,轻节点不接受不提供任何证据的稳定交易单元。

检查重复性checkDuplicate

在数据库表units中搜索是否已有相同的交易单元。

检查headers激励接收者validateHeadersCommissionRecipients

当交易单元涉及的author大于1个时,必须明确earned_headers_commission_recipientsearned_headers_commission_recipients中的地址必须按升序排列,并且分配比例之和为100。

检查Hash树validateHashTree

objJoint中包含ball时,即该交易单元为稳定的,需要检查Hash树是否已经有该交易单元。

子结点变成ball时,其父结点也必须是ballball的计算包括4个部分:

var objBall = {
  unit: unit,
  parent_balls: arrParentBalls,
  skiplist_balls: arrSkiplistBalls,
  is_nonserial: bNonserial
}

对上述对象进行Base64Hash得到ball。通过上述过程,需要检查objJoint中的ball是否正确。

hash_tree_balls在Catch Up过程中使用,表中前一个ball是后一个balllast_ball

检查父单元validateParents

检查规则:

  1. 每个结点的父结点最多16个;
  2. 检查每个父结点的信息是否已知;
  3. 如果父结点个数超过1个,则
    • 父结点需按照字母排序
    • 父结点之间不存在包含关系
    • 父结点不能包含相同的地址
  4. 检查last_ball_unit是否满足要求,从父结点的视角来看last_ball_unit必须达到稳定且位于主链上;
  5. 当前结点的last_ball_mci应大于等于其父结点中最大的last_ball_mci

检查跳跃列表validateSkiplist

检查规则:

  1. 跳跃列表中的单元按照字母排序
  2. 跳跃列表中的单元必须在主链上,且达到稳定
  3. 跳跃列表中的单元MCI必须被10整除

允许跳跃列表中的单元暂时没有达到稳定,当它达到稳定时,还需要再做进一步的检查

检查见证人列表validateWitnesses

每个交易单元可以通过两种方式给出见证人:

  1. 通过引用witness_list_unit,与witness_list_unit具有相同的见证人列表,witness_list_unit必须达到稳定且位于last_ball之后;
  2. 直接给出见证人列表,见证人必须按序排列,并且见证人至少发出一个已经稳定的交易单元。

对于交易单元的见证人列表,需要进行如下检查:

  1. 要求从该交易单元出发到达last_ball_unit的主链上的所有结点对应的见证人列表witnesses差别不超过一个;
  2. 要求见证人的定义中没有引用其它的地址;
  3. 要求该交易单元的见证级别witnessed_level不小于父结点。

检查签名地址validateAuthors

对于交易单元的签名地址,需要检查如下条件:

  1. 每个交易单元的签名地址数不超过16个;
  2. 签名地址之间按序排列;
  3. 交易单元签名地址数据最多包含3个字段:address, authentifiers, definition
  4. 获取签名地址的定义,并根据定义检查签名;
  5. 检查相同地址发出来的交易单元是否连续(即相同地址发出的交易单元都可以连通);
  6. 检查地址定义修改所在单元是否达到稳定;
  7. 检查地址定义所在交易单元是否达到稳定;
  8. 检查地址定义是否发生重复。

检查消息内容validateMessages

消息中允许包含的字段包括:

objMessage = {
  'app',
  'payload_hash',
  'payload_location',  // 消息内容位置,包括'inline', 'uri', 'none'
  'payload',
  'payload_uri',
  'payload_uri_hash',
  'spend_proofs': [{   // 隐私资产的花费证明列表
    'spend_prrof',
    'address'
  }]
}

payload_location='none'时,不允许包含payloadpayload_uripayload_uri_hash。当payload_location='uri'时,不允许包含payload;否则,不允许包含payload_uripayload_uri_hash。当payload_location='inline'时,不允许包含spend_proofs

  • payment:支付消息,最重要的是检查是否发送双花;
  • text:文本消息;
  • address_definition_change:地址定义修改消息,payload包含definition_chashaddress
  • poll:发起投票消息,payload包含questionchoices
  • vote:响应投票消息,payload包含unitchoice
  • data_feed:数据订阅消息,payload包含数据内容;
  • profile:用户简介消息;
  • data:数据消息;
  • definition_template:发布地址定义模板消息;
  • attestation:认证消息;
  • asset:资产声明消息;
  • asset_attestors:资产发布者消息。

其中,address_definition_changedata_feeddefinition_templateassetasset_attestorsattestationpollvote这些类型的消息的payload_location必须为inline

版权所有。发布者:Alan During,转载请注明出处:https://bbfans.org/2018/10/27/byteball-unit-validation/

发表评论

登录后才能评论

联系我们

加入ByteBall技术群请添加

QR code