Elixirでビットコインを使用します

最近、私はビットコインの魔法の世界魅了されました 。 知識への渇望はとどまるところを知らず、Andreas Antonopoulos による素晴らしい本「Mastering Bitcoin」とビットコイン開発への完全な没入は、それを癒すのに役立ちました。 この本はビットコインの技術的基礎を詳細にカバーしていますが、練習のような新しいビジネスを学ぶのに何も助けになりません。







私の意見では、完全なビットコインノードを管理し、JSON-RPCインターフェースを介し通信するためのElixirのシンプルなアプリケーションは、素晴らしい「Hello、World!」です。 行こう!







完全なノードを取得する場所



完全なBitcoin Coreノードとの接続を確立するには、まずどこかで接続する必要があります。 JSON-RPCインターフェースが開いているパブリックノードは指で数えることができるため、ノードをローカル起動するだけで十分です。







bitcoind



bitcoind



し、 bitcoin.config



ファイルで構成します。







 rpcuser=<username> rpcpassword=<password>
      
      





決定された値<username>



および<password>



は、ビットコインノードにリクエストを送信する際の認証に使用されます。







セットアップが完了したら、フルノードを開始します。







 bitcoind -conf=<path to bitcoin.config> -daemon
      
      





起動すると、フルノードデーモンはピアへの接続を開始し、ブロック単位でトランザクションをロードして検証します。







すべてが正常に機能することを確認します。







 bitcoin-cli getinfo
      
      





このコマンドは、ノードのバージョンや受信および検証済みブロックの数など、ノードに関する基本情報を返します。 ブロックチェーン全体のダウンロードと検証には数日かかる場合がありますが、現時点では、プロジェクトの作業を継続します。







JSON-RPCインターフェース



BitcoinノードはJSON-RPCインターフェースを介して機能します。これは、ブロックチェーンに関する情報を抽出し、ノードと対話するために使用できます。







ノードに関する情報を取得するために以前に使用したbitcoin-cli



がJSON-RPC APIの上で機能することは興味深いです。 ノードで可能なすべてのRPCコマンドのリストは、 bitcoin-cli help



呼び出すか、 Bitcoin Wikiを参照することで表示できます。







JSON-RPCプロトコルは、HTTPサーバーを介して着信コマンドを受信します。つまり、 bitcoin-cli



を使用せずにこれらのRPCコマンドを自分で作成できます。







たとえば、 getinfo



getinfoを getinfo



getinfo



ます







 curl --data-binary '{"jsonrpc":"1.0","method":"getinfo","params":[]}' \ http://<user>:<pass>@localhost:8332/
      
      





同様に、Elixir!など、HTTPクライアントを使用するプログラミング環境でこのようなコマンドを実行できます。







Elixirアプリケーション開発



完全なBitcoinノードと対話するための戦略を熟考して、Elixirアプリケーションを取り上げます。







新しいプロジェクトを作成し、 mix.exs



を更新して、JSONオブジェクトの暗号化と復号化に必要なpoison



ライブラリを追加しましょうhttpoison



は、Elixirの最高のHTTPクライアントの1つです。







 defp deps do [ {:httpoison, "~> 0.13"}, {:poison, "~> 3.1"} ] end
      
      





コード生成を担当する部分が完了したので、ビットコインノードとの対話の実装に移りましょう。







HelloBitcoin



モジュールの操作を始めましょう。まず、 getinfo



関数のスタブをgetinfo



ます。







 defmodule HelloBitcoin do def getinfo do raise "TODO: Implement getinfo" end end
      
      





簡単にするために、 iex -S mix



介してこのモジュールとやり取りします。 次のステップに進む前に、すべてが正しく機能することを確認しましょう。







HelloBitcoin.getinfo



スタブを呼び出すと、ランタイム例外が発生します。







 iex(1)> HelloBitcoin.getinfo HelloBitcoin.getinfo ** (RuntimeError) TODO: Implement getinfo (hello_bitcoin) lib/hello_bitcoin.ex:4: HelloBitcoin.getinfo/0
      
      





素晴らしい。 エラー。 あるべきです。







GetInfo



構築する



getinfo関数getinfo



コンテンツを入力getinfo



ます。







繰り返しますPOST



メソッドを使用してHTTPリクエストをBitcoinノードのHTTPサーバーに送信し(通常はhttp://localhost:8332



リッスンしhttp://localhost:8332



)、 GetInfo



コマンドと必要なパラメーターを含むJSONオブジェクトを渡す必要があります。







httpoison



は、次の2つの方法でこのタスクに対処することが判明しました。







 def getinfo do with url <- Application.get_env(:hello_bitcoin, :bitcoin_url), command <- %{jsonrpc: "1.0", method: "getinfo", params: []}, body <- Poison.encode!(command), headers <- [{"Content-Type", "application/json"}] do HTTPoison.post!(url, body, headers) end end
      
      





最初に、アプリケーション構成のbitcoin_url



キーからurl



を取得します。 アドレスはconfig/config.exs



あり、ローカルノードを指している必要があります。







 config :hello_bitcoin, bitcoin_url: "http://<user>:<password>@localhost:8332"
      
      





次に、JSON-RPCコマンドを表す辞書を作成します。 この場合、 method



フィールドに"getinfo"



と書き込み、 params



