Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】A Senior Engineer's Guide to Sending EVM Transactions in Python

2025年10月03日に「Dev.to」が公開したITニュース「A Senior Engineer's Guide to Sending EVM Transactions in Python」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Pythonとweb3.pyでEVMブロックチェーンにデータを書き込む方法を解説。読み込みと異なり、書き込みには秘密鍵、ガス代、トランザクションの署名・送信・確認が必要となる。堅牢なClientクラスを構築し、トークン承認の具体例を通して、安全でスケーラブルなトランザクション送信の基礎を学ぶ。

ITニュース解説

システムエンジニアを目指す初心者がブロックチェーンの世界に足を踏み入れる際、まず遭遇するのは「ブロックチェーンからの読み取り」だ。例えば、Web3.pyのようなツールを使って、特定のウォレットの残高を確認したり、スマートコントラクトに保存されているデータ(ビュー関数やピュア関数と呼ばれるもの)を照会したりすることは、比較的容易に行える。これは、インターネット上の情報を閲覧するのと同じ感覚で、ブロックチェーンの情報を「読む」行為に当たる。しかし、ブロックチェーンの真価を発揮し、その「状態」を変化させ、ネットワークに能動的に「参加」するためには、「書き込み」、つまりトランザクションを送信する能力が必要になる。

「読み取り」と「書き込み」は根本的に異なる。読み取りは、ブロックチェーンのノードが持つデータのローカルコピーを照会するだけで、ネットワーク全体に影響を与えることはないため、手数料はかからない。一方、書き込み(トランザクション)は、その変更が新しいブロックとして生成され、ネットワーク全体で検証・承認される必要がある。このプロセスには、三つの重要な要素が伴う。一つ目は「本人確認(Identity)」で、トランザクションは特定のウォレットから発信されたことを、暗号学的な署名によって証明する必要がある。これには、ウォレットの「秘密鍵」が不可欠だ。二つ目は「費用(Cost)」、通称「ガス代」である。トランザクションの実行にはネットワークのリソースが消費されるため、その対価としてネットワークのネイティブ通貨(イーサリアムならETH、PolygonならMATICなど)を支払う必要がある。三つ目は「状態変更(State Change)」で、成功したトランザクションはブロックチェーンの状態を恒久的に変化させる。これらの理由から、トランザクションは単なるデータ照会とは異なり、秘密鍵による署名とガス代の支払いが必要な、より複雑な操作となる。

コード上で秘密鍵を安全に管理することは非常に重要だ。web3.pyでは、秘密鍵を直接コード中に記述するのではなく、「アカウントオブジェクト」という形でカプセル化して扱う。これにより、秘密鍵が外部に漏れるリスクを低減しつつ、ウォレットの公開アドレスへのアクセスやトランザクションの署名といった操作を行える。また、Pythonの型ヒント(Type Annotations)を適切に利用することで、コードの可読性が向上し、開発効率も上がる。例えば、account: LocalAccountのように型を明示すれば、開発環境がそのオブジェクトが持つメソッドやプロパティを自動的に補完してくれるため、間違いが少なくなり、開発がスムーズに進む。これはプロフェッショナルなコードを書く上で欠かせない習慣だ。

より複雑なアプリケーションを開発する際には、単一のスクリプトでは限界がある。複数のウォレットを管理したり、異なるブロックチェーンネットワークとやり取りしたり、あるいは特定の目的のためにリクエストをプロキシ経由でルーティングしたりする場合、オブジェクト指向プログラミングの概念が非常に役立つ。「Clientクラス」を導入することで、一つのウォレットに関連するすべてのロジック(秘密鍵、ネットワーク接続、トランザクション送信メソッドなど)をまとめて管理できるようになる。これにより、コードの保守性が高まり、将来的な拡張も容易になる。例えば、複数のウォレットを持つ場合でも、それぞれにClientオブジェクトを作成するだけでよく、非常にスケーラブルなシステムを構築できる。

