日曜大工の暗号通貨の支払いの受け入れ

こんにちは、Habr!







時々、サードパーティのサービスを使用せずに自分のサイトでビットコインの支払いを受け入れる方法についての質問に気づきます。 それは非常に簡単ですが、落とし穴があることを心に留めておく必要があります。







この記事では、プログラミング言語に重点を置くことなく、可能な限り詳細に説明しようとします。ビットコインの支払いを受け入れる方法(および必要に応じて、ライトコイン、ダッシュ、ビットコインキャッシュ、スティープ、オニオンなど)フルノードの展開と、支払いの領収書の確認による完了。







前提条件



VPSでホストされているWebサイトがあり、これにルートアクセスできること、およびウォレットのサーバーの支払いに15ドル以上を費やすことをいとわないことが理解されています。







ウォレットのセットアップ



まず、ウォレットをホストするために別のサーバーを選択する必要があります。 なぜ別のサーバーなのですか? 別のサーバーは、メインサイトをハッキングした場合に、攻撃者がすべての資金を引き出すリスクを減らします。 まあ、ブロックチェーンを保存するには多くのディスク容量が必要であることを忘れないでください(〜150GBのディスク容量など。詳細はリンクを参照してください)。







安価なサーバーのオプションは何ですか? 私の意見では、それらの質量が最も適切です-hetzner.deまたはchipcore.comのサーバー。 たとえば、chipcore.comでは、たった990ルーブル(約17ドル)の500Gbディスク(BTCおよびさらに2、3個のブロックチェーンに十分)を使用できます。 もっと安いものを知っているなら-非常に興味深いコメントを書いてください(私だけではありません)。







ウェブサイトで暗号通貨を受け入れ、サーバーを購入する(または既存のものを使用する)ことを意識的に決定した後、ビットコインノードをインストールする必要があります。







適切なオペレーティングシステムをサーバーにインストールする必要があります。最も簡単なオプションはUbuntu 16.10です(実際、最良の選択ではありません。16.04をインストールするか、18.04まで待ってから安定するまで数か月待つことをお勧めします)。 原則として、ディスクのパーティション分割に煩わされることは意味がなく、スワップで2-4Gbを安全に使用し、残りをルートパーティション(/またはルート)に移動させることができます。







サーバーが使用可能になった後、最初に行うことは、パスワード認証を無効にし、sshキーを使用して認証を構成することです。 これを行うのは非常に簡単です。DigitalOceanからの説明があります。







サーバーの構成後、完全なウォレットノードを起動するには、いくつかのコマンドで十分です







ビットコインをインストールする



sudo apt-add-repository ppa:bitcoin/bitcoin sudo apt-get update sudo apt-get install bitcoind
      
      





ノードをインストールするのに必要なことはそれだけです。







ビットコインのセットアップ



最初のステップは、 bitcoin



ユーザーを作成することです。







 adduser bitcoin #       -  
      
      





サービスディレクトリを作成します。







 mkdir -p /etc/bitcoin chown bitcoin: /etc/bitcoin mkdir -p /run/bitcoind chown bitcoin: /run/bitcoind mkdir -p /var/lib/bitcoind chown bitcoin: /var/lib/bitcoind
      
      





これで、ささいなことが残ります-JSON RPCリクエストを受信するようにノードを正しく設定します。







最小構成は次のようになります。







 rpcuser=USERNAME rpcpassword=PASSWORD rpcbind=127.0.0.1 rpcallowip=127.0.0.1/32
      
      





/etc/bitcoin/bitcoin.conf



に配置する必要があります。 そして、正しい所有者を設定することを忘れないでください:







 chown bitcoin: /etc/bitcoin/bitcoin.conf
      
      





重要:USERNAMEとPASSWORDの使用は非推奨の方法であり、少し安全ではありません。 rpcauthを使用する方がより正確です。 リンクの例を参照してください







さらに、systemdサービスを構成してノードを起動するだけで十分です(再起動後も含む)。







これを行うには、 アドレスにあるユニットファイルをディレクトリ/etc/systemd/system/



コピーするだけです。







 wget https://raw.githubusercontent.com/bitcoin/bitcoin/master/contrib/init/bitcoind.service -O /etc/systemd/system/bitcoind.service
      
      





次に、起動して自動実行を設定します。







 systemctl daemon-reload systemctl start bitcoind systemctl enable bitcoind
      
      





これで、ノードのスレーブ可能性を確認できます。







 curl --data-binary '{"jsonrpc": "1.0", "method": "getinfo", "params": [] }' -H 'Content-Type: application/json' http://USERNAME:PASSWORD@127.0.0.1:8332/
      
      





