ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Diem 网络协议 DiemNet 完整技术指南:拓扑、Noise 加密、握手与消息分帧规范

Diem 网络协议 DiemNet 完整技术指南:拓扑、Noise 加密、握手与消息分帧规范 区块链金融科技【免费下载链接】diemDiem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.项目地址https://gitcode.com/gh_mirrors/di/diem点击查看免费下载DiemNet 是 Diem 生态系统中任意两个节点间通信的核心网络协议本文以其官方规范 specifications/network/README.md 为骨架结合配套子规范Noise、Handshake v1、Messaging v1、NetworkAddress、On-chain Discovery与仓库源码实现系统讲解 DiemNet 的标准网络拓扑、节点类型、双阶段连接握手流程、消息分帧与最大帧限制等关键技术细节。读完本文你将理解 Diem 验证节点V、全节点VFN/PFN与客户端如何通过版本化、可升级的协议栈建立加密且认证的连接并能直接在仓库中找到对应的源码实现与测试用例。DiemNet 是什么根据 DiemNet 规范DiemNet 是 Diem 生态系统中任意两个节点之间通信所使用的主要网络协议。该协议只描述消息在传输线上的结构与顺序而将实际的消息投递交给底层传输TCP完成。与此同时所有节点之间的通信必须使用 Noise 协议进行加密和认证。DiemNet 支持在单条连接上并发多路复用多个应用协议multiplexing。对每个应用协议DiemNet 提供两种消息语义DirectSend即发即忘fire-and-forget的单向消息投递Unary RPC一元 RPC即一对请求-响应的同步调用。规范的版本与状态标注为2020/07/14 v1 Draftv1 草案。核心术语Connection连接拨号方dialer与监听方listener之间的一次传输会话实例。Client客户端在一次连接的语境中指发起连接的一方也常被称为 initiator 或 dialer。Server服务端在一次连接的语境中指接收连接的一方也常被称为 responder 或 listener。PeerId对等节点的 id一个 16 字节的值其取值规则为在**验证节点网络Validator Network**中是验证节点在链上的 AccountAddress在其他所有网络中是节点静态 x25519 公钥的后 16 字节。从实现看PeerId的这些派生规则与 network/src/noise/handshake.rs 中握手时对initiator_peer_id的校验逻辑一一对应。标准网络拓扑DiemNet 本身并不假设某种特定网络拓扑但规范为了表述清晰以 Diem 的标准网络拓扑为框架展开说明。节点类型验证节点Validator Node, VDiem 网络中的核心节点类型。验证节点网络由当前 epoch 注册的所有验证节点组成其成员由OnChainConfig中的ValidatorSet定义。出于抗 DDoS 与纵深防御defense-in-depth考虑验证节点应当与其他节点类型隔离仅允许与其他验证节点以及其控制的 VFN 通信。验证全节点Validator Full Node, VFN由 Diem 验证节点所有并运营的全节点。VFN 通常通过内部 VPC 连接到其所属验证节点以保持验证节点的隔离性VFN 也可以在面向公网的端点上服务所有节点类型。公共全节点Public Full Node, PFN非验证节点运营的全节点主要通过与 VFN 通信来接入 Diem。客户端节点Client Node, C本质上是不存储账本历史的 PFN。认证模式双向认证Mutual连接双方在安全传输握手中都认证对方。仅服务端认证Server-only只有拨号方client在安全传输握手中认证监听方server。网络类型验证节点网络Validator Network, VN由验证节点组成的全连接、双向认证网络。非验证节点即当前 epoch 验证节点集合中没有密钥对的任何对等节点明确不允许加入其他验证节点会拒绝任何未经认证的入站连接。验证节点在 VN 中通过 mempool 同步交易池、通过 consensus 对交易进行排序与执行并通过 state sync 同步账本状态。验证节点内部全节点网络Validator-internal Full Node Network, VFNN每个验证节点运营一个逻辑私有网络仅包含该验证节点与其 VFN。出于运维简单性v1 版本的每个 VFNN 采用仅服务端认证模式验证节点作为服务端、VFN 作为客户端。VFN 通常通过 mempool 将交易转发给上游验证节点并通过 state sync 与上游验证节点同步账本状态。公共验证全节点网络Public Validator Full Node Network, PVFNNVFN 组成的可公开访问网络为所有节点类型提供交易提交与状态查询服务。例如公共客户端可以通过 PVFNN 向 Diem 网络提交交易并同步账本状态。公共全节点网络Public Full Node Network, PFNNDiem v1 中不存在公共 PFN 网络。下图展示了标准 Diem 节点类型、不同网络配置以及不同的连接认证模式基础传输层Base TransportDiemNet 对底层传输作出以下假设面向连接connection-oriented消息有序且可靠投递ordered and reliable delivery单播通信unicast会话本地状态——协议状态不会跨传输会话保留。当前 DiemNet 仅支持 TCP 作为基础传输并预留了通过寻址方案addressing scheme升级到新基础传输的能力。仓库中的 TCP 传输实现位于 network/netcore/src/transport/tcp.rs另有用于测试与基准的内存传输 network/netcore/src/transport/memory.rs 和网络基准测试 network/benches/socket_bench.rs。安全传输层Secure Transport所有节点间通信必须使用 DiemNet Noise IK 协议进行加密与认证。由于使用了 Noise IK 握手客户端总是认证服务端Noise 的初始握手消息是加密的只有持有预期密钥对的服务端才能解密并响应。这种模式类似于客户端对每条连接使用固定到特定公钥的 TLS 证书固定certificate pinning。与之相对服务端是否认证客户端取决于具体网络配置。在 Diem v1 中只有验证节点网络VN使用双向认证——验证节点只允许来自其他当前验证节点的入站连接。Noise 层实现要点配套规范 specifications/network/noise.md 详细描述了 Noise 层的实现握手模式使用 Noise IK 握手模式one-round trip客户端预先知道服务端静态公钥并在握手中发送自己的静态公钥IK: - s ... - e, es, s, ss - e, ee, se加密原语X25519 密钥交换、AES-GCM 认证加密、SHA-256 哈希协议名为Noise_IK_25519_AESGCM_SHA256。握手消息尺寸HANDSHAKE_MSG_1 32 (32 16) (8 16)包含一个公钥、一个加密公钥和一个加密的 8 字节载荷HANDSHAKE_MSG_2 32 16包含一个公钥与加密的 0 字节载荷。客户端载荷客户端在首条握手消息的 8 字节载荷中携带当前 Unix 时间戳毫秒精度。在双向认证的 VN 中服务端会校验该时间戳严格递增作为防重放replay计数器检测到重放时可将 Diffie-Hellman 密钥交换次数从 4 次减半到 2 次。密钥轮换当前实现不进行会话 rekey因此会话是长期存活的且不具备前向/后向保密性规范认为这不是问题因为验证节点之间不交换机密数据且重要消息在应用层还有额外签名。这些细节与源码 network/src/noise/handshake.rs 中upgrade_outbound/upgrade_inbound的实现一致时间戳载荷的构造与校验、基于trusted_peers的公钥校验等。DiemNet 版本化方案为防止协议僵化protocol ossification并支持不兼容的协议升级所有 DiemNet 协议都带版本号并可通过多种方式进行协商。主要地DiemNet 握手协议负责协商 DiemNet 消息协议的版本以及所支持的应用协议版本。握手协议本身通过节点公告的 NetworkAddress 进行预协商pre-negotiated因为它不打算频繁变更。握手协议的数据结构与协商逻辑handshake-v1.md 定义了握手消息的数据结构pub struct HandshakeMsg { pub supported_protocols: BTreeMapMessagingProtocolVersion, SupportedProtocols, } pub struct SupportedProtocols(BitVec); pub struct BitVec { inner: Vecu8, } pub enum MessagingProtocolVersion { V1 0, }握手过程是对称的无论拨号方还是监听方都执行相同流程构造HandshakeMsg→ 序列化并加上大端u16长度前缀 → 通过 Noise 包装的 socket 发送 → 接收对方的HandshakeMsg→ 双方必须选取最高的交集MessagingProtocolVersion用于后续通信。接收方只应使用其公告过的ProtocolId若收到未公告或不支持的协议接收方可以返回ErrorCode::NotSupported错误消息。源码实现位于 network/src/protocols/wire/handshake/v1/mod.rs其中HandshakeMsg还额外携带了chain_id与network_id字段perform_handshake会依次校验链 ID、网络 ID 一致再在降序遍历中找到最高的交集协议版本不匹配时报InvalidChainId/InvalidNetworkId/NoCommonProtocols。ProtocolId枚举定义了各应用协议的唯一标识ConsensusRpc 0、ConsensusDirectSend 1、MempoolDirectSend 2、StateSyncDirectSend 3、DiscoveryDirectSend 4、HealthCheckerRpc 5、ConsensusDirectSendJSON 6。DiemNet NetworkAddressDiemNet 使用NetworkAddress封装拨号一个对等节点所需的精确协议集合。v1 中规范的 DiemNet 地址按顺序包含以下协议以人类可读格式表示基础传输取其一/ip4/ipaddr/tcp/port/ip6/ipaddr/tcp/port/dns/name/tcp/port/dns4/name/tcp/port/dns6/name/tcp/port安全传输升级/ln-noise-ik/x25519-public-keyDiemNet 握手升级/ln-handshake/version一个完整的人类可读 DiemNetNetworkAddress示例/ip4/10.0.0.61/tcp/6080/ln-noise-ik/080e287879c918794170e258bfaddd75acac5b3e350419044655e4983a487120/ln-handshake/0其中x25519-public-key是公告方advertising peer在 Noise 术语中的远端静态公钥握手版本当前仅支持0。NetworkAddress 的设计与约束network-address.md 指出NetworkAddress是一种紧凑、高效、自描述且面向未来的网络地址表示为协议栈a stack of protocols灵感来自 libp2p 的 multiaddr主要区别在于使用 BCS 描述二进制格式并缩减了支持的协议集合。数据结构上NetworkAddress是一组Protocol的序列pub struct NetworkAddress(VecProtocol); pub enum Protocol { Ip4(Ipv4Addr), Ip6(Ipv6Addr), Dns(DnsName), Dns4(DnsName), Dns6(DnsName), Tcp(u16), Memory(u16), NoiseIK(x25519::PublicKey), Handshake(u8), }人类可读格式的规则是每个段形如/Protocol/ProtocolConfig其中Protocol与ProtocolConfig不能包含正斜杠/且必须可 UTF-8 编码例如Ip4([127, 0, 0, 1]) /ip4/127.0.0.1, Dns(example.com) /dns/example.com, Tcp(6080) /tcp/6080, Memory(1234) /memory/1234, NoiseIK(b080e2878...a487120) /ln-noise-ik/080e287879c918794170e258bfaddd75acac5b3e350419044655e4983a487120, Handshake(0) /ln-handshake/0,一个地址必须满足恰好包含一个 Layer3 协议Ip4/Ip6/Dns之一与一个 Layer4 协议TcpMemory是同时充当 Layer3 与 Layer4 的特殊协议任一协议至多使用一次地址不能以/结尾。可升级性节点可以同时公告多个NetworkAddress从而实现不兼容的网络协议升级。例如从Noise_IK_25519_AESGCM_SHA256切换到Noise_IX_25519_ChaChaPoly_BLAKE2s时新版本二进制可同时公告新旧两种握手协议addrs : [ /ip4/1.2.3.4/tcp/6181/ln-noise-ix/pubkey/ln-handshake/0, // new protocol /ip4/1.2.3.4/tcp/6180/ln-noise-ik/pubkey/ln-handshake/0, // old protocol ]旧节点拨号时选用旧协议地址新节点之间可用新协议通信从而在升级滚动期间保持连通性全部节点升级后再轮换掉旧协议并最终从代码库中移除旧握手逻辑。仓库中的类型定义与 BCS 序列化实现见 types/src/network_address/mod.rs其文档注释给出了一个序列化示例/ip4/10.0.0.16/tcp/80序列化为字节[09 02 00 0a 00 00 10 05 80 00]。DiemNetNetworkAddress通过 onchain discovery 协议公告或存储在本地配置中。发现机制DiscoveryDiemNet 不规定单一的节点发现方法验证节点网络与全节点网络使用不同的发现机制验证节点之间通过 onchain discovery 协议互相发现所有节点通过 onchain discovery 协议发现 VFN初始引导bootstrap所需的发现信息以seed peers的形式通过配置提供。这些发现协议运行在核心 DiemNet 协议之上。On-chain Discovery 要点onchain-discovery.md 说明链上发现是一个认证的发现协议节点借此学习验证节点与 VFN 的网络地址和网络身份公钥。它利用 Move 语言与 Diem 区块链作为认证数据源将验证节点的RawEncNetworkAddress与 VFN 的RawNetworkAddress公告信息以ValidatorSet形式存储在OnChainConfig中struct ValidatorSet { scheme: ConsensusScheme, payload: VecValidatorInfo, } struct ValidatorInfo { account_address: AccountAddress, consensus_voting_power: u64, config: ValidatorConfig, } struct ValidatorConfig { consensus_public_key: Ed25519PublicKey, validator_network_addresses: VecRawEncNetworkAddress, full_node_network_addresses: VecRawNetworkAddress, }引导Bootstrapping节点使用存储中已知的最新验证节点集合可能是创世状态进行引导若落后太多则使用本地配置中的 seed peers。只要至少有一个对等节点接受引导节点的连接引导节点就能逐步追赶到最新 epoch 并学习该 epoch 的ValidatorSet。稳态Steady State节点跟上进度后通过自己的 state-sync 模块接收链上验证节点集合的更新。密钥与地址轮换网络密钥/地址轮换与共识密钥轮换遵循同一流程——提交交易设置ValidatorInfo→ 等待交易提交并触发 reconfiguration → 验证节点观察到 reconfiguration 后本地更新监听地址/出站公钥。规范还给出了自动化密钥轮换的示例从pubkey1轮换到pubkey2及边缘情况分析如提交轮换交易后崩溃、旧公钥不再被信任时可通过公共 VFN 端点 epoch sync 恢复或采用两阶段轮换先同时公告新旧公钥。注意事项Caveats修改发现信息需要仲裁quorum。若验证节点集合失去仲裁如 1/3 以上验证节点崩溃并丢失身份公钥验证节点将无法通过提交交易恢复连通性此时可行的回退方案是手动为每个验证节点配置 seed peers或由 Diem 协会签发新的 Genesis Transaction 手动设置新的验证节点集合。连接生命周期Connection Lifecycle连接建立Connection Establishment连接握手过程的展开视图如下server: TCP::bind [address] client: discover server_address /ip4/[address]/ln-noise-ik/[public_key]/ln-handshake/[version] ... // TCP handshake client: TCP::connect [address] server: TCP::accept // DiemNet Noise IK handshake client: server_peer_id Noise::upgrade_outbound [public_key] server: client_peer_id Noise::upgrade_inbound // DiemNet version handshake client: (server_version, server_protocols) Handshake::upgrade [version] server: (client_version, client_protocols) Handshake::upgrade [version]其中Noise::upgrade_outbound与Noise::upgrade_inbound定义于 Noise#HandshakeHandshake::upgrade定义于 Handshake-v1。整体上一条 DiemNet 连接经过三阶段建立TCP 三次握手 → Noise IK 安全握手建立加密与认证→ DiemNet 版本握手协商消息协议版本与应用协议集合。连接去重Connection DeduplicationDiemNet v1 尝试维护每对等节点至多一条连接。若某对等节点尝试向同一服务端打开多条连接服务端只保留最新连接并关闭更早的连接。在点对点模式下两个节点也可能同时拨号对方此时需要确定性的 tie-breaking 规则双方比较两条连接的拨号方PeerId保留拨号方PeerId更大按字典序的那条连接。消息协议与分帧Messaging Protocol Framing连接建立并协商完成后对等节点开始按照 DiemNet 消息协议交换消息。消息在通过底层 TCP 连接收发前使用 Noise#Post-handshake 定义的Noise::encrypt与Noise::decrypt进行分帧、加密和解密。注意一个 Noise 帧中可以承载多个NetworkMsg。消息类型在线上用 BCS 编码首个字节为消息类型最多支持 127 种消息类型enum NetworkMessage { Error(ErrorCode), RpcRequest(RpcRequest), RpcResponse(RpcResponse), DirectSendMsg(DirectSendMsg), }RPC 协议请求方发送NetworkMessage::RpcRequest含request_id、protocol_id、priority与原始请求载荷响应方以相同request_id的NetworkMessage::RpcResponse回复应用层错误应封装在RpcResponse内部。DirectSend 协议发送方以NetworkMessage::DirectSendMsg发送单向即发即忘消息protocol_id标识应用协议。消息优先级RpcRequest/RpcResponse/DirectSendMsg均含priority字段0..255越大越紧急作为收发两端的尽力而为的调度信号规范明确参考实现当前并不真正依据priority重排或丢弃消息。错误处理错误以NetworkMessage::Error发送ErrorCode指示错误类型如NotSupported(1, ProtocolId)规范不强制要求回复错误且一条消息至少要有 2 字节长度才足以触发有意义的错误响应。流控Flow controlDiemNet 不定义背压/流控机制各端点可自由实现本地策略如不发放 TCP 窗口更新来防范话痨邻居。分帧Framing每条序列化后的 DiemNet 消息以大端 4 字节u32长度前缀分帧。这些消息帧随后通过 Noise 包装的 socket其内部有独立的分帧、加密与解密发送。因此一个消息帧可能横跨多个 Noise 帧一个 Noise 帧也可能包含多个消息帧[u32-length-prefix] || [serialized-message-bytes] || ..最大帧尺寸每条serialized-message-bytes必须 ≤ 8 MiB8388608 字节该长度不含u32长度前缀。服务端应拒绝超过 8 MiB 的入站消息客户端禁止发送超过该限制的出站消息。读取单条消息的伪代码const MAX_DIEMNET_FRAME_LEN: u32 8388608; // 8 MiB let length_prefix: u32 noise_socket.read(4).to_host_endian(); if length_prefix MAX_DIEMNET_FRAME_LEN { reject; } let message_bytes noise_socket.read(length_prefix); let message bcs::from_bytes(message_bytes);Noise 层分片由于 Noise 层将帧大小限制在至多65535字节其中16字节始终预留给 AES-GCM 认证标签因此序列化的NetworkMsg含大端 4 字节长度前缀在发送前必须先切分为至多65535 - 16 65519字节的块。规范给出了发送单条NetworkMsg的简化伪 Rust 代码const MAX_NOISE_FRAME_LEN: u16 65519; // u16::MAX - AES_GCM_TAG_LEN const MAX_DIEMNET_FRAME_LEN: u32 8388608; // 8 MiB fn send_one_msg_and_flush(socket: TcpStream, msg: NetworkMsg) { // Serialize the message using BCS let msg_bytes bcs::to_bytes(msg); if msg_bytes.len() MAX_DIEMNET_FRAME_LEN { abort(serialized message is too large!); } let msg_len: [u8; 4] msg_bytes.len().to_big_endian_bytes(); // Concatenate the msg length and serialized msg bytes into a msg frame let msg_frame msg_len || msg_bytes; // Split the msg frame into chunks of size at-most MAX_NOISE_FRAME_LEN bytes for msg_chunk in msg_frame.chunks(MAX_NOISE_FRAME_LEN) { // Encrypt the msg chunk (and append the authentication tag) let crypto_bytes Noise::encrypt_with_ad(null, msg_chunk); let crypto_len: [u8; 2] crypto_bytes.len().to_big_endian_bytes(); // Concatenate the length and encrypted bytes into a crypto frame let crypto_frame crypto_len || crypto_bytes; // Send the encrypted frame over-the-wire socket.send(crypto_frame); } }这套分帧逻辑在源码中的对应实现位于 network/src/protocols/wire/messaging/v1/mod.rsnetwork_message_frame_codec通过LengthDelimitedCodec配置 4 字节大端长度字段与最大帧长限制NetworkMessageSink用 BCS 序列化消息后写入帧NetworkMessageStream读取帧后反序列化为NetworkMessage反序列化失败会记录帧长与帧前缀用于调试。其配套测试见同目录下的test.rs。连接终止Connection Termination对等节点可能在任何时刻无警告地崩溃或断开连接合规实现必须处理这些情况。优雅关闭graceful shutdown的流程为先排空待发送的未决出站消息drain pending outbound messages然后发送 TCP 写半关闭write half-close最后继续排空入站消息直到观察到远端对等节点的 TCP 写半关闭。从规范到实现如何在仓库中继续深入围绕本规范你可以在仓库中按以下路径继续研读DiemNet 总规范specifications/network/README.md子规范noise.mdNoise 层、handshake-v1.md握手协议、messaging-v1.md消息协议、network-address.mdNetworkAddress、onchain-discovery.md链上发现网络栈源码network/src/protocols/wire/handshake/v1/mod.rs握手消息与perform_handshake、network/src/protocols/wire/messaging/v1/mod.rs消息类型与分帧编解码、network/src/noise/handshake.rsNoise 握手与时间戳载荷、types/src/network_address/mod.rsNetworkAddress类型与 BCS 序列化传输层network/netcore/src/transport/tcp.rsTCP 传输、network/netcore/src/transport/memory.rs内存传输用于测试网络模块入口network/src/lib.rs、network/src/peer_manager/mod.rs对等节点管理与连接去重值得注意的一点是规范文档与代码在个别细节上存在演进差异例如规范中的ProtocolId枚举列出 8 个变体含OnchainDiscoveryRpc/IdentityDirectSend而当前源码 network/src/protocols/wire/handshake/v1/mod.rs 实现为 7 个变体含ConsensusDirectSendJSON读取源码时以当前实现为准。规范中HandshakeMsg的数据结构与源码实现也存在类似差异源码额外携带chain_id与network_id以增强握手校验。理解这种规范描述理想形态、源码承载落地实现的关系有助于你更准确地把握 DiemNet 的真实行为。赞分享区块链金融科技【免费下载链接】diemDiem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.项目地址https://gitcode.com/gh_mirrors/di/diem点击查看免费下载相关推荐CANN/asc-devkit向量计算APIasc_int162half 产品支持情况 | 产品 | 是否支持 | | : | : :| | term Atlas A3 训练系列产品/Atlas A3人工智能深度学习算子库CANNAscendShiny.BluetoothLE开发教程轻松实现跨平台蓝牙通信Shiny.BluetoothLE开发教程轻松实现跨平台蓝牙通信 Shiny.BluetoothLE是一个强大的.NET框架组件专为iOS、Android和nanomsg网络协议解析从TCP握手到消息解码的完整指南nanomsg网络协议解析从TCP握手到消息解码的完整指南 nanomsg是一个高性能的异步消息传递库它实现了多种通信模式包括请求 响应、发布 订阅、管道消息队列通信创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表