#bls #arpa #threshold #dkg #threshold-signature #randcast #signature-scheme

bin+lib arpa-node

该crate为ARPA BLS阈值签名方案(BLS-TSS)网络节点端提供了一套工具,包括基于链上随机数服务(Randcast)的阈值-BLS。

2个版本

0.2.2 2024年6月17日
0.2.0 2024年6月3日

#6 in #arpa

Download history 151/week @ 2024-06-01 19/week @ 2024-06-08 140/week @ 2024-06-15 8/week @ 2024-06-22 6/week @ 2024-06-29 12/week @ 2024-07-06

76 个下载/月

MIT/Apache

2MB
24K SLoC

Arpa节点

概述

该crate为ARPA BLS阈值签名方案(BLS-TSS)网络节点端提供了一套工具,包括基于链上随机数服务(Randcast)的阈值-BLS。

它包括

  • ARPA节点客户端
  • ARPA节点配置检查器
  • ARPA节点命令行界面
  • 管理grpc服务器

ARPA节点客户端

ARPA节点客户端是一个长时间运行的程序,用于运行ARPA节点。

如果配置文件中的数据路径不存在,在第一次运行节点时,客户端将生成一个DKG密钥对(在分组过程中作为身份使用)。

用法

cd crates/arpa-node
cargo run --bin node-client

要打印帮助信息,使用 -- -h

cargo run --bin node-client -- -h

要指定配置文件,使用 -- -c <config_file>

cargo run --bin node-client -- -c conf/config.yml

ARPA节点配置检查器

ARPA节点配置检查器是一个检查节点配置文件正确性的工具。如果配置文件正确,它将打印节点身份(钱包)的校验和编码地址,否则将打印错误信息。

用法

要指定配置文件,使用 -- -c <config_file>

cd crates/arpa-node
cargo run --bin node-config-checker -- -c conf/config.yml

ARPA节点命令行界面

ARPA节点命令行界面是一个快速且详尽的REPL,用于ARPA节点的操作员。将使用与ARPA节点客户端相同的节点配置文件。作为ARPA节点客户端的补充,它提供了一套命令来检查节点状态和与链上合约交互,例如,作为Eigenlayer EOA操作员手动将节点注册到网络。

用法

要打印帮助信息,使用 -- -h

cd crates/arpa-node
cargo run --bin node-shell -- -h

要指定配置文件,使用 -- -c <config_file>

cargo run --bin node-shell -- -c conf/config.yml

要设置历史文件路径,使用 -- -H <history_file>

cargo run --bin node-shell -- -H node-shell.history

REPL命令

Commands:
  show      Show information of the config file and node database
  call      Get views from on-chain contracts
  history   Show command history
  send      *** Be careful this will change on-chain state and cost gas ***
                Send trxs to on-chain contracts
  generate  Generate node identity(wallet) corresponding to ARPA node format
  inspect   Connect to the node client and inspect the node status
  help      Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

子命令

Show information of the config file and node database

Usage: show [COMMAND]

Commands:
  address  Show address of the node identity(wallet) [aliases: a]
  config   Print node config [aliases: c]
  node     Print node info from node database [aliases: n]
  help     Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help
Get views and events from on-chain contracts

Usage: call [COMMAND]

