メインコンテンツまでスキップ

SPOとしてガバナンスアクションに投票する方法

SPOがガバナンスアクションに投票するには以下の手順に従います。
進行中のガバナンスアクションのアクションIDを取得、投票のスタンスを決定し、必要に応じて議論に参加します。
その後Cardano CLIを使用して投票ファイルを作成し、ブロックチェーンに送信します。

前提条件
  • 支払いキーペア
  • 資金のあるアドレス
  • ステークプールキー
ガバナンスアクションの内容の確認

新しい憲法提案のアクションID ${ga_id}#0が与えられたと仮定します。
ガバナンス状態から新しい憲法提案のURLとハッシュを取得します。

  1. governanceディレクトリ作成
mkdir -p $NODE_HOME/governance
  1. 対象のガバナンスアクションIDを変数に代入します。
ga_id=

例)0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9

  1. ガバナンスアクションの内容を取得します。
cd "$NODE_HOME/governance"

cardano-cli latest query gov-state ${NODE_NETWORK} \
| jq -r --arg govActionId "${ga_id}" '
.proposals
| to_entries[]
| select(.value.actionId.txId | contains($govActionId))
| .value
' \
> "$NODE_HOME/governance/${ga_id}.json"
  1. 元帳状態に登録されているURLからファイルをダウンロードします。
anchor_url=$(jq -r '.proposalProcedure.anchor.url'       "$NODE_HOME/governance/${ga_id}.json")
anchor_datahash=$(jq -r '.proposalProcedure.anchor.dataHash' "$NODE_HOME/governance/${ga_id}.json")
ga_ix=$(jq -r '.actionId.govActionIx' "$NODE_HOME/governance/${ga_id}.json")
echo "URL=${anchor_url}"
echo "Ix =${ga_ix}"
  1. URL からファイルをダウンロード(IPFS対応)
out="$NODE_HOME/governance/${ga_id}-ga.txt"

if [[ "$anchor_url" =~ ^ipfs:// || "$anchor_url" == */ipfs/* ]]; then
ipfs_path="${anchor_url#ipfs://}"
ipfs_path="${ipfs_path#/ipfs/}"
gateways=(
"https://ipfs.io/ipfs"
"https://gateway.pinata.cloud/ipfs"
"https://nftstorage.link/ipfs"
"https://dweb.link/ipfs"
"https://cloudflare-ipfs.com/ipfs"
)
ok=""
for gw in "${gateways[@]}"; do
echo "Trying ${gw}/${ipfs_path} ..."
if curl -L --fail --max-time 45 --retry 2 --retry-delay 1 \
-o "$out" "${gw}/${ipfs_path}"; then
echo "Downloaded via: $gw"
ok="yes"; break
fi
done
[[ -z "$ok" ]] && { echo "全ゲートウェイ失敗"; exit 1; }
else
curl -L --fail --max-time 60 --retry 2 --retry-delay 1 \
-o "$out" "$anchor_url"
fi
  1. dataHash の検証(BLAKE2b-256)
expected="$(echo "$anchor_datahash" | sed 's/^0x//' | tr '[:upper:]' '[:lower:]')"

if command -v b2sum >/dev/null 2>&1; then
calculated="$(b2sum -l 256 "$out" | awk '{print tolower($1)}')"
elif command -v openssl >/dev/null 2>&1; then
calculated="$(openssl dgst -blake2b256 "$out" | awk '{print tolower($2)}')"
else
echo "b2sum/openssl が必要です"; exit 2
fi

echo "expected: $expected"
echo "calculated: $calculated"
[[ "$calculated" = "$expected" ]] && echo "OK: dataHash一致" || { echo "NG: dataHash不一致"; exit 2; }

93106d082a93e94df5aff74f678438bae3a647dac63465fbfcde6a3058f41a1e

93106d082a93e94df5aff74f678438bae3a647dac63465fbfcde6a3058f41a1e 0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9-ga.txt

  1. 投票ファイルに使用するガバナンスアクションのindexを控える URLのテキストはデータハッシュと一致しており、URLのテキストがまさに私たちが投票しているものであることが確認されています。 将来的には、投票アプリ、エクスプローラー、ウォレット、その他のツールがフィルタリングを実行し、URL コンテンツが元帳状態のハッシュに対して検証されたアクションのみが表示されるようになります。
echo ${ga_ix}

出力されたガバナンスアクションのindex番号

投票ファイル作成

  1. governanceディレクトリ作成
mkdir -p $NODE_HOME/governance
  1. 対象のガバナンスアクションIDを変数に代入します。
ga_id=

例)Hard Fork to Protocol Version 10 ("Plomin" Hard Fork)Hashをコピーします。
0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b900

ハッシュ値の最後の00は不要です。

  1. 投票ファイルに使用するガバナンスアクションのindexを変数に代入します。
ga_ix=0
  1. 作成したメタデータのURLを変数に代入します。
anchor_data_url=

次のファイルを参考にファイル名や内容commentのみを修正します。
例)https://akyo3.github.io/AKYO/vote/gov_action1pvv5wmjqhwa4u85vu9f4ydmzu2mgt8n7et967ph2urhx53r70xusqnmm525.json

  1. 以下のコマンドでハッシュ値を出力します。
