イーサリアムブロックチェーン用のNode.jsAPIを構築する方法

公開: 2022-03-10
簡単なまとめ↬この記事では、John Agbanusiが、分散化のためにイーサリアムブロックチェーンを構築してデプロイすることにより、Node.jsAPIを最初から構築する方法について説明します。 また、APIとブロックチェーンの両方を「分散型アプリケーションAPI」と呼ばれる単一のAPIに統合するステップバイステップのプロセスも示しています。

ブロックチェーンテクノロジーは過去10年間で増加しており、Chainalysis(金融技術)、Burstiq(健康技術)、フィラメント(IoT)、Opus(音楽ストリーミング)など、数多くの製品とプラットフォームを実現しています。および眼球(サイバーセキュリティ)。

これらの例から、ブロックチェーンは多くの製品とユースケースにまたがっており、非常に重要で有用であることがわかります。 fintech(finance tech)では、Chain、Chainalysisなどの場所でセキュリティと透明性のための分散型元帳として使用され、BurstiqやRobomedの機密性の高い健康データのセキュリティのための健康技術でも役立ちます。Opusなどのメディア技術を忘れないでください。ロイヤルティの透明性のためにブロックチェーンも使用しているため、完全なロイヤルティを取得するAudius。

Ocularは、生体認証システムのID管理にブロックチェーンに付属するセキュリティを使用し、Filamentは、リアルタイムの暗号化通信にブロックチェーン元帳を使用します。 これは、私たちの生活をより良くすることによって、ブロックチェーンが私たちにとってどれほど重要になったかを示しています。 しかし、ブロックチェーンとは正確には何ですか?

ブロックチェーンは、コンピューターのネットワーク全体で共有されるデータベースです。 レコードがチェーンに追加されると、変更するのは非常に困難です。 データベースのすべてのコピーが同じであることを確認するために、ネットワークは常にチェックを行います。

では、なぜブロックチェーンが必要なのですか? ブロックチェーンは、ハッキング、エラー、およびダウンタイムが非常に発生する可能性がある従来のレコードまたはデータベースと比較して、アクティビティを記録し、データを最新の状態に保ちながら、その履歴の記録を維持するための安全な方法です。 データが誰かによって破損したり、誤って削除されたりすることはありません。また、データの履歴と、サーバーのダウンタイムが原因で消去したりアクセスできなくなったりすることのない、即座に最新のレコードの両方を利用できます。

ブロックチェーン全体が多くのコンピューター間で複製されるため、すべてのユーザーがブロックチェーン全体を表示できます。 トランザクションまたはレコードは、1人の中央管理者ではなく、データの検証とコンセンサスの達成に取り組むユーザーのネットワークによって処理されます。

ブロックチェーンを使用するアプリケーションは、 dApps (分散型アプリケーション)と呼ばれます。 今日を振り返ると、フィンテックには分散型アプリがほとんどありますが、ブロックチェーンは分散型ファイナンスを超えています。 上記のように、ヘルスプラットフォーム、音楽ストリーミング/共有プラットフォーム、eコマースプラットフォーム、サイバーセキュリティプラットフォーム、および分散型アプリケーション(dApps)に移行するIOTがあります。

では、標準のデータベースやレコードではなく、アプリケーションにブロックチェーンを使用することを検討するのはいつ意味がありますか?

ジャンプした後もっと! 以下を読み続けてください↓

