SPO JAPAN GUILD
ステークプール運用

ノードアップデート

このガイドは ノードバージョン11.1.3に対応しています。

最終更新日:

留意点

11.0.1以前から11.1.3へのアップデートでは大幅な変更があります。

  • ログシステム変更(cardano-tracer常駐)
  • stdoutログ形式をJSONに変更
  • Configファイル変更(cardano-tracer用)
  • Prometheus設定変更
  • GenesisModeへ切り替え
  • Topologyファイルアップデート(生成フォーム新設)
  • ブロックログ関連スクリプトアップデート
  • BlockNotifyアップデート
  • SJGTOOLアップデート
  • blocks.shアップデート
  • Grafana本体のアップデート(13.2.2)
  • Grafanaダッシュボードアップデート

以下も必ずお読みください

  • 今回のアップデートは多くの変更を含むためリレー・BPを行き来する作業があります。そのためすべてのノードを同日にアップデートすることを推奨します。
  • アップデート作業中のトラブル対応を見越してまとまった作業時間を確保すると共に、ブロック生成タイミングまで数時間の余裕があることを確認してください。
  • 文章をしっかりと読み、流れ作業でコマンドを実行しないでください!!リレーとBPで実行コマンドが異なる箇所が多くあります。

バージョン対応表

OSNodeCLIGHCCabalCNCLI
ubuntu 24.04.*11.1.311.2.3.09.6.73.12.1.06.8.0

■アップデートパターンDB再構築有無

バージョンDB再構築有無設定ファイル更新有無トポロジーファイル更新有無
11.0.1 → 11.1.3なし更新あり更新あり

0. 事前準備

すべてのノードアップデートが終わるまでGrafana通知を一時的にオフにしてください

  1. Grafanaログイン
  2. 左メニュー「Alert」→「Silences」→「Add Silence」
  3. 項目を編集する
  • Duration:1d (日付は自動的に変わるので変更しないでください)
  • Label:alertname
  • Operator:=~
  • Value:.+

  1. Save silence

1. 依存環境アップデート

現在のノードバージョンを変数に代入

current_node=$(cardano-node version | grep cardano-node)
echo $current_node

システムのアップデートと依存関係のインストール

sudo apt update && sudo apt upgrade -y

依存関係バージョン確認

cabalバージョン確認

cabal --version
期待される表示例:
cabal-install version 3.12.1.0
compiled using version 3.12.1.0 of the Cabal library 

GHCバージョン確認

ghc --version
期待される表示例:
The Glorious Glasgow Haskell Compilation System, version 9.6.7

libsodiumコミット確認

cd $HOME/git/libsodium
git branch --contains | grep -m1 HEAD | cut -c 21-28
期待される表示例:
dbb48cce

secp256k1バージョン確認

cd $HOME/git/secp256k1
git branch --contains | grep -m1 HEAD | cut -c 21-27
期待される表示例:
acf5c55

Blstバージョン確認
インストール済みバージョン

cat /usr/local/lib/pkgconfig/libblst.pc | grep Version
期待される表示例:
Version: 0.3.14

各アプリのバージョン(戻り値)が上記と異なる場合は、該当する項目を開いて対応してください。

CNCLIバージョン確認

CNCLIバージョン確認

cncli --version
期待される表示例:
cncli v6.8.0 <~~~> (x86_64-unknown-linux-gnu)

2. ノードアップデート

バイナリファイルインストール方法の違いについて

  • ビルド済みバイナリ・・・IntersectMBOリポジトリソースコードからビルドされたバイナリファイルをダウンロードします。ビルド不要のためビルド時間を短縮できます。

  • ソースコードからビルド・・・ご自身のサーバーでソースコードからビルドしてバイナリファイルを作成します。検証目的やソースコードからビルドしたい場合に利用できます。ビルドに30分前後かかります。Raspberry Piを使用してプールを構築する場合は、ARM用バイナリを使用する必要があります。

バイナリダウンロード

旧バイナリの削除

rm -rf $HOME/git/cardano-node-old/

バイナリファイルのダウンロード

mkdir -p $HOME/git/cardano-node2
cd $HOME/git/cardano-node2
wget -4 https://github.com/IntersectMBO/cardano-node/releases/download/11.1.3/cardano-node-11.1.3-linux-amd64.tar.gz

解凍

tar zxvf cardano-node-11.1.3-linux-amd64.tar.gz ./bin/cardano-node ./bin/cardano-cli ./bin/snapshot-converter ./bin/cardano-tracer

ノードの停止

sudo systemctl stop cardano-node

Tracerの停止

sudo systemctl stop cardano-tracer

バイナリインストール

バイナリーファイルをシステムフォルダーへコピー

sudo cp $(find $HOME/git/cardano-node2 -type f \( -name "cardano-node" -o -name "cardano-cli" -o -name "cardano-tracer" \)) /usr/local/bin/

システムに反映されたノードバージョンの確認

cardano-node version
cardano-cli version
cardano-tracer --version
期待される表示例:
cardano-node 11.1.3 - linux-x86_64 - ghc-9.6
git rev 938cba990357ae7c4b7f95c8f75dd9d31174bbeb

cardano-cli 11.2.3.0 - linux-x86_64 - ghc-9.6
git rev 938cba990357ae7c4b7f95c8f75dd9d31174bbeb

0.5.0

ソースコードダウンロード

現在のノードバージョンを変数に代入

current_node=$(cardano-node version | grep cardano-node)
echo $current_node

TMUXセッションを展開

tmux new -s build

アップデート作業中にSSHが中断した場合は、tmux a -t buildで再開できます。

以前ビルドしたディレクトリの削除

rm -rf $HOME/git/cardano-node-old/

ソースコードのダウンロード

cd $HOME/git
git clone https://github.com/IntersectMBO/cardano-node.git cardano-node2
cd cardano-node2/

2-2.ソースコードからビルド

cabal clean
cabal update
git fetch --all --recurse-submodules --tags
git checkout tags/11.1.3
cabal configure --with-compiler=ghc-9.6.7
cabal build all cardano-cli

ヒント

  • ビルド完了までに数十分ほどかかります。
  • SSH接続が途中で切断された場合、再度接続してtmux a -t buildで再開してください。
  • ビルド中にデタッチ(Ctrl+B D)してバックグラウンド処理へ切り替えられます。

