当前同步算法
dag 同步
名词解释
tips 节点
即 dag 的尖端节点。也就是如果我们把 dag 看成单链,那么就是当前高度最高的节点,放到 dag 图中,则是在当前某个时间领域内的无子区块的节点。
确认的 tips 节点表示需要从这些节点开始同步后续的子节点。
accumulator
merkle tree,叶子节点即我们的数据的hash值节点,可以快速验证和遍历叶子节点。更多详见https://cookbook.starcoin.org/zh/docs/concepts/accumulator
dag accumulator 构建流程
1)Genesis 是 accumulator 的最左叶子节点;是 accumulator 的起始节点。
2)每次对 dag 节点的子节点做 hash 运算,hash 值作为 accumulator 中的节点下一个叶子节点。若 dag 的节点没有子节点,则保留下来,继续参与 hash 运算。
3)若所有节点都没有子节点,则构建 accumulator 完成,tips节点也找到了。
如下图,从 Genesis 开始,accumulator 的叶子节点都是上一个节点的子节点的 hash,从而构建出一个 accumulator(只画出叶子节点,省略没有画出 accumulator 的根节点和非叶子节点):
同步的三大任务
确认tips节点和验证历史节点
为什么要确认和验证
主要原因有两个:
1、握手;同步两个节点之间的状态;同步
2、防止恶意 peer 假冒诚实节点,必须通过历史区块的验证才能识别出节点是否为诚实节点。
确认和验证流程
对应代码
待补充
同步新的tips节点
获取后续节点
拉取数据内容
对应代码
拉取区块数据
攻击和异常
使用老旧的父节点作为新节点造成大量回滚
冒充诚实节点
时间复杂度
获得 current tips
只有 Genesis 区块
此时 Genesis 区块就是 current tips。 Genesis 是一个特殊的 tips,如果当前 tips 是 Genesis,那么说明 dag 中前面没有 parents 了。
starcoin 的单链在转向 dag 升级时,会指定某一个区块为 dag 的 Genesis 区块,以此区块开始,后续都会走 dag 协议。
普通的 tips 区块
例如上图的 J,M 和 L 就是普通的 tips 节点。普通 tips 节点,经过不断的回溯父节点,总是能回到 Genesis 节点,可能有些 tips 节点能提前回到 Genesis 节点,但若两个 node 有相同的 dag,则它们返回到 Genesis 所沿途的 accmulator 节点应该是一致的。
确认 tips 节点以及前序节点
为什么要确认 tisp 节点
相当于两个 node 要先握手,保证两个 node 的tips节点之前的 dag 结构是一致的。
为什么要确认前序节点
因为如果对方是恶意节点,我们用 accumulator info 确认的时候无法验证对方的节点是否完整可靠,因此必须发送前序节点验证。
构建 accumulator
1)Genesis 是 accumulator 的最左叶子节点;
2)每次tips 节点的子节点做 hash 运算,作为本次 tips节点的下一个 accumulator 兄弟节点;
如下图,从 Genesis 开始,accumulator 的叶子节点都是上一个节点的子节点的 hash,从而构建出一个 accumulator(只画出叶子节点,省略没有画出 accumulator 的根节点和非叶子节点):
使用 accumulator 确认 tips 节点
构建好 accumulator 后,可以拿出 accumulator 的最后一个节点(存放在 startup info 中,似乎从 accumulator 中读也行)去另一个 node 中同步看大家的 accumulator 是否相同,若相同,开始从 tips 节点拉取后面的子节点。
例如,另一个节点已经产生了新的节点 P 和 V,它的 dag 结构和 accumulator 如下(新增黄色节点):
可以看到,另一个节点的 accumulator 和 本节点的 accumulator 从 JMKL 开始就不一致,因此确认的 tips应该是 JMKL 而不是 JML。
另一种情况是如下图:
这种情况下,由于 V 的父节点包含了 K,那么导致 ac
cumulator 从 JMKL 开始后面也是不一致的,那么此时确认的 tips 节点应该也是 JMKL,即应该从 JMKL 开始同步后续的子节点。
使用时间戳保证 accumulator 不会混乱
若不控制节点的插入,那么 accumulator 会变得很不稳定,例如下图中,突然插入一个 X 节点,导致几乎整个 accumulator 都变了:
因此必须防止 X 这样的节点插入进来,因此,dag 的插入应该对区块的时间戳进行校验,若父子区块的时间戳差值超过窗口时间,则子区块应该被拒绝,从而减少 accumulator 的不稳定。