ブロックチェーンの一般的なアプリケーション

  • デジタル関係の管理と保護
    資産の長期的で透明性のある記録を保持したい場合はいつでも(たとえば、財産やアパートの権利を記録するために)、ブロックチェーンが理想的なソリューションになる可能性があります。 特にイーサリアムの「スマートコントラクト」は、デジタル関係を促進するのに最適です。 スマートコントラクトを使用すると、トランザクションの当事者が条件が満たされていることに同意したときに、自動支払いをリリースできます。
  • 仲買人/ゲートキーパーの排除
    たとえば、ほとんどのプロバイダーは現在、AirbnbやUberなどの集中型アグリゲータープラットフォームを介してゲストとやり取りする必要があります(これにより、各トランザクションが削減されます)。 ブロックチェーンはそれをすべて変える可能性があります。
    たとえば、TUIはブロックチェーンの力を確信しているため、ホテル経営者と顧客を直接つなぐ先駆的な方法です。 そうすれば、中央の予約プラットフォームではなく、ブロックチェーンを介して簡単、安全、一貫した方法で取引できます。
  • 信頼を確保するためにパートナー間の安全なトランザクションを記録する
    従来のデータベースは、2者間の単純なトランザクションを記録するのに適している場合がありますが、事態がさら​​に複雑になると、ブロックチェーンはボトルネックを減らし、関係を単純化するのに役立ちます。 さらに、分散型システムのセキュリティが強化されているため、ブロックチェーンは一般的なトランザクションに最適です。
    例としては、レコードをブロックチェーンに保存し始めたメルボルン大学があります。 高等教育におけるブロックチェーンの最も有望なユースケースは、学位、証明書、卒業証書の「記録管理」を変革することです。 これにより、ストレージまたはレコード専用のサーバーから多くのコストを節約できます。
  • データが絶え間なく変化するアプリケーションの過去のアクションの記録を保持する
    ブロックチェーンは、アクティビティを記録し、その履歴の記録を維持しながらデータを最新の状態に保つための、より優れた、より安全な方法です。 データが誰かによって破損したり、誤って削除されたりすることはありません。また、データの履歴と即座に最新の記録の両方を利用できます。 良いユースケースの例は、eコマースのブロックチェーンです。ブロックチェーンとeコマースの両方にトランザクションが含まれます。
    ブロックチェーンは、eコマースアクティビティがそれらに依存している間、これらのトランザクションをより安全かつ高速にします。 ブロックチェーンテクノロジーにより、ユーザーはデジタル資産を自動と手動の両方で共有し、安全に保存できます。 このテクノロジーには、支払い処理、製品検索、製品購入、カスタマーケアなどのユーザーアクティビティを処理する能力があります。 また、在庫管理と支払い処理にかかる費用も削減されます。
  • 分散化により、どこでも使用できるようになります
    為替政策などのさまざまな理由で特定の地域に限定しなければならない以前とは異なり、支払いゲートウェイの制限により、あなたの地域や大陸にない多くの国の財源へのアクセスが困難になります。 ブロックチェーンの分散化またはピアツーピアシステムの台頭と力により、これは他の国との連携が容易になります。
    たとえば、ヨーロッパのeコマースストアはアフリカに消費者を置くことができ、支払い要求を処理するために仲介業者を必要としません。 さらに、これらのテクノロジーは、オンライン小売業者がビットコイン、つまり暗号通貨を使用して遠くの国の消費者市場を利用するための扉を開いています。
  • BlockhainIsTechnology-ニュートラル
    ブロックチェーンは、開発者が使用しているすべてのテクノロジースタックで機能します。 ブロックチェーンを使用したり、Golangを学習したりするために、Python開発者としてNodeを学習する必要はありません。 これにより、ブロックチェーンが非常に使いやすくなります。
    実際には、Vue / Reactのフロントエンドアプリで直接使用できます。ブロックチェーンは、単純で単純なタスクの唯一のデータベースとして機能し、データのアップロードやユーザーのレコードを表示するためのハッシュの取得、カジノなどのフロントエンドゲームの構築などのユースケースを使用できます。ゲームと賭けゲーム(高い信頼が必要な場合)。 また、web3の機能により、データをチェーンに直接保存できます。

これで、ブロックチェーンを使用することの多くの利点がわかりましたが、ブロックチェーンをまったく使用しないのはいつですか?

ブロックチェーンのデメリット

  • デジタルトランザクションの速度の低下
    ブロックチェーンは大量の計算能力を必要とし、デジタルトランザクションの速度を低下させる傾向がありますが、回避策はありますが、ミリ秒単位の高速トランザクションが必要な場合は集中型データベースを使用することをお勧めします。
  • データの不変性
    データの不変性は、常にブロックチェーンの最大の欠点の1つです。 サプライチェーンや金融システムなど、複数のシステムがこのメリットを享受していることは明らかです。 ただし、一度データを書き込むと削除できないという問題があります。 地球上のすべての人はプライバシーの権利を持っています。 ただし、同じ人物がブロックチェーンテクノロジーで実行されるデジタルプラットフォームを利用している場合、システムから不要なトレースを削除することはできません。 簡単に言えば、彼が自分の痕跡を取り除く方法はありません—プライバシー権をバラバラに残します。
  • 専門知識が必要です
    ブロックチェーンプロジェクトの実装と管理は困難です。 プロセス全体を実行するには、完全な知識が必要です。 これが、ブロックチェーンの専門家を訓練するのに多くの時間と労力を要するため、ブロックチェーンの専門家や専門家に出会うのが難しい理由です。 したがって、この記事は開始するのに適した場所であり、すでに開始している場合は優れたガイドです。
  • 相互運用性
    分散型台帳の問題を解決するために懸命に取り組んでいる複数のブロックチェーンネットワークは、それらを相互に関連付けたり、相互に統合したりすることを困難にします。 これにより、異なるチェーン間の通信が困難になります。
  • レガシーアプリケーションの統合
    多くの企業やアプリケーションは、依然としてレガシーシステムとアーキテクチャを使用しています。 ブロックチェーン技術を採用するには、これらのシステムを完全にオーバーホールする必要がありますが、多くのシステムでは実現不可能であると言わざるを得ません。

