> ## Documentation Index
> Fetch the complete documentation index at: https://docs.intention.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# プログラムサービス

> コミット済みの取引履歴からアカウント状態をオフチェーンで導出し、その結果をプロトコルトランザクションでチェーンへ書き戻すサービス群です。

取引所がアカウントについて知っておく必要のあることの一部は、ブロックの実行中には計算できません。出来高ティアは30日分の取引に依存します。報酬はまだ締まっていない期間に依存します。リファラルの帰属は、数か月前に成立した関係に依存します。

この処理をブロック実行の中に置くのは、二重に誤りです。ほとんどのブロックが必要としない計算のコストを、すべてのブロックが負担することになります。そのうえ、カーネルは他に保持する理由のない履歴を抱え込むことになります。

プログラムサービスは、向きを逆転させることでこれを解決します。計算はブロックの**外側**で、コミット済みの記録に対して実行されます。その*結果*だけがプロトコル状態としてチェーンへ**書き戻され**、実行時には他の設定と同じく定数時間で読み出せます。

<div className="dg" data-dg="program-writeback">
  <div className="dg-c" style={{aspectRatio:"720 / 348"}}>
    <svg className="dg-w" viewBox="0 0 720 348" aria-hidden="true">
      <path className="dg-wire" d="M 144.00 70.00 L 169.60 70.00" />

      <path className="dg-head" d="M 176.00 70.00 L 169.60 74.40 L 169.60 65.60 Z" />

      <path className="dg-wire dg--sky" d="M 344.00 70.00 L 369.60 70.00" />

      <path className="dg-head dg--sky" d="M 376.00 70.00 L 369.60 74.40 L 369.60 65.60 Z" />

      <path className="dg-wire" d="M 534.00 70.00 L 561.75 38.78" />

      <path className="dg-head" d="M 566.00 34.00 L 565.04 41.71 L 558.46 35.86 Z" />

      <path className="dg-wire dg--blue" d="M 534.00 70.00 L 561.33 95.62" />

      <path className="dg-head dg--blue" d="M 566.00 100.00 L 558.32 98.83 L 564.34 92.41 Z" />

      <path className="dg-wire dg--blue" d="M 645.00 128.00 L 645.00 136.00 L 465.00 136.00 L 465.00 142.00" />

      <path className="dg-head dg--blue" d="M 465.00 142.00 L 460.60 135.60 L 469.40 135.60 Z" />

      <path className="dg-wire dg--green" d="M 554.00 181.00 L 567.60 181.00" />

      <path className="dg-head dg--green" d="M 574.00 181.00 L 567.60 185.40 L 567.60 176.60 Z" />
    </svg>

    <div className="dg-b" style={{left:"0.0000%",top:"11.4943%",width:"19.4444%",height:"17.2414%"}}><span className="dg-t">コミット済み取引履歴</span></div>
    <div className="dg-b dg--sky" style={{left:"25.0000%",top:"5.7471%",width:"22.2222%",height:"28.7356%"}}><span className="dg-t">プログラムサービス</span><span className="dg-s">ブロックの外側での期間ごとの計算</span><span className="dg-n">手数料表はチェーンからライブで読む</span></div>
    <div className="dg-b dg--yellow dg-round" style={{left:"52.7778%",top:"10.3448%",width:"20.8333%",height:"19.5402%"}}><span className="dg-t">前回の適用から変化したか</span></div>
    <div className="dg-b" style={{left:"79.1667%",top:"2.8736%",width:"20.8333%",height:"13.7931%"}}><span className="dg-t">書き込みなし</span></div>
    <div className="dg-b dg--blue" style={{left:"79.1667%",top:"21.8391%",width:"20.8333%",height:"13.7931%"}}><span className="dg-t">プロトコルトランザクション</span></div>
    <div className="dg-b dg--green" style={{left:"52.7778%",top:"41.9540%",width:"23.6111%",height:"20.1149%"}}><span className="dg-t">チェーン状態</span></div>
    <div className="dg-b dg--green" style={{left:"80.2778%",top:"41.9540%",width:"19.7222%",height:"20.1149%"}}><span className="dg-t">実行中に読み取り</span><span className="dg-s">定数時間で</span></div>
    <div className="dg-b dg-dashed dg-left" style={{left:"0.0000%",top:"70.1149%",width:"48.8889%",height:"24.1379%"}}><span className="dg-t">差分は料率に対して取る、ティア位置ではない</span><span className="dg-s">しきい値が動いても、ティアの料率が付け替えられても、ティアのインデックスは変わらないままアカウントの支払額が変わります。</span></div>
    <div className="dg-b dg-dashed dg-left" style={{left:"51.1111%",top:"70.1149%",width:"48.8889%",height:"24.1379%"}}><span className="dg-t">最終的な料率を解決するのはチェーン</span><span className="dg-s">ある期間が適用済みとして記録されるのは、すべてのバッチがコミットされたあとだけです。クラッシュすれば期間全体をやり直しますが、計算は冪等なので安全です。</span></div>
  </div>
</div>

