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

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

pythonweb3.py
初級
✍️Marc Garreau
📚Snake charmers(opens in a new tab)
📆 2020年9月8日
⏱️22 分の読書 minute read

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

前提条件(ソフト)

この投稿は、幅広いデベロッパーに参照していただきたいと考えています。 Python ツールを使用しますが、これらは概念を伝える手段にすぎませんので、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は、単に前のブロックのハッシュ値です。

注: イーサリアムはハッシュ関数(opens in a new tab)を定期的に使用して、固定サイズの値(ハッシュ)を生成します。 イーサリアムではハッシュ値が重要な役割を果たしますが、今のところは固有のIDと考えておくとよいでしょう。

ブロックチェーンと各ブロック内のデータを表す図

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

このデータ構造は目新しいものではありませんが、ネットワークを管理するルール(つまり、ピアツーピアプロトコル)は目新しいものです。 中央集権型ではないため、ピアのネットワークは連携してネットワークを維持する必要がありますが、次のブロックに含めるトランザクションを決定する際には競い合うことになります。 例えば、友人に送金する場合、トランザクションをネットワークにブロードキャストして、そのトランザクションが次のブロックに含まれるのを待つ必要があります。

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

新しいパラダイム

この新しい分散型技術スタックは、新しいデベロッパーツールを生み出しました。 このようなツールは多くのプログラミング言語に存在しますが、今回は Python を例にとって説明します。 繰り返しになりますが、Python 以外の言語をご使用の場合でも、内容を理解するのはそれほど難しいことではありません。

イーサリアムと対話する必要がある Python デベロッパーは、Web3.py(opens in a new tab)にアクセスしてください。 Web3.py は、イーサリアムノードへの接続と、そのノードとのデータの送受信を簡単に行えるようにするライブラリです。

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

イーサリアムクライアント は、プロセス間通信(IPC)(opens in a new tab)、HTTP、または WebSocket で接続するように設定できるため、Web3.py でも同じ設定にする必要があります。 Web3.py は、これらの接続オプションをプロバイダーとして参照します。 Web3.py インスタンスをノードに接続するために、3 つのプロバイダーのいずれかを選択する必要があります。

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

同じプロトコル(この図ではプロセス間通信(IPC))を介して通信するようにイーサリアムノードと Web3.py を設定します。

Web3.py が正しく設定できたら、ブロックチェーンとの対話を開始できます。 参考までに、Web3.py の使用例をいくつか示します。

1# read block data:
2w3.eth.get_block('latest')
3
4# send a transaction:
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

あと 1 つ操作が必要です。後でブロックチェーンのシミュレーションを行いますが、それにはさらに数個の依存関係が必要となります。 それらは以下のコマンドでインストールできます。

$ pip install 'web3[tester]'

これで準備完了です。

サンドボックスの起動

ターミナルで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 のモジュールには、この変換のためだけのfromWei(opens in a new tab)toWei(opens in a new tab)のようなヘルパーメソッドがあります。

注: コンピュータは小数の計算処理が苦手です。 小数点以下を含む計算を避けるため、デベロッパーはしばしばドルをセントに換算して格納します。 例えば、価格が $5.99の商品は、599としてデータベースに保存されます。イーサ(ETH)でトランザクションを処理する場合も、同様のパターンが使用されます。 ただし、ETH の小数点は 2 桁ではなく、18 桁です! ETH の最小単位はweiと呼ばれます。これが、トランザクションを送信するときに指定される値です。

1 ETH = 1000000000000000000 wei

1 wei = 0.000000000000000001 ETH

好きな数字で wei と ETH(ether)を変換してみてください。 なお、ETH と wei の間には、さまざまな単位の名称があります(opens in a new tab)。 その中でよく使われているのは gweiです。これは基本的に手数料を意味します。

1In [2]: Web3.toWei(1, 'ether')
2Out[2]: 1000000000000000000
3
4In [3]: Web3.fromWei(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))が挙げられます。 これらについては、この連載の後半で取り上げます。 利用可能なすべてのメソッドとプロパティを表示するには、Web3.と入力し、 ピリオドの後でタブキーを 2 回押して IPython の自動補完機能を利用してください。

チェーンとの通信

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

HTTP プロバイダーを使用した場合の完全なワークフローの例としては、次のようなものがあります(ここでは、この手順は実行しません)。

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