フィールドは空のままにします。 そしてPoison.encode!



を使用してコマンドをJSON形式に変換して、リクエスト本文をPoison.encode!



Poison.encode!









HelloBitcoin.getinfo



呼び出しは、ステータスコード200



のbitcoinノードから正常な応答と、JSON形式のgetinfo



結果をgetinfo



ます。







 %HTTPoison.Response{ body: "{\"result\":{\"version\":140200,\"protocolversion\":70015,\"walletversion\":130000,\"balance\":0.00000000,\"blocks\":482864,\"timeoffset\":-1,\"connections\":8,\"proxy\":\"\",\"difficulty\":888171856257.3206,\"testnet\":false,\"keypoololdest\":1503512537,\"keypoolsize\":100,\"paytxfee\":0.00000000,\"relayfee\":0.00001000,\"errors\":\"\"},\"error\":null,\"id\":null}\n", headers: [{"Content-Type", "application/json"}, {"Date", "Thu, 31 Aug 2017 21:27:02 GMT"}, {"Content-Length", "328"}], request_url: "http://localhost:8332", status_code: 200 }
      
      





素晴らしい。







本文の結果のJSONテキストを解読し、結果を取得します。







 HTTPoison.post!(url, body) |> Map.get(:body) |> Poison.decode!
      
      





これで、 HelloBitcoin.getinfo



から受信したHelloBitcoin.getinfo



呼び出しの結果がより便利な形式で表示されます。







 %{"error" => nil, "id" => nil, "result" => %{"balance" => 0.0, "blocks" => 483001, "connections" => 8, "difficulty" => 888171856257.3206, "errors" => "", "keypoololdest" => 1503512537, "keypoolsize" => 100, "paytxfee" => 0.0, "protocolversion" => 70015, "proxy" => "", "relayfee" => 1.0e-5, "testnet" => false, "timeoffset" => -1, "version" => 140200, "walletversion" => 130000}}
      
      





必要なデータ( "result"



)は、リクエスト自体に関するメタデータを含む辞書にラップされている"result"



注意してください。 このメタデータには、エラーの可能性がある文字列とリクエスト識別子が含まれています。







getinfo



関数を書き換えて、エラー処理を含め、エラーのないクエリ実行の場合に実際のデータを返すようにします。







 with url <- Application.get_env(:hello_bitcoin, :bitcoin_url), command <- %{jsonrpc: "1.0", method: "getinfo", params: []}, {:ok, body} <- Poison.encode(command), {:ok, response} <- HTTPoison.post(url, body), {:ok, metadata} <- Poison.decode(response.body), %{"error" => nil, "result" => result} <- metadata do result else %{"error" => reason} -> {:error, reason} error -> error end
      
      





エラーがなければ、 getinfo



関数はRPC呼び出しの結果を含むタプル{:ok, result}



を返します。そうでない場合は、エラーの説明を含むタプル{:error, reason}



を取得します。







チームの概要



同様に、他のブロックチェーンRPCコマンド、たとえばgetblockhash



実装できます。







 def getblockhash(index) do with url <- Application.get_env(:hello_bitcoin, :bitcoin_url), command <- %{jsonrpc: "1.0", method: "getblockhash", params: [index]}, {:ok, body} <- Poison.encode(command), {:ok, response} <- HTTPoison.post(url, body), {:ok, metadata} <- Poison.decode(response.body), %{"error" => nil, "result" => result} <- metadata do {:ok, result} else %{"error" => reason} -> {:error, reason} error -> error end end
      
      





インデックス0でgetblockhash



を呼び出すgetblockhash



、チェーンの最初のブロックを取得します。







 HelloBitcoin.getblockhash(0) {:ok, "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"}
      
      





getblockhash



関数は正しく機能し、 getinfo



関数とほとんど同じです。







コードの重複を避けるために、新しい補助関数bitcoin_rpc



共通の機能部分を強調します。







 defp bitcoin_rpc(method, params \\ []) do with url <- Application.get_env(:hello_bitcoin, :bitcoin_url), command <- %{jsonrpc: "1.0", method: method, params: params}, {:ok, body} <- Poison.encode(command), {:ok, response} <- HTTPoison.post(url, body), {:ok, metadata} <- Poison.decode(response.body), %{"error" => nil, "result" => result} <- metadata do {:ok, result} else %{"error" => reason} -> {:error, reason} error -> error end end
      
      





次に、 getblockhash



関数に従ってgetinfo



およびgetblockhash



関数を再定義します。







 def getinfo, do: bitcoin_rpc("getinfo") def getblockhash(index), do: bitcoin_rpc("getblockhash", [index])
      
      





bitcoin_rpc



はビットコイン用の本格的なRPCインターフェイスであり、任意のRPCコマンドを簡単に実行できることがbitcoin_rpc



ます。







上記のすべてをマシンに実装することに興味がある場合は、プロジェクトのソースコードがGitHubにあります







おわりに



さて、比較的単純なアイデアを説明するかなり長い記事が終わりました。 完全なBitcoinノードは、JSON-RPCインターフェイスを提供します。これには、任意の言語(Elixirなど)またはスタックを使用してアクセスできます。 ビットコインの開発は驚くほど面白く、さらに掘り下げてみるのも面白いです。







Elixirでのビットコインの操作に関する一連の記事の次の部分はこちらです。








All Articles