メインコンテンツへスキップ

Pythonデベロッパーのためのイーサリアム入門、パート1

Python
web3.py
初級
Marc Garreau
2020年9月8日
21 分の読書

これまで耳にしてきたイーサリアムの世界へ飛び込む準備はできましたか? この投稿では、ブロックチェーンの基礎について簡単に説明し、次に、シミュレートされたイーサリアムノードとの対話(ブロックデータの読み取り、アカウント残高の確認、トランザクションの送信)の方法について説明します。 その過程で、アプリを構築する従来の方法とこの新しい分散型パラダイムの違いに焦点を当てます。

(ソフトな)前提条件

この投稿は、幅広いデベロッパーに参照していただきたいと考えています。 Pythonツールを使用しますが、これらは概念を伝える手段にすぎませんので、Pythonデベロッパーでなくても問題ありません。 しかし、ここでは皆さんがすでに知っていることを前提に話を進めますので、すぐにイーサリアムに特化した部分の説明に移ります。

前提知識:

  • ターミナルを操作できる、
  • Pythonで数行のコードを書いたことがある、
  • お使いのマシンにPythonバージョン3.6以降がインストールされていること(仮想環境 (opens in a new tab)の使用を強く推奨します)、そして
  • Pythonのパッケージインストーラーであるpipを使用したことがある。 もしこれらのいずれかに当てはまらない場合や、この記事のコードを再現する予定がない場合でも、問題なく読み進めることができるでしょう。

ブロックチェーンの概要

イーサリアムを説明する方法はたくさんありますが、その中心となるのはブロックチェーンです。 ブロックチェーンは一連のブロックで構成されています。まずはその説明から始めましょう。 簡単に言うと、イーサリアムブロックチェーンの各ブロックは、いくつかのメタデータとトランザクションのリストにすぎません。 JSON形式では、次のようになります。

1{
2 "number": 1234567,
3 "hash": "0xabc123...",
4 "parentHash": "0xdef456...",
5 ...,
6 "transactions": [...]
7}

ブロックは、その前のブロックへの参照を持ちます。parentHashは、単に前のブロックのハッシュです。

注: イーサリアムはハッシュ関数を定期的に使用して、固定サイズの値(「ハッシュ」)を生成します。 ハッシュはイーサリアムで重要な役割を果たしますが、今のところはユニークIDとして考えて差し支えありません。

ブロックチェーンと各ブロック内のデータを描いた図

ブロックチェーンは本質的にリンクリストであり、各ブロックは前のブロックへの参照を持ちます。

このデータ構造は新しいものではありませんが、ネットワークを統制するルール(ピアツーピアプロトコル)は新しいものです。 中央機関は存在しません。ピアのネットワークは、ネットワークを維持するために協調しなければならず、次のブロックにどのトランザクションを含めるかを決定するために競争しなければなりません。 ですから、友人に送金したいときは、そのトランザクションをネットワークにブロードキャストし、それが次のブロックに含まれるのを待つ必要があります。

ブロックチェーンがあるユーザーから別のユーザーへのお金が本当に送金されたことを検証する唯一の方法は、そのブロックチェーンに固有の(つまり、そのブロックチェーンによって作成され、管理される)通貨を使用することです。 イーサリアムでは、この通貨はイーサと呼ばれ、イーサリアムブロックチェーンにはアカウント残高の唯一の公式記録が含まれています。

新しいパラダイム

この新しい分散型技術スタックは、新しいデベロッパーツールを生み出しました。 このようなツールは多くのプログラミング言語に存在しますが、今回はPythonを例にとって説明します。 繰り返しになりますが、Pythonがあなたの選んだ言語でなくても、ついていくのにそれほど問題はないはずです。

イーサリアムと対話したいPythonデベロッパーは、Web3.py (opens in a new tab)に手を伸ばすことになるでしょう。 Web3.pyは、イーサリアムノードへの接続、およびノードとのデータの送受信を大幅に簡素化するライブラリです。

注: 「イーサリアムノード」と「イーサリアムクライアント」は同じ意味で使用されます。 いずれの場合も、イーサリアムネットワークの参加者が実行するソフトウェアを指します。 このソフトウェアは、ブロックデータを読み取り、新しいブロックがチェーンに追加されたときに更新情報を受信し、新しいトランザクションをブロードキャストするなどの機能を持ちます。 技術的には、クライアントはソフトウェアであり、ノードはソフトウェアを実行しているコンピュータです。