cardano-node、cardano-cli、cardano-tracerバイナリをbinディレクトリにコピーします。

ノードの停止

sudo systemctl stop cardano-node

Tracerの停止

sudo systemctl stop cardano-tracer
cd $HOME/git/cardano-node2
sudo cp -p "$(./scripts/bin-path.sh cardano-node)" "$(./scripts/bin-path.sh cardano-cli)" "$(./scripts/bin-path.sh cardano-tracer)" /usr/local/bin/

cardano-node、cardano-cli、cardano-tracerのバージョンが最新Gitタグバージョンであることを確認してください。

cardano-node version
cardano-cli version
cardano-tracer --version
期待される表示例:
cardano-node 11.1.3 - linux-x86_64 - ghc-9.6  
git rev 938cba990357ae7c4b7f95c8f75dd9d31174bbeb  

cardano-cli 11.2.3.0 - linux-x86_64 - ghc-9.6  
git rev 938cba990357ae7c4b7f95c8f75dd9d31174bbeb  

0.5.0

TMUXセッションを閉じます。

exit

設定ファイル更新

既存ファイルのバックアップ

mkdir -p $NODE_HOME/backup

cp $NODE_HOME/${NODE_CONFIG}-byron-genesis.json $NODE_HOME/${NODE_CONFIG}-shelley-genesis.json $NODE_HOME/${NODE_CONFIG}-alonzo-genesis.json $NODE_HOME/${NODE_CONFIG}-conway-genesis.json $NODE_HOME/${NODE_CONFIG}-config.json $NODE_HOME/${NODE_CONFIG}-topology.json $NODE_HOME/backup/

設定ファイルをダウンロードします。

cd $NODE_HOME
WGET_OPTS=(-4 --no-use-server-timestamps --tries=5 --waitretry=3 --connect-timeout=10 --read-timeout=30)
wget "${WGET_OPTS[@]}" https://download.spojapanguild.net/node_config/11.1.3/${NODE_CONFIG}-byron-genesis.json -O ${NODE_CONFIG}-byron-genesis.json
wget "${WGET_OPTS[@]}" https://download.spojapanguild.net/node_config/11.1.3/${NODE_CONFIG}-shelley-genesis.json -O ${NODE_CONFIG}-shelley-genesis.json
wget "${WGET_OPTS[@]}" https://download.spojapanguild.net/node_config/11.1.3/${NODE_CONFIG}-alonzo-genesis.json -O ${NODE_CONFIG}-alonzo-genesis.json
wget "${WGET_OPTS[@]}" https://download.spojapanguild.net/node_config/11.1.3/${NODE_CONFIG}-conway-genesis.json -O ${NODE_CONFIG}-conway-genesis.json
wget "${WGET_OPTS[@]}" https://download.spojapanguild.net/node_config/11.1.3/${NODE_CONFIG}-config.json -O ${NODE_CONFIG}-config.json
wget "${WGET_OPTS[@]}" https://download.spojapanguild.net/node_config/11.1.3/${NODE_CONFIG}-topology.json -O ${NODE_CONFIG}-topology.json
wget "${WGET_OPTS[@]}" https://download.spojapanguild.net/node_config/11.1.3/${NODE_CONFIG}-checkpoints.json -O ${NODE_CONFIG}-checkpoints.json

ファイル確認

for f in "${NODE_CONFIG}"-{byron-genesis,shelley-genesis,alonzo-genesis,conway-genesis,config,topology,checkpoints}.json; do
  if jq -e -s 'length == 1 and (.[0] | type == "object")' "$f" >/dev/null 2>&1; then
    echo "OK  $f"
  else
    echo "NG  $f"
  fi
done

ファイル確認の注意点

すべてのファイルが「OK」になることを確認してください。「NG」がある場合は、後続の手順には進まずに該当ファイルを再ダウンロードして確認し直してください。

期待される表示例:
OK  mainnet-byron-genesis.json
OK  mainnet-shelley-genesis.json
OK  mainnet-alonzo-genesis.json
OK  mainnet-conway-genesis.json
OK  mainnet-config.json
OK  mainnet-topology.json
OK  mainnet-checkpoints.json

リレーのみで実行

peer-snapshot.jsonのダウンロード

cd $NODE_HOME
wget "${WGET_OPTS[@]}" https://download.spojapanguild.net/node_config/11.1.3/${NODE_CONFIG}-peer-snapshot.json -O ${NODE_CONFIG}-peer-snapshot.json

config.jsonのTraceOptionNodeNameを、各ノードを識別するためのNode名に変更します。

TraceOptionNodeNameを${NODE_CONFIG}-relay-1に変更します。

sed -i "s/\"TraceOptionNodeName\": \"\"/\"TraceOptionNodeName\": \"${NODE_CONFIG}-relay-1\"/" ${NODE_CONFIG}-config.json

TraceOptionNodeNameを${NODE_CONFIG}-relay-2に変更します。

sed -i "s/\"TraceOptionNodeName\": \"\"/\"TraceOptionNodeName\": \"${NODE_CONFIG}-relay-2\"/" ${NODE_CONFIG}-config.json

TraceOptionNodeNameを${NODE_CONFIG}-bpに変更します。

sed -i "s/\"TraceOptionNodeName\": \"\"/\"TraceOptionNodeName\": \"${NODE_CONFIG}-bp\"/" ${NODE_CONFIG}-config.json

設定したNode名を確認します。

jq -r '.TraceOptionNodeName' $NODE_HOME/${NODE_CONFIG}-config.json
期待される表示例:
mainnet-relay-1 または mainnet-relay-2 または mainnet-bp

トポロジーファイルの変更

この手順では、GenesisMode を使用する構成を前提としています。
Genesis Modeでは bootstrapPeers を使用せず、リレーは peerSnapshotFile を使用してGenesis同期を行います。
BPは自リレーのみに接続し、peerSnapshotFile は使用しません。

以下のフォームで、接続先に合わせたファイル作成コマンドを生成できます。

トポロジーファイル作成コマンドを生成

接続先の情報を入力してください。入力内容はSJGサーバーには送信・保存されず、再読み込みでリセットされます。

作成対象を切り替えると、自リレーの入力欄をリセットします。

リレー1用のトポロジーを作成します。BP・自分が管理する他のリレー・外部リレーを分けて入力してください。不要なリレー欄は削除できます。

BP(localRoots)

有効な IP アドレスを入力してください。

