# 独立运行的 PoSter 节点

在早期版本中,虽然 damocles-manager 已经支持通过 daemon run 命令的 --poster--miner 参数来选择是否启用相应的模块,但由于 post 证明过程与扇区定位信息的强关联,使得真正使用时,局限性比较大,且难以扩展。

从 v0.2.0 版本起,我们提供了一系列的功能组合,使得易用、可扩展的独立 PoSter 节点成为大体量多矿工号 SP 的一种可选方案。

以下,我们会介绍这些新的功能点,并提供一种通过这些功能完成独立 PoSter 节点部署的实践。后续文档都以开启 --poster 的节点作为示例,独立的 --miner 节点运作方式与之类似,不再单独阐述。


在 v0.8.0 版本中,damocles 支持三种方式独立运行 PoSter 节点,分别是 worker-prover 模式、代理节点模式、ext-prover 模式 (外部执行器模式)。

# worker-prover 模式

worker-prover 模式是 v0.8.0 新增的功能,特点是简单,可以非常轻松的支持多机 wdpost。

# 基本原理

worker-prover 模式利用 damocles-worker 计算 window post 证明,通过 RPC 的方式从 damocles-manager 获取 window post 任务和返回计算的结果。

damocles-worker 新增 wdpost planner 用于执行 window post 任务。

# Architecture

                +-----------------------------------+
                |     damocles-manager daemon       |
                |     with --worker-prover flag     |
                |                                   |
                |        +-----------------+        |
                |        |damocles-manager |        |
                |        |  poster module  |        |
                |        +-------+-^-------+        |
                |           send | |recv            |
                |                | |                |
                |        +-------v-+-------+        |
                |        |  worker-prover  |        |
       +--------+-------->      module     <--------+--------+
       |        |        +--------^--------+        |        |
       |        |                 |                 |        |
       |        +-----------------+-----------------+        |
       |                          |                          |
-------+--------------------------+--------------------------+------------
       |                          |                          |
       | pull job                 | pull job                 | pull job
       | push res                 | push res                 | push res
       | by rpc                   | by rpc                   | by rpc
       |                          |                          |
+------+--------+         +-------+-------+           +------+--------+
|damocles-worker|         |damocles-worker|           |damocles-worker|
|wdpost planner |         |wdpost planner |  ...      |wdpost planner |
+---------------+         +---------------+           +---------------+

# damocles-manager 配置与启动

新增配置:

# ~/.damocles-manager/sector-manager.cfg

# ...

[Common.Proving.WorkerProver]
# WindowPoSt 任务的最大尝试次数,可选项,数字类型
# 默认值为 2
# 尝试次数超过 JobMaxTry 的 WindowPoSt 任务只能通过手动 reset 的方式被重新执行
JobMaxTry = 2
# WindowPoSt 任务的心跳超时时间,可选项,时间字符串类型
# 默认值为 15s
# 超过此时间没有发送心跳的任务将会被设置为失败并重试
HeartbeatTimeout = "15s"
# WindowPoSt 任务的过期时间,可选项,时间字符串类型
# 默认值为 25h
# 创建时间超过此时间的 WindowPoSt 任务将会被删除
JobLifetime = "25h0m0s"

# ...

启动 damocles-manager 进程:

# --miner flag 可选添加,表示启动 miner 模块用于执行 WinningPoSt 并出块
# --poster flag 必须添加,表示启动 WindowPoSt 模块
# --worker-prover 必须添加,表示使用 WorkerProver 模块执行 WindowPoSt
./damocles-manager daemon run --miner --poster --worker-prover

# damocles-worker 配置

配置解释:

[[sealing_thread]]
# 配置使用 wdpost plan
plan = "wdpost"
# 配置只允许执行指定矿工号的任务,为空则表示不限制
# sealing.allowed_miners = [6666, 7777]
# 配置只允许运行指定 size 的扇区的任务
# allowed_sizes = ["32GiB", "64GiB"]

[[attached]]
# 配置此 worker 执行 window post 任务过程中会用到的永久存储
name = "miner-6666-store"
location = "/mnt/miner-6666-store"


# 控制 window_post 任务并发 (可选),不配置则不限制
[processors.limitation.concurrent]
window_post = 2

[[processors.window_post]]
# 使用自定义 wdpost 算法 (可选),如果不配置 bin,则默认使用内置算法
bin="~/my_algorithm"
args = ["window_post"]
# 限制子进程可使用的 cpu
cgroup.cpuset = "10-19"
# 配置自定义算法的环境变量 (可选)
envs = { BELLMAN_GPU_INDEXS="0", CUDA_VISIBLE_DEVICES="0", TMPDIR = "/tmp/worker-prover1/", ... }
# 配置本进程最大并发数量 (可选),不配置则不限制
concurrent = 1
# 一份最简的只启动一个 wdpost sealing_thread 的配置如下:
# /path/to/your-damocles-worker-config.toml