ブロックチェーンはまだ進化と成熟を続けているので、今日言及されているこれらの短所が後でプロに変わっても驚かないでください。 暗号通貨であるビットコインはブロックチェーンの人気のある例の1つであり、ビットコイン暗号通貨とは別に増加している人気のあるブロックチェーンはイーサリアムブロックチェーンです。 ビットコインは暗号通貨に焦点を当てていますが、イーサリアムは新しい技術プラットフォームの主要な推進力であるスマートコントラクトに焦点を当てています。

推奨読書ビットコインとイーサリアム:違いは何ですか?

APIの構築を始めましょう

ブロックチェーンをしっかりと理解したところで、Ethereumブロックチェーンを構築してNode.jsの標準APIに統合する方法を見てみましょう。 最終的な目標は、dAppとブロックチェーンプラットフォームがどのように構築されているかをよく理解することです。

ほとんどのdAppは、同様のアーキテクチャと構造を持っています。 基本的に、dAppフロントエンド(Webまたはモバイル)と対話するユーザーがいて、その後、バックエンドAPIと対話します。 次に、バックエンドは、要求に応じて、パブリックノードを介してスマートコントラクトまたはブロックチェーンと対話します。 これらはNode.jsアプリケーションを実行するか、バックエンドがNode.jsソフトウェアを直接実行してブロックチェーンを使用します。 これらのプロセスの間には、完全分散型アプリケーションまたは半分散型アプリケーションの構築の選択から、分散型アプリケーションの選択や秘密鍵の安全な保管方法まで、まだ多くのことがあります。

推奨読書分散型アプリケーションアーキテクチャ:バックエンド、セキュリティ、およびデザインパターン

最初に知っておくべきこと

このチュートリアルでは、Ethereumブロックチェーンの機能を使用して音楽を保存し、ダウンロードやストリーミングで共有する分散型ミュージックストアアプリのバックエンドを構築してみます。

構築しようとしているアプリケーションの基本構造は、次の3つの部分で構成されています。

  1. 電子メールで行われる認証。 もちろん、暗号化されたパスワードをアプリに追加する必要があります。
  2. 音楽データを含むデータの保存は、最初にipfsに保存され、保存アドレスは取得のためにブロックチェーンに保存されます。
  3. 取得。認証されたユーザーは、プラットフォームに保存されているデータにアクセスして使用できます。

これはNode.jsでビルドしますが、Pythonやその他のプログラミング言語でビルドすることもできます。 また、メディアデータをIPFSに保存する方法、アドレスを取得する方法、およびこのアドレスを保存するための関数を書き込む方法、およびSolidityプログラミング言語を使用してブロックチェーンからこのアドレスを取得する方法についても説明します。

イーサリアムとNode.jsを構築または操作するために自由に使えるツールをいくつか紹介します。

  • Node.js
    最初の要件はノードアプリケーションです。 Node.jsアプリを作成しようとしているので、コンパイラが必要です。 Node.jsがインストールされていることを確認してください—そして最新のロングタームサポートバイナリ( LTS )をダウンロードしてください。
  • トリュフスイート
    Truffleは、契約の開発およびテスト環境であり、Ethereumブロックチェーンのアセットパイプラインでもあります。 スクリプトをコンパイル、パイプライン化、および実行するための環境を提供します。 ブロックチェーンの開発について話していると、Truffleは人気のある場所です。 Truffle Suite:SmartContracts用のSweetToolsのTruffleSuiteについて確認してください。
  • ガナッシュCLI
    Truffleと連携して機能するもう1つのツールは、Ganache-CLIです。 TruffleSuiteチームによって構築および保守されています。 ビルドしてコンパイルした後、ブロックチェーンアプリを開発して実行し、使用するスマートコントラクトをデプロイするためのエミュレーターが必要です。 Ganacheを使用すると、取引コストやリサイクル可能なアカウントなどに実際のお金を使用せずに、エミュレーターで契約を簡単に展開できます。 GanacheCLIおよびGanacheでGanacheCLIの詳細をご覧ください。
  • リミックス
    RemixはGanacheの代替手段のようなものですが、Ethereumスマートコントラクトのデプロイとテストをナビゲートするのに役立つGUIも付属しています。 詳細については、Remix — Ethereum IDE&コミュニティをご覧ください。 https://remix.ethereum.orgにアクセスし、GUIを使用してスマートコントラクトを作成およびデプロイするだけです。
  • Web3
    Web3は、イーサリアムノードとの対話を可能にするライブラリのコレクションです。 これらは、HTTP、IPC、またはWebSocketを介したコントラクトのローカルノードまたはリモートノードである可能性があります。 Web3.jsの紹介・Ethereum Blockchain Developer Crash Courseは、Web3について少し学ぶのに適した場所です。
  • IPFS
    dAppの構築に使用されているコアプロトコル。 InterPlanetary File System (IPFS)は、分散ファイルシステムにデータを保存および共有するためのプロトコルおよびピアツーピアネットワークです。 IPFS Powers the Distributed Webは、IPFSとその通常の使用方法について詳しく説明しています。