ポートは 1〜65535 の整数で入力してください。

BP ノードで次のコマンドを実行し、表示された PORT= の値をポート欄に入力してください。

grep -E '^[[:space:]]*PORT=' "$NODE_HOME/startBlockProducingNode.sh"

advertise: false(固定)

自リレー localRoots

リレー2の IP・ポートを入力してください。それ以外にも接続する自リレーがある場合は「+ 自リレーを追加」で登録してください。リレー1自身は登録しないでください。

リレー2

有効な IP アドレスまたは DNS 名を入力してください。

この接続先を他のノードに知らせるか。デフォルトは true

外部リレー publicRoots

外部リレー(publicRoots)は、通常は追加しなくても問題ありません。必要な場合のみ登録してください。

通常はこのままで問題ありません。独自のパスを採用している場合は変更してください。環境変数はコマンド実行時に対象ノードの値へ展開されます。

リレー1用 ファイル作成コマンド

以下のコマンドをコピーしてサーバーで実行してください

入力内容を確認してください。すべての入力が有効になるとコマンドが表示されます。

構文チェックと再起動

jq . $NODE_HOME/${NODE_CONFIG}-topology.json

JSON がそのまま表示されれば問題ありません。
parse error のときは {} [] , を確認してください。

3. Tracer設定

ノード起動スクリプトの修正

リレーのポート番号を確認します。

