Ethereum Blockchain용 Node.js API를 빌드하는 방법

게시 됨: 2022-03-10
빠른 요약 ↬ 이 기사에서 John Agbanusi는 탈중앙화를 위한 이더리움 블록체인을 구축 및 배포하여 Node.js API를 처음부터 구축하는 방법을 설명합니다. 그는 또한 API와 블록체인을 "분산형 애플리케이션 API"라는 단일 API로 통합하는 단계별 프로세스를 보여줍니다.

블록체인 기술은 지난 10년간 상승세를 타고 있으며 Chainalysis(금융 기술), Burstiq(건강 기술), Filament(IoT), Opus(음악 스트리밍)와 같은 많은 제품과 플랫폼에 생명을 불어넣었습니다. 및 Ocular(사이버 보안).

이러한 예에서 우리는 블록체인이 많은 제품과 사용 사례에 걸쳐 있어 매우 중요하고 유용하다는 것을 알 수 있습니다. 핀테크(금융 기술)에서는 Chain, Chainalysis와 같은 곳에서 보안 및 투명성을 위한 분산 원장으로 사용되며 Burstiq 및 Robomed에서 민감한 건강 데이터의 보안을 위한 건강 기술에서도 유용합니다. Opus와 같은 미디어 기술도 빼놓을 수 없습니다. 로열티 투명성을 위해 블록체인을 사용하여 완전한 로열티를 받는 Audius.

Ocular는 생체 인식 시스템의 신원 관리를 위해 블록체인과 함께 제공되는 보안을 사용하고 Filament는 실시간 암호화 통신을 위해 블록체인 원장을 사용합니다. 이것은 우리의 삶을 더 좋게 만들어 블록체인이 우리에게 얼마나 필수적인지 보여줍니다. 그러나 블록체인이란 정확히 무엇입니까?

블록체인은 컴퓨터 네트워크를 통해 공유되는 데이터베이스 입니다. 레코드가 체인에 추가되면 변경하기가 매우 어렵습니다. 데이터베이스의 모든 복사본이 동일한지 확인하기 위해 네트워크는 지속적으로 확인합니다.

그렇다면 왜 블록체인이 필요한가 ? 블록체인은 활동을 기록하고 데이터를 최신 상태로 유지하면서 해킹, 오류 및 다운타임이 발생할 가능성이 매우 높은 기존의 기록 또는 데이터베이스와 비교하여 기록을 유지하는 안전한 방법 입니다. 데이터는 누군가에 의해 손상되거나 실수로 삭제될 수 없으며, 데이터의 과거 추적과 서버 다운타임으로 인해 지워지거나 액세스할 수 없게 되는 즉시 최신 기록의 이점을 누릴 수 있습니다.

전체 블록체인이 많은 컴퓨터에 복제되기 때문에 모든 사용자가 전체 블록체인을 볼 수 있습니다. 거래 또는 기록은 한 명의 중앙 관리자가 처리하는 것이 아니라 데이터를 확인하고 합의를 도출하기 위해 작업하는 사용자 네트워크에 의해 처리됩니다.

블록체인을 사용하는 애플리케이션을 dApp (탈중앙화 애플리케이션)이라고 합니다. 오늘날 우리는 핀테크에서 탈중앙화 앱을 대부분 찾아볼 수 있지만 블록체인은 탈중앙화 금융을 넘어선다. 위에서 언급한 바와 같이 건강 플랫폼, 음악 스트리밍/공유 플랫폼, 전자 상거래 플랫폼, 사이버 보안 플랫폼 및 IOT가 분산 응용 프로그램(dApp)으로 이동하고 있습니다.

그렇다면 표준 데이터베이스나 기록이 아닌 애플리케이션에 블록체인을 사용하는 것이 적절한 경우는 언제일까요?

점프 후 더! 아래에서 계속 읽기 ↓