すべて問題なければ、次のメッセージが返されます。







 {"result":{"balance":0.000000000000000,"blocks":59952,"connections":48,"proxy":"","generate":false, "genproclimit":-1,"difficulty":16.61907875185736},"error":null,"id":"curltest"}
      
      





プライマリサイトサーバーを構成する



サイトが配置されているサーバーを構成するためだけに残ります。







バックエンドでウォレットAPIを使用できるようにする最も安全で簡単な方法は、systemdサービス(またはその他のinitサービス)を介してsshトンネルを送信することです。 systemdを使用する場合、サービスの構成は可能な限り簡単です。







 [Unit] Description=SSH Tunnel BTC After=network.target [Service] Restart=always RestartSec=20 User=tunnel ExecStart=/usr/bin/ssh -NT -o ServerAliveInterval=60 -L 127.0.0.1:8332:127.0.0.1:8332 tunnel@YOUR_SERVER_IP [Install] WantedBy=multi-user.target
      
      





この構成は、パス/etc/systemd/system/sshtunnel-btc.service



配置する必要があります。







その後、サービスを自動起動し、実行します:







 systemctl enable sshtunnel-btc.service systemctl start sshtunnel-btc.service
      
      





確認するには、localhostポートをノックして、すべてが正常であることを確認します。







 curl --data-binary '{"jsonrpc": "1.0", "method": "getinfo", "params": [] }' -H 'Content-Type: application/json' http://USERNAME:PASSWORD@127.0.0.1:8332/
      
      





APIドキュメント



すべてのメソッドのリストは、 ここで最も便利に見つかります







curlを使用して呼び出すことは非常に簡単です。以前にgetinfoメソッドを使用してノードに関する情報を取得するときにリクエストの例を使用しました。







パラメーターを渡すには、配列または辞書の2つのオプションがあります。







以下に、配列とディクショナリーを介してパラメーターを渡す新しいアドレスのリクエストの例を示します。







 # array curl --data-binary '{"jsonrpc": "1.0", "method": "getnewaddress", "params": ["test"] }' -H 'Content-Type: application/json' http://USERNAME:PASSWORD@127.0.0.1:8332/ # object curl --data-binary '{"jsonrpc": "1.0", "method": "getnewaddress", "params": {"account": "test"} }' -H 'Content-Type: application/json' http://USERNAME:PASSWORD@127.0.0.1:8332/
      
      





シンプルなAPIクライアント



使用するには、必要な機能を備えたシンプルなラッパーを作成すると便利です(または、言語に合わせて既存のライブラリを使用できます)。 ルビーの例:







 class Btc class BtcError < StandardError; end SUPPORTED_METHODS = %w(get_new_address get_addresses_by_account get_info get_net_totals get_balance get_received_by_address send_to_address list_transactions get_transaction) class << self def method_missing(method_name, *args) if SUPPORTED_METHODS.include?(method_name.to_s) send_request(method_name.to_s, args.empty? ? nil : args) else super end end def respond_to_missing?(method_name, _include_private = false) SUPPORTED_METHODS.include?(method_name) || super end protected def host ENV["HOST"] || "http://username:password@127.0.0.1:8332" end private def send_request(method, params = nil) uri = URI.parse(host) request = Net::HTTP::Post.new(uri) request.basic_auth uri.user, uri.password request.body = JSON.dump( jsonrpc: "1.0", method: method.tr("_", ""), params: params ) req_options = { use_ssl: uri.scheme == "https" } response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http| http.request(request) end begin result = JSON.parse(response.body) rescue JSON::ParserError raise BtcError.new(response.body) end raise BtcError.new(result["error"].to_json) if result["error"] result["result"].is_a?(Hash) ? result["result"].deep_symbolize_keys : result["result"] end end end
      
      





その後、次の形式で便利に使用できます。







 # run with HOST env variable (HOST=http://username:password@localhost:8332) Btc.get_info # => {result: {...}}
      
      





