T3 · 取引がコードからチェーンへ届くまで
構築から確認まで、コードは何を行う必要があるのか?
- 練習する能力
- BuilderOnchain Literacy
- 実践
- コードからテストネット取引を送り、意図的にガス代を低くして滞留させ、同じノンスで置き換える。
- AI Lab
- AI に取引失敗の 10 パターンと対応するエラーを列挙させ、そのうち 3 つをテストネットで再現する。
現実の問題
出金機能を公開しました。利用者が金額を入れて確認すると、ボタンが回ります。
最初の週に三種類の問い合わせが来ました。
- 「引かれたのに届かない」。取引はチェーンにあり、赤い印が付いています。手数料だけが引かれ、金額は動いていません。
- 「三十分も処理中」。ハッシュはありますが、どのブロックにもなく、エラーもありません。
- 「二回出金した」。待ち切れず再度押し、両方が成功しました。
共通点は、コードが要求を送ったことしか知らず、その後を知らないことです。
プロセスから実際の着金まで何段階を経て、各段階はどう失敗するのでしょうか。
思考実験
取引を、厳密な郵便局へ送る、送料付きの書留と考えます。
規則は四つです。
第一に、番号は 0 から一通ずつ増え、飛ばせません。5 が未処理なら 6 は止まり、エラーなく動きません。
第二に、送料は自分で決めます。高いものから処理し、安いものは返送されず、空くまで待ちます。
第三に、同番号の新しい手紙を送れます。 十分高い送料なら古いものを置き換えます。 取消と加速の唯一の手段です。取り戻すのではなく上書きします。
第四に、配達しても受取成功とは限りません。拒否でも送料はかかり、台帳上の配達と業務の成功は別です。
問い合わせと照合します。
- 引かれて未着は、第四の拒否です。
- 処理中は、番号の欠落か低い送料です。
- 二回は、新番号で独立した二通を送った結果です。
三つの bug ではなく、同じモデルの欠落です。
あなたが決める
いつ出金成功と表示できますか。
結果を観察する
四つは、同じ流れの異なる地点です。
| 成功を宣言する時点 | 分かること | 未知のこと |
|---|---|---|
| 署名 | 利用者の同意 | 送信したか |
| ハッシュ | 一ノードが受けた | 取込み、置換、破棄 |
| ブロック | 実行した | 成功か巻戻しか |
| レシート成功と確認 | 成功し、短期には戻りにくい | 極端な深い再編 |
一段階ではなく五段階で、各段階の失敗は独立し、例外、コード、無応答の停滞など表れ方も異なります。
最も危険なのは静かな停滞で、問い合わせまで処理していないことがあります。
モデルを作る
五段階です。
- 構築 Construct
- 署名 Sign
- 送信 Broadcast
- 実行 Execute
- 確認 Confirm
各段階の役割と失敗です。
| 段階 | コードの役割 | 典型的失敗 | 表れ方 |
|---|---|---|---|
| 構築 | to、value、data、nonce、Gas と費用の上限、チェーン番号 | 番号、単位、チェーンの誤り | 即エラーか、誤ったチェーンで成功 |
| 署名 | 内容へ署名して送信可能なバイトを作る | 鍵やチェーン形式の誤り | 拒否か別アドレスの復元 |
| 送信 | バイトをノードへ渡す | 低費用、使用済み・飛んだ番号、基本料不足 | 即エラーか、静かに受けて永久に停滞 |
| 実行 | ブロック内で実行しレシートを作る | revert、Gas 不足、状態変化 | 失敗レシートでも手数料はかかる |
| 確認 | 後続ブロックを待つ | 再編、置換、プールから破棄 | 見えた取引が後に見えなくなる |
四つを詳しく考えます。
1.番号には二つの読み方があります。
確定分だけか、プールの待機分も含むかを選びます。連続送信は後者でなければ番号が重なりますが、先頭が永遠に入らないと後続も止まります。
2.費用不足はエラーより停滞です。
従来の成功・失敗に加え、受け入れられたが無期限の保留があります。ハッシュだけでは何も起きていないと分かりません。
3.失敗でも実行した分の費用を払います。
ノードは計算したので合理的でも、利用者には支払ったのに得られなかった状態です。正直な説明がなければ、自分が資金を取ったと思われます。
4.取消には同番号の新しい取引を使います。
撤回ではなく、高い費用で自分へゼロを送ります。先に入ったほうが有効です。新旧のハッシュは異なるため、両方を追わないと成功を失敗と扱います。
何と呼ぶか
アドレスごとの、0 から増える飛ばせない番号です。
再使用を防ぎ、同じアドレスの順序を決めます。
暗号学では一回限りの乱数(T2)、ここではカウンターで、別のものです。
計算量の上限と、単位あたりに払う価格です。
Gas 不足は途中で失敗して課金、費用不足は実行前の停滞です。混同すると調査を誤ります。
署名済みで送信できるバイトです。
ハッシュは送信前に決まるため、取得だけでチェーンが知るとは限りません。
ノードが保持する未取込み取引です。
ローカルで、チェーンの一部ではありません。全ノードにあることも、残り続けることも保証されません。T4 で扱います。
同 nonce と高い費用で、古い取引を置き換えます。
加速と取消は同じ機構です。最低の値上げ幅があり、不足なら置換の提示額が低いと拒否されます。
確認数は上に重なったブロック数、最終確定はプロトコルの巻戻し不能の宣言です。
両者は違い、前者は確率、後者は約束です。最新と最終確定の明示的なタグを T4 で扱います。
実践
テスト通貨に価値はなく、実資産は使いません。資金のあるウォレットでなく、専用のものを作ります。
二種類の nonce を比較します。
curl -s -X POST <テストネット-RPC-アドレス> \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_getTransactionCount",
"params":["<あなたのアドレス>","latest"]}'
curl -s -X POST <テストネット-RPC-アドレス> \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_getTransactionCount",
"params":["<あなたのアドレス>","pending"]}'最初は等しく、後で差ができます。
現在の費用を見ます。
curl -s -X POST <テストネット-RPC-アドレス> \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_gasPrice","params":[]}'十六進数の wei を十進数へ変え、10 の 9 乗で割って gwei にします。記録し、次は十分低い値を使います。
正常な取引で経路を確認します。
自分の別のテストアドレスへ少額を送り、ハッシュを調べます。
curl -s -X POST <テストネット-RPC-アドレス> \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_getTransactionByHash","params":["<ハッシュ>"]}'blockNumber が null なら未取込みです。送信と取込みの区別に使います。
意図的に止めます。
高度な設定で費用上限を第二段階の十分の一、nonce を既定にして送ります。
ハッシュがあっても、eth_getTransactionByHash の blockNumber が null のままか観測します。
正常に見えて動かない失敗です。エクスプローラーでは pending か、見つからない状態になります。
後続の停滞を観測します。
先頭を止めたまま、通常の費用で次の nonce を送ります。
費用が十分でも、先頭が未処理なら後も待ちます。第一段階の二番号の差が 2 になります。
一件で全出金が止まる、よくある事故です。
同 nonce で置換します。
第四段階の取引を加速か取消すると、同じ nonce で高い費用の取引を作ります。
手動なら、同番号と現在の二倍以上の上限を使います。値上げ不足なら拒否されます。
成功後を確認します。
- 旧ハッシュの
eth_getTransactionByHashは null となり、旧取引は存在しなくなります。 - 新ハッシュの
blockNumberは null ではありません。 - 後続も取込みされます。
実行の成功を確認します。
curl -s -X POST <テストネット-RPC-アドレス> \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_getTransactionReceipt","params":["<新しいハッシュ>"]}'status の 0x1 は成功、0x0 は失敗で、gasUsed は実際の消費です。
コードへこの段階を入れます。状態を見ず成功とすると、問い合わせを残します。
AI Lab
三段階で問いかけます。
第一段階:
Ethereum 取引の構築から確認までの十種類の失敗を表にしてください。
段階、ノードの典型的なエラー原文、利用者の見え方、
手数料の有無、正しい対応を示してください。
第二段階:
エラーを出さず動かないものはどれですか。
検出方法と検出間隔を示してください。
第三段階:
第二、第五、第八の失敗を、JSON-RPC と普通のウォレットだけで
テストネット上に再現する具体的な手順を示してください。
SDK は使わないでください。例外のない失敗こそ本番事故の源泉なので、第二段階が中心です。
第三で実行すると、エラーの違いを発見できます。ノードごとの表現をモデルが混ぜているためです。
実際に使うノードを基準にエラー表を作り、モデルの記憶に頼りません。T14 で利用者の文言へ変えます。
AI の回答後、自分で必ず検証すること
- エラー文字列を実際のノードで再現できる
- 低い提示額と、低い置換提示額を区別している
- 失敗なら手数料不要と言っていない
- Gas 不足と費用上限不足を逆にしていない
- SDK の名前と引数が公式文書に存在する
- wei、gwei、十六進数の換算が正しい
- ブロックの存在と成功を区別している
実例
急騰した費用へ追い付かない出金が、エラーなく止まりました。
後続が数千件積み上がっても、失敗要求がないので監視は通知しませんでした。
同番号の高い費用で再送すれば直りますが、気付くのが難しい問題です。
未取込みの期限、値上げ再送、pending と latest の差の警報を設けます。
送金より三桁大きい手数料を払った例があります。
金額と費用の欄を逆にしたと推測されています。
構築コードに単位の断言と上限検査が必要です。人の入力ミスを送信前に防ぎます。
ウォレットが同番号を高い費用で再送し、成功しました。
システムは旧ハッシュだけを見て、失敗扱いで残高を解放しましたが、資金はすでに出ています。
アドレスと nonce の最終結果も監視し、T14 で置換を独立状態にします。
revert した取引のレシートは失敗で、手数料が引かれました。
取込みしか確認しないウォレットや画面は緑の成功を示しても、資金は届きません。
status は明示的に検査し、既定で成功としません。
変数を一つ変える
同じ番号を取得し、後が置換として拒否されるか、前を上書きします。
再現しにくい不規則な欠落になります。
単なるロックより、単一の割当者と、送信記録と同じトランザクションの保存が必要です。T15 で設計します。
費用上限は固定され、数分から数日待つ可能性があります。
監視して期限切れに同番号で値上げ再送します。そのループも冪等にし、相互に置換する取引を増やしません。
独立した二取引となり、二回支払います。
同じ出金要求には同じ番号と内容を対応させ、同じ署名済みバイトを再送します。
連番より最近のブロックハッシュを使い、期限切れで停滞ではなく無効になります。再構築と再署名が必要です。
送信済みか不明という別問題になり、実行エラーも確認します。T6 と T14 で二方式を比べます。
持ち帰る問い
発信アドレスが失敗も含めて払います。肩代わりするなら、ホットウォレット、番号管理、悪用の防御も必要です。
停滞は利用者の待ちと自分のサポート、失敗は利用者の費用、照合不一致は通常自分の損失です。責任も異なる三状態を区別します。
Agent はタイムアウトで新しい取引を作り、二回払いがちです。nonce の冪等な意味を理解しないため、再試行はコードへ固定します。
章末チェック
言えません。送信前に決まる名前です。
取込みは eth_getTransactionByHash の blockNumber、成功はレシートの status を見ます。
まったく異なります。
Gas 不足は実行途中に戻り、課金されます。 費用不足は取込みされず、課金なしで動きません。
支払って失敗するか、払わず未処理かで、調査と表示が異なります。
同 nonce と十分高い費用で新取引を送り、置き換えます。
自分へゼロを送り、新旧のハッシュ、またはアドレスと番号を追います。
同アドレスは番号順で、飛ばせません。
5 が未処理なら 6、7、8 は高くても実行できず、プロトコル上の順番が未到来です。
全出金を止めるため、高並行のシステムは複数アドレスへ分散します。
正解は一つではありません。次を確認します。
- 署名待ち、署名済み、送信済み、取込み、確認、失敗、置換、期限切れ再送を含みますか。
- 単一の番号割当と、業務記録との同時保存がありますか。
- 同じ署名済みバイトを再送する冪等性がありますか。
- 相互置換を増やさない未取込みの背景処理がありますか。
- pending と latest の差を監視しますか。
- status を明示的に検査しますか。
- 利用者の加速によるハッシュ変更を失敗と誤認しませんか。
第三、第四、第七まで書ければ、demo を超えています。
要点
取引の構築、署名、送信、実行、承認には、それぞれ異なる失敗の形がある。