블록체인의 일반적인 응용

  • 디지털 관계 관리 및 보안
    자산에 대한 장기적이고 투명한 기록을 유지하려는 경우(예: 재산 또는 아파트 권리 기록) 블록체인이 이상적인 솔루션이 될 수 있습니다. 특히 이더리움 '스마트 계약'은 디지털 관계를 용이하게 하는 데 탁월합니다. 스마트 계약을 사용하면 거래 당사자가 조건이 충족되었다는 데 동의할 때 자동 지불이 해제될 수 있습니다.
  • 중개인/게이트키퍼 제거
    예를 들어, 대부분의 제공업체는 현재 Airbnb 또는 Uber와 같은 중앙 집중식 집계 플랫폼을 통해 게스트와 상호 작용해야 합니다(이는 차례로 각 거래에 대해 삭감됨). 블록체인은 이 모든 것을 바꿀 수 있습니다.
    예를 들어, TUI는 블록체인의 힘을 확신하여 호텔리어와 고객을 직접 연결하는 방법을 개척하고 있습니다. 그렇게 하면 중앙 예약 플랫폼을 통하지 않고 블록체인을 통해 쉽고 안전하며 일관된 방식으로 거래할 수 있습니다.
  • 신뢰를 보장하기 위해 파트너 간의 안전한 거래를 기록
    기존 데이터베이스는 두 당사자 간의 간단한 거래를 기록하는 데 유용할 수 있지만 상황이 더 복잡해지면 블록체인이 병목 현상을 줄이고 관계를 단순화하는 데 도움이 될 수 있습니다. 또한 분산 시스템의 추가된 보안으로 인해 블록체인은 일반적으로 거래에 이상적입니다.
    블록체인에 기록을 저장하기 시작한 멜버른 대학교가 그 예입니다. 고등 교육에서 블록체인의 가장 유망한 사용 사례는 학위, 수료증 및 졸업장의 "기록 보관"을 혁신하는 것입니다. 이것은 저장 또는 기록을 위한 전용 서버로부터 많은 비용을 절약합니다.
  • 데이터가 일정하게 흐르는 애플리케이션에 대한 과거 작업 기록 유지
    블록체인은 활동을 기록하고 기록을 유지하면서 데이터를 최신 상태로 유지하는 더 좋고 안전한 방법입니다. 데이터는 누군가에 의해 손상되거나 실수로 삭제될 수 없으며 데이터의 과거 추적과 즉각적인 최신 기록의 이점을 모두 누릴 수 있습니다. 좋은 사용 사례의 예로는 전자 상거래의 블록체인이 있습니다. 블록체인과 전자 상거래는 모두 거래를 포함합니다.
    블록체인은 전자 상거래 활동이 거래에 의존하는 동안 이러한 거래를 더 안전하고 빠르게 만듭니다. 블록체인 기술을 통해 사용자는 자동 및 수동으로 디지털 자산을 공유하고 안전하게 저장할 수 있습니다. 이 기술은 결제 처리, 상품 검색, 상품 구매, 고객 관리와 같은 사용자 활동을 처리할 수 있는 능력을 가지고 있습니다. 또한 재고 관리 및 지불 처리에 소요되는 비용을 줄일 수 있습니다.
  • 탈중앙화를 통해 어디서나 사용 가능
    환전 정책 등 여러 가지 이유로 특정 지역으로 제한해야 했던 이전과 달리 결제 게이트웨이의 제한으로 인해 해당 지역이나 대륙이 아닌 많은 국가의 재정 자원에 액세스하기가 어렵습니다. 블록체인의 탈중앙화 또는 P2P 시스템의 등장과 힘으로 다른 국가와 협력하기가 더 쉬워졌습니다.
    예를 들어, 유럽의 전자 상거래 상점은 아프리카에 소비자를 가질 수 있으며 중개자가 지불 요청을 처리할 필요가 없습니다. 또한, 이러한 기술은 온라인 소매업체가 비트코인, 즉 암호 화폐를 사용하여 머나먼 국가의 소비자 시장을 활용할 수 있는 기회를 제공하고 있습니다.
  • 블록체인은 기술 중립적이다
    블록체인은 개발자가 사용하는 모든 기술 스택과 함께 작동합니다. 블록체인을 사용하거나 Golang을 배우기 위해 Python 개발자로서 Node를 배울 필요가 없습니다. 이것은 블록체인을 사용하기 매우 쉽게 만듭니다.
    우리는 Vue/React의 프론트엔드 앱에서 블록체인을 사용하여 단순하지 않은 작업과 데이터 업로드 또는 사용자 기록 표시를 위한 해시 가져오기 또는 카지노와 같은 프론트엔드 게임 구축과 같은 사용 사례를 위한 유일한 데이터베이스 역할을 하여 실제로 직접 사용할 수 있습니다. 게임 및 베팅 게임(높은 신뢰가 필요한 경우). 또한 web3의 힘으로 체인에 직접 데이터를 저장할 수 있습니다.

