首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spectrum光谱链共识算法的分析

Spectrum光谱链共识算法的分析

作者头像
rectinajh
发布2018-10-10 17:28:11
5270
发布2018-10-10 17:28:11
举报

Spectrum(光谱链)是SmartMesh生态下的公链,承载去中心化Mesh网络实现万物互联dapp的底层公链。由Payment Channel的建构的SmartRaiden(光子网络)和多子链侧链的并行的SmartPlasma的Layer2次级架构,保证了主链安全的同时极大的提升了交易速度。Token动态转移技术(Atmosphere)是Spectrum生态重要一环,是Token可以在不同链进行兑换的跨链协议。共识机制是一种新型的能力证明机制(Proof of Capability,PoC),能力的定义是为系统贡献资源的节点,能力证明衡量了节点对系统的贡献程度,能力越强就有更高的出块权重,并且很好的支持移动设备运行光谱轻节点,保证公链在无互联网环境也可以正常运行。

核心代码实现: https://github.com/SmartMeshFoundation/Spectrum/blob/master/contracts/chief/src/chief_0.0.6.sol

节点能力的定义

能力被定义为节点与网络共享资源的各种因素的加权权重,具体包括如下: 1,节点是否在Meshbox上运行(为系统共享多少通信带宽,数据存储,交互能量(太阳能电池的能量)) 2,Token投资(LockedDeposit(要成为志愿者至少抵押1个smt)或者Photon Payment Channel(提升系统交易频率走Payment支付通道),其实就是抵押SMT。 3,节点成功出块的次数,产生坏块的次数。

Capability = (WMB * OnMeshBox) * [ (WCBW x CommBW) + (WS x Storage) + (WSBW x StorageBW) + (WE x Energy) ] + (WLD0 * SMT LockedDeposit) + (WLD1 * Token 1 LD) + ... + (WLDN * Token N LD) + (WPD * Sum of all Photon Deposits associated with the node) + (WSS x SuccessfulSigning)

Spectrum节点分为四组,每组都有一个结构体数组,签名者节点被轮流成为签名者(出块节点),志愿者节点不出块,等待被提升为签名者节点,正常节点被提升为志愿者节点,行为不端的节点。

//signer info
struct SignerInfo {
    uint score;
    uint number;
}

//volunteer object
struct VolunteerInfo {
    uint weight; // new volunteer weight = 5
    uint number;
}

每次节点成功为一个块签名,SuccessfulSigning 会增加 1.但是,如果该节点无法生成一个好块, 则 SuccessfulSigning 会减少一个大数,例如 10 作为惩罚。

从上面可以看出, 即使节点的所有者没有财务资源(MeshBox 或存款),它仍然可以通过在有机会 成为签名者时产生正确的块来增加其能力。所以还是比较公平的,只是出块的机会比较小了。

光谱链诞生需要有一个出块节点的列表,它随区块链的诞生而产生,负责形成最初的出块节点联盟(一个被初始化的出块节点列表,和一个空的候选节点列表)。

网络上的每一个普通全节点都有资格申请成为一个出块节点。但是,由于申请时的出块节点联盟的状 态不同,导致节点被提名成出块节点的流程略有不同:

• 当出块节点总数小于极限值时:普通节点发出申请,可以被现有的出块节点提名,直接进入出 块节点列表。

• 当出块节点总数等于极限值时:普通节点发出申请,可以被现有的出块节点提名,放入候选节 点(volunteer)的列表,等待轮换参与出块。

节点联盟的更新频率

普通的节点在每个出块周期(14-22 秒)内,实际大概是12.5s,都有机会被出块节点选入到联盟列表中。如果出块节点 列表有空位,则新节点进入出块节点列表中,参与下一轮的出块。 如果出块节点列表已经没有空位, 则新节点进入候选节点列表中,等待空位。 没有进入黑名单的候选节点将会有五次出块机会,然后会 放到黑名单中休息一个epoch 。

节点联盟出块规则

1,出块节点必须保证连续正确的为网络出块,如果不能正常出块(不出块,出错块)就会被从出 块节点中剔除,会有一个候选节点来替代它。 2,一个节点不能正常出块,系统会将其判断成不合格节点,将其放入黑名单中,进入黑名单的机 器,在 24 小时之内不能重复申请成为出块节点。

具体规则分以下几种情况:

  1. 出块节点列表未满 每个节点3分,每错出或者漏出一个块扣1分,0分时被放入黑名单,在当前epoch不在被选拔。 /* 在志愿者列表中随机选出17个节点替换当前列表, 在进入这个方法之前,已经判断过志愿者列表尺寸了,所以这里只管随机拼装即可 */ function generateSignersRule3() private { address g = _signerList[0]; // 清理旧的列表 address[] memory sl = new address[](_signerList.length); for (uint j = 0; j < sl.length; j++) { sl[j] = _signerList[j]; } for (uint i0 = sl.length; i0 > 0; i0--) { uint sIndex = i0 - 1; deleteSigner(sIndex); address signerI = sl[sIndex]; if (sIndex > 0 && signerI != uint160(0)) { if (volunteersMap[signerI].weight == 0) { pushVolunteer(signerI, 5); } pushVolunteer(signerI, volunteersMap[signerI].weight - 1); } } // 顺序选出一个创世签名人放到首位 if (genesisSigner[g] && _genesisSignerList.length > 1) { // 这个循环一定会找到一个 genesisSigner 放到 signers 中 for (uint i1 = 0; i1 < _genesisSignerList.length; i1++) { if (_genesisSignerList[i1] == g) { if (i1 == (_genesisSignerList.length - 1)) { pushSigner(_genesisSignerList[0], 3); } else { pushSigner(_genesisSignerList[i1 + 1], 3); } break; } } } else { pushSigner(_genesisSignerList[0], 3); } // 随机填满整个 signerList , 走到这个逻辑时 volunteer 一定比 signers 多,所以一定能填满 // 这个地方循环下来很可能造成 signerList.length < signerLimit 的情况, 后续需要补充 uint[] memory tiList = new uint[](signerLimit); uint ii = 0; for (uint i2 = 0; i2 < _volunteerList.length; i2++) { if (ii >= signerLimit) break; uint ti = getRandomIdx(_volunteerList[i2], _volunteerList.length - uint(1)); if (repeatTi(tiList, ti)) continue; pushSigner(_volunteerList[ti], 3); tiList[ii] = ti; ii = ii + 1; } // 如果不满需要补满 if (ii < signerLimit) { for (uint i3 = 0; i3 < _volunteerList.length; i3++) { //不存在就放进去 if (signersMap[_volunteerList[i3]].number == 0) pushSigner(_volunteerList[i3], 3); //放满了就退出循环 if (_signerList.length >= signerLimit) break; } } }
  2. 出块节点列表已满,候选节点列表小于出块节点列表 此时主要选拔候选节点,为每个被选拔的节点设置weight = 5,出块规则与“出块节点列表未满”时规则相同。 /* rule 1 : 出块节点列表未满 每个节点3分,每错出或漏出一个块扣1分,0分时被放入黑名单 在当前 epoch 不再被选拔 rule 2 : �出块节点列表已满,候选节点列表小于出块节点列表 此时主要工作是选拔候选节点,为每个被选拔的节点设置 weight = 5, 出块规则与 “出块节点列表未满” 时的规则相同 */ function updateRule1() private { fixRule1(); // mine // 如果当前块 不是 signers[ blockNumber % signers.length ] 出的,就给这个 signer 减分 // 否则恢复成 3 分 uint signerIdx = blockNumber % _signerList.length; //初始签名人不做处理 if (!genesisSigner[_signerList[signerIdx]]) { SignerInfo storage signer = signersMap[_signerList[signerIdx]]; // 序号对应的不是我,则扣它一分 if (msg.sender != _signerList[signerIdx]) { if (signer.score > 1) { signer.score -= 1; signer.number = blockNumber; } else { // move to blacklist and cannot be selected in this epoch pushVolunteer(_signerList[signerIdx], 0); // vsn-0.0.3 // score == 0 , remove on signerList deleteSigner(signerIdx); } } else { // 恢复分数 signer.score = 3; } }
  3. 出块节点列表已满,候选节点列表大于出块节点列表 在这个规则生效时,签名节点的分数已经没有意义了, 此时的规则是每出一轮块就要替换掉全部的出块节点, 从候选节点列表中随机提拔一批新的出块节点到出块节点列表,将原出块节点列表移入候选节点列表,并将 weight - 1, 当 weight == 0 时则移入黑名单,当前 epoch 将不在被选拔。 假设出块节点列表最大长度 17 ,候选节点列表最大长度为 1234。每一轮出块,指的就是每 17 个块,每笔交易的确认时间也是 17 块,但是对于交易所来说应该至少经过 34 个块才能确认一笔交易。 /* rule 3 : 出块节点列表已满,候选节点列表大于出块节点列表 在这个规则生效时,签名节点的分数已经没有意义了, 此时的规则是每出一轮块就要替换掉全部的出块节点, 从候选节点列表中按 weight 随机提拔一批新的出块节点到出块节点列表, 将原出块节点列表移入候选节点列表,并将 weight - 1, 当 weight == 0 时则移入黑名单,等待下一个 epoch 假设出块节点列表最大长度 17 ,候选节点列表最大长度与 epoch 相等。每一轮出块,指的就是每 17 个块,每笔交易的确认时间也是 17 块,但是对于交易所来说应该至少经过 34 个块才能确认一笔交易。 */ function updateRule3() private { uint l = _signerList.length; uint signerIdx = uint(blockNumber % l); address si = _signerList[signerIdx]; //1 : 初始签名人不做处理,不是正常签名人 0 分放回志愿者列表,否则 weight - 1 if (signerIdx > uint(0)) { // 序号对应的不是我,把序号对应的 signer 以 weight=0 扔回志愿者列表 (其实就是删除) if (msg.sender != si) { pushVolunteer(si, 0); //此处还不能直接删除,因为不能破坏列表长度,否则对后续取模逻辑有影响,用 0 占位吧 delete signersMap[si]; _signerList[signerIdx] = uint160(0); } } //2 : 如果当前块是签名人列表的最后一块,则生成下一轮的列表 if (signerIdx == uint(l - 1)) { //if (volunteersMap[msg.sender].weight == 0) {pushVolunteer(msg.sender, 5);} //pushVolunteer(msg.sender, volunteersMap[msg.sender].weight - 1); generateSignersRule3(); } }

共识机制攻击分析:

1,比如一个SMT大户抵押巨多的SMT,节点权重很高,是否就可以一直霸占出块节点,然后等待作恶呢? 答:出块节点列表未满,当出块节点很少的时候,他可以很容易进入出块列表,轮流出块。但是如果出块节点已满,有越多节点出块,做恶机会就越低,因为出块后在一个epoch周期就会被换掉,让其他节点出块。

2,节点接收到一个错误的块,或者受到连续错误的块,会不会出现分叉? 答:如果节点收到一个新挖出的区块,但是 parent 与主分支上的不一致,节点将会保存该区块,但是并不切换主分支,如果多个区块中不包含预定节点的区块,则记录全部的区块,并将主链切换到时间最早的区块上,如果多个区块中包含预定节点的区块,则记录全部的区块,并将主链切换到预定节点的区块上。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.09.25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 节点能力的定义
  • 节点联盟的更新频率
  • 节点联盟出块规则
  • 共识机制攻击分析:
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档