PORT=`grep "PORT=" $NODE_HOME/startRelayNode1.sh`
r_PORT=${PORT#"PORT="}
echo "リレーポートは ${r_PORT} です"

リレーのポート番号が表示されることを確認します。

起動スクリプトファイルの作成

cat > $NODE_HOME/startRelayNode1.sh << EOF 
#!/bin/bash
DIRECTORY=$NODE_HOME
PORT=${r_PORT}
HOSTADDR=0.0.0.0
TOPOLOGY=\${DIRECTORY}/${NODE_CONFIG}-topology.json
DB_PATH=\${DIRECTORY}/db
SOCKET_PATH=\${DIRECTORY}/db/socket
CONFIG=\${DIRECTORY}/${NODE_CONFIG}-config.json
TRACER_SOCKET_PATH=\${DIRECTORY}/tracer/socket
/usr/local/bin/cardano-node run +RTS -N --disable-delayed-os-memory-return -I0.1 -Iw300 -A16m -F1.5 -H2500M -RTS --topology \${TOPOLOGY} --database-path \${DB_PATH} --socket-path \${SOCKET_PATH} --host-addr \${HOSTADDR} --port \${PORT} --config \${CONFIG} --tracer-socket-path-connect \${TRACER_SOCKET_PATH}
EOF

ノードポート番号を確認します。

PORT=`grep "PORT=" $NODE_HOME/startBlockProducingNode.sh`
b_PORT=${PORT#"PORT="}
echo "BPポートは ${b_PORT} です"

BPのポート番号が表示されることを確認します。

起動スクリプトにKES、VRF、運用証明書のパスを追記し、更新します。

cat > $NODE_HOME/startBlockProducingNode.sh << EOF 
#!/bin/bash
DIRECTORY=$NODE_HOME
PORT=${b_PORT}
HOSTADDR=0.0.0.0
TOPOLOGY=\${DIRECTORY}/${NODE_CONFIG}-topology.json
DB_PATH=\${DIRECTORY}/db
SOCKET_PATH=\${DIRECTORY}/db/socket
CONFIG=\${DIRECTORY}/${NODE_CONFIG}-config.json
TRACER_SOCKET_PATH=\${DIRECTORY}/tracer/socket
KES=\${DIRECTORY}/kes.skey
VRF=\${DIRECTORY}/vrf.skey
CERT=\${DIRECTORY}/node.cert
/usr/local/bin/cardano-node run +RTS -N --disable-delayed-os-memory-return -I0.1 -Iw300 -A32m -n4m -F1.5 -H2500M -RTS --topology \${TOPOLOGY} --database-path \${DB_PATH} --socket-path \${SOCKET_PATH} --host-addr \${HOSTADDR} --port \${PORT} --config \${CONFIG} --tracer-socket-path-connect \${TRACER_SOCKET_PATH} --shelley-kes-key \${KES} --shelley-vrf-key \${VRF} --shelley-operational-certificate \${CERT}
EOF

cardano-tracerサービス設定

Tracer用のディレクトリとログ保存用のディレクトリを作成します。

mkdir -p ${NODE_HOME}/tracer
mkdir -p ${NODE_HOME}/logs

既存のNodeログがある場合は、cardano-tracer導入前のログをarchiveディレクトリへ移動します。

mkdir -p ${NODE_HOME}/logs/archive

find ${NODE_HOME}/logs -maxdepth 1 -type f -name 'node-*.json' \
  -exec mv {} ${NODE_HOME}/logs/archive/ \;

[ -L ${NODE_HOME}/logs/node.json ] && \
  mv ${NODE_HOME}/logs/node.json ${NODE_HOME}/logs/archive/

環境変数設定

grep -q '^export CARDANO_TRACER_SOCKET_PATH=' $HOME/.bashrc || echo "export CARDANO_TRACER_SOCKET_PATH=\"${NODE_HOME}/tracer/socket\"" >> $HOME/.bashrc
sed -i 's#journalctl -u cardano-node -f#journalctl -q -u cardano-node -f -o cat | jq -cC --unbuffered .#g' "$HOME/.bashrc"
source $HOME/.bashrc

設定を確認します。

echo ${CARDANO_TRACER_SOCKET_PATH}

以下のように表示されることを確認します。

期待される表示例:
/home/<USER>/cnode/tracer/socket

cnodeコマンド確認

cat $HOME/.bashrc | grep "alias cnode"

以下のように表示されることを確認します。

期待される表示例:
alias cnode="journalctl -q -u cardano-node -f -o cat | jq -cC --unbuffered ."

tracer-config.jsonの取得

Tracer用の設定ファイルを取得します。

cd ${NODE_HOME}/tracer
WGET_OPTS=(-4 --no-use-server-timestamps --tries=5 --waitretry=3 --connect-timeout=10 --read-timeout=30)
wget "${WGET_OPTS[@]}" https://download.spojapanguild.net/node_config/11.1.3/${NODE_CONFIG}-tracer-config.json -O ${NODE_CONFIG}-tracer-config.json

tracer-config.jsonの設定

tracer-config.jsonのログ保存先、Unix SocketのPATH、Network Magicを環境に合わせて変更します。

NETWORK_MAGIC=$(jq -r '.networkMagic' $NODE_HOME/${NODE_CONFIG}-shelley-genesis.json)
sed -i \
  -e "s|\"logRoot\": \"\"|\"logRoot\": \"${NODE_HOME}/logs\"|" \
  -e "s|\"contents\": \"\"|\"contents\": \"${NODE_HOME}/tracer/socket\"|" \
  -e "s|\"networkMagic\": 0|\"networkMagic\": ${NETWORK_MAGIC}|" \
  ${NODE_CONFIG}-tracer-config.json

cardano-tracerのsystemd service作成

cardano-tracerのsystemd serviceファイルを作成します。

cat > ${NODE_HOME}/tracer/cardano-tracer.service << EOF
[Unit]
Description=Cardano Tracer Service
Wants=network-online.target
After=network-online.target
Before=cardano-node.service
PartOf=cardano-node.service
StartLimitIntervalSec=0

[Service]
User=${USER}
Type=simple
WorkingDirectory=${NODE_HOME}
ExecStart=/usr/local/bin/cardano-tracer --config ${NODE_HOME}/tracer/${NODE_CONFIG}-tracer-config.json
Restart=always
RestartSec=5
LimitNOFILE=32768

[Install]
WantedBy=cardano-node.service
EOF

systemdへ配置します。

sudo cp ${NODE_HOME}/tracer/cardano-tracer.service /etc/systemd/system/cardano-tracer.service

systemdへ設定を反映します。

sudo systemctl daemon-reload

cardano-tracerの自動起動を有効化します。

sudo systemctl enable --now cardano-tracer.service

Firewallの設定

💡

AWS等のVPS側でFirewallを使用している場合は、管理コンソールからFirewallの設定を行ってください。

Grafana稼働サーバーでは、Prometheusからlocalhost:12808へアクセスするため、12808ポートのFirewall設定は不要です。

BPまたはリレー2以降では、Grafana稼働サーバーからcardano-tracerの12808ポートへの接続を許可します。

従来、PrometheusからCardano Nodeの12798ポートへ直接アクセスするためにFirewallで接続を許可していた場合は、該当するルールを削除します。

現在のFirewallルールを番号付きで確認します。

sudo ufw status numbered

12798ポートへの接続を許可しているルールの番号を確認し、削除します。

sudo ufw delete 番号

確認を求められた場合はyを入力します。

Grafana稼働サーバーのIPアドレスを入力します。

prometheus_ipv4=

Grafana稼働サーバーのIPアドレスからcardano-tracerの12808ポートへの接続を許可します。

sudo ufw allow from ${prometheus_ipv4} to any port 12808 proto tcp

Firewallの設定を確認します。

sudo ufw status

Firewallの設定をリロードします。

sudo ufw reload

systemdサービスのログ設定を変更

StandardOutput、StandardError、SyslogIdentifierの設定を各systemdサービスから削除します。

cardano-node.serviceからStandardOutput、StandardError、SyslogIdentifierを削除します。

sudo sed -i \
  -e '/^[[:space:]]*StandardOutput[[:space:]]*=/d' \
  -e '/^[[:space:]]*StandardError[[:space:]]*=/d' \
  -e '/^[[:space:]]*SyslogIdentifier[[:space:]]*=/d' \
  /etc/systemd/system/cardano-node.service
sed -i \
  -e '/^[[:space:]]*StandardOutput[[:space:]]*=/d' \
  -e '/^[[:space:]]*StandardError[[:space:]]*=/d' \
  -e '/^[[:space:]]*SyslogIdentifier[[:space:]]*=/d' \
  "${NODE_HOME}/cardano-node.service"

削除されていることを確認します。

grep -HnE '^[[:space:]]*(StandardOutput|StandardError|SyslogIdentifier)[[:space:]]*=' \
  /etc/systemd/system/cardano-node.service \
  "${NODE_HOME}/cardano-node.service" \
  || echo "OK: syslog directives removed"

以下が表示されれば問題ありません。

期待される表示例:
OK: syslog directives removed

systemdへ変更を反映します。

sudo systemctl daemon-reload

以下のBP関連サービスからStandardOutput、StandardError、SyslogIdentifierを削除します。

for service in \
  cnode-blocknotify.service \
  cnode-cncli-leaderlog.service \
  cnode-cncli-sync.service \
  cnode-cncli-validate.service \
  cnode-logmonitor.service
do
  sed -i \
    -e '/^[[:space:]]*StandardOutput[[:space:]]*=/d' \
    -e '/^[[:space:]]*StandardError[[:space:]]*=/d' \
    -e '/^[[:space:]]*SyslogIdentifier[[:space:]]*=/d' \
    "${NODE_HOME}/service/${service}"

  sudo sed -i \
    -e '/^[[:space:]]*StandardOutput[[:space:]]*=/d' \
    -e '/^[[:space:]]*StandardError[[:space:]]*=/d' \
    -e '/^[[:space:]]*SyslogIdentifier[[:space:]]*=/d' \
    "/etc/systemd/system/${service}"
done

削除されていることを確認します。

grep -HnE '^[[:space:]]*(StandardOutput|StandardError|SyslogIdentifier)[[:space:]]*=' \
  "${NODE_HOME}/service/cnode-blocknotify.service" \
  "${NODE_HOME}/service/cnode-cncli-leaderlog.service" \
  "${NODE_HOME}/service/cnode-cncli-sync.service" \
  "${NODE_HOME}/service/cnode-cncli-validate.service" \
  "${NODE_HOME}/service/cnode-logmonitor.service" \
  /etc/systemd/system/cnode-blocknotify.service \
  /etc/systemd/system/cnode-cncli-leaderlog.service \
  /etc/systemd/system/cnode-cncli-sync.service \
  /etc/systemd/system/cnode-cncli-validate.service \
  /etc/systemd/system/cnode-logmonitor.service \
  || echo "OK: syslog directives removed"

以下が表示されれば問題ありません。

期待される表示例:
OK: syslog directives removed

systemdへ変更を反映します。

sudo systemctl daemon-reload

サーバー再起動

作業フォルダリネーム

以前のバージョンで使用していたバイナリフォルダをリネームし、バックアップとして保持します。
最新バージョンを構築したフォルダをcardano-nodeとして使用します。

cd $HOME/git
mv cardano-node/ cardano-node-old/
mv cardano-node2/ cardano-node/

サーバーの再起動

sudo reboot

SSH接続後、ノード同期状況の確認

cnode

色付きログになっていることを確認してください

同期までしばらくお待ちください

ノードログメッセージ確認

以下のメッセージがログに含まれている場合に同期状況を判断できます。

メッセージステータス
GenesisReadFileErrorジェネシスファイルエラー
InvalidYaml設定ファイルエラー
Invalid option起動オプションエラー
Invalid argument起動コマンドエラー
Address in useノード起動ポートが競合しています

gliveでノード同期状況を確認します。

glive

TraceMempoolについて

以前のバージョンではTraceMempoolオプションを無効(false)にすることでCPUリソースを抑えるのに効果的でしたが、新Tracerへ移行したv11.xではTXの検証機能が改善されたことで、この問題はすでに解決されています。そのため、現バージョンではgLiveViewでMempoolの数値を確認できるようになりました。

cardano-tracerが正常に起動していることを確認します。

sudo systemctl status cardano-tracer --no-pager
期待される表示例:
Active: active (running) 

cardano-node.serviceとcardano-tracer.serviceの連動設定を確認します。

systemctl show cardano-tracer.service -p PartOf --value
systemctl list-dependencies cardano-node.service --plain | grep cardano-tracer.service

以下のように両方のコマンドでcardano-node.service、cardano-tracer.serviceがそれぞれ表示されれば問題ありません。

期待される表示例:
cardano-node.service
cardano-tracer.service

以降はcardano-node.serviceを操作するだけで、Tracerも連動して起動・停止・再起動します。

Tracer Socketの確認

test -S ${CARDANO_TRACER_SOCKET_PATH} && echo "Tracer socket OK"
期待される表示例:
Tracer socket OK

cardano-tracerにCardano Nodeが接続していることを確認します。

curl -s http://127.0.0.1:12808/

Node名が表示されれば、Cardano Nodeがcardano-tracerに正常に接続されています。

期待される表示例:
<html><head><title>Prometheus metrics</title></head><body><ul><li><a href="/mainnet-bp">mainnet-bp</a></li></ul></body></html>

4. 関連ツール・サービスの更新

Guild Operators の gLiveView.sh と env を再取得し、構築時と同じ置換を適用します。
UPDATE_CHECK による自動更新は使わず、ファイルを置き換えてから sed で設定し直します。

上書き時の注意

  • 既存の gLiveView.sh / env は上書きされます。env に手作業で追加した設定がある場合は、置換後に再設定してください。
  • logMonitor.sh / blocks.sh / sjgtool.sh は Guild Operators ではなく、後述の sjg-tools 更新で取得します。

スクリプトを再取得します。

cd $NODE_HOME/scripts
curl -o gLiveView.sh https://raw.githubusercontent.com/cardano-community/guild-operators/master/scripts/cnode-helper-scripts/gLiveView.sh
curl -o env https://raw.githubusercontent.com/cardano-community/guild-operators/master/scripts/cnode-helper-scripts/env
chmod 755 gLiveView.sh

ノードポートを確認します。

PORT=`grep "PORT=" $NODE_HOME/startRelayNode1.sh`
b_PORT=${PORT#"PORT="}
echo "リレーポートは${b_PORT}です"

env ファイル内の定義を修正します。

sed -i $NODE_HOME/scripts/env \
    -e '1,73s!#CNODE_HOME="/opt/cardano/cnode"!CNODE_HOME="'${NODE_HOME}'"!' \
    -e '1,73s!#CNODE_PORT=6000!CNODE_PORT='${b_PORT}'!' \
    -e '1,73s!#UPDATE_CHECK="Y"!UPDATE_CHECK="N"!' \
    -e '1,73s!#CONFIG="${CNODE_HOME}/files/config.json"!CONFIG="${CNODE_HOME}/'${NODE_CONFIG}'-config.json"!' \
    -e '1,73s!#SOCKET="${CNODE_HOME}/sockets/node.socket"!SOCKET="${CNODE_HOME}/db/socket"!' \
    -e '1,73s!#PROM_HOST=127.0.0.1!PROM_HOST=127.0.0.1!' \
    -e '1,73s!#PROM_PORT=12798!PROM_PORT=12798!'

gLiveView を起動してバージョンを確認します。

glive
期待される表示例:
Koios gLiveView v1.32.1

スクリプトを再取得します。

cd $NODE_HOME/scripts
curl -o gLiveView.sh https://raw.githubusercontent.com/cardano-community/guild-operators/master/scripts/cnode-helper-scripts/gLiveView.sh
curl -o env https://raw.githubusercontent.com/cardano-community/guild-operators/master/scripts/cnode-helper-scripts/env
chmod 755 gLiveView.sh

ノードポートを確認します。

PORT=`grep "PORT=" $NODE_HOME/startBlockProducingNode.sh`
b_PORT=${PORT#"PORT="}
echo "BPポートは${b_PORT}です"

env ファイル内の定義を、ブロックログ用の設定を含めて修正します。

sed -i $NODE_HOME/scripts/env \
  -e '1,73s!#CNODEBIN="${HOME}/.local/bin/cardano-node"!CNODEBIN="/usr/local/bin/cardano-node"!' \
  -e '1,73s!#CCLI="${HOME}/.local/bin/cardano-cli"!CCLI="/usr/local/bin/cardano-cli"!' \
  -e '1,73s!#CNCLI="${HOME}/.local/bin/cncli"!CNCLI="${HOME}/.cargo/bin/cncli"!' \
  -e '1,73s!#CNODE_HOME="/opt/cardano/cnode"!CNODE_HOME="'${NODE_HOME}'"!' \
  -e '1,73s!#CNODE_PORT=6000!CNODE_PORT='${b_PORT}'!' \
  -e '1,73s!#UPDATE_CHECK="Y"!UPDATE_CHECK="N"!' \
  -e '1,73s!#CONFIG="${CNODE_HOME}/files/config.json"!CONFIG="${CNODE_HOME}/'${NODE_CONFIG}'-config.json"!' \
  -e '1,73s!#SOCKET="${CNODE_HOME}/sockets/node.socket"!SOCKET="${CNODE_HOME}/db/socket"!' \
  -e '1,73s!#PROM_HOST=127.0.0.1!PROM_HOST=127.0.0.1!' \
  -e '1,73s!#PROM_PORT=12798!PROM_PORT=12798!' \
  -e '1,73s!#BLOCKLOG_TZ="UTC"!BLOCKLOG_TZ="Asia/Tokyo"!' \
  -e '1,73s!#ENABLE_KOIOS=Y!ENABLE_KOIOS=N!' \
  -e '1,73s!#POOL_NAME=""!POOL_DIR=${CNODE_HOME}!' \
  -e '1,116s!#WALLET_PAY_ADDR_FILENAME="payment.addr"!WALLET_PAY_ADDR_FILENAME="payment.addr"!' \
  -e '1,116s!#WALLET_STAKE_ADDR_FILENAME="reward.addr"!WALLET_STAKE_ADDR_FILENAME="stake.addr"!' \
  -e '1,116s!#POOL_HOTKEY_VK_FILENAME="hot.vkey"!POOL_HOTKEY_VK_FILENAME="kes.vkey"!' \
  -e '1,116s!#POOL_HOTKEY_SK_FILENAME="hot.skey"!POOL_HOTKEY_SK_FILENAME="kes.skey"!' \
  -e '1,116s!#POOL_COLDKEY_VK_FILENAME="cold.vkey"!POOL_COLDKEY_VK_FILENAME="node.vkey"!' \
  -e '1,116s!#POOL_COLDKEY_SK_FILENAME="cold.skey"!POOL_COLDKEY_SK_FILENAME="node.skey"!' \
  -e '1,116s!#POOL_OPCERT_COUNTER_FILENAME="cold.counter"!POOL_OPCERT_COUNTER_FILENAME="node.counter"!' \
  -e '1,116s!#POOL_OPCERT_FILENAME="op.cert"!POOL_OPCERT_FILENAME="node.cert"!' \
  -e '1,116s!#POOL_VRF_SK_FILENAME="vrf.skey"!POOL_VRF_SK_FILENAME="vrf.skey"!'

gLiveView を起動してバージョンを確認します。

glive
期待される表示例:
Koios gLiveView v1.32.1

BP関連ツールの更新・確認

cncli.sh / cntools.library の更新

cncli.sh と cntools.library を再取得し、構築時と同じ置換を適用します。

CNCLI 関連サービスを停止します。

sudo systemctl stop cnode-cncli-sync.service cnode-cncli-validate.service cnode-cncli-leaderlog.service

スクリプトを再取得します。

cd $NODE_HOME/scripts
wget -4 https://raw.githubusercontent.com/cardano-community/guild-operators/master/scripts/cnode-helper-scripts/cncli.sh -O ./cncli.sh
wget -4 https://raw.githubusercontent.com/cardano-community/guild-operators/master/scripts/cnode-helper-scripts/cntools.library -O ./cntools.library
chmod 755 cncli.sh

プールIDの確認

pool_hex=`cat $NODE_HOME/pool.id`
pool_bech32=`cat $NODE_HOME/pool.id-bech32`
printf "\nプールID(hex)は \e[32m${pool_hex}\e[m です\n\n"
printf "\nプールID(bech32)は \e[32m${pool_bech32}\e[m です\n\n"

ご自身のプールID 2種類が表示されていることを確認してください
プールIDが表示されていない場合は、こちらの手順を実行してください。

cncli.shファイルの修正

sed -i $NODE_HOME/scripts/cncli.sh \
  -e '1,30s!#POOL_ID=""!POOL_ID="'${pool_hex}'"!' \
  -e '1,30s!#POOL_ID_BECH32=""!POOL_ID_BECH32="'${pool_bech32}'"!' \
  -e '1,30s!#POOL_VRF_SKEY=""!POOL_VRF_SKEY="${CNODE_HOME}/vrf.skey"!' \
  -e '1,30s!#POOL_VRF_VKEY=""!POOL_VRF_VKEY="${CNODE_HOME}/vrf.vkey"!'

CNCLI 関連サービスを起動します。

sudo systemctl start cnode-cncli-sync.service cnode-cncli-validate.service cnode-cncli-leaderlog.service

同期状況を確認します。

cnclilog
期待される表示例:
INFO cncli::nodeclient::sync: block ******** of ********: 100.00% sync'd

sjgtoolの更新

cd $NODE_HOME/scripts
wget -4 https://raw.githubusercontent.com/kuhito-inc/sjg-tools/main/sjgtool.sh -O sjgtool.sh
chmod 755 sjgtool.sh

起動してバージョンを確認します。

gtool
期待される表示例:
>> SPO JAPAN GUILD TOOL Version 5.0.0 <<

BPノードが完全に同期した後、サービス起動状態を確認します。

  • leaderlog
  • validate

logMonitorの更新

logMonitorはCardano Nodeのログを監視し、ブロック生成に関する情報をCNCLIのblocklogへ反映するためのスクリプトです。

logMonitorサービスを停止します。

sudo systemctl stop cnode-logmonitor.service

新しいTracingシステムに対応したlogMonitorを取得します。

cd $NODE_HOME/scripts

wget -4 https://raw.githubusercontent.com/kuhito-inc/sjg-tools/main/logMonitor.sh -q -O ./logMonitor.sh
chmod 755 logMonitor.sh

SQLiteの一時的なデータベースロック発生時に即時エラーとなるのを避けるため、SQLiteのタイムアウトを設定します。

grep -qxF '.timeout 5000' "$HOME/.sqliterc" 2>/dev/null || printf '.timeout 5000\n' >> "$HOME/.sqliterc"

SQLiteのタイムアウトが設定されていることを確認します。

sqlite3 "$NODE_HOME/guild-db/blocklog/blocklog.db" 'PRAGMA busy_timeout;'
期待される表示例:
-- Loading resources from /home/<USER>/.sqliterc
5000

CNCLI関連サービスを再起動します。

sudo systemctl reload-or-restart cnode-cncli-sync.service

logMonitorサービスを起動します。

sudo systemctl start cnode-logmonitor.service

サービスが正常に起動していることを確認します。

sudo systemctl status cnode-logmonitor
期待される表示例:
Active: active (running)

logMonitorのログを確認します。

logmonitor

blocksの更新

cd $NODE_HOME/scripts
wget -4 https://raw.githubusercontent.com/kuhito-inc/sjg-tools/main/blocks.sh -O blocks.sh
chmod 755 blocks.sh

起動してバージョンを確認します。

blocks
期待される表示例:
ブロックログ @ Developed by Guild Operators & Customized by BTBF v2.0.1

blocknotifyの更新

導入していない方は不要です。

SPO BlockNotifyの停止

sudo systemctl stop cnode-blocknotify.service

アップデートファイルのダウンロード

bn_release="$(curl -s https://api.github.com/repos/btbf/block-notify/releases/latest | jq -r '.tag_name')"
wget -4 https://raw.githubusercontent.com/btbf/block-notify/refs/tags/${bn_release}/block_notify.py -O $NODE_HOME/scripts/block-notify/block_notify.py

設定ファイルの更新

cd $NODE_HOME/scripts/block-notify
sed -i 's/^prometheus_port[[:space:]]*=.*/prometheus_port = 12808/' config.ini
grep -q '^node_config[[:space:]]*=' config.ini || sed -i "/^node_home[[:space:]]*=/a node_config = %(node_home)s/${NODE_CONFIG}-config.json" config.ini

SPO BlockNotifyの起動

sudo systemctl start cnode-blocknotify.service

起動確認

blocknotify

バージョンの確認

$HOME/notify-venv/bin/python $NODE_HOME/scripts/block-notify/block_notify.py version
期待される表示例:
v2.6.0

それぞれのサービスを起動して、正常に起動していることを確認してください。

すでに正常稼働していれば不要です。

cnclilog
leaderlog
validate
logmonitor
blocknotify

5. 監視環境の再構築

Grafanaのアップデート

Grafana稼働サーバー(例:リレー1)で、Grafanaを最新メジャーリリースの13.2.2へアップデートします。

現在のバージョン確認

12.xの場合:

grafana-server -v

13.xの場合:

grafana server -v

既に13.2.2以上であれば、この節の以降の手順は不要です。
次のPrometheusの設定変更へ進んでください。

APTリポジトリの確認と復旧

apt-cache policy grafana

Version table:が/var/lib/dpkg/statusのみ、またはhttps://apt.grafana.comが表示されない場合は、リポジトリを再登録します。

sudo rm -f /usr/share/keyrings/grafana.key /etc/apt/keyrings/grafana.gpg
sudo mkdir -p /etc/apt/keyrings
wget -4 -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/grafana.gpg
echo 'deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main' | sudo tee /etc/apt/sources.list.d/grafana.list

不要な旧Grafanaリポジトリ設定ファイルを削除します。

sudo mv /etc/apt/sources.list.d/grafana.list.distUpgrade /etc/apt/sources.list.d/grafana.list.distUpgrade.disabled 2>/dev/null
sudo apt update
apt-cache policy grafana | head -n 10
期待される表示例:
grafana:
  Installed: 12.4.0
  Candidate: 13.2.2
  Version table:
     13.2.2 500
        500 https://apt.grafana.com stable/main amd64 Packages

Candidateが13.2.2であり、出典がhttps://apt.grafana.comであることを確認してください。

Grafanaの更新

sudo apt install -y grafana
sudo grafana cli plugins update-all

Infinity datasourceを最新版に更新します。未導入の場合はインストールします。

sudo grafana cli plugins install yesoreyeram-infinity-datasource
sudo systemctl daemon-reload
sudo systemctl enable --now grafana-server.service
sudo systemctl restart grafana-server.service
sudo systemctl --no-pager status grafana-server.service

Active: active (running)であることを確認します。

バージョン確認

grafana server -v
期待される表示例:
Version 13.2.2

ブラウザからGrafanaへログインし、既存ダッシュボードが表示されることを確認してください。

すでに表示されている場合は、ブラウザをリロードしてください。

Prometheusの設定変更

Cardano Nodeのmetricsをcardano-tracer経由で取得するため、Grafana稼働サーバーのPrometheus設定を変更します。

従来はCardano Nodeの12798ポートから直接metricsを取得していましたが、cardano-tracer導入後は12808ポートから取得します。

Prometheusの設定ファイル作成

以下のコマンドはGrafana稼働サーバー(例.リレー1)で実行してください

リレー2のIPアドレスまたはDNSを=の後に入力して実行してください

relay2_ipv4_or_dns=

BPのIPアドレスを=の後に入力して実行してください

bp_ipv4=

Node名を設定します。

以下はそのまま実行してください。

NODE_NAME_RELAY_1=${NODE_CONFIG}-relay-1
NODE_NAME_RELAY_2=${NODE_CONFIG}-relay-2
NODE_NAME_BP=${NODE_CONFIG}-bp

設定するNode名は、各Cardano NodeのTraceOptionNodeNameと一致している必要があります。

現在のPrometheus設定ファイルをバックアップします。

sudo cp /etc/prometheus/prometheus.yml /etc/prometheus/prometheus.yml.bak

Prometheusの設定ファイルを作成します。

cat > $HOME/prometheus.yml << EOF
global:
  scrape_interval: 15s

  external_labels:
    monitor: 'codelab-monitor'

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9100']
        labels:
          alias: 'relaynode1'
          type: 'system'

      - targets: ['${relay2_ipv4_or_dns}:9100']
        labels:
          alias: 'relaynode2'
          type: 'system'

      - targets: ['${bp_ipv4}:9100']
        labels:
          alias: 'block-producing-node'
          type: 'system'

      - targets: ['localhost:12808']
        labels:
          alias: 'relaynode1'
          type: 'cardano-node'
          __metrics_path__: '/${NODE_NAME_RELAY_1}'

      - targets: ['${relay2_ipv4_or_dns}:12808']
        labels:
          alias: 'relaynode2'
          type: 'cardano-node'
          __metrics_path__: '/${NODE_NAME_RELAY_2}'

      - targets: ['${bp_ipv4}:12808']
        labels:
          alias: 'block-producing-node'
          type: 'cardano-node'
          __metrics_path__: '/${NODE_NAME_BP}'
EOF

備考

9100はprometheus-node-exporterによるCPU、メモリ、ディスクなどのシステムmetricsです。

12808はcardano-tracerが公開するCardano Nodeのmetricsです。

Prometheus設定ファイルの構文を確認します。

sudo promtool check config $HOME/prometheus.yml

構文エラーがない場合は、以下のように表示されます。

正常時の表示例:
Checking /home/$USER/prometheus.yml
SUCCESS: /home/$USER/prometheus.yml is valid prometheus config file syntax

Prometheus設定ファイルを配置します。

sudo mv $HOME/prometheus.yml /etc/prometheus/prometheus.yml

Prometheusを再起動します。

sudo systemctl restart prometheus.service

Prometheusが正常に起動していることを確認します。

sudo systemctl status prometheus.service --no-pager
期待される表示例:
Active: active (running) 

Dashboardのインポート

BPで実行してください

Grafanaパネル用のJSONファイルをダウンロードします。

curl -o $NODE_HOME/spo-japan-guild-cardano-node-dashboard.json https://docs.spojapanguild.net/grafana/cardano-node/spo-japan-guild-cardano-node-dashboard.json
sed -i \
  -e "s/bech32_id_of_your_pool/$(cat $NODE_HOME/pool.id-bech32)/g" \
  $NODE_HOME/spo-japan-guild-cardano-node-dashboard.json
  1. BPのcnodeフォルダにあるspo-japan-guild-cardano-node-dashboard.jsonをローカルPCにダウンロードします。

  2. 左ペインの「Dashboards」→「New」→「Import dashboard」を選択します。

  3. 「Import via dashboard JSON model」を選択し、ダウンロードしたspo-japan-guild-cardano-node-dashboard.jsonを指定します。

  4. 「DS_PROMETHEUS」→「Prometheus」を選択し、「DS_YESOREYERAM-INFINITY-DATASOURCE」→「yesoreyeram-infinity-datasource」を選択し、「Import」を選択します。

Grafanaアラートの対象メトリクス変更

左ペインの「Alerting」→「Alert rules」→「Manage alert rules」→「SJG→ノード監視」→「BPリレー接続監視」のメトリクスを変更して保存します。

cardano_node_metrics_peerSelection_ActivePeers{alias="block-producing-node"}から

cardano_node_metrics_peerSelection_ActivePeers_int{alias="block-producing-node"}

へと変更してください。

6. エアギャップアップデート

SFTP機能ソフト導入

R-loginの転送機能が遅いので、大容量ファイルをダウン・アップロードする場合は、SFTP接続可能なソフトを使用すると効率的です。(FileZilaなど)
ファイル転送にはSFTPソフト設定を行ってください。

sudo cp $(find $HOME/git/cardano-node -type f -name "cardano-cli") ~/cardano-cli
cardano-cli リレーサーバー ローカルのホストマシン

USBを用いてcardano-cliをエアギャップに移動します。

cardano-cli ローカルのホストマシン エアギャップ

ディレクトリ作成

mkdir -p $HOME/git/cardano-node2

$HOME/git/cardano-node2/ にcardano-cliを格納します。

cardano-cli バイナリの配置

sudo cp $(find $HOME/git/cardano-node2 -type f -name "cardano-cli") /usr/local/bin/cardano-cli
sudo chmod +x /usr/local/bin/cardano-cli

バージョンの確認

cardano-cli version

戻り値確認

期待される表示例:
cardano-cli 11.2.3.0 - linux-x86_64 - ghc-9.6  
git rev 938cba990357ae7c4b7f95c8f75dd9d31174bbeb
cd $HOME/git/cardano-node
sudo cp $(./scripts/bin-path.sh cardano-cli) ~/cardano-cli

必要ライブラリ取得

SODIUM_PATH=$(ldconfig -p | grep "libsodium.so.23" | head -1 | awk '{print $NF}')
SECP_PATH=$(ldconfig -p | grep "libsecp256k1.so.2" | head -1 | awk '{print $NF}')

cp -L "$SODIUM_PATH" $HOME/libsodium.so.23
cp -L "$SECP_PATH" $HOME/libsecp256k1.so.2

確認

ll $HOME/cardano-cli $HOME/libsodium.so.23 $HOME/libsecp256k1.so.2

戻り値確認

期待される表示例:
cardano-cli
libsecp256k1.so.2
libsodium.so.23

ファイル転送

USBを用いてcardano-cli、libsecp256k1.so.2、libsodium.so.23をエアギャップの$HOME/git/cardano-node2に移動します。

cardano-cli / libsecp256k1.so.2 / libsodium.so.23 リレーサーバー エアギャップ

エアギャップで以下を実行します。

ディレクトリ作成

mkdir -p $HOME/git/cardano-node2

cardano-cliの配置

sudo cp $HOME/git/cardano-node2/cardano-cli /usr/local/bin/cardano-cli

権限付与

sudo chmod +x /usr/local/bin/cardano-cli

依存ライブラリ配置用ディレクトリ作成

sudo mkdir -p /usr/local/lib

libディレクトリにlibsecp256k1.so.2、libsodium.so.23を配置

sudo cp $HOME/git/cardano-node2/libsecp256k1.so.2 /usr/local/lib/
sudo cp $HOME/git/cardano-node2/libsodium.so.23 /usr/local/lib/

権限設定

sudo chown root:root /usr/local/lib/libsecp256k1.so.2
sudo chown root:root /usr/local/lib/libsodium.so.23
sudo chmod 755 /usr/local/lib/libsecp256k1.so.2
sudo chmod 755 /usr/local/lib/libsodium.so.23

シンボリックリンク作成

cd /usr/local/lib

libsecp256k1

sudo ln -sf libsecp256k1.so.2 libsecp256k1.so

libsodium

sudo ln -sf libsodium.so.23 libsodium.so

リンカーの更新

echo '/usr/local/lib' | sudo tee /etc/ld.so.conf.d/local.conf
sudo ldconfig

依存関係確認

ldd /usr/local/bin/cardano-cli | grep -E "secp|sodium"

戻り値確認

期待される表示例:
libsodium.so.23 => /usr/local/lib/libsodium.so.23 (*****)
libsecp256k1.so.2 => /usr/local/lib/libsecp256k1.so.2 (*****)

cardano-cliの動作確認

cardano-cli version

戻り値確認

期待される表示例:
cardano-cli 11.2.3.0 - linux-x86_64 - ghc-9.6  
git rev 938cba990357ae7c4b7f95c8f75dd9d31174bbeb

Last updated on

Cookieの使用について

当サイトでは、ドキュメントの効果測定と利用状況の把握のため、Google Analytics を使用しています。

同意すると、分析用 Cookie が有効になります。