node.jsのアナログ例:







 var http = require('http'); function BtcApi(host, port, username, password) { this.host = host; this.port = port; this.username = username; this.password = password; }; BtcApi.methods = [ 'getNewAddress', 'getAddressesByAccount', 'getInfo', 'getNetTotals', 'getBalance', 'getReceivedByAddress', 'sendToAddress', 'listTransactions', 'getTransaction', ]; BtcApi.prototype.sendRequest = function(method, params, callback) { if (BtcApi.methods.indexOf(method) === -1) { throw new Error('wrong method name ' + method) }; if (callback == null) { callback = params; }; var body = JSON.stringify({ jsonrpc: '1.0', method: method.toLowerCase(), params: params, }); var auth = 'Basic ' + Buffer.from(this.username + ':' + this.password).toString('base64'); var options = { host: this.host, port: this.port, path: '/', method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': auth }, }; var request = http.request(options, function (response) { var result = ''; response.setEncoding('utf8'); response.on('data', function (chunk) { result += chunk; }); // Listener for intializing callback after receiving complete response response.on('end', function () { try { callback(JSON.parse(result)); } catch (e) { console.error(e); callback(result); } }); }); request.write(body) request.end() }; for (var i = 0; i < BtcApi.methods.length; i++) { BtcApi.prototype[BtcApi.methods[i]] = function (method) { return function (params, callback) { this.sendRequest(method, params, callback) } }(BtcApi.methods[i]) } module.exports = BtcApi
      
      





およそ次のように使用できます。







 var BtcApi = require('./btc'); var client = new BtcApi('127.0.0.1', 8332, 'username', 'password'); client.listTransactions({ count: 1 }, function (response) { console.log('response: ', JSON.stringify(response)); }); // {"result":[{...}]}
      
      





Pythonの場合は、さらに簡単です-公式な方法は次を使用することです:







 from jsonrpc import ServiceProxy access = ServiceProxy("http://user:password@127.0.0.1:8332") access.getinfo()
      
      





実際、PHPにも問題はありません( http://jsonrpcphp.org/を使用することをお勧めします)。







  require_once 'jsonRPCClient.php'; $bitcoin = new jsonRPCClient('http://user:password@127.0.0.1:8332/'); echo "<pre>\n"; print_r($bitcoin->getinfo()); echo "\n"; echo "Received: ".$bitcoin->getreceivedbylabel("Your Address")."\n"; echo "</pre>";
      
      





適切なドキュメントの選択はこちらです。







上記の例は、ここにリストされているもののわずかに変更されたバージョンです。







ウェブサイトの統合



残っている簡単な部分は、支払いを受け取り、補充用の住所を生成する処理を構成することです。







クリプトと支払いの受け入れの統合のプロセスは次のようになります。









受信用のアドレスを生成するには、いくつかの異なるアプローチを使用できます-入金ごとに新しいアドレスを作成するか、ユーザーアカウントに永続的なアドレスを使用します。







最初のオプションはより安全(支払人による繰り返しの支払いを追跡するのがより難しいため)でシンプルですが、あまり強力でないハードウェアを使用する場合に問題になる可能性があります(生成されたアドレスごとにノードの負荷が増加しますが、数百万のアドレスからのみ顕著になります)。







2番目のオプションは、ユーザーが頻繁に登録して支払いを行う必要がある場合により便利ですが、同時に安全性が低下します(たとえば、ユーザーのアカウントに受け取ったすべての資金を追跡できます)。







リチャージアドレスを生成するには、getnewaddressメソッドを呼び出す必要があります。このメソッドは、応答で新しい補充アドレスを返します。 便宜上、作成されたアドレスがバインドされるパラメーター(アカウント)としてアカウントを渡すことができます。 特定のユーザーのトランザクションを表示すると便利な場合があります。







バランスの確認にはいくつかの方法が適しています。 最も簡単な方法は、補充用に生成されたアドレスごとにデータベースにエントリを作成し、 getreceivedbyaddress



メソッドを使用して資金を受け取る各エントリをチェックすることです(最も生産的なオプションではありませんが、ほとんどの状況に適しています)。







別の良いオプションは、最新の操作に関するリストトランザクションを介して情報を取得し、残高を受け取るユーザーを探すことです。 使用する実装のタイプ-選択します。







トランザクションをチェックする際の重要なポイントは、さまざまな攻撃から保護するための確認の数を正しく示すことです。 ほとんどの暗号通貨については、通常、ホワイトペーパーに記載されています。







ビットコインの場合、現時点での推奨値は、少量の場合に6回の確認です。 ここではすべてが詳しく説明されています。







使用する技術に大きく依存するため、ここではコード例を記述しません。







おわりに



他のウォレットの統合について、サーバー要件について、およびサイトがルートアクセスなどのVPSでホストされていない場合の支払いを受け入れる方法についての詳細については、もっと書きたいと思いましたが、記事が大きくなることがわかったので、おもしろいでしょう。次のいずれかの記事でこれを公開する方が良いでしょう。








All Articles