Commands:
  block                        Get block information [aliases: b]
  current-gas-price            Get current gas price [aliases: cgp]
  trx-receipt                  Get transaction receipt [aliases: tr]
  balance-of-eth               Get balance of eth [aliases: boe]
  last-randomness              Get last randomness [aliases: lr]
  pending-request-commitment   Get pending commitment by request id [aliases: prc]
  controller-config            Get controller config [aliases: cc]
  adapter-config               Get adapter config [aliases: ac]
  last-assigned-group-index    Get last assigned group index in randomness generation [aliases: lagi]
  randomness-count             Get randomness count [aliases: rc]
  cumulative-data              Get cumulative data(FlatFee, CommitterReward and PartialSignatureReward) of randomness generation [aliases: cd]
  fulfillments-as-committer    Get all fulfillment events as committer in history [aliases: fac]
  fulfillments-as-participant  Get all fulfillment events as participant in history [aliases: fap]
  node                         Get node info by id address [aliases: n]
  group                        Get group info by index [aliases: g]
  valid-group-indices          Get valid group indices which are ready for randomness generation [aliases: vgi]
  group-epoch                  Get global group epoch [aliases: ge]
  group-count                  Get global group count [aliases: gc]
  belonging-group              Get the group index and member index of a given node [aliases: bg]
  member                       Get group member info by group index and member index [aliases: m]
  coordinator                  Get group coordinator during a running dkg process by group index [aliases: c]
  node-withdrawable-tokens     Get node withdrawable tokens(eth and arpa rewards) by id-address [aliases: nwt]
  stake                        Get node staked arpa amount [aliases: s]
  delegation-reward            Get node delegation reward [aliases: dr]
  delegates-count              Get eligible nodes count [aliases: dc]
  balance-of-arpa              Get balance of arpa [aliases: boa]
  frozen-principal             Get frozen principal and unfreeze time [aliases: fp]
  help                         Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help
*** Be careful this will change on-chain state and cost gas as well as block time***
Send trxs to on-chain contracts

Usage: send [COMMAND]

Commands:
  approve-arpa-to-staking          Approve arpa to staking contract [aliases: aats]
  stake                            Stake arpa to staking contract [aliases: s]
  unstake                          Unstake(then freeze) arpa from staking contract and claim delegation rewards instantly after exit [aliases: u]
  claim-frozen-principal           Claim frozen principal from staking after unstake [aliases: cfp]
  register-as-eigenlayer-operator  Register node as Eigenlayer operator [aliases: raeo]
  activate-as-eigenlayer-operator  Activate node after exit or slashing as Eigenlayer operator [aliases: aaeo]
  quit                             Quit node from Randcast network [aliases: q]
  change-dkg-public-key            Change dkg public key(recorded in node database) after exit or slashing [aliases: cdpk]
  withdraw                         Withdraw node reward to any address [aliases: w]
  help                             Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help
Generate node identity(wallet) corresponding to ARPA node format

Usage: generate [COMMAND]

Commands:
  private-key  Generate private key(not recommended) [aliases: pk]
  keystore     Generate keystore file [aliases: k]
  hd-wallet    Generate hierarchical deterministic wallet and save the mnemonic to a file [aliases: hw]
  help         Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

Connect to the node client and inspect the node status

Usage: inspect [COMMAND]

Commands:
  list-fixed-tasks  List fixed tasks of the node [aliases: lft]
  help              Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

管理grpc服务器

该服务器支持检查状态和与正在运行节点交互。

请参阅 management.proto 获取详细API。

依赖项

安装 protocfoundry,然后运行

cargo build

故障排除

"错误:未找到链接器 cc..." 在运行 cargo build

sudo apt install build-essential
sudo apt install pkg-config
sudo apt install libssh-dev

节点配置

conf/config.yml 中的配置项如下所示

