2. P2P网络管理

2.1. 概述

chainmaker网络模块支持Libp2pLiquid两种模式 下面详细介绍每种模式的管理操作。

了解网络模块的设计方案,请点击如下链接: P2P网络设计文档

2.2. Libp2p管理

2.2.1. 在chainmaker中启用Libp2p

Lib2p2的参数配置主要在chainmaker.yml(-c 启动参数指定的文件)配置文件中net标签下,具体参数如下:

net:
  # 底层网络类型,必选项,支持libp2p
  provider: LibP2P
  # 本地网路监听地址及端口,必选项
  listen_addr: /ip4/0.0.0.0/tcp/11301
  # 每个节点连接stream池大小上限,可选项,不配默认为100
  peer_stream_pool_size: 100
  # 允许与本节点建立链接的节点总数量,可选项,不配默认为20
  max_peer_count_allow: 10
  # 节点连接淘汰策略,可选项,1 Random, 2 FIFO, 3 LIFO。不配默认为3
  peer_elimination_strategy: 3
  # 种子节点地址列表,用于节点发现,可选项
  # 建议将所有已知共识节点网络地址都配置为种子节点
  # seeds ip格式为: "/ip4/127.0.0.1/tcp/11301/p2p/"+nodeid
  # seeds dns格式为:"/dns/cm-node1.org/tcp/11301/p2p/"+nodeid
  seeds: 
    - "/ip4/127.0.0.1/tcp/11301/p2p/QmQZn3pZCcuEf34FSvucqkvVJEvfzpNjQTk17HS6CYMR35"
  # TLS认证相关配置
  tls:
    # TLS认证开关,必选项,当前必须为true
    enabled: true
    # TLS证书配置,必选项
    priv_key_file: ./crypto-config/wx-org1.chainmaker.org/node/consensus1/consensus1.tls.key
    cert_file:     ./crypto-config/wx-org1.chainmaker.org/node/consensus1/consensus1.tls.crt
  # 组网黑名单配置,可选项,不配默认不开启黑名单
  blacklist:
    # 黑名单地址,可选项,[ip]:[port]或者[ip]两者均可
    addresses:
      - "127.0.0.1:11305"
      - "192.168.1.8"
    # 黑名单节点ID,可选项
    node_ids:
      - "QmeyNRs2DwWjcHTpcVHoUSaDAAif4VQZ2wQDQAUNDP33gH"
      - "QmVSCXfPweL1GRSNt8gjcw1YQ2VcCirAtTdLKGkgGKsHqi"

2.2.2. 节点总连接数管理

节点连接数到达上限后,当新的节点要连接本节点时,本节点会根据连接淘汰策略,从现有的连接淘汰一个,淘汰策略有:

  1. Random策略:

如果新节点优先级为高,优先随机淘汰一个低优先级节点,若没有低优先级节点,则随机淘汰一个高优先级节点。

如果新节点优先级为低,随机淘汰一个低优先级节点,若没有低优先级节点,则淘汰该新节点。

  1. FIFO: 先进先出策略:

如果新节点优先级为高,优先淘汰一个最早添加的低优先级节点,若没有低优先级节点,则淘汰一个最早添加的高优先级节点。

如果新节点优先级为低,淘汰一个低优先级节点,若没有低优先级节点,则淘汰该新节点。

  1. LIFO: 后进先出策略:

如果新节点优先级为高,优先淘汰一个最晚添加的低优先级节点,若没有低优先级节点,则淘汰该新节点。

如果新节点优先级为低,淘汰该新节点。

Libp2p的淘汰策略与Liquid保持一致

2.2.3. 节点连接认证

在链初始化阶段,网络模块会将根据链配置(例如:bc1.yml)中的trust_roots配置的根证书创建TLS根证书池,在节点连接建立时,TLS握手阶段会依次使用每条链的TLS根证书池验证对方节点TLS证书,若认证通过则认为对方节点属于当前根证书池对应的链,确定链ID,并将对方节点ID加入到对应链的pubsub服务白名单中。这样就可以保证链内的广播消息不会发送给不属于该链组织的节点。

在多链场景下,只需要保证每个链的trust_roots里都配有该节点TLS证书对应的CA或根证书即可,不需要额外的其他配置。

例如:

1.假设节点N有两个链分别是blockchain1、blockchain2;