ゼロからのバックエンドAPIの作成

したがって、最初に使用するバックエンドを作成する必要があり、Node.jsを使用しています。 新しいNode.jsAPIを作成する場合、最初に行うことはnpmパッケージを初期化することです。 ご存知かもしれませんが、npmはNode Package Managerの略で、Node.jsバイナリがあらかじめパッケージ化されています。 そこで、新しいフォルダを作成し、それを「blockchain-music」と呼びます。 そのフォルダディレクトリでターミナルを開き、次のコマンドを実行します。

 $ npm init -y && touch server.js routes.js

これにより、 package.jsonファイルを使用してプロジェクトが起動し、すべてのプロンプトに「はい」と答えます。 次に、APIでroutes関数を作成するためのserver.jsファイルとroutes.jsファイルも作成します。

これらすべての後で、ビルドを簡単かつ簡単にするために必要なパッケージをインストールする必要があります。 このプロセスは継続的なものです。つまり、プロジェクトの開発中はいつでもパッケージをインストールできます。

今必要な最も重要なものをインストールしましょう:

  • Express.js
  • @ truffle / Contract
  • Truffle.js
  • web3.js
  • dotenv
  • short-id
  • MongoDB
  • nodemon

また、Truffle.jsをグローバルにインストールする必要があるため、ローカル環境のどこでも使用できます。 それらすべてを一度にインストールする場合は、ターミナルで次のコードを実行します。

 $ npm install nodemon truffle-contract dotenv mongodb shortid express web3 --save && npm install truffle -g

--saveフラグは、パッケージの名前をpackage.jsonファイルに保存するためのものです。 -gフラグは、この特定のパッケージをグローバルに格納するためのものであり、これにより、作業するすべてのプロジェクトで使用できます。

次に、MongoDBデータベースのシークレットURIを保存して使用できる.envファイルを作成します。 これを行うには、ターミナルでtouch.envを実行します。 MongoDBのデータベースアカウントをまだ持っていない場合は、最初にMongoDBページから始めてください。

dotenvパッケージは、保存された変数をNode.jsプロセス環境にエクスポートします。 パスワードやプライベートデータの漏洩を防ぐために、パブリックリポジトリにプッシュするときに.envファイルをプッシュしないように注意してください。

