最近、私はビットコインの魔法の世界に魅了されました 。 知識への渇望はとどまるところを知らず、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でのビットコインの操作に関する一連の記事の次の部分はこちらです。