2.假设节点N的TLS证书是由组织ID为“wx-org2.chainmaker.org”的CA证书签发;

3.假设blockchain1链的配置文件为bc1.yml,blockchain2链的配置文件为bc2.yml。

那么bc1.yml中trust_roots配置:

trust_roots:
  - org_id: "wx-org1.chainmaker.org"
    root: "../config/wx-org1/certs/ca/wx-org1.chainmaker.org/ca.crt"
  - org_id: "wx-org2.chainmaker.org"
    root: "../config/wx-org2/certs/ca/wx-org2.chainmaker.org/ca.crt"

bc2.yml中trust_roots配置:

trust_roots:
  - org_id: "wx-org2.chainmaker.org"
    root: "../config/wx-org2/certs/ca/wx-org2.chainmaker.org/ca.crt"
  - org_id: "wx-org3.chainmaker.org"
    root: "../config/wx-org3/certs/ca/wx-org3.chainmaker.org/ca.crt"

这样节点N就既属于blockchain1链也属于blockchain2链,但两个链间的数据是隔离的。

2.3. Liquid管理

2.3.1. 在chainmaker中启用Liquid

Liquid的参数配置同样在chainmaker.yml(-c 启动参数指定的文件)配置文件中net标签下,具体参数如下:

net:
  # 底层网络类型,必选项,支持liquid
  provider: liquid
  # 本地网路监听地址及端口,必选项
  listen_addr: /ip4/0.0.0.0/tcp/11301
  # 每个节点连接stream池大小上限,可选项,不配默认为100
  peer_stream_pool_size: 100
  # 允许与本节点建立链接的节点总数量,可选项,不配默认为20
  max_peer_count_allow: 10
  # 节点链接淘汰策略,可选项,1 Random, 2 FIFO, 3 LIFO。不配默认为3
  peer_elimination_strategy: 3
  # 节点最大连接数
  max_conn_count_each_peer: 5
  # 大消息体拆包/组包
  pkt_enabled: true
  # 消息发送优先级控制
  priority_control: true
  # 种子节点地址列表,用于节点发现,可选项
  # 建议将所有已知共识节点网络地址都配置为种子节点
  # seeds ip格式为: "/ip4/127.0.0.1/tcp/11301/p2p/"+nodeid
  # seeds dns格式为:"/dns/cm-node1.org/tcp/11301/p2p/"+nodeid
  seeds: 
    - "/ip4/127.0.0.1/tcp/11301/p2p/QmQZn3pZCcuEf34FSvucqkvVJEvfzpNjQTk17HS6CYMR35"
  # TLS认证相关配置
  tls:
    # TLS认证开关,必选项,当前必须为true
    enabled: true
    # TLS证书配置,必选项
    priv_key_file: ./crypto-config/wx-org1.chainmaker.org/node/consensus1/consensus1.tls.key
    cert_file:     ./crypto-config/wx-org1.chainmaker.org/node/consensus1/consensus1.tls.crt
  # 组网黑名单配置,可选项,不配默认不开启黑名单
  blacklist:
    # 黑名单地址,可选项,[ip]:[port]或者[ip]两者均可
    addresses:
      - "127.0.0.1:11305"
      - "192.168.1.8"
    # 黑名单节点ID,可选项
    node_ids:
      - "QmeyNRs2DwWjcHTpcVHoUSaDAAif4VQZ2wQDQAUNDP33gH"
      - "QmVSCXfPweL1GRSNt8gjcw1YQ2VcCirAtTdLKGkgGKsHqi"

要想在chainmaker-go中启用Liquid作为网络实现,只需将

net:
  provider: libp2p

改为

net:
  provider: liquid

Liquid与Libp2p传输协议不兼容,所以使用Liquid的节点与使用Libp2p的节点无法建立连接。

Liquid支持TCP、QUIC两种底层传输协议,具体使用哪种协议会根据本地监听地址自动识别。

使用TCP举例:

net:
  listen_addr: /ip4/0.0.0.0/tcp/11301

使用QUIC举例:

net:
  listen_addr: /ip4/0.0.0.0/udp/11301/quic

其他节点地址格式也需要对应,例如:

使用TCP:

/ip4/127.0.0.1/tcp/11302/p2p/QmcQHCuAXaFkbcsPUj7e37hXXfZ9DdN7bozseo5oX4qiC4