イーサリアムクライアントは、IPC (opens in a new tab)、HTTP、またはWebsocketsで到達可能に設定できるため、Web3.pyはこの設定を反映させる必要があります。 Web3.pyはこれらの接続オプションをプロバイダーと呼びます。 Web3.pyインスタンスをノードにリンクさせるには、3つのプロバイダーの中から1つを選択します。

web3.pyがIPCを使用してアプリケーションをイーサリアムノードに接続する方法を示す図

この図のIPCのように、イーサリアムノードとWeb3.pyが同じプロトコルで通信するように設定します。

Web3.pyが正しく設定されると、ブロックチェーンとの対話を開始できます。 今後のプレビューとして、Web3.pyの使用例をいくつか紹介します。

1# ブロックデータを読み込む:
2w3.eth.get_block('latest')
3
4# トランザクションを送信する:
5w3.eth.send_transaction({'from': ..., 'to': ..., 'value': ...})

インストール

このウォークスルーでは、Pythonインタプリタ内でのみ作業します。 ディレクトリ、ファイル、クラス、関数は作成しません。

注: 以下の例では、$で始まるコマンドはターミナルで実行するためのものです。 ($は入力しないでください。行の始まりを示しているだけです。)

まず、探索のためのユーザーフレンドリーな環境として、IPython (opens in a new tab)をインストールします。 IPythonは、タブ補完などの機能を提供しており、Web3.pyで何が可能かを確認するのが非常に簡単になります。

pip install ipython

Web3.pyはweb3という名前で公開されています。 次のようにインストールします。

pip install web3

もう一つ、後でブロックチェーンをシミュレートしますが、それにはさらにいくつかの依存関係が必要です。 それらは次のようにインストールできます。

pip install 'web3[tester]'

これで準備完了です!

注:web3[tester]パッケージは Python 3.10.xx まで動作します。

サンドボックスの起動

ターミナルでipythonを実行して、新しいPython環境を開きます。 これはpythonの実行に似ていますが、より多くの追加機能が付属しています。

ipython

これにより、実行中のPythonとIPythonのバージョンに関する情報が出力され、入力を待つプロンプトが表示されます。

1In [1]:

現在、対話型のPythonシェルが表示されています。 基本的には、自由に試せるサンドボックスです。 ここまで来たら、Web3.pyをインポートしましょう。

1In [1]: from web3 import Web3

Web3モジュールの紹介

イーサリアムへのゲートウェイであることに加えて、Web3 (opens in a new tab)モジュールはいくつかの便利な機能を提供します。 いくつか見てみましょう。

イーサリアムアプリケーションでは、通貨の単位を変換する必要がよくあります。 Web3モジュールは、まさにこのためにいくつかのヘルパーメソッドを提供しています:from_wei (opens in a new tab)to_wei (opens in a new tab)です。

注:コンピュータは小数の計算が苦手なことで有名です。 これを回避するために、デベロッパーはドル額をセント単位で保存することがよくあります。 例えば、$5.99の価格のアイテムは、データベースに599として保存されることがあります。

イーサでの取引を処理する際にも同様のパターンが使われます。 しかし、小数点以下2桁ではなく、イーサは18桁です! イーサの最小単位はweiと呼ばれ、それがトランザクション送信時に指定される値です。

1 ether = 1000000000000000000 wei

1 wei = 0.000000000000000001 ether

いくつかの値をweiとの間で変換してみましょう。 イーサとweiの間には多くの単位に名前がある (opens in a new tab)ことに注意してください。 その中でよく知られているものの一つがgweiです。トランザクション手数料がgweiで表されることが多いためです。

1In [2]: Web3.to_wei(1, 'ether')
2Out[2]: 1000000000000000000
3
4In [3]: Web3.from_wei(500000000, 'gwei')
5Out[3]: Decimal('0.5')

Web3モジュールの他のユーティリティメソッドには、データ形式コンバータ(例:toHex (opens in a new tab))、アドレスヘルパー(例:isAddress (opens in a new tab))、ハッシュ関数(例:keccak (opens in a new tab))などがあります。 これらの多くは、このシリーズの後半で取り上げます。 利用可能なすべてのメソッドとプロパティを表示するには、IPythonのオートコンプリート機能を利用してWeb3.と入力し、 ピリオドの後にTabキーを2回押します。

チェーンと対話する

便利なメソッドも素晴らしいですが、ブロックチェーンに移りましょう。 次のステップは、イーサリアムノードと通信するようにWeb3.pyを設定することです。 ここでは、IPC、HTTP、またはWebsocketプロバイダーを使用するオプションがあります。

この道筋はたどりませんが、HTTPプロバイダーを使用した完全なワークフローの例は次のようになります。

  • Geth (opens in a new tab)などのイーサリアムノードをダウンロードします。
  • 一つのターミナルウィンドウでGethを開始し、ネットワークが同期するのを待ちます。 デフォルトのHTTPポートは8545ですが、設定可能です。
  • localhost:8545で、Web3.pyにHTTP経由でノードに接続するように指示します。 w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))
  • w3インスタンスを使用してノードと対話します。

これは「実際の」方法の一つですが、同期プロセスには数時間かかり、開発環境が欲しいだけの場合は不要です。 Web3.pyはこの目的のために4番目のプロバイダー、EthereumTesterProviderを公開しています。 このテスタープロバイダーは、緩和された権限と自由に使える偽の通貨を持つシミュレートされたイーサリアムノードにリンクします。

EthereumTesterProviderがweb3.pyアプリケーションをシミュレートされたイーサリアムノードにリンクする図

EthereumTesterProviderはシミュレートされたノードに接続し、迅速な開発環境に便利です。

そのシミュレートされたノードはeth-tester (opens in a new tab)と呼ばれ、pip install web3[tester]コマンドの一部としてインストールしました。 Web3.pyをこのテスタープロバイダーを使用するように設定するのは、次のように簡単です。

1In [4]: w3 = Web3(Web3.EthereumTesterProvider())

これでチェーンをサーフィンする準備ができました! そんなことを言う人はいませんが。 私が今作った言葉です。 簡単なツアーを始めましょう。

クイックツアー

まず最初に、サニティチェックです。

1In [5]: w3.is_connected()
2Out[5]: True

テスタープロバイダーを使用しているので、これはあまり価値のあるテストではありませんが、もし失敗した場合、w3変数をインスタンス化する際に何かを間違って入力した可能性があります。 内側の括弧、つまりWeb3.EthereumTesterProvider()を含めたか再確認してください。

ツアーの立ち寄り先#1:アカウント

便宜上、テスタープロバイダーはいくつかのアカウントを作成し、テスト用のイーサをプリロードしています。

まず、それらのアカウントのリストを見てみましょう。

1In [6]: w3.eth.accounts
2Out[6]: ['0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',
3 '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',
4 '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', ...]

このコマンドを実行すると、0xで始まる10個の文字列のリストが表示されるはずです。 それぞれが公開アドレスであり、ある意味では当座預金口座の口座番号に似ています。 あなたにイーサを送りたい人にこのアドレスを提供します。

前述のように、テスタープロバイダーはこれらの各アカウントにテスト用のイーサをプリロードしています。 最初のアカウントにいくら入っているか見てみましょう。

1In [7]: w3.eth.get_balance(w3.eth.accounts[0])
2Out[7]: 1000000000000000000000000

たくさんのゼロですね! 偽の銀行に笑いながら行く前に、先ほどの通貨単位に関する教訓を思い出してください。 イーサの値は最小単位であるweiで表されます。 それをイーサに変換します。

1In [8]: w3.from_wei(1000000000000000000000000, 'ether')
2Out[8]: Decimal('1000000')

100万テストイーサ――悪くないですね。

ツアーの立ち寄り先#2:ブロックデータ

このシミュレートされたブロックチェーンの状態を覗いてみましょう。

1In [9]: w3.eth.get_block('latest')
2Out[9]: AttributeDict({
3 'number': 0,
4 'hash': HexBytes('0x9469878...'),
5 'parentHash': HexBytes('0x0000000...'),
6 ...
7 'transactions': []
8})

ブロックに関して多くの情報が返されますが、ここで指摘すべき点はいくつかあります。

  • ブロック番号はゼロです――テスタープロバイダーをいつ設定したかに関係なく。 12秒ごとに新しいブロックを追加する実際のイーサリアムネットワークとは異なり、このシミュレーションは何か仕事を与えるまで待ちます。
  • transactionsは空のリストです。同じ理由で、私たちはまだ何もしていません。 この最初のブロックは、チェーンを開始するための空のブロックです。
  • parentHashがただの空のバイトの束であることに注意してください。 これは、チェーンの最初のブロック、ジェネシスブロックとしても知られていることを示しています。

ツアーの立ち寄り先#3:トランザクション

保留中のトランザクションがあるまでブロックゼロで止まっているので、一つ与えてみましょう。 あるアカウントから別のアカウントに、数テストイーサを送金します。

1In [10]: tx_hash = w3.eth.send_transaction({
2 'from': w3.eth.accounts[0],
3 'to': w3.eth.accounts[1],
4 'value': w3.to_wei(3, 'ether'),
5 'gas': 21000
6})

これは通常、トランザクションが新しいブロックに含まれるのを数秒待つ時点です。 完全なプロセスは次のようになります。

  1. トランザクションを送信し、トランザクションハッシュを保持します。 トランザクションを含むブロックが作成されブロードキャストされるまで、トランザクションは「保留中」です。 tx_hash = w3.eth.send_transaction({ … })
  2. トランザクションがブロックに含まれるのを待ちます: w3.eth.wait_for_transaction_receipt(tx_hash)
  3. アプリケーションロジックを続行します。 成功したトランザクションを表示するには: w3.eth.get_transaction(tx_hash)

私たちのシミュレートされた環境は、トランザクションを新しいブロックに即座に追加するため、すぐにトランザクションを表示できます。

1In [11]: w3.eth.get_transaction(tx_hash)
2Out[11]: AttributeDict({
3 'hash': HexBytes('0x15e9fb95dc39...'),
4 'blockNumber': 1,
5 'transactionIndex': 0,
6 'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',
7 'to': '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',
8 'value': 3000000000000000000,
9 ...
10})
すべて表示

ここには見慣れた詳細がいくつかあります。fromtovalueフィールドは、send_transaction呼び出しの入力と一致するはずです。 もう一つの安心できる点は、このトランザクションがブロック番号1内の最初のトランザクション('transactionIndex': 0)として含まれていることです。

また、関与した2つのアカウントの残高を確認することで、このトランザクションの成功を簡単に確認できます。 3イーサが一方から他方へ移動したはずです。

1In [12]: w3.eth.get_balance(w3.eth.accounts[0])
2Out[12]: 999996999979000000000000
3
4In [13]: w3.eth.get_balance(w3.eth.accounts[1])
5Out[13]: 1000003000000000000000000

後者は良さそうですね! 残高は1,000,000イーサから1,000,003イーサに増えました。 しかし、最初のアカウントはどうなったのでしょうか? 3イーサよりわずかに多く失われたようです。 残念ながら、人生に無料のものはありません。イーサリアムのパブリックネットワークを使用するには、その支援的な役割に対してピアに補償する必要があります。 トランザクションを送信したアカウントから少額のトランザクション手数料が差し引かれました。この手数料は、消費されたガスの量(ETH転送の場合は21000単位のガス)に、ネットワークのアクティビティに応じて変動するベースフィーと、トランザクションをブロックに含めるバリデータへのチップを加えたものを掛けたものです。

ガスについての詳細

注:パブリックネットワークでは、トランザクション手数料はネットワークの需要とトランザクションをどれだけ早く処理したいかに基づいて変動します。 手数料がどのように計算されるかの内訳に興味がある場合は、トランザクションがどのようにブロックに含まれるかについての私の以前の投稿を参照してください。

一息つきましょう

しばらくこれに取り組んできたので、一休みするには良い場所のようです。 ウサギの穴はまだ続きます。このシリーズのパート2で探求を続けます。 今後のコンセプト:実際のノードへの接続、スマートコントラクト、トークン。 フォローアップの質問はありますか? お知らせください! あなたのフィードバックが、ここからどこへ向かうかに影響します。 Twitter (opens in a new tab)経由でリクエストを歓迎します。

最終更新: 2025年2月6日

このチュートリアルは役に立ちましたか?