Note: To protect secrets, several items can be set with literal `env` as placeholder. Their env keys are:

    - ARPA_NODE_MANAGEMENT_SERVER_TOKEN (node_management_rpc_token)
    - ARPA_NODE_ACCOUNT_PRIVATE_KEY (account, private_key)
    - ARPA_NODE_ACCOUNT_KEYSTORE_PASSWORD (account, keystore, password)
    - ARPA_NODE_HD_ACCOUNT_MNEMONIC (account, hdwallet, mnemonic)

    Items below can also be set with arbitrary environment variables starting with `$`:

    - $<CUSTOMIZED_ENV_VARIABLE_KEY>(provider_endpoint / relayed_chains.provider_endpoint)
    - $<CUSTOMIZED_ENV_VARIABLE_KEY>(node_management_rpc_token)
    - $<CUSTOMIZED_ENV_VARIABLE_KEY>(account, private_key)
    - $<CUSTOMIZED_ENV_VARIABLE_KEY>(account, keystore, password)
    - $<CUSTOMIZED_ENV_VARIABLE_KEY>(account, hdwallet, mnemonic)
  • node_committer_rpc_endpoint: 此节点将用于创建服务器套接字以暴露提交者 gRPC 服务的端点。一旦此值更改,节点必须重新激活自身以通知控制器,以便控制器可以通过重新分组来更新端点。(例如:"0.0.0.0:50060")

  • node_advertised_committer_rpc_endpoint: 组中其他成员连接到此节点的端点。如果此设置未设置,则使用 node_committer_rpc_endpoint 的值并发布到其他节点。注意:此设置每次节点启动时都会更新,但直到下一次重新分组之前不会广播到其他节点。(例如:"10.0.0.1:50060")

  • node_management_rpc_endpoint: 配置暴露管理 gRPC 服务的端点。(例如:"0.0.0.0:50099")

  • node_management_rpc_token: 用于通过 authorization 标头对管理 gRPC 请求进行身份验证的配置令牌短语。(例如:"arpa_network")

  • node_statistics_http_endpoint: 配置暴露统计 http 服务的端点。(例如:"0.0.0.0:50081")

  • provider_endpoint: 配置与链提供者交互的 WebSocket 端点。(例如:"ws://127.0.0.1:8546")

  • is_eigenlayer: 配置节点是否注册为 eigenlayer 运营商或原生质押运营商。(例如:false)

  • is_consistent_asset_and_node_account: 配置节点的资产账户是否与节点账户一致。(例如:false)

  • chain_id: 配置主链的链 ID。(例如:31337)

  • controller_address: 配置用于管理节点和分组的控制器合约地址。(例如:"0x0000000000000000000000000000000000000001")

  • controller_relayer_address: 配置用于将分组传递到中继链的控制器中继合约地址。(例如:"0x0000000000000000000000000000000000000001")

  • adapter_address: 配置用于请求和完成随机性任务的适配器合约地址。(例如:"0x0000000000000000000000000000000000000001")

  • adapter_deployed_block_height(可选,用于 ARPA 节点 CLI):配置适配器合约部署的块高度,以加速事件的查询。(例如:100000)

  • arpa_address(可选,用于 ARPA 节点 CLI):配置链上 ARPA 代币合约地址。(例如:"0x9fe46736679d2d9a65f0992f2272de9f3c7fa6e0")

  • data_path(可选):配置用于持久化的数据库文件。(例如:"data.sqlite")

  • logger(可选):配置日志记录设置。

    • example(default)

      logger:
        context_logging: false
        log_file_path: log/running/
        rolling_file_size: 10 gb
      
    • context_logging: 设置是否记录当前节点信息和组信息的上下文。由于启用此设置将显著增加日志大小,建议在生产中将其设置为 false。

    • log_file_path: 设置日志文件路径。`node-client` 将在 `log_file_path` 下创建一个 `node.log` 以及一个 `node_err.log`,然后分别以信息和错误级别记录到它们中。

    • rolling_file_size: 当日志文件达到此大小限制时将被删除。支持以下单位(不区分大小写):"b","kb","kib","mb","mib","gb","gib","tb","tib"。如果未指定,则默认为字节。

  • account: 配置网络中的节点身份。有三种可用的账户类型。

    • example(not recommended): private_key: "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"

    • example

      keystore:
          password: env
          path: test.keystore
      
    • example

      hdwallet:
          mnemonic: env
          path: "m/44'/60'/0'/0"
          index: 0
          passphrase: "custom_password"
      

      路径和密码短语是可选的。

  • time_limits(可选):配置不同任务的时间限制。所有时间限制都是以毫秒或块数量。

    • example

      time_limits:
        block_time: 3
        dkg_timeout_duration: 40
        randomness_task_exclusive_window: 10
        listener_interval_millis: 10000
        dkg_wait_for_phase_interval_millis: 10000
        provider_polling_interval_millis: 10000
        provider_reset_descriptor:
          interval_millis: 5000
          max_attempts: 17280
          use_jitter: false
        contract_transaction_retry_descriptor:
          base: 2
          factor: 1000
          max_attempts: 3
          use_jitter: true
        contract_view_retry_descriptor:
          base: 2
          factor: 500
          max_attempts: 5
          use_jitter: true
        commit_partial_signature_retry_descriptor:
          base: 2
          factor: 1000
          max_attempts: 5
          use_jitter: false
      
    • block_time: 链的块时间。此值用于计算随机性任务的最大挂起时间。(例如:3)

    • 这些值需要根据链上控制器合约的配置进行设置。

      • dkg_timeout_duration: DKG 开始和超时之间的块数量。(例如:40)
      • randomness_task_exclusive_window: 只能由分配的组完成的随机性任务的块数量。(例如:10)
    • 这些值可以由节点所有者或管理员根据提供商的速率限制进行设置。设置较小的值有利于节点响应任务。建议设置不大于链块时间的值。

      • listener_interval_millis:当监听器失败时,两次重试之间的毫秒数。(例如:10000)
      • dkg_wait_for_phase_interval_millis:两次查询下一个DKG阶段的轮询之间的毫秒数。(例如:10000)
      • provider_polling_interval_millis:两次查询待处理交易之间的毫秒数。(例如:10000)
    • 当无法重新连接时,我们使用固定间隔重置提供商。

      • provider_reset_descriptor:(默认间隔序列:5s,10s,...,24h)
    • 当事务或视图调用失败,或对提交者的rpc请求失败时,我们使用指数退避策略进行重试。每次间隔将是基数乘以因子的指数,并在交互成功时重置。

      • interval = factor * base ^ attempt
    • 在间隔中添加抖动,以避免所有任务同时轮询的情况。它将0.5和1.0之间的随机数乘以间隔。

      • contract_transaction_retry_descriptor:(无抖动的间隔序列:2s,4s,8s)
      • contract_view_retry_descriptor:(无抖动的间隔序列:1s,2s,4s,8s,16s)
      • commit_partial_signature_retry_descriptor:(无抖动的间隔序列:2s,4s,8s,16s,32s)
  • listeners(可选):配置与节点客户端一起运行的监听器以自定义服务。默认情况下,将启用所有监听器。可以通过显式设置空值来禁用所有监听器。

    • example
    listeners:
      - l_type: Block
        interval_millis: 0
        use_jitter: true
      - l_type: NewRandomnessTask
        interval_millis: 0
        use_jitter: true
      - l_type: PreGrouping
        interval_millis: 0
        use_jitter: true
      - l_type: PostCommitGrouping
        interval_millis: 10000
        use_jitter: true
      - l_type: PostGrouping
        interval_millis: 10000
        use_jitter: true
      - l_type: ReadyToHandleRandomnessTask
        interval_millis: 10000
        use_jitter: true
      - l_type: RandomnessSignatureAggregation
        interval_millis: 2000
        use_jitter: false
    
    • Block、NewRandomnessTask、PreGrouping、PostCommitGrouping、PostGrouping、ReadyToHandleRandomnessTask、RandomnessSignatureAggregation是监听器的类型。我们使用固定间隔在监听轮失败时重试。interval_millis和use_jitter与time_limits相同。

      • Block、NewRandomnessTask和PreGrouping的轮询间隔由time_limits中的provider_polling_interval_millis决定。

      • PostCommitGrouping、PostGrouping和ReadyToHandleRandomnessTask的轮询由链上的视图调用触发,因此interval_millis应设置为不大于链块时间的值。

      • RandomnessSignatureAggregation的轮询由节点本身触发,因此interval_millis可以设置得相对较小。

  • relayed_chains:配置我们支持的所有中继链的chain_id、描述、合约地址、端点、time_limits和监听器。

    • example
    relayed_chains:
    - chain_id: 901
      description: "OP"
      provider_endpoint: "ws://127.0.0.1:9546"
      controller_oracle_address: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9"
      adapter_address: "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707"
      adapter_deployed_block_height: 14224644
      arpa_address: "0xA129BEA1a5d9E37Eb2C505c8D302231A28B0A82b"
      listeners:
        - l_type: Block
          interval_millis: 0
          use_jitter: true
        - l_type: NewRandomnessTask
          interval_millis: 0
          use_jitter: true
        - l_type: ReadyToHandleRandomnessTask
          interval_millis: 1000
          use_jitter: true
        - l_type: RandomnessSignatureAggregation
          interval_millis: 2000
          use_jitter: false
      time_limits:
        block_time: 2
        randomness_task_exclusive_window: 10
        listener_interval_millis: 1000
        provider_polling_interval_millis: 1000
        provider_reset_descriptor:
          interval_millis: 5000
          max_attempts: 17280
          use_jitter: false
        contract_transaction_retry_descriptor:
          base: 2
          factor: 1000
          max_attempts: 3
          use_jitter: true
        contract_view_retry_descriptor:
          base: 2
          factor: 500
          max_attempts: 5
          use_jitter: true
        commit_partial_signature_retry_descriptor:
          base: 2
          factor: 1000
          max_attempts: 5
          use_jitter: false
    
    • 节点在中继链上与主链具有相同的身份,因此节点必须在主链上首先注册(将在新运行时自动执行)。

    • 目前最新的分组信息是从主链中继到中继链,因此PreGrouping、PostCommitGrouping和PostGrouping的监听器不需要。

    • 中继链的时间限制独立于主链。设置方式与主链相同。