使用QUIC:

/ip4/127.0.0.1/udp/11302/quic/p2p/QmcQHCuAXaFkbcsPUj7e37hXXfZ9DdN7bozseo5oX4qiC4

2.3.2. Liquid在chainmaker中的扩展特性支持

2.3.2.1. 多连接自动扩容复用并行发送

Liquid支持多连接复用并行发送,假设我们允许与每个其他节点最多创建5个连接,可通过如下配置开启:

net:
  max_conn_count_each_peer: 5

2.3.2.2. 大消息体拆包/组包

LiquidNet支持将大消息体拆分为最多256个小包并行发送和将接收的若干小包组装为一个大消息体的功能。目的是提升大消息体的发送效率。可通过如下配置开启:

net:
  pkt_enabled: true

2.3.2.3. 消息发送优先级控制

LiquidNet支持消息发送优先级控制,可通过如下配置开启:

net:
  priority_control: true

优先级总共划分为[0,9]总共10级,值越高,优先级越高。

默认优先级:

优先级9:共识引擎消息

优先级8:区块消息

优先级7:交易消息

优先级5:同步引擎消息

2.3.2.4. 中继转发

Liquid Relay(中继)介绍

Relay(中继)的使用需要在特殊的网络环境下,例如下图:

../_images/P2P-Relay-Demo.png

场景:

  • node1位于内网1

  • node2,node3,node4位于内网2,并且node2,node3和node4之间采用内网地址互相连接

  • node2有一个外网可以访问的地址和端口映射

在这种场景下,如果不采用Relay或者NAT穿透功能的话,虽然node1和node2之间可以建立连接,但是node1与node3,node1与node4之间并不能打通进行直接通信。当我们启用中继功能,配置中继地址的话,就可以通过node2作为媒介,将node1<—>node3node1<—>node4建立。具体配置如下:

在节点配置文件chainmaker.yml里,我们找到网络的配置部分

net:
  # Network provider, can be libp2p or liquid.
  # libp2p: using libp2p components to build the p2p module.
  # liquid: a new p2p network module. We build it from 0 to 1.
  # This item must be consistent across the blockchain network.
  provider: liquid

  # The address and port the node listens on.
  # By default, it uses 0.0.0.0 to listen on all network interfaces.
  listen_addr: /ip4/0.0.0.0/tcp/11301

  # Max stream of a connection.
  # peer_stream_pool_size: 100

  # Max number of peers the node can connect.
  # max_peer_count_allow: 20

  # The strategy for eliminating node when the amount of connected peers reaches the max value
  # It could be: 1 Random, 2 FIFO, 3 LIFO. The default strategy is LIFO.
  # peer_elimination_strategy: 3

  # The seeds list used to setup network among all the peer seed when system starting.
  # The connection supervisor will try to dial seed peer whenever the connection is broken.
  # Example ip format: "/ip4/127.0.0.1/tcp/11301/p2p/"+nodeid
  # Example dns format:"/dns/cm-node1.org/tcp/11301/p2p/"+nodeid
  seeds:
    - "/ip4/82.156.18.139/tcp/11302/p2p/QmUiTTdDZ1SSEozG9nCKZwndM2r4eTHUXKtBEJrBGKpnR4"
    - "/ip4/82.156.18.139/tcp/11302/p2p/QmUiTTdDZ1SSEozG9nCKZwndM2r4eTHUXKtBEJrBGKpnR4/p2p-circuit/p2p/QmcVgh7SioZJo8Fq5XKr7DeoHqmtGz5yDZ6XtXw2HmFz2d"
    - "/ip4/82.156.18.139/tcp/11302/p2p/QmUiTTdDZ1SSEozG9nCKZwndM2r4eTHUXKtBEJrBGKpnR4/p2p-circuit/p2p/QmVwpnUqq6VYCGzRMGkPLvVqLfWHWttdg4DpqBRQofXFvU"