이제 우리는 블록체인을 사용하여 많은 이점을 보았지만 언제 블록체인을 전혀 사용하지 않아야 합니까?

블록체인의 단점

  • 디지털 거래 속도 감소
    블록체인은 엄청난 양의 컴퓨팅 성능을 필요로 하므로 디지털 트랜잭션의 속도를 줄이는 경향이 있지만 밀리초 단위의 고속 트랜잭션이 필요한 경우 중앙 집중식 데이터베이스를 사용하는 것이 좋습니다.
  • 데이터 불변성
    데이터 불변성은 항상 블록체인의 가장 큰 단점 중 하나였습니다. 공급망, 금융 시스템 등을 포함하여 여러 시스템에서 이점이 있음이 분명합니다. 하지만 한번 쓴 데이터는 삭제할 수 없다는 단점이 있습니다. 지구상의 모든 사람은 프라이버시에 대한 권리가 있습니다. 그러나 동일한 사람이 블록체인 기술에서 실행되는 디지털 플랫폼을 사용하는 경우 원하지 않을 때 시스템에서 추적을 제거할 수 없습니다. 간단히 말해서, 그가 그의 흔적을 제거할 수 있는 방법은 없습니다.
  • 전문 지식이 필요합니다
    블록체인 프로젝트를 구현하고 관리하는 것은 어렵습니다. 모든 과정을 거치기 위해서는 철저한 지식이 필요합니다. 그렇기 때문에 블록체인 전문가를 양성하는 데는 많은 시간과 노력이 필요하기 때문에 블록체인 전문가나 전문가를 만나기 어렵다. 따라서 이 기사는 시작하기에 좋은 곳이며 이미 시작했다면 좋은 가이드입니다.
  • 상호 운용성
    분산 원장 문제를 고유하게 해결하기 위해 열심히 노력하는 여러 블록체인 네트워크는 서로 연관시키거나 통합하기 어렵습니다. 이것은 서로 다른 체인 간의 통신을 어렵게 만듭니다.
  • 레거시 애플리케이션 통합
    많은 기업과 애플리케이션은 여전히 ​​레거시 시스템과 아키텍처를 사용합니다. 블록체인 기술을 채택하려면 이러한 시스템에 대한 완전한 점검이 필요하며 많은 시스템에서 실현 가능하지 않습니다.

블록체인은 여전히 ​​진화하고 성숙하고 있으므로 오늘 언급한 이러한 단점이 나중에 전문가로 변하더라도 놀라지 마십시오. 암호화폐인 비트코인은 블록체인의 대표적인 사례 중 하나이며, 비트코인 ​​암호화폐와 함께 떠오르는 인기 블록체인은 이더리움 블록체인이다. 비트코인은 암호화폐에 초점을 맞추고 이더리움은 새로운 기술 플랫폼의 주요 원동력이 된 스마트 계약에 더 중점을 둡니다.

추천 자료 : 비트코인 ​​대 이더리움: 차이점은 무엇입니까?

API 구축을 시작해 봅시다

블록체인에 대한 확실한 이해를 바탕으로 이제 이더리움 블록체인을 구축하고 Node.js의 표준 API에 통합하는 방법을 살펴보겠습니다. 궁극적인 목표는 dApp과 블록체인 플랫폼이 어떻게 구축되고 있는지 잘 이해하는 것입니다.