cd $NODE_HOME
cardano-cli hash anchor-data \
--url ${anchor_data_url} \
--out-file $NODE_HOME/governance/anchor-data-hash.txt
  1. ハッシュ値の出力
echo $(cat $NODE_HOME/governance/anchor-data-hash.txt)
ファイル転送

BPの$NODE_HOME/governance/anchor-data-hash.txtをエアギャップの$NODE_HOME/governanceディレクトリにコピーします。

  1. governanceディレクトリ作成
mkdir -p $NODE_HOME/governance
  1. BPで出力したハッシュ値と比較します。
echo $(cat $NODE_HOME/governance/anchor-data-hash.txt)

BPで出力したハッシュ値と同じであること

  1. 変数に対象のガバナンスアクションIDを代入します。
ga_id=

例)0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9

  1. 変数に対象のガバナンスアクションのIndexを代入します。
ga_ix=0
  1. 以下の変数にオプションを設定します。
voting_stance=
3つのオプション
--yes
--no
--abstain
  1. metadataを付与したい場合は以下の変数にURLを代入します。
anchor_data_url=

例)https://akyo3.github.io/AKYO/vote/gov_action1pvv5wmjqhwa4u85vu9f4ydmzu2mgt8n7et967ph2urhx53r70xusqnmm525.json

  1. メタデータを付与する場合
chmod u+rwx $HOME/cold-keys
cd $NODE_HOME
cardano-cli latest governance vote create \
${voting_stance} \
--governance-action-tx-id ${ga_id} \
--governance-action-index ${ga_ix} \
--cold-verification-key-file $HOME/cold-keys/node.vkey \
--anchor-url ${anchor_data_url} \
--anchor-data-hash $(cat $NODE_HOME/governance/anchor-data-hash.txt) \
--out-file $NODE_HOME/governance/${ga_id}-ga.vote
ファイル転送

エアギャップの$NODE_HOME/governance/${ga_id}-ga.voteをBPの$NODE_HOME/governanceディレクトリにコピーします。

トランザクション構築

トランザクションに投票を含めます。

トランザクションに投票を含めます。

  1. 最も多いUTXOを変数に代入
TX_FULL=$(cardano-cli latest query utxo ${NODE_NETWORK} \
--address "$(cat $NODE_HOME/payment.addr)" --out-file /dev/stdout \
| jq -r 'to_entries | sort_by(.value.value.lovelace) | reverse | .[0].key')

