在之前介绍过的tendermint共识机制中提到过,共识协议能够容忍小于1/3的byzantine节点。但是即使在>=1/3的节点出现byzantine问题后,tendermint依然提供了一个尽力而为的安全机制-evidence,用于找出系统中存在的byzantine节点并通知其他正常的节点,避免系统出现问题。需要说明的是,被发现的byzantine节点可能会受到没收stake的惩罚,但是evidence机制本身并不执行惩罚,它只是在链上提交evidence,并通知上层的应用。
首先,来介绍一下evidence的检测和产生机制。在tendermint中当前存在两类evidence,分别为DuplicateVoteEvidence和LightClientAttackEvidence。
当byzantine节点控制+1/3的投票权后,可以成功发起重复投票攻击,在同一个height的同一个round内对两个不同的block同时确认并投票,并分别与网络中其他的剩余正常节点达成+2/3共识,就可以导致tendermint网络出现不一致的确认状态。但是DuplicateVoteEvidence机制的存在,有机会可以发现并解决这类攻击。例如当一个节点发现来自同一个节点的矛盾的投票(同一个height的同一个round内对两个不同的block同时确认并投票),就可以构造一个DuplicateVoteEvidence并广播。DuplicateVoteEvidence结构如下:
type DuplicateVoteEvidence struct {
VoteA *Vote
VoteB *Vote
// abci specific information
TotalVotingPower int64
ValidatorPower int64
Timestamp time.Time
}
其中,VoteA和VoteB就是受到的来自同一个节点的矛盾的两个投票。
light client节点没有足够的资源来验证并执行交易,只是简单向正常节点拉取所需的状态,并对header做轻量的验证工作。light client会连上全节点中的若干集合,选取一个节点作为primary,其他节点作为witnesses,向primary拉取所需状态和header,并同时向witnesses拉取header作为对比验证。这里有两种机制,一种是primary+witnesses需要包含+2/3的投票权,另一种是只需包含+1/3的投票权。第二种是默认的执行机制,因为所需资源更少,而且一般情况下集群中不会出现+1/3的byzantine节点。但是如果出现+1/3点byzantine节点,就有可能对light client节点进行欺骗。如下图所示,light client在height 11时,从primary收到了'A,但从witness收到了'B,存在矛盾。

light client在验证header的过程中,一旦发现不一致的header,就会向双方各自发送LightClientAttackEvidence,LightClientAttackEvidence中记录了矛盾的block:
type LightClientAttackEvidence struct {
ConflictingBlock *LightBlock
CommonHeight int64
// abci specific information
ByzantineValidators []*Validator
TotalVotingPower int64
Timestamp time.Time
}
其中ConflictingBlock为与消息接收节点矛盾的block。如上图中,light client会向primary发送包含'B的LightClientAttackEvidence,向witness发送包含'A的LightClientAttackEvidence。
上面介绍了DuplicateVoteEvidence和LightClientAttackEvidence的检测和产生机制。接下来介绍一下evidence的执行机制。首先,节点在收到evidence消息后,会验证evidence是否合法以及是否超时。合法且未超时的evidence会持续在全网广播,确保全部节点都收到了该evidence或者evidence超时为止。evidence有两个超时参数:MaxAgeNumBlocks和MaxAgeDuration,超时的evidence将会被忽略。由于stake的质押撤回是需要时间的,因此只要evidence的超时时间小于质押撤回时间,就可以有机会惩罚恶意节点。同时节点中也记录了evidence pool,用于evidence的去重。evidence是在链上被提交的,proposer会优先打包evidence到block上,节点在验证完evidence的合法性之后,就可以对该block进行prevote和precommit的投票,从而最终提交该evidence。