대부분의 dApp은 유사한 아키텍처와 구조를 가지고 있습니다. 기본적으로 웹이든 모바일이든 dApp 프론트엔드와 상호작용하는 사용자가 있습니다. 이 프론트엔드는 백엔드 API와 상호작용합니다. 그런 다음 백엔드는 요청 시 공개 노드를 통해 스마트 계약 또는 블록체인과 상호 작용합니다. 이들은 Node.js 애플리케이션을 실행하거나 백엔드가 Node.js 소프트웨어를 직접 실행하여 블록체인을 사용합니다. 이러한 프로세스 사이에는 완전히 분산된 애플리케이션 또는 반 분산된 애플리케이션을 구축하도록 선택하는 것부터 분산되어야 하는 항목과 개인 키를 안전하게 저장하는 방법을 선택하는 것까지 여전히 많은 것들이 있습니다.

추천 자료 : 분산 애플리케이션 아키텍처: 백엔드, 보안 및 디자인 패턴

먼저 알아야 할 것들

이 튜토리얼에서는 이더리움 블록체인의 힘을 사용하여 음악을 저장하고 다운로드 또는 스트리밍을 위해 공유하는 분산형 뮤직 스토어 앱 의 백엔드를 구축하려고 합니다.

빌드하려는 애플리케이션의 기본 구조는 세 부분으로 구성됩니다.

  1. 이메일로 수행되는 인증 물론 앱에 암호화된 비밀번호를 추가해야 합니다.
  2. 음악 데이터와 함께 데이터 저장은 먼저 ipfs에 저장되고 저장 주소는 검색을 위해 블록체인에 저장됩니다.
  3. 검색 , 인증된 모든 사용자가 당사 플랫폼에 저장된 데이터에 액세스하고 이를 사용할 수 있습니다.

우리는 이것을 Node.js로 빌드할 것이지만 Python이나 다른 프로그래밍 언어로 빌드할 수도 있습니다. 또한 미디어 데이터를 IPFS에 저장하고 주소를 가져오고 이 주소를 저장할 함수를 작성하고 Solidity 프로그래밍 언어를 사용하여 블록체인에서 이 주소를 검색하는 방법도 알아보겠습니다.

다음은 Ethereum 및 Node.js를 구축하거나 작업할 때 사용할 수 있는 몇 가지 도구입니다.

  • 노드.js
    첫 번째 요구 사항은 노드 애플리케이션입니다. Node.js 앱을 빌드하려고 하므로 컴파일러가 필요합니다. Node.js가 설치되어 있는지 확인하고 최신 장기 지원 바이너리( LTS )를 다운로드하세요.
  • 트러플 스위트
    Truffle은 계약 개발 및 테스트 환경이자 이더리움 블록체인의 자산 파이프라인입니다. 스크립트 컴파일, 파이프라이닝 및 실행을 위한 환경을 제공합니다. 블록체인 개발에 대해 이야기할 때 Truffle은 인기 있는 곳입니다. Truffle Suite의 Truffle Suite: 스마트 계약을 위한 달콤한 도구를 확인하십시오.
  • 가나슈 CLI
    Truffle과 함께 잘 작동하는 또 다른 도구는 Ganache-CLI입니다. Truffle Suite 팀에서 구축 및 유지 관리합니다. 빌드 및 컴파일 후 블록체인 앱을 개발 및 실행하고 사용할 스마트 계약을 배포하려면 에뮬레이터가 필요합니다. Ganache를 사용하면 거래 비용, 재활용 가능한 계정 등에 실제 돈을 사용하지 않고도 에뮬레이터에서 계약을 더 쉽게 배포할 수 있습니다. Ganache CLI 및 Ganache에서 Ganache CLI에 대해 자세히 알아보십시오.
  • 리믹스
    Remix는 Ganache의 대안과 비슷하지만 Ethereum 스마트 계약의 배포 및 테스트를 탐색하는 데 도움이 되는 GUI도 함께 제공됩니다. Remix — Ethereum IDE 및 커뮤니티에서 이에 대해 자세히 알아볼 수 있습니다. https://remix.ethereum.org를 방문하여 GUI를 사용하여 스마트 계약을 작성하고 배포하기만 하면 됩니다.
  • 웹3
    Web3는 이더리움 노드와 상호 작용할 수 있는 라이브러리 모음입니다. HTTP, IPC 또는 웹 소켓을 통한 계약의 로컬 또는 원격 노드일 수 있습니다. Web3.js 소개 · 이더리움 블록체인 개발자 단기집중과정은 Web3에 대해 조금 배울 수 있는 좋은 장소입니다.
  • IPFS
    dApp 구축에 사용되는 핵심 프로토콜입니다. IPFS( InterPlanetary File System )는 분산 파일 시스템에서 데이터를 저장하고 공유하기 위한 프로토콜 및 P2P 네트워크입니다. IPFS Powers Distributed Web은 IPFS와 일반적으로 사용되는 방법에 대해 자세히 설명합니다.