TX_HASH=${TX_FULL%%#*}
TX_IX=${TX_FULL##*#}
  1. 変数の内容を確認
echo "$TX_HASH#$TX_IX"
  1. トランザクションをビルドします。
cardano-cli latest transaction build \
${NODE_NETWORK} \
--tx-in ${TX_HASH}#${TX_IX} \
--change-address $(cat $NODE_HOME/payment.addr) \
--vote-file $NODE_HOME/governance/${ga_id}-ga.vote \
--witness-override 2 \
--out-file $NODE_HOME/governance/vote-tx.raw

Estimated transaction fee: Coin XXXXXX

ファイル転送

BPの$NODE_HOME/governance/vote-tx.rawをエアギャップの$NODE_HOME/governanceディレクトリにコピーします。

トランザクション署名

  1. SPOコールドキーで署名します。
cd $NODE_HOME
cardano-cli latest transaction sign \
${NODE_NETWORK} \
--tx-body-file $NODE_HOME/governance/vote-tx.raw \
--signing-key-file $HOME/cold-keys/node.skey \
--signing-key-file $NODE_HOME/payment.skey \
--out-file $NODE_HOME/governance/vote-tx.signed

chmod a-rwx $HOME/cold-keys
ファイル転送

エアギャップの$NODE_HOME/governance/vote-tx.signedをBPの$NODE_HOME/governanceディレクトリにコピーします。

トランザクション送信

  1. トランザクションをブロックチェーンに送信します。
cardano-cli latest transaction submit \
${NODE_NETWORK} \
--tx-file $NODE_HOME/governance/vote-tx.signed

Transaction successfully submitted.

特定のガバナンス アクション ID に対する「賛成」、「反対」、「棄権」の投票の合計数を表示します。

エアギャップの$NODE_HOME/governance/vote-tx.signedをBPの$NODE_HOME/governanceディレクトリにコピーします。

ga_id=
ガバナンスアクションの内容の確認

HOSKY

15f82a365bdee483a4b03873a40d3829cc88c048ff3703e11bd01dd9e035c916

IKIGAI

59fd353253eb177e2104e8f23ea4c63e3d32ef95c7865d03e90d3884424dc1db

Atrium

7fd6429add8f2611ad8d48c0cc49101463093aec285faea402e8cfde78ea58d7

Plomin Hard Fork

fff0df644d328a5367212f45bab59060bde3c4091dc96c723062896fd6197314

Hard Fork to Protocol Version 10 ("Plomin" Hard Fork)

0b19476e40bbbb5e1e8ce153523762e2b6859e7ecacbaf06eae0ee6a447e79b9

Replace Interim Constitutional Committee

47a0e7a4f9383b1afc2192b23b41824d65ac978d7741aca61fc1fa16833d1111

投票の合計数確認

cardano-cli latest query gov-state ${NODE_NETWORK} \
| jq -r --arg actionTxId ${ga_id} --arg actionIndex "0" ' .proposals
| to_entries[]
| select(.value.actionId.txId == $actionTxId and .value.actionId.govActionIx == ($actionIndex | tonumber))
| {
govActionId: .value.actionId,
dRepVoteYesCount: (.value.dRepVotes | with_entries(select(.value == "VoteYes")) | length),
dRepVoteNoCount: (.value.dRepVotes | with_entries(select(.value == "VoteNo")) | length),
dRepAbstainCount: (.value.dRepVotes | with_entries(select(.value == "Abstain")) | length),
stakePoolVoteYesCount: (.value.stakePoolVotes | with_entries(select(.value == "VoteYes")) | length),
stakePoolVoteNoCount: (.value.stakePoolVotes | with_entries(select(.value == "VoteNo")) | length),
stakePoolAbstainCount: (.value.stakePoolVotes | with_entries(select(.value == "Abstain")) | length),
committeeVoteYesCount: (.value.committeeVotes | with_entries(select(.value == "VoteYes")) | length),
committeeVoteNoCount: (.value.committeeVotes | with_entries(select(.value == "VoteNo")) | length),
committeeAbstainCount: (.value.committeeVotes | with_entries(select(.value == "Abstain")) | length)
}
'