![見出し画像](https://assets.st-note.com/production/uploads/images/93063521/rectangle_large_type_2_7474d9073808570ecf7e5afdc594de51.jpeg?width=1200)
【Symbol Blog】ハードフォークの仕組み(2022/12/10)
この記事はSymbol Blogに投稿された記事「10 DEC MECHANICS OF A HARD FORK」を機械翻訳したものです。著者はSymbol/NEMのコア開発者であるJaguarさんです。
このガイドでは、最近の 1.0.3.4 のフォークを例として、catapult クライアントをフォークするために必要な変更について説明します。このガイドは、すべての、あるいはほとんどのフォークに必要な共通の変更について説明することを目的としているので、そのフォークにおける特定の修正については詳しく説明しません。完全な変更を見るには、このコミットを確認してください。
背景
ハードフォークとは、後方互換性のないプロトコルの更新のことです。重要なのは、アップグレードしないクライアントは、アップグレードするクライアントと同期できず、結果としてチェーンが分裂してしまうことです。
少なくとも2/3の投票重要度を集めたチェーンがブロックを確定することができ、他のチェーンはdHealthのように、外部の介入なしにブロックを確定することができない煉獄の状態で終了します。ファイナライズのない他のチェーン(NEMやビットコインなど)では、最長のチェーンがフォークに勝利します。Symbolの場合もそうですが、オーファンとなったチェーンでは積極的な難易度調整(低め)が行われているため、しばらくはチェーンが拮抗することになります。
この記事を書いている時点では、アップグレードされたチェーン(1.0.3.4+)の高さが1800243であるのに対し、オーファンとなったチェーン(1.0.3.3)の高さは1757636であることに注目してください。
フォークブロック
フォークブロックは、(互換性のない)新しい機能や変更された機能が有効になる特別なブロックです。このブロック以降で、新しい機能を使用することができます。
注意すべきは、オリジナルとアップグレードのチェーンは、必ずしもフォークブロックでフォークするわけではないということです。フォークは新しい機能が最初に使われたときに起こります。
例えば、1.0.3.4のアップグレードでは、フォークブロックは1690500でしたが、新しい機能(バージョン2のアグリゲート)はブロック1690553(このトランザクション)で最初に使用されました。その結果、チェーンは1690500ではなく、ブロック1690553でフォークした。なぜなら、そのブロックにはバージョン2のアグリゲートが含まれており、元の1.0.3.3クライアントがそれを拒否したためである。
アップグレード
アップグレードされたクライアントは、フォークブロックまでの元の機能のみを許可することが重要です。その理由を理解するために、代替となる可能性のある動作を考えてみましょう。
全ブロックで新機能のみ可
これは、新しい機能がフォークブロックより前のブロックに適用される可能性があり、望ましくないため、ノードがゼロから同期するのを中断します。バグフィックスの場合でも、ノードがゼロから同期できなくなる可能性があります。1.0.3.4 のアップグレードでは、ノードがゼロから同期できるようにするために、不正な計算を特に許可(および検証)する必要がありました。
フォークブロックの前に新機能、旧機能の両方が許される
これにより、クライアントのアップグレード後、フォークブロックの前に、新しい機能を持つブロックをネットワークにプッシュすることができるようになります。これはノード管理者にとって複雑なことです。なぜなら、分割されたブロックがまったくわからないため、アップグレードの期限について合意することができないからです。また、よりオンラインであるノード運用者にやや不公平な優位性を与えることになります。
コンフィギュレーション
最初のステップは、新しい(互換性のない)機能を含むブロックを定義することです。これは設定の中で行います。これにより、testnet で同様のアップグレードを実行(そしてテスト!)することができます。新しい機能がブロック1690500で有効になることを示すstrictAggregateTransactionHashプロパティを追加しています。
[fork_heights]
totalVotingBalanceCalculationFix = 528000
treasuryReissuance = 689761
strictAggregateTransactionHash = 1690500
また、BlockChainConfigurationに対応するフィールド(StrictAggregateTransactionHash)を追加する必要があり、これはクライアントがconfig-network.settingsの設定をロードしてアクセスするために使用されます。
/// Fork heights configuration.
struct ForkHeights {
/// Height of fork to fix TotalVotingBalance calculation.
Height TotalVotingBalanceCalculationFix;
/// Height of fork at which to reissue the treasury.
Height TreasuryReissuance;
/// Height of fork at which aggregate transaction hash is strictly enforced.
Height StrictAggregateTransactionHash;
};
config-network.propertiesのプロパティとStrictAggregateTransactionHeightフィールドを接続するために必要なのは、次の行だけです。
LOAD_FORK_HEIGHT_PROPERTY(StrictAggregateTransactionHash);
プロトコル変更
1.0.3.4 のアップグレードでは、フォークブロック以降のすべてのアグリゲート・トランザクションはバージョン 2 でなければなりません。また、fork ブロックより前のすべてのアグリゲートはバージョン 1 でなければなりません。
この制約を強化するために、新しい AggregateTransactionVersion バリデーターを追加しました。その実装は非常にシンプルです。アグリゲートトランザクション(完了または結合)を検出すると、現在の高さをフォークの高さと比較する。高さがフォークの高さより前であれば、そのアグリゲートはバージョン1であることが要求される。高さがフォークの高さかそれ以降である場合、アグリゲートがバージョン2であることを要求する。
バリデータはチェーンの高さに依存するため、ステートレスではなくステートフルである。
DECLARE_STATEFUL_VALIDATOR(AggregateTransactionVersion, Notification)(Height v2ForkHeight) {
return MAKE_STATEFUL_VALIDATOR(AggregateTransactionVersion, ([v2ForkHeight](
const Notification& notification,
const ValidatorContext& context) {
if (!IsAggregate(notification.EntityType))
return ValidationResult::Success;
if (context.Height < v2ForkHeight)
return 1 == notification.EntityVersion ? ValidationResult::Success : Failure_Aggregate_V2_Prohibited;
else
return 2 <= notification.EntityVersion ? ValidationResult::Success : Failure_Aggregate_V1_Prohibited;
}));
}
フォークの高さは、AggregatePluginからv2ForkHeightの引数として渡される。
auto v2ForkHeight = manager.config().ForkHeights.StrictAggregateTransactionHash;
manager.addStatefulValidatorHook([v2ForkHeight](auto& builder) {
builder.add(validators::CreateAggregateTransactionVersionValidator(v2ForkHeight));
});
追記
新機能は熟考の上、慎重に追加する必要があります。新しい動作を有効にするための正確なメカニズムは、追加される特定の動作に依存します。
理想的には、機能はほとんど自己完結しており、対象となるプラグインや拡張機能を修正または追加する以外の変更は最小限であることが望ましいです。
機能を有効にするためのチェックは、最小限かつ十分な数であるべきです。もし多くのバリデータでフォークの高さをチェックする必要があると感じたら、 一歩下がって設計を考え直してみてください。
金融生地の文脈では、「早く動いて壊す」というのはあまり効果がないことを覚えておいてください。ゆっくり動いて、壊さないようにしましょう
![](https://assets.st-note.com/img/1670730954225-6IaqBbBKT4.png)