以太坊源码分析——Whisper
摘要:前言是以太坊中一项非常有趣的技术,它是一种基于身份的通信系统,专为人与人之间的小量数据通信而设计。 该协议运行在以太坊协议的框架之上,所有运行该协议的节点以下统称为节点组成网络。
[目录]
前言
Whisper 是以太坊中一项非常有趣的技术。 它是一种基于身份的通信系统,专为 Dapp 之间的少量数据通信而设计。 Whisper协议运行在以太坊p2p协议框架之上,所有运行Whisper协议的节点(以下简称节点)组成一个Whisper网络。 通过节点间的消息转发,理论上每个节点都可以接收到所有的Whisper消息。
特征
Whisper 具有以下基本特征和概念
通信加密
每条 Whisper 消息在网络上都是加密传输的,您可以选择两种加密算法之一:非对称加密(椭圆曲线)和对称加密(AES GSM)。
信封
信封是 Whisper 消息在网络中传输的基本单位,包含加密后的原始消息和消息相关的控制信息:
过期时间:消息的超时时间,超过这个时间,消息将不会被节点处理或转发
TTL:消息的生存时间。 消息只能在创建后的 TTL 时间内存活。 过了这个时间,消息在网络中超时
主题:消息的主题
AESNonce:使用AES对称密钥加密算法时使用的Nonce值
EnvNonce:用于PoW计算
当一个节点从一个Peer收到一个Envelope时,它会把这个Envelope转发给其他Peer,而不管它是否关心里面的数据(Topic是否满足设定值),这是Whisper的固有机制。
话题
每个 Envelope 指定封装消息的 Topic。 如果节点不关心主题,则不需要尝试打开(解密)信封。 通常一个Topic对应一个Key用于消息加密(无论是对称加密还是非对称加密)。 因此,如果一个节点收到它关心的主题的信封,它应该能够打开信封
筛选
Dapp 可以在节点上安装多个 Filter。 每个过滤器都包含一组条件。 只有满足这些条件的信封才能打开。 准确的说,不是节点打开了Envelope,而是节点上安装的Filter打开了Envelope。 每个 Filter 都有一个缓冲区来存储解密后的消息。 如果一个 Envelope 满足多个 Filter,则该消息将存储在多个 Filter 中。 过滤器可以设置以下条件:
主题:感兴趣的主题的集合
发件人地址:创建此消息的节点
Recipient address:指定接收节点的地址
PoW要求:消息需要的工作量证明
AcceptP2P:节点是否接受P2P消息,此类消息有特殊用途
工作证明
工作量证明用于防止节点恶意发送大量消息,采用的算法类似于PoW共识算法。 消息的创建者需要找到一个nonce,使得消息的哈希值小于一个值。这个值与消息的大小和TTL有关。 消息越大,TTL 越大,就越难找到 nonce。 计算工作量的公式为
其中$BestBit$为Hash值中从左到右第一个为1的位的位置(值越大,需要尝试nonce的次数越多)
源码分解
这部分主要涉及到Whisper filter envelope,它们的联系如下:
耳语
Whisper代表一个协议实例,负责整个Whisper功能的运行。 比较重要的字段如下:
protocol——Whisper协议的具体取值以太坊密钥破解,最重要的是Run字段,表示协议的操作入口
filter - 此节点上安装的所有过滤器
privateKeys - 存储在该节点上的非对称密钥对的集合,一个 Whisper 实例可以存储多个密钥对
symKeys - 本次会话存储的对称密钥的集合,一个Whisper实例可以存储多个对称密钥
envelopes - 信封池,保存所有要通过广播发送的信封。 信封池的存储键值为信封的Hash
expirations - 超时池,记录信封的过期时间,超时池的存储key值为unix时间,值为信封的Hash
peers——活跃Peer节点的集合,数据源为p2p底层
msgQueue - 普通 Whisper 消息的信封处理通道
以太坊源码分析——p2p节点发现与协议运行中提到,两个节点在底层连接后,会运行彼此支持的协议的Run函数。 对于 Whisper 协议,它是 HandlerPeer 函数。
HandlePeer最终运行在两个Go例程中以太坊密钥破解,一个是Whisper.runMessageLoop(),负责从底层读取消息,另一个是Peer.update(),负责定期发送信封池中未发送的信封到对端删除过期信封。
信封
Envelope 表示一个 Whisper 消息,它有两个来源
出方向由NewEnvelope()构造
从Peer节点接收入站方向
它的重要领域是
Topic——Envelope中数据的主题,节点的过滤器可以过滤感兴趣的主题进行解密
EnvNonce - 消息创建者在 PoW 中找到的随机数
pow - 消息的 pow 值
消息发送的典型流程
下面是节点广播发送一小段数据payload,封装到Envelope中,然后添加到Envelope pool中的过程,其中wh代表Whisper实例
首先构造发送参数,包括原始数据载荷、主题Topic等。
构造带发送参数的SentMessage
根据发送参数将SentMessage封装到新建的Envelope中,这一步包括签名(sign)加密(encrypt)计算随机数(Seal)
将信封添加到信封池
消息接收的典型流程
下面是一个典型的Whisper消息接收流程,其中w代表Whisper实例
w.runMessageLoop()接收到底层的Whisper消息,解码成Envelope,加入Envelope池,调用postEvent()将事件写入w.messageQueue
另一方面,当w被Start启动时,它从w.messageQueue接收事件并开始Filter匹配
使用每个已安装的 Filter 来匹配 Envelope。 如果匹配,Envelope 将被打开(解密),最后放入 Filter 的缓冲区。
演示
写了一个whipser chat-room demo,托管在github上,有兴趣的可以看看