次に、プロジェクトのビルドフェーズと開発フェーズのスクリプトをpackage.jsonファイルに追加する必要があります。 現在、 package.jsonは次のようになっています。

 { "name": "test", "version": "1.0.0", "description": "", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1", "socket.io": "^2.3.0", "truffle-contract": "^4.0.31", "web3": "^1.3.0" } }

次に、開始スクリプトをpackage.jsonファイルに追加して、nodemonサーバーを使用します。これにより、変更を加えるたびにサーバー自体が再起動し、ノードサーバーを直接使用するビルドスクリプトは次のようになります。

 { "name": "test", "version": "1.0.0", "description": "", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon server.js", "build": "node server.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1", "socket.io": "^2.3.0", "truffle-contract": "^4.0.31", "web3": "^1.3.0" } }

次に、以前にグローバルにインストールしたTruffleパッケージを使用して、スマートコントラクトで使用するためにTruffleを初期化する必要があります。 プロジェクトの同じフォルダーで、ターミナルで次のコマンドを実行します。

 $ truffle init

次に、 server.jsファイルにコードを書き始めることができます。 繰り返しになりますが、私たちはシンプルな分散型ミュージックストアアプリを構築しようとしています。このアプリでは、顧客が他のすべてのユーザーがアクセスして聴くことができるように音楽をアップロードできます。

server.jsは、コンポーネントの結合と分離を容易にするためにクリーンである必要があるため、ルートやその他の機能は、 routes.jsなどの他のファイルに配置されます。 server.jsの例は次のようになります。

 require('dotenv').config(); const express= require('express') const app =express() const routes = require('./routes') const Web3 = require('web3'); const mongodb = require('mongodb').MongoClient const contract = require('truffle-contract'); app.use(express.json()) mongodb.connect(process.env.DB,{ useUnifiedTopology: true },(err,client)=>{ const db =client.db('Cluster0') //home routes(app,db) app.listen(process.env.PORT || 8082, () => { console.log('listening on port 8082'); }) })

基本的に、上記では、 requireで必要なライブラリをインポートし、 app.useを使用してAPIでJSONを使用できるミドルウェアを追加し、MongoDBデータベースに接続してデータベースにアクセスし、どのデータベースクラスターを指定します。アクセスしようとしています(このチュートリアルでは「Cluster0」です)。 この後、関数を呼び出して、 routesファイルからインポートします。 最後に、ポート8082で接続の試行をリッスンします。

このserver.jsファイルは、アプリケーションを開始するための最低限のファイルです。 ルート.jsをインポートしたことに注意してください。 このファイルは、APIのルートエンドポイントを保持します。 また、 server.jsファイルで使用する必要のあるパッケージをインポートして初期化しました。

ユーザーが使用する5つのエンドポイントを作成します。

  1. 電子メールだけでユーザーを登録するための登録エンドポイント。 理想的には、電子メールとパスワードを使用してこれを行いますが、各ユーザーを識別したいだけなので、このチュートリアルの簡潔さのために、パスワードのセキュリティとハッシュに挑戦するつもりはありません。
     POST /register Requirements: email
  2. 電子メールによるユーザーのログインエンドポイント。
     POST /login Requirements: email
  3. ユーザーのアップロードエンドポイント—音楽ファイルのデータを取得するAPI。 フロントエンドはMP3/WAVファイルをオーディオバッファに変換し、そのバッファをAPIに送信します。
     POST /upload Requirements: name, title of music, music file buffer or URL stored
  4. 音楽バッファデータを要求する登録ユーザーに音楽バッファデータを提供し、それにアクセスしたユーザーを記録するアクセスエンドポイント。
     GET /access/{email}/{id} Requirements: email, id
  5. また、音楽ライブラリ全体へのアクセスを提供し、登録ユーザーに結果を返したいと考えています。
     GET /access/{email} Requirements: email

次に、 routes.jsファイルにroute関数を記述します。 データベースの保存および取得機能を利用し、ファイルの最後にあるルート関数をエクスポートして、別のファイルまたはフォルダーにインポートできるようにします。

 const shortid = require('short-id') function routes(app, db){ app.post('/register', (req,res)=>{ let email = req.body.email let idd = shortid.generate() if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.status(400).json({"status":"Failed", "reason":"Already registered"}) }else{ db.insertOne({email}) res.json({"status":"success","id":idd}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/login', (req,res)=>{ let email = req.body.email if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.json({"status":"success","id":doc.id}) }else{ res.status(400).json({"status":"Failed", "reason":"Not recognised"}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/upload', (req,res)=>{ let buffer = req.body.buffer let name = req.body.name let title = req.body.title if(buffer && title){ }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.get('/access/:email/:id', (req,res)=>{ if(req.params.id && req.params.email){ }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) } module.exports = routes

このroute関数内には、 appパラメーターとdbパラメーターの両方で呼び出される他の多くの関数があります。 これらは、ユーザーがURLでエンドポイントを指定できるようにするAPIエンドポイント関数です。 最終的に、実行するこれらの関数の1つを選択し、着信要求への応答として結果を提供します。

4つの主要なエンドポイント機能があります。

  1. get :レコード操作の読み取り用
  2. post :レコード操作を作成するため
  3. put :レコード操作を更新するため
  4. delete :レコード操作を削除するため

このroutes関数では、 get操作とpost操作を使用しました。 登録、ログイン、アップロードの操作にはpostを使用し、データ操作へのアクセスにはgetを使用します。 これについてもう少し詳しくは、Jamie Corkhillの記事「ノードの使用を開始する方法:API、HTTP、ES6+JavaScriptの概要」をご覧ください。

上記のコードでは、レジスタルートのようないくつかのデータベース操作も確認できます。 新しいユーザーのメールをdb.createaで保存し、ログイン機能でdb.findOneを使用してメールをチェックしました。 ここで、すべてを実行する前に、 db.collectionメソッドを使用してコレクションまたはテーブルに名前を付ける必要があります。 それがまさに次に取り上げる内容です。

MongoDBでのデータベース操作の詳細については、mongoシェルメソッドのドキュメントを確認してください。

堅牢性を備えたシンプルなブロックチェーンスマートコントラクトの構築

次に、Solidity(スマートコントラクトが記述される言語)でブロックチェーンコントラクトを記述し、データを保存して必要なときに取得するだけです。 保存するデータは音楽ファイルデータです。つまり、音楽をIPFSにアップロードしてから、バッファーのアドレスをブロックチェーンに保存する必要があります。

まず、contractフォルダーに新しいファイルを作成し、 Inbox.solという名前を付けます。 スマートコントラクトを作成するには、Solidityをよく理解しておくと便利ですが、JavaScriptに似ているため、難しくはありません。

Solidityについて詳しく知りたい場合は、記事の下部にいくつかのリソースを追加して開始します。

 pragma solidity ^0.5.0; contract Inbox{ //Structure mapping (string=>string) public ipfsInbox; //Events event ipfsSent(string _ipfsHash, string _address); event inboxResponse(string response); //Modifiers modifier notFull (string memory _string) { bytes memory stringTest = bytes(_string); require(stringTest.length==0); _; } // An empty constructor that creates an instance of the conteact constructor() public{} //takes in receiver's address and IPFS hash. Places the IPFSadress in the receiver's inbox function sendIPFS(string memory _address, string memory _ipfsHash) notFull(ipfsInbox[_address]) public{ ipfsInbox[_address] = _ipfsHash; emit ipfsSent(_ipfsHash, _address); } //retrieves hash function getHash(string memory _address) public view returns(string memory) { string memory ipfs_hash=ipfsInbox[_address]; //emit inboxResponse(ipfs_hash); return ipfs_hash; } }

コントラクトには、 getHash sendIPFSの2つの主要な関数があります。 関数について説明する前に、最初にInboxと呼ばれるコントラクトを定義する必要があることがわかります。 このクラス内には、 ipfsInboxオブジェクトで使用される構造体があります(最初のイベント、次に修飾子)。

構造とイベントを定義した後、 constructor関数を呼び出してコントラクトを初期化する必要があります。 次に、3つの関数を定義しました。 ( checkInbox関数は、結果をテストするためのテストで使用されました。)

sendIPFSは、ユーザーが識別子とハッシュアドレスを入力した後、ブロックチェーンに格納される場所です。 getHash関数は、識別子が与えられたときにハッシュアドレスを取得します。 繰り返しになりますが、この背後にあるロジックは、最終的に音楽をIPFSに保存したいということです。 それがどのように機能するかをテストするには、Remix IDEにアクセスして、コントラクトをコピー、貼り付け、テストし、エラーをデバッグして再実行します(必要がないことを願っています)。

コードがリミックスで正しく機能することをテストした後、Truffleスイートを使用してローカルでコードをコンパイルすることに移りましょう。 ただし、最初に、ファイルにいくつかの変更を加え、 ganache-cliを使用してエミュレーターをセットアップする必要があります。

まず、 ganache-cliをインストールしましょう。 同じディレクトリで、ターミナルで次のコマンドを実行します。

 $ npm install ganache-cli -g

次に、別のターミナルを開いて、同じフォルダで別のコマンドを実行してみましょう。

 $ ganache-cli

これにより、ブロックチェーンコントラクトが接続して機能するためのエミュレーターが起動します。 ターミナルを最小化し、使用していた他のターミナルを続行します。

Linux / Mac OSまたはWindowsでtruffle-config.jsを使用している場合は、 truffle.jsファイルに移動し、このファイルを次のように変更します。

 const path = require("path"); module.exports = { // to customize your Truffle configuration! contracts_build_directory: path.join(__dirname, "/build"), networks: { development: { host: "127.0.0.1", port: 8545, network_id: "*" //Match any network id } } };

基本的に、スマートコントラクトがJSONファイルに変換されるビルドフォルダーのパスを追加しました。 次に、Truffleが移行に使用するネットワークも指定しました。

次に、移行フォルダーにも2_migrate_inbox.jsという名前の新しいファイルを作成し、ファイル内に次のコードを追加します。

 var IPFSInbox = artifacts.require("./Inbox.sol"); module.exports = function(deployer) { deployer.deploy(IPFSInbox); };

これは、契約ファイルを取得し、Truffleの移行中にdeployer機能を使用してJSONに自動的にデプロイするために行いました。

上記の変更後、以下を実行します。

 $ truffle compile

最後に、コンパイルが成功したことを示す次のようなメッセージが表示されます。

 > Compiled successfully using: - solc: 0.5.16+commit.9c3226ce.Emscripten.clang

次に、以下を実行して契約を移行します。

 $ truffle migrate

コントラクトの移行に成功すると、最後に次のようなものが表示されます。

 Summary ======= > Total deployments: 1 > Final cost: 0.00973432 ETH

そして、ほぼ完了です! Node.jsを使用してAPIを構築し、スマートコントラクトを設定して構築しました。

また、契約の動作をテストし、それが望ましい動作であることを確認するために、契約のテストを作成する必要があります。 テストは通常​​、作成され、 testフォルダーに配置されます。 テストフォルダーに作成されたInboxTest.jsという名前のファイルに書き込まれたテストの例は次のとおりです。

 const IPFSInbox = artifacts.require("./Inbox.sol") contract("IPFSInbox", accounts =>{ it("emit event when you send a ipfs address", async()=>{ //ait for the contract const ipfsInbox = await IPFSInbox.deployed() //set a variable to false and get event listener eventEmitted = false //var event = () await ipfsInbox.ipfsSent((err,res)=>{ eventEmitted=true }) //call the contract function which sends the ipfs address await ipfsInbox.sendIPFS(accounts[1], "sampleAddress", {from: accounts[0]}) assert.equal(eventEmitted, true, "sending an IPFS request does not emit an event") }) })

したがって、次のコマンドを実行してテストを実行します。

 $ truffle test

テストフォルダー内のファイルを使用してコントラクトをテストし、成功したテストと失敗したテストの数を示します。 このチュートリアルでは、次の情報を取得する必要があります。

 $ truffle test Using network 'development'. Compiling your contracts... =========================== > Compiling .\contracts\Inbox.sol > Artifacts written to C:\Users\Ademola\AppData\Local\Temp\test--2508-n0vZ513BXz4N > Compiled successfully using: — solc: 0.5.16+commit.9c3226ce.Emscripten.clang Contract: IPFSInbox √ emit event when you send an ipfs address (373ms) 1 passing (612ms)

Web3を使用したスマートコントラクトのバックエンドAPIへの統合

ほとんどの場合、チュートリアルを見ると、フロントエンドをブロックチェーンに直接統合するように構築された分散型アプリが表示されます。 ただし、サードパーティのバックエンドAPIやサービスを使用する場合や、ブロックチェーンを使用してCMSを構築する場合など、バックエンドへの統合も必要になる場合があります。

Web3の使用は、リモートまたはローカルのイーサリアムノードにアクセスしてアプリケーションで使用するのに役立つため、この原因にとって非常に重要です。 先に進む前に、ローカルおよびリモートのイーサリアムノードについて説明します。 ローカルノードは、 ganache-cliなどのエミュレーターを使用してシステムにデプロイされたノードですが、リモートノードは、 ropstenrinkebyなどのオンライン蛇口/プラットフォームにデプロイされたノードです。 さらに深く掘り下げるには、TruffleとRopstenを使用してスマートコントラクトをデプロイするためのropsten 5分間ガイドにデプロイする方法に関するチュートリアルに従うか、Truffleウォレットプロバイダーを使用して、スマートコントラクトをデプロイするためのより簡単な方法でデプロイすることができます。

このチュートリアルではganache ganache-cliを使用していますが、ropstenにデプロイする場合は、コントラクトアドレスを.envファイルなどの場所にコピーまたは保存してから、 server.jsファイルの更新、web3のインポート、インポートに進む必要があります。移行されたコントラクトとWeb3インスタンスをセットアップします。

 require('dotenv').config(); const express= require('express') const app =express() const routes = require('./routes') const Web3 = require('web3'); const mongodb = require('mongodb').MongoClient const contract = require('truffle-contract'); const artifacts = require('./build/Inbox.json'); app.use(express.json()) if (typeof web3 !== 'undefined') { var web3 = new Web3(web3.currentProvider) } else { var web3 = new Web3(new Web3.providers.HttpProvider('https://localhost:8545')) } const LMS = contract(artifacts) LMS.setProvider(web3.currentProvider) mongodb.connect(process.env.DB,{ useUnifiedTopology: true }, async(err,client)=>{ const db =client.db('Cluster0') const accounts = await web3.eth.getAccounts(); const lms = await LMS.deployed(); //const lms = LMS.at(contract_address) for remote nodes deployed on ropsten or rinkeby routes(app,db, lms, accounts) app.listen(process.env.PORT || 8082, () => { console.log('listening on port '+ (process.env.PORT || 8082)); }) })

server.jsファイルで、web3インスタンスがすでに初期化されているかどうかを確認します。 そうでない場合は、前に定義したネットワークポート( 8545 )で初期化します。 次に、移行されたJSONファイルとtruffle-contractパッケージに基づいてコントラクトを構築し、コントラクトプロバイダーをWeb3インスタンスプロバイダーに設定します。これは、これまでに初期化されている必要があります。

次に、 web3.eth.getAccountsでアカウントを取得します。 開発段階では、コントラクトクラスでデプロイされた関数を呼び出します。この関数は、まだ実行中ganache-cliに、使用するコントラクトアドレスを提供するように要求します。 ただし、コントラクトをリモートノードに既にデプロイしている場合は、引数としてアドレスを入力する関数を呼び出します。 サンプル関数は、上記のコードで定義されたlms変数の下にコメントされています。 次に、 routes関数を呼び出して、アプリインスタンス、データベースインスタンス、コントラクトインスタンス( lms )、およびアカウントデータを引数として入力します。 最後に、ポート8082でリクエストをリッスンします。

また、これまでに、MongoDBパッケージをインストールしているはずです。これは、APIでデータベースとして使用しているためです。 それができたら、ルートページに移動します。ここで、コントラクトで定義されたメソッドを使用して、音楽データの保存や取得などのタスクを実行します。

最終的に、routes.jsは次のようになります。

 const shortid = require('short-id') const IPFS =require('ipfs-api'); const ipfs = IPFS({ host: 'ipfs.infura.io', port: 5001,protocol: 'https' }); function routes(app, dbe, lms, accounts){ let db= dbe.collection('music-users') let music = dbe.collection('music-store') app.post('/register', (req,res)=>{ let email = req.body.email let idd = shortid.generate() if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.status(400).json({"status":"Failed", "reason":"Already registered"}) }else{ db.insertOne({email}) res.json({"status":"success","id":idd}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/login', (req,res)=>{ let email = req.body.email if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.json({"status":"success","id":doc.id}) }else{ res.status(400).json({"status":"Failed", "reason":"Not recognised"}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/upload', async (req,res)=>{ let buffer = req.body.buffer let name = req.body.name let title = req.body.title let id = shortid.generate() + shortid.generate() if(buffer && title){ let ipfsHash = await ipfs.add(buffer) let hash = ipfsHash[0].hash lms.sendIPFS(id, hash, {from: accounts[0]}) .then((_hash, _address)=>{ music.insertOne({id,hash, title,name}) res.json({"status":"success", id}) }) .catch(err=>{ res.status(500).json({"status":"Failed", "reason":"Upload error occured"}) }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.get('/access/:email', (req,res)=>{ if(req.params.email){ db.findOne({email: req.body.email}, (err,doc)=>{ if(doc){ let data = music.find().toArray() res.json({"status":"success", data}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.get('/access/:email/:id', (req,res)=>{ let id = req.params.id if(req.params.id && req.params.email){ db.findOne({email:req.body.email},(err,doc)=>{ if(doc){ lms.getHash(id, {from: accounts[0]}) .then(async(hash)=>{ let data = await ipfs.files.get(hash) res.json({"status":"success", data: data.content}) }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) } module.exports = routes

At the beginning of the routes file, we imported the short-id package and ipfs-http-client and then initialized IPFS with the HTTP client using the backend URL ipfs.infura.io and port 5001 . This allowed us to use the IPFS methods to upload and retrieve data from IPFS (check out more here).

In the upload route, we save the audio buffer to IPFS which is better compared to just storing it on the blockchain for anyone registered or unregistered to use. Then we saved the address of the buffer in the blockchain by generating an ID and using it as an identifier in the sendIFPS function. Finally, then we save all the other data associated with the music file to our database. We should not forget to update our argument in the routes function since we changed it in the server.js file.

In the access route using id , we then retrieve our data by getting the id from the request, using the id to access the IPFS hash address, and then access the audio buffer using the address. But this requires authentication of a user by email which is done before anything else.

Phew, we're done ! Right now we have an API that can receive requests from users, access a database, and communicate to a node that has the software running on them. We shouldn't forget that we have to export our function with module.exports though!

As we have noticed, our app is a decentralized app . However, it's not fully decentralized as we only stored our address data on the blockchain and every other piece of data was stored securely in a centralized database which is the basis for semi-dApps . So the consumption of data can be done directly via request or using a frontend application in JavaScript to send fetch requests.

Our music store backend app can now safely store music data and provide access to anyone who needs to access it, provided it is a registered user. Using blockchain for music sharing makes it cheaper to store music data while focusing on connecting artists directly with users, and perhaps it could help them generate revenue that way. This wouldn't require a middleman that uses royalty; instead, all of the revenue would go to the artist as users request their music to either download or stream. A good example of a music streaming application that uses blockchain just like this is Opus OPUS: Decentralized music sharing platform. However, there are also a few others like Musicoin, Audius, and Resonate.

次は何?

The final thing after coding is to start our server by running npm run start or npm run build and test our backend endpoints on either the browser or with Postman. After running and testing our API we could add more features to our backend and blockchain smart contract. If you'd like to get more guidance on that, please check the further reading section for more articles.

It's worth mentioning that it is critical to write unit and integration tests for our API to ensure correct and desirable behaviors. Once we have all of that done, we can deploy our application on the cloud for public use. This can be done on its own with or without adding a frontend (microservices) on Heroku, GCP, or AWS for public use. Happy coding!

Note : You can always check my repo for reference. Also, please note that the .env file containing the MongoDB database URI is included for security reasons.

Further Reading And Related Resources

  • “How to Build Ethereum Dapp with React.js: Complete Step-By-Step Guide,” Gregory McCubbin
  • “Ethereum + IPFS + React DApp Tutorial Pt. 1,” Alexander Ma
  • “Ethereum Development with Go,” Miguel Mota
  • “Create your first Ethereum dAPP with Web3 and Vue.JS (Part 1),” Nico Vergauwen
  • “Deploy a Smart Contract on Ethereum with Python, Truffle and web3py,” Gabriel Saldanha
  • “Why Use Blockchain Technology?,” Bernard Marr
  • “How To Build Your Own Blockchain Using Node.js,” DevTeam.Space
  • “How To Build A Blockchain App With Ethereum, Web3.js & Solidity Smart Contracts,” Gregory McCubbin
  • “How To Build A Simple Cryptocurrency Blockchain In Node.js,” Alfrick Opidi
  • “How Blockchain Technology Is Going To Revolutionize Ecommerce,” Sergii Shanin
  • “4 Ways Blockchain Will Transform Higher Education — Smarter With Gartner,” Susan Moore
  • “How To Learn Solidity: The Ultimate Ethereum Coding Tutorial,” Ryan Molecke
  • “Developing Ethereum Smart Contracts For Beginners,” Coursetro
  • “Learn about Ethereum,” Ethereum official site