本地测试

# unit tests
cargo test --all -- --test-threads=1 --nocapture

使用anvil启动本地测试网

# produces a new block every 1 second
anvil --block-time 1

部署Controller和Adapter合约

cd contracts
# controller address 0xdc64a140aa3e981100a9beca4e685f962f0cf6c9
# adapter_address: 0xa513e6e4b8f2a923d98304ec87f64353c4d5c853
# user contract address 0x712516e61C8B383dF4A63CFe83d7701Bce54B03e
forge script script/ControllerLocalTest.s.sol:ControllerLocalTestScript --fork-url https://127.0.0.1:8545 --broadcast

添加运营商,启动质押池并为用户和一些节点质押

# nodes addresses are generated from index 10 by mnemonic "test test test test test test test test test test test junk"(anvil default)
# offset and length can be set by STAKING_NODES_INDEX_OFFSET and STAKING_NODES_INDEX_LENGTH in .env
forge script script/StakeNodeLocalTest.s.sol:StakeNodeLocalTestScript --fork-url https://127.0.0.1:8545 --broadcast -g 150

运行3个节点以形成一个组

cd crates/arpa-node
cargo run --bin node-client -- -c test/conf/config_test_1.yml
cargo run --bin node-client -- -c test/conf/config_test_2.yml
cargo run --bin node-client -- -c test/conf/config_test_3.yml

部署用户合约(GetRandomNumberExample)并请求随机数

cd contracts
# this should be executed after we have an available group as logging e.g."Group index:0 epoch:1 is available, committers saved." in node terminal
forge script script/GetRandomNumberLocalTest.s.sol:GetRandomNumberLocalTestScript --fork-url https://127.0.0.1:8545 --broadcast

节点应签署随机数,组中的某个提交者将履行结果,通过cast检查结果

# check the randomness result recorded by the adapter and the user contract respectively
cast call 0xa513e6e4b8f2a923d98304ec87f64353c4d5c853 \
  "getLastRandomness()(uint256)"

cast call 0x712516e61C8B383dF4A63CFe83d7701Bce54B03e \
  "lastRandomnessResult()(uint256)"

# the above two outputs of uint256 type should be identical

依赖项

~103MB
~2M SLoC