トランザクションの送信は、トランザクションを構築し、署名し、ネットワークに送り、そして最終的な確認を待つという、複数のステップからなる。トランザクションは、いくつかの重要なパラメータを持つ辞書のようなものだ。chainIdはネットワーク固有の識別子で、異なるチェーンでのリプレイ攻撃を防ぐ。nonceはアカウントから送信されるトランザクションの連番であり、一つ前のトランザクションのnonceより常に一つ大きい値でなければならない。これにより、トランザクションが正しい順序で処理され、重複が防止される。fromはトランザクションの発信元ウォレットアドレス、toは送信先のアドレス(別のウォレットか、スマートコントラクト)だ。dataフィールドは、ネイティブ通貨の送金であれば空だが、スマートコントラクトの特定の関数を呼び出す際には、その関数とその引数をエンコードしたデータが格納される。valueは、トランザクションとともに送るネットワークのネイティブ通貨の量を示す。例えば、NFTのミントやETHの送金に使うが、ERC-20トークンの送金にはdataフィールド内の関数呼び出しを利用する。

ガス代の支払いモデルも進化しており、多くのモダンなネットワークではEIP-1559というモデルが採用されている。これはガス代を二つの部分に分けて考える。一つはmaxPriorityFeePerGasで、これはトランザクションを迅速にブロックに含めてもらうために、バリデータ(マイナー)に支払う「チップ」だ。もう一つはmaxFeePerGasで、これはトランザクションごとに変動するbaseFee(ネットワークの混雑度によって決定される)と、先に述べたチップを合わせた、ユーザーが「これ以上は払わない」と宣言する最大料金だ。このモデルは、従来の単純なgasPrice方式よりも、ガス料金の予測可能性を高めることを目的としている。トランザクションを送信する際には、これらのガス料金パラメータを設定し、さらにトランザクションが消費するガス量を事前に「見積もり」、少しのバッファを追加することが一般的だ。

すべてのパラメータが設定されたら、秘密鍵を使ってトランザクションに署名し、署名済みの「生のトランザクション」をネットワークにブロードキャストする。この時、すぐに「トランザクションハッシュ」が返されるが、これはトランザクションがネットワークに受け入れられたという「レシート」のようなものであり、まだブロックに取り込まれ、成功したという保証ではない。トランザクションが実際にブロックに含められ、その結果が確定するまでには時間がかかるため、wait_for_transaction_receiptのようなメソッドを使って、ネットワークにトランザクションの最終的なレシートが発行されるのを待つ必要がある。このレシートにはstatusフィールドがあり、値が1なら成功、0なら失敗を示す。この確認を行うことで、トランザクションの結果を確実に把握し、エラー発生時に適切に対処できる。

具体的な例として、分散型取引所(DEX)がユーザーのERC-20トークン(例えばUSDT)を操作できるように「承認(approve)」するトランザクションを考えてみよう。この操作は、トークンをスワップする前の一般的なステップだ。まず、承認したいトークン(USDT)と、承認先(DEXのルーターコントラクト)のアドレス、そしてトークンコントラクトのABI(Application Binary Interface)が必要になる。ABIは、コントラクトが提供する関数やイベントの定義を記述したJSON形式のファイルだ。これらを使ってClientオブジェクトとトークンのコントラクトオブジェクトを初期化する。トランザクションを送信する前に、現在の承認額を照会する「事前チェック」を行うのがベストプラクティスだ。もし現在の承認額が十分であれば、無駄なトランザクションを送る必要はない。承認が必要な場合、approve関数とその引数をエンコードしてdataフィールドに格納し、Clientsend_transactionメソッドで送信する。この際、ネイティブ通貨を送るわけではないのでvalueは0にする。その後、verify_transactionメソッドで結果が成功したことを確認すれば、一連のプロセスは完了となる。

ブロックチェーンの読み取りから書き込みへ移行することは、大きな一歩であり、EVMの仕組みに対する深い理解を必要とする。しかし、Clientクラスのようなオブジェクト指向のアプローチを採用し、トランザクションの各パラメータの意味を深く理解し、EIP-1559のようなモダンなガスモデルを活用し、そして常にトランザクションの最終的な結果を検証することで、スケーラブルで保守性の高い、プロフェッショナルな分散型アプリケーションを構築するための強固な基盤を築ける。受動的な観察者から能動的な参加者へと変わり、ブロックチェーンの世界で自ら変化を生み出す力を手に入れることができるだろう。

関連コンテンツ

関連IT用語

関連ITニュース