権威はあくまでチェーンにあります。サービスはネットワークが依存する状態を保持しません。値を提案するだけであり、実在するのはチェーンが受け入れたものだけです。

<h2 id="what-runs-today">
  現在稼働しているもの
</h2>

**出来高ベースの手数料ティア**。このサービスはノードからストリーミングされる取引履歴を取り込み、アカウントごとの出来高を積み上げ、スケジュールに従ってスナップショットを取ります。期間が締まると、各アカウントのローリングウィンドウ出来高を計算し、**チェーンからライブで読み取った**手数料設定に照らしてティアを決め、変化したアカウントをバッチで書き戻します。

この説明の細部には、それぞれ役割があります。

* **ティア表はチェーンから読み取るものであり、ハードコードしません**。自前のコピーを抱えるサービスは、ネットワークが表を変えたあとも昨日の内容を適用し続けます。
* **差分は料率に対して取り、ティアの位置に対しては取りません**。ティアの*インデックス*を比べると、現実に起きる2つのケースを取りこぼします。しきい値が動いた結果、何も変わっていないアカウントが別のティアに入る場合と、インデックスは同じままティアの料率が付け替えられる場合です。どちらもアカウントの支払額を変えますが、インデックスは変えません。
* **最終的な料率を解決するのはチェーンです**。トランザクションが運ぶのはティアのインデックスであり、実行時にライブの手数料設定に照らして解決されます。有効範囲外のティアインデックスは、一部だけ適用されるのではなくバッチ全体を失敗させます。
* **ある期間が適用済みとして記録されるのは、すべてのバッチがコミットされたあとだけです**。期間の途中でクラッシュすると期間全体をやり直すことになりますが、計算は冪等なので安全です。同じウィンドウは同じ結果を返します。

<h2 id="the-failure-model">
  障害モデル
</h2>

これらのサービスは、それぞれ時折利用できなくなる2つのシステムの間に位置します。設計はそれを例外として扱うのではなく、前提として組み込んでいます。

依存先の障害（データベース、ノードのストリーム、ノードのAPI）はバックオフ付きでリトライします。プロセスは終了させません。再起動しても到達できない依存先は直らず、障害時間にコールドスタートが上乗せされるだけだからです。致命的なままにしてあるのは、再起動で*直る*もの、または運用者が必ず気づくべきものです。起動時の不正な設定、ヘルスエンドポイントをバインドできないこと、パニックです。

障害の間、プロセスは動き続け、自らをnot-readyと報告し、エラーを数えます。したがって運用上のシグナルは「**プロセスが生きているか**」ではなく「**N分間not-readyのままか**」になります。有用なのはこちらの問いです。1時間にわたって取り込みに失敗している生きたプロセスこそが、実際のインシデントだからです。

オーケストレータが送るシグナルに対しては、グレースフルにシャットダウンします。処理を止め、チェックポイントをフラッシュし、クリーンに終了します。これがなければ、通常のデプロイのたびに未フラッシュのウィンドウと再計算の代償を払うことになります。

<Note>
  計算は済んでいるがまだ適用されていない期間は、失われた期間ではありません。計算は冪等であり、適用済みの期間は書き込みが成功したあとにのみ記録されるため、中断された実行は当該ウィンドウを飛ばすのではなくやり直す形で再開します。
</Note>

<h2 id="why-the-pattern-generalizes">
  このパターンが一般化する理由
</h2>

書き戻しの経路は汎用です。アカウント単位の設定を書き込むプロトコルトランザクションと、グローバル設定を書き込むプロトコルトランザクションが用意されており、プログラムサービスとは、そのいずれかに入れる値をコミット済みの履歴から計算するプロセスの総称です。

稼働しているのは手数料ティアだけです。インセンティブプログラム、リファラルの帰属、キャンペーンの参加資格も同じ形になります。取引履歴に対する期間区切りの計算、現在適用されている値との差分、バッチでの書き戻しです。これらがカーネルではなくここに属する理由も手数料ティアと同じで、計算は周期的かつ履歴的である一方、実行側は答えが定数時間の参照であることを必要とするからです。いずれもまだ実装されていません。一般化するのはパターンであって、これらが実際にそれを使うという約束ではありません。

これらのプログラムの商業的な条件は[手数料とプログラム](/ja/programs/fees)にあります。このページが扱うのは、その結果がどうやってオンチェーンに載るかです。

<h2 id="where-to-go-next">
  次に読む
</h2>

<CardGroup cols={2}>
  <Card title="インデクサー" href="/ja/protocol/architecture/indexer">
    これらのサービスが取り込むストリームです。
  </Card>

  <Card title="手数料" href="/ja/programs/fees">
    商業面。ティアの中身と、それがいくらかかるのかです。
  </Card>

  <Card title="IntentionKernel" href="/ja/protocol/architecture/kernel">
    書き戻された設定が、実行中にどう読まれるのかです。
  </Card>

  <Card title="ステートモデル" href="/ja/protocol/architecture/state/model">
    設定キーがバージョン付きである理由と、クライアントがそれをライブで解決すべき理由です。
  </Card>
</CardGroup>