처음부터 백엔드 API 만들기

따라서 먼저 사용할 백엔드를 생성해야 하며 Node.js를 사용하고 있습니다. 새로운 Node.js API를 생성하고자 할 때 가장 먼저 할 일은 npm 패키지를 초기화하는 것입니다. 아시다시피 npm은 Node Package Manager 의 약자이며 Node.js 바이너리와 함께 미리 패키징되어 제공됩니다. 그래서 우리는 새 폴더를 만들고 "blockchain-music" 이라고 부릅니다. 해당 폴더 디렉터리에서 터미널을 열고 다음 명령을 실행합니다.

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

그러면 package.json 파일로 프로젝트가 시작되고 모든 프롬프트에 yes 로 응답합니다. 그런 다음 API에서 routes 기능을 작성하기 위한 server.js 파일과 route.js 파일도 생성합니다.

이 모든 작업이 끝나면 빌드를 쉽고 간단하게 만드는 데 필요한 패키지를 설치해야 합니다. 이 프로세스는 연속 프로세스입니다. 즉, 프로젝트 개발 중에 언제든지 패키지를 설치할 수 있습니다.

지금 당장 필요한 가장 중요한 것을 설치합시다.

  • 익스프레스.js
  • @트러플/계약
  • 트러플.js
  • 웹3.js
  • 도텐브
  • short-id
  • 몽고DB
  • 노드몬

또한 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" } }

그런 다음 nodemon 서버를 사용하기 위해 package.json 파일에 시작 스크립트를 추가하여 변경할 때마다 서버 자체를 다시 시작하고 노드 서버를 직접 사용하는 빌드 스크립트는 다음과 같이 보일 수 있습니다.

 { "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 는 구성 요소의 쉬운 결합 및 분리가 깨끗해야 하므로 경로 및 기타 기능은 route.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" 임). 그런 다음 함수를 호출하고 경로 파일 에서 가져옵니다. 마지막으로 포트 8082 에서 시도된 연결을 수신합니다.

server.js 파일은 애플리케이션을 시작하기 위한 기본적인 것입니다. route.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

그런 다음 route.js 파일에 경로 기능을 작성합니다. 우리는 데이터베이스 저장 및 검색 기능을 활용하고 다른 파일이나 폴더로 가져올 수 있도록 파일 끝에 경로 기능을 내보내는지 확인합니다.

 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 함수 내에는 appdb 매개변수 내에서 호출되는 다른 많은 함수가 있습니다. 이는 사용자가 URL에서 엔드포인트를 지정할 수 있도록 하는 API 엔드포인트 기능입니다. 궁극적으로 우리는 이러한 기능 중 하나를 선택하여 실행하고 들어오는 요청에 대한 응답으로 결과를 제공합니다.

네 가지 주요 엔드포인트 기능이 있습니다.

  1. get : 레코드 작업 읽기용
  2. post : 레코드 작업 생성용
  3. put : 레코드 작업 업데이트용
  4. delete : 레코드 작업 삭제용