これは「実際に行われている」方法ですが、同期プロセスには時間がかかるため、開発環境のみが必要な場合は不要です。 Web3.py は、開発環境のみが必要なデベロッパー向けに第 4 のプロバイダーとしてEthereumTesterProviderを提供しています。 このテストプロバイダーは、制約の少ない権限が適用され、偽の通貨でさまざまなことを試せるようになっている、シミュレートされたイーサリアムノードにつながります。

シミュレートされたイーサリアムノードにWeb3.pyアプリケーションをつなげるEthereumTesterProviderを表す図

EthereumTesterProvider はシミュレートされたノードに接続します。これは、簡単な開発環境で使用する場合に便利です。

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

1In [4]: w3 = Web3(Web3.EthereumTesterProvider())
📋 コピー

これで「チェーンサーフィン」をする準備ができました! そのような呼び方をする人はいないと思いますが、 そう呼ぶことにしました。 さあ、クイックツアーを始めましょう。

クイックツアー

最初に、正常に接続できているかサニティチェックをします。

1In [5]: w3.isConnected()
2Out[5]: True
📋 コピー

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

ツアー #1: アカウント

テスタープロバイダーでは便宜上、複数のアカウントが作成されており、テスト用の ETH が入金されています。

まず、これらのアカウントの一覧を表示しましょう。

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

このコマンドを実行すると、0xで始まる 10 個の文字列のリストが表示されます。 それぞれがパブリックアドレスであり、これらはある意味、当座預金の口座番号のようなものです。 あなた宛てに ETH を送金する人に、これらのアドレスを教えることになります。

前述のとおり、テスタープロバイダーでは、これらの各アカウントにテスト用の ETH があらかじめ入金されています。 では、最初のアカウントにいくらあるかを調べてみましょう。

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

なんとたくさんの 0 でしょうか! 満面の笑みで偽の銀行に駆け込む前に、前述した通貨の単位の説明を思い出してください。 ETH の値は、最小単位である wei で表されます。 ETH(ether)に変換すると次のようになります。

1In [8]: w3.fromWei(1000000000000000000000000, 'ether')
2Out[8]: Decimal('1000000')
📋 コピー

テスト用とはいえ 100 万 ETH です。依然として素晴らしい額です。

ツアー #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: トランザクション

保留中のトランザクションが存在するまで、ゼロのブロックで止まっているので、トランザクションを作成してみましょう。 あるアカウントから別のアカウントに、テスト用の ETH(ether)を少し送金します。

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

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

  1. トランザクションを送信し、トランザクションハッシュを保持します。 トランザクションを含むブロックが作成され、ブロードキャストされるまで、トランザクションは「保留中(pending)」になります。 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 つのアカウントの残高を確認することで、このトランザクションが成功していることを簡単に検証できます。 1 つ目のアカウントから 2 つ目のアカウントへ、3 ETH が移動しているはずです。

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
📋 コピー

2 つ目のアカウントの残高は正しいようですね! 残高が 1,000,000 ETH から 1,000,003 ETH になっています。 しかし、1 つ目のアカウントはどうなったのでしょうか? 3 ETH より少し多く減っているようです。 残念ながら、人生にはタダというものはなく、イーサリアムのパブリックネットワークを利用するには、そのサポート役であるピアに対価を支払う必要があります。 トランザクションを送信したアカウントから、少額のトランザクションフィーが差し引かれました。このフィーは、消費されたガスの量(ETH 送金では 21000 単位のガス)にベースフィーを掛けたものです。ベースフィーは、ネットワークのアクティビティに加えて、ブロック内にトランザクションを含めるバリデータに送信されるチップによって異なります。

ガスの詳細

注: パブリックネットワークにおいてトランザクションフィーは、ネットワークの需要やどれだけ迅速にトランザクションを処理する必要があるのかによって変動します。 フィー(手数料)の計算方法の内訳に興味がある場合は、ブロックに含まれるトランザクションの仕組み(opens in a new tab)に関する以前の投稿をご覧ください。

ちょっと一息

しばらく続けたので、ここで一息つきたいところです。 イーサリアムの世界はまだまだ続き、この連載の第 2 回へと探索は続きます。 今後のコンセプト: 実際のノードへの接続、スマートコントラクト、トークン。 質問はありますか? 教えてください! 皆様からのご意見は、今後の活動に反映させていきます。 Twitter(opens in a new tab)でリクエストを受け付けています。

最終編集者: @hesoponyo(opens in a new tab), Invalid DateTime

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