在网络的配置部分,我们找到种子节点配置seeds,按照上文图片中的案例,依次配置node1,node2,node3,node4的seeds部分

  • 已知环境

    node2 ID:QmUiTTdDZ1SSEozG9nCKZwndM2r4eTHUXKtBEJrBGKpnR4

    node3 ID:QmcVgh7SioZJo8Fq5XKr7DeoHqmtGz5yDZ6XtXw2HmFz2d

    node4 ID:QmVwpnUqq6VYCGzRMGkPLvVqLfWHWttdg4DpqBRQofXFvU

    node2 内网IP端口:172.21.32.5:11302

    node2 外网IP端口:82.156.18.139:11302

    node3 内网IP端口:172.21.32.7:11303

    node4 内网IP端口:172.21.32.6:11304

  • 具体配置

    node1 seeds:

    seeds:
        - "/ip4/82.156.18.139/tcp/11302/p2p/QmUiTTdDZ1SSEozG9nCKZwndM2r4eTHUXKtBEJrBGKpnR4"
        - "/ip4/82.156.18.139/tcp/11302/p2p/QmUiTTdDZ1SSEozG9nCKZwndM2r4eTHUXKtBEJrBGKpnR4/p2p-circuit/p2p/QmcVgh7SioZJo8Fq5XKr7DeoHqmtGz5yDZ6XtXw2HmFz2d"
        - "/ip4/82.156.18.139/tcp/11302/p2p/QmUiTTdDZ1SSEozG9nCKZwndM2r4eTHUXKtBEJrBGKpnR4/p2p-circuit/p2p/QmVwpnUqq6VYCGzRMGkPLvVqLfWHWttdg4DpqBRQofXFvU"
    

    node2 seeds:

    seeds:
        - "/ip4/172.21.32.7/tcp/11303/p2p/QmcVgh7SioZJo8Fq5XKr7DeoHqmtGz5yDZ6XtXw2HmFz2d"
        - "/ip4/172.21.32.6/tcp/11304/p2p/QmVwpnUqq6VYCGzRMGkPLvVqLfWHWttdg4DpqBRQofXFvU"
    

    node3 seeds:

    seeds:
        - "/ip4/172.21.32.5/tcp/11302/p2p/QmUiTTdDZ1SSEozG9nCKZwndM2r4eTHUXKtBEJrBGKpnR4"
        - "/ip4/172.21.32.6/tcp/11304/p2p/QmVwpnUqq6VYCGzRMGkPLvVqLfWHWttdg4DpqBRQofXFvU"
    

    node4 seeds:

    seeds:
        - "/ip4/172.21.32.5/tcp/11302/p2p/QmUiTTdDZ1SSEozG9nCKZwndM2r4eTHUXKtBEJrBGKpnR4"
        - "/ip4/172.21.32.7/tcp/11303/p2p/QmcVgh7SioZJo8Fq5XKr7DeoHqmtGz5yDZ6XtXw2HmFz2d"
    
  • 配置详解

    假设节点QmA要通过中继节点QmR连接节点QmB

    /ip4/7.7.7.7/tcp/55555/p2p/QmR/p2p-circuit/p2p/QmB
    
    • ip4:ipv4协议的标志

    • 7.7.7.7:中继节点QmR的IP地址

    • tcp:采用tcp协议

    • 55555:中继节点QmR的端口号

    • p2p:p2p协议标志(用于切割地址的符号)

    • QmR:节点QmR的PeerId

    • p2p-circuit:中继地址的标志(用于切割中继地址的符号)

    • QmB:要连接目的节点的PeerId

2.3.2.5. NAT穿透

在满足两个节点所在NAT类型是可以打洞成功的条件下,liquid网络一般无需添加额外配置,即可实现NAT穿透。

特出情况:如果同时满足下面3个条件,需要在chainmaker.yml中额外配置 enable_punch: true

  • ①两个需要NAT穿透才能互联的节点。

  • ②两节点的chainmaker.yml文件中listen_addr字段均为tcp协议。

  • ③两节点的listen_addr端口是相同的(即他们的tcp listen端口相同)。

(只有tcp会出现这种情况的原因是:liquid针对tcp协议实现了特有的tls握手方式,该握手方式对端口有一定要求)

下面实例表示 enable_punch: true 和seeds处于同一级,不需要配置 enable_punch: true以外的任何内容。正常情况建议 不要配置这个选项。

seeds:
    - "/ip4/172.21.32.5/tcp/11302/p2p/QmUiTTdDZ1SSEozG9nCKZwndM2r4eTHUXKtBEJrBGKpnR4"

enable_punch: true