routes 함수에서는 getpost 작업을 사용했습니다. 등록, 로그인 및 업로드 작업에 post 를 사용하고 데이터 작업에 액세스하기 get 을 사용합니다. 이에 대한 조금 더 자세한 설명은 Jamie Corkhill의 "How To Get Started With Node: An Introduction To APIs, HTTP And ES6+ JavaScript" 기사를 참조하십시오.

위의 코드에서 레지스터 경로와 같은 일부 데이터베이스 작업도 볼 수 있습니다. 새 사용자의 이메일을 db.createa 로 저장하고 로그인 기능에서 db.findOne 으로 이메일을 확인했습니다. 이제 모든 작업을 수행하기 전에 db.collection 메서드를 사용하여 컬렉션 또는 테이블의 이름을 지정해야 합니다. 그것이 바로 다음에 다룰 내용입니다.

참고 : MongoDB의 데이터베이스 작업에 대해 자세히 알아보려면 mongo Shell Methods 설명서를 확인하세요.

Solidity로 간단한 블록체인 스마트 계약 구축

이제 우리는 단순히 데이터를 저장하고 필요할 때 검색하기 위해 Solidity(스마트 계약이 작성된 언어)로 블록체인 계약을 작성할 것입니다. 저장하려는 데이터는 음악 파일 데이터입니다. 즉, 음악을 IPFS에 업로드한 다음 버퍼 주소를 블록체인에 저장해야 합니다.

먼저 계약 폴더에 새 파일을 만들고 이름을 Inbox.sol 로 지정합니다. 스마트 컨트랙트를 작성하기 위해서는 솔리디티를 잘 이해하는 것이 좋지만, 자바스크립트와 비슷해서 어렵지 않습니다.

참고 : 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; } }

우리의 계약에는 두 가지 주요 기능이 있습니다: sendIPFSgetHash 기능. 함수에 대해 이야기하기 전에 먼저 Inbox 라는 계약을 정의해야 함을 알 수 있습니다. 이 클래스 내부에는 ipfsInbox 객체에 사용된 구조가 있습니다(첫 번째 이벤트, 그 다음 수정자).

구조와 이벤트를 정의한 후 constructor 함수를 호출하여 계약을 초기화해야 합니다. 그런 다음 세 가지 기능을 정의했습니다. (테스트 결과 테스트에서는 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 와 같은 에뮬레이터를 사용하여 시스템에 배포된 노드이지만 원격 노드는 ropsten 또는 rinkeby 와 같은 온라인 수도꼭지/플랫폼에 배포된 노드입니다. 더 자세히 알아보려면 Truffle 및 Ropsten을 사용하여 스마트 계약을 배포하는 ropsten 5분 가이드에 대한 자습서를 따르거나 트러플 지갑 공급자를 사용하고 스마트 계약을 배포하는 더 쉬운 방법을 통해 배포할 수 있습니다.

이 튜토리얼에서는 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 truffle-contract 패키지를 기반으로 계약을 작성하고 계약 공급자를 지금까지 초기화되었을 Web3 인스턴스 공급자로 설정합니다.

그런 다음 web3.eth.getAccounts 로 계정을 얻습니다. 개발 단계에서는 아직 실행 중인 ganache-cli 에 사용할 계약 주소를 제공하도록 요청하는 계약 클래스의 배포된 함수를 호출합니다. 그러나 이미 계약을 원격 노드에 배포했다면 주소를 인수로 입력하는 함수를 호출합니다. 샘플 함수는 위 코드에서 정의된 lms 변수 아래에 주석 처리되어 있습니다. 그런 다음 앱 인스턴스, 데이터베이스 인스턴스, 계약 인스턴스( lms ) 및 계정 데이터를 인수로 입력하는 routes 함수를 호출합니다. 마지막으로 포트 8082 에서 요청을 수신합니다.

또한 API에서 데이터베이스로 사용하고 있기 때문에 지금쯤 MongoDB 패키지를 설치했어야 합니다. 그런 다음에는 계약에 정의된 방법을 사용하여 음악 데이터 저장 및 검색과 같은 작업을 수행하는 경로 페이지로 이동합니다.

결국 route.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