Pythonデベロッパーのためのイーサリアム入門、パート1
これまで耳にしてきたイーサリアムの世界へ飛び込む準備はできましたか? この投稿では、ブロックチェーンの基礎について簡単に説明し、次に、シミュレートされたイーサリアムノードと対話(ブロックデータの読み取り、アカウント残高の確認、トランザクションの送信)する方法について説明します。 その過程で、アプリを構築する従来の方法とこの新しい分散型パラダイムの違いに焦点を当てます。
前提条件(ソフト)
この投稿は、幅広いデベロッパーに参照していただきたいと考えています。 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
は、単に前のブロックのハッシュ値です。
ブロックチェーンは基本的にはリンクリストであり、各ブロックは前のブロックを参照します。
このデータ構造は目新しいものではありませんが、ネットワークを管理するルール(つまり、ピアツーピアプロトコル)は目新しいものです。 中央集権型ではないため、ピアのネットワークは連携してネットワークを維持する必要がありますが、次のブロックに含めるトランザクションを決定する際には競い合うことになります。 例えば、友人に送金する場合、トランザクションをネットワークにブロードキャストして、そのトランザクションが次のブロックに含まれるのを待つ必要があります。
ブロックチェーンにおいて、あるユーザーから別のユーザーに本当に送金されたのかを検証するための唯一の手段は、そのブロックチェーンに固有の(そのブロックチェーンで作成され管理される)通貨を使用することです。 イーサリアムでは、この通貨は「イーサ(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 つのプロバイダーのいずれかを選択する必要があります。
同じプロトコル(この図ではプロセス間通信(IPC))を介して通信するようにイーサリアムノードと Web3.py を設定します。
Web3.py が正しく設定できたら、ブロックチェーンとの対話を開始できます。 参考までに、Web3.py の使用例をいくつか示します。
1# read block data:2w3.eth.get_block('latest')34# 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)のようなヘルパーメソッドがあります。
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]: 100000000000000000034In [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を提供しています。 このテストプロバイダーは、制約の少ない権限が適用され、偽の通貨でさまざまなことを試せるようになっている、シミュレートされたイーサリアムノードにつながります。
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.accounts2Out[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': 210006})コピー
通常はここで、自分のトランザクションが新しいブロックに含まれるまで数秒間待つことになります。 全体のプロセスは次のようになります。
- トランザクションを送信し、トランザクションハッシュを保持します。 トランザクションを含むブロックが作成され、ブロードキャストされるまで、トランザクションは「保留中(pending)」になります。
tx_hash = w3.eth.send_transaction({ … })
- トランザクションがブロックに含まれるのを待ちます。
w3.eth.wait_for_transaction_receipt(tx_hash)
- アプリケーションロジックが続行されます。 成功したトランザクションを表示します。
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})すべて表示コピー
from
、to
、value
の各フィールドは、send_transaction
呼び出し時の入力と一致しなければなりません。 このトランザクションが、ブロック番号 1 の最初のトランザクション('transactionIndex': 0
)として含まれていることを確認できることも心強い点です。
さらに、関係する 2 つのアカウントの残高を確認することで、このトランザクションが成功していることを簡単に検証できます。 1 つ目のアカウントから 2 つ目のアカウントへ、3 ETH が移動しているはずです。
1In [12]: w3.eth.get_balance(w3.eth.accounts[0])2Out[12]: 99999699997900000000000034In [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 単位のガス)にベースフィーを掛けたものです。ベースフィーは、ネットワークのアクティビティに加えて、ブロック内にトランザクションを含めるバリデータに送信されるチップによって異なります。
ちょっと一息
しばらく続けたので、ここで一息つきたいところです。 イーサリアムの世界はまだまだ続き、この連載の第 2 回へと探索は続きます。 今後のコンセプト: 実際のノードへの接続、スマートコントラクト、トークン。 質問はありますか? 教えてください! 皆様からのご意見は、今後の活動に反映させていきます。 Twitter(opens in a new tab)でリクエストを受け付けています。
最終編集者: @hesoponyo(opens in a new tab), Invalid DateTime