[worker]
name = "damocles-worker-USA-01"

[sector_manager]
rpc_client.addr = "/ip4/your-damocles-manager-address-here/tcp/1789"

[[sealing_thread]]
plan = "wdpost"
# 尝试领取任务的时间间隔,默认为 60s,
# 针对 wdpost plan 我们可以调小此值便于更快的领取到新的 wdpost 任务
sealing.recover_interval = "15s"
# sealing.allowed_miners = [6666]
# sealing.allowed_sizes = ["32GiB"]
# ...

[[attached]]
name = "miner-6666-store"
location = "/mnt/miner-6666-store"
# 单机单卡同时做 2 个 wdpost 的配置示例
# /path/to/your-damocles-worker-config.toml

[worker]
name = "damocles-worker-USA-01"

[sector_manager]
rpc_client.addr = "/ip4/your-damocles-manager-address-here/tcp/1789"

[[sealing_thread]]
plan = "wdpost"
sealing.recover_interval = "15s"
sealing.allowed_miners = [6666]
# ...

[[sealing_thread]]
plan = "wdpost"
sealing.recover_interval = "15s"
sealing.allowed_miners = [7777]
# ...

[[attached]]
name = "miner-6666-store"
location = "/mnt/miner-6666-store"

[[attached]]
name = "miner-7777-store"
location = "/mnt/miner-7777-store"

# -------------------------

[[processors.window_post]]
bin="~/my_algorithm"
# args = ["window_post", ...]
cgroup.cpuset = "10-19"
envs = { CUDA_VISIBLE_DEVICES="0", TMPDIR = "/tmp/worker-prover1/", ... }
concurrent = 1

[[processors.window_post]]
bin="~/my_algorithm"
# args = ["window_post", ...]
cgroup.cpuset = "20-29"
envs = { CUDA_VISIBLE_DEVICES="0", TMPDIR = "/tmp/worker-prover1/", ... }
concurrent = 1

单卡同时做 2 个 wdpost 的意义在于因为计算 vanilla_proofs 时不使用显卡,两个 wdpost 任务的 vanilla_proofs 可以并行计算,而计算 snark_proof 时利用 TMPDIR 中的 gpu 锁文件串行计算。可以大幅度提高 GPU 的利用率。

# 单机两张显卡同时做 wdpost 的配置示例
# /path/to/your-damocles-worker-config.toml

[worker]
name = "damocles-worker-USA-01"

[sector_manager]
rpc_client.addr = "/ip4/your-damocles-manager-address-here/tcp/1789"

[[sealing_thread]]
plan = "wdpost"
sealing.recover_interval = "15s"
sealing.allowed_miners = [6666]
# ...

[[sealing_thread]]
plan = "wdpost"
sealing.recover_interval = "15s"
sealing.allowed_miners = [7777]
# ...

[[attached]]
name = "miner-6666-store"
location = "/mnt/miner-6666-store"

[[attached]]
name = "miner-7777-store"
location = "/mnt/miner-7777-store"

# -------------------------

[[processors.window_post]]
# bin="~/my_algorithm"
# args = ["window_post", ...]
envs = { ... }
concurrent = 2

# ----------- 或者 ---------

#[[processors.window_post]]
# bin="~/my_algorithm"
# args = ["window_post", ...]
# cgroup.cpuset = "10-19"
# envs = { CUDA_VISIBLE_DEVICES="0", TMPDIR = "/tmp/worker-prover1/", ... }
# concurrent = 1

# [[processors.window_post]]
# bin="~/my_algorithm"
# args = ["window_post"]
# cgroup.cpuset = "20-29"
# envs = { CUDA_VISIBLE_DEVICES="1", TMPDIR = "/tmp/worker-prover2/", ... }
# concurrent = 1

damocles-worker 在运行 wdpost plan 时不需要使用 damocles-worker store sealing-init -l 命令初始化封装过程中数据的本地存储目录。

# 管理 window post 任务

  • # 显示 window post 任务列表

# 默认显示未完成的任务和失败的任务, 其中 DDL 字段表示任务的 deadline Index, Try 字段是任务的尝试次数
./damocles-manager util worker wdpost list

JobID           MinerID  DDL Partitions  Worker        State       Try  CreateAt        Elapsed      Heartbeat  Error
3FgfEnvrub1     1037     3   1,2         10.122.63.30  ReadyToRun  1    07-27 16:37:31  -            -
gbCVH4TUgEf     1037     2   1,2                       ReadyToRun  0    07-27 16:35:56  -            -
CrotWCLaXLa     1037     1   1,2         10.122.63.30  Succeed     1    07-27 17:19:04  6m38s(done)  -

# 显示全部任务
./damocles-manager util worker wdpost list --all
# ...

# 显示 window post 任务详细信息
./damocles-manager util worker wdpost list --detail
# ...
  • # 重置任务

当 window post 任务执行失败且自动重试次数达到上限时,可以手动重置任务状态,使其可以继续被 damocles-worker 领取并执行。

./damocles-manager util worker wdpost reset gbCVH4TUgEf 3FgfEnvrub1
  • # 删除任务

删除任务和重置任务能达到的效果类似。当执行了删除任务的命令后,damocles-manager 的重试机制会检测当前 deadline 的 window post 任务是否存在于数据库中,如果不存在则会重新下发一遍任务,并记录到数据库中。

另外 worker-prover 会自动的定时删除创建时间超过一定时间的任务 (默认为 25 小时,时间可配置)。

# 删除指定的任务
./damocles-manager util worker wdpost remove gbCVH4TUgEf 3FgfEnvrub1

# 删除全部任务
./damocles-manager util worker wdpost remove-all --really-do-it

# 禁止 damocles-manager 使用 GPU

启用 worker-prover 功能后,winning_post 由 damocles-manager 执行。如果不想让 winning_post 使用 GPU,可以使用如下命令编译 damocles-manager 禁止其使用 GPU。

make dist-clean
FFI_BUILD_FROM_SOURCE=1 FFI_USE_GPU=0 make build-manager

# 代理节点模式

我们知道,对于 PoSter 节点来说,最重要的能力是获取实时、准确的扇区定位信息。在当前 damocles-manager 版本中,我们暂时仅提供基于本地内嵌式 kv 数据库的元数据管理方式。

这使得数据仅能被一个进程管理,无法进行跨进程的直接数据共享。

因此,我们设计了代理节点模式,将部分元数据通过网络接口提供给其他需要的节点,以此实现数据共享。

# 代理节点的使用方式

我们在 daemon run 命令中增加了 --proxy 参数。它的格式是 {ip}:{port} 这样的地址格式。当启动命令包含有效的 --proxy 参数时,节点将会以其指向的另一个 damocles-manager 节点作为数据源,并构造出必要的元数据(只读)管理模块。

除了 --proxy 外,我们还提供了控制具体数据管理模块是否启用代理模式的开关。

目前,我们暂时仅提供 --proxy-sector-indexer-off 这一个开关。当启用 --proxy-sector-indexer-off 时,节点会使用自己的数据目录下的 SectorIndexer 数据库。

如果代理节点采用本地数据库且集群还在封装扇区时,不要启用 --proxy-sector-indexer-off,新封装的扇区元数据无法同步到代理节点的数据库,一旦 winningPoSt 选中了新封装扇区,无法正确计算证明,出块会失败!

举例来说,如果按 damocles-manager daemon run --miner 命令启动,那么将会存在一个使用 ~/.damocles-manager 作为数据目录,监听 1789 端口的 damocles-manager 实例,且启用挖矿模块。

这时,我们可以通过以下命令,在同一台机器上初始化并启动一个以上述实例作为数据源的代理节点,这个代理节点将会使用 ~/.damocles-manager2 作为数据目录,并监听 2789 端口。

damocles-manager --home ~/.damocles-manager2 daemon init
// 维护配置文件
damocles-manager --home ~/.damocles-manager2 daemon run --proxy="127.0.0.1:1789" --listen=":2789" --poster

代理节点能够提供与源节点完全一致且实时的扇区定位信息。

# 代理节点使用已有配置文件

按照上一节所述的方法,我们已经可以启动一个代理节点,但这种启动方式还存在一个问题:代理节点的配置文件需要再次编写一遍,或从源节点的数据目录中拷贝过来。这会带来额外的维护工作,尤其是在配置文件可能频繁发生变化的时候。

为此,我们还提供了一个 --conf-dir 参数,它的格式是一个可用的目录路径。当启动命令包含有效的 --conf-dir 参数时,节点将会使用指定目录中已存在的配置文件作为自己的配置文件。

这样,就可以省去编写、维护在同一台机器上的、为同一组集群提供服务的、不同源节点和代理节点的配置文件的工作。

基于这个功能,上一节中所提到的代理节点启动方式可以变成:

damocles-manager --home ~/.damocles-manager2 daemon run --proxy="127.0.0.1:1789" --listen=":2789" --conf-dir="~/.damocles-manager" --poster

此时,源节点和代理节点将会使用同一批配置文件。

# ext-prover 执行器

除了共享扇区信息之外,独立的 PoSter 节点面临的另一个挑战则是硬件资源的利用。

受限于底层算法库,计算节点对于 GPU 的使用只能以进程为单位。这使得 PoSter 节点难以有效发挥多块 GPU 的计算能力,也难以在多个 SP 存在 WindostPoSt 证明窗口期冲突的情况下,安全地避免证明超时。

为此,我们提供了类似 damocles-workerext processorext-prover 机制。

ext-prover 机制包含两个组成部分:

  1. daemon run 命令的 --ext-prover 参数
  2. 节点数据目录中的 ext-prover.cfg 配置文件

一个默认的 ext-prover.cfg 文件形如:

# Default config:
#[[WdPost]]
#Bin = "/path/to/custom/bin"
#Args = ["args1", "args2", "args3"]
#Concurrent = 1
#Weight = 1
#ReadyTimeoutSecs = 5
#[WdPost.Envs]
#ENV_KEY = "ENV_VAL"
#
#[[WinPost]]
#Bin = "/path/to/custom/bin"
#Args = ["args1", "args2", "args3"]
#Concurrent = 1
#Weight = 1
#ReadyTimeoutSecs = 5
#[WinPost.Envs]
#ENV_KEY = "ENV_VAL"
#

在最新版本中,daemon init 会初始化 ext-prover.cfg 文件。

使用者可以自行编写,或从一个由最新版本初始化的数据目录中拷贝相应文件到已存在的数据目中。

ext-prover.cfg 中各配置项的作用方式与 damocles-worker 中的配置块极为类似,使用者可以查阅相应文档进行参考。

damocles-manager 的启动命令中包含 --ext-prover 参数时,节点将使用配置目录中的 ext-prover.cfg 配置文件作为启动子进程的依据。对于这个配置文件,设置 --conf-dir 参数也会带来效果。

使用者看到类似这样的日志时,就表明 ext-prover 已就绪。

2022-04-27T19:15:00.441+0800    INFO    porver-ext      ext/prover.go:122       response loop start     {"pid": 24764, "ppid": 24732, "loop": "resp"}
2022-04-27T19:15:00.441+0800    INFO    porver-ext      ext/prover.go:155       request loop start      {"pid": 24764, "ppid": 24732, "loop": "req"}
2022-04-27T19:15:00.468+0800    INFO    processor-cmd   processor/processor.go:35       ready   {"pid": 24764, "ppid": 24732, "proc": "wdpost"}

# 部署实践

假设我们存在一台配置了 8 GPU 的节点机器,那么我们可以通过以下配置方式来提供更强的时空证明处理能力。

  1. 配置并启动源节点

    damocles-manager daemon run --miner
    

    此时,源节点只提供封装相关的功能和能力;

  2. 配置 ext-prover.cfg 文件:

    [[WdPost]]
    [WdPost.Envs]
    CUDA_VISIBLE_DEVICES = "0"
    TMPDIR = "/tmp/ext-prover0/"
    
    [[WdPost]]
    [WdPost.Envs]
    CUDA_VISIBLE_DEVICES = "1"
    TMPDIR = "/tmp/ext-prover1/"
    
    [[WdPost]]
    [WdPost.Envs]
    CUDA_VISIBLE_DEVICES = "2"
    TMPDIR = "/tmp/ext-prover2/"
    
    [[WdPost]]
    [WdPost.Envs]
    CUDA_VISIBLE_DEVICES = "3"
    TMPDIR = "/tmp/ext-prover3/"
    
    [[WdPost]]
    [WdPost.Envs]
    CUDA_VISIBLE_DEVICES = "4"
    TMPDIR = "/tmp/ext-prover4/"
    
    [[WdPost]]
    [WdPost.Envs]
    CUDA_VISIBLE_DEVICES = "5"
    TMPDIR = "/tmp/ext-prover5/"
    
    [[WdPost]]
    [WdPost.Envs]
    CUDA_VISIBLE_DEVICES = "6"
    TMPDIR = "/tmp/ext-prover6/"
    
    [[WdPost]]
    [WdPost.Envs]
    CUDA_VISIBLE_DEVICES = "7"
    TMPDIR = "/tmp/ext-prover7/"
    
    
  3. 初始化并启动独立 PoSter 节点

    damocles-manager --home=~/.damocles-individual-poster daemon init
    damocles-manager --home=~/.damocles-individual-poster daemon run --proxy="127.0.0.1:1789" --poster --listen=":2789" --conf-dir="~/.damocles-manager" --ext-prover
    

这种部署方式下,

  • 源节点同时提供封装和挖矿的支持
  • 代理节点提供 WindowPoSt 的支持
    • 代理节点启用 ext-prover,且每个子进程独立使用一块 GPU、一个计算锁目录

winning post 和 window post 之间不会因设备使用而形成冲突

# 局限性

当目前为止,我们已经讲解了独立 PoSter 节点依托的功能、原理和简单的使用范例。

但是,这种模式对于超大规模的 SP 集群仍然有一些局限性,具体体现在:

  • 时空证明的调度、证明窗口期的严重冲突,仍然需要在一定程度依赖运维层面的调配;