이더리움 Dapp 개발 맛보기(feat. truffle)

Bobby·2021년 10월 28일
3
post-thumbnail

Dapp(Decentralized Application) 탈중앙화 어플리케이션..처음에 들을 때는 이해가 되지 않았었다. truffle은 뭔지, Solidity는 뭔지, Ganache는 뭔지,, 앱에 블록체인을 연동하는 것은 또 뭔지.. 공부하다 보니 웹 개발과 크게 다르지 않다. 큰 차이점이 있다면 데이터를 어디에 저장할 것인가? 이다. 기존의 중앙화 방식은 한 기업에서 데이터를 관리 했다면, Dapp에서는 분산 저장을 한다는 것이다. 블록체인 기술을 공부하면 쉽게 이해할 수 있다!

  • 다음과 같이 자바 웹 개발과 비교해 볼 수 있다.
자바 웹 개발이더리움 컨트랙트 개발
언어JavaSolidity
프레임워크SpringTruffle
개발환경Tomcat, Weblogic, ...Ganache, geth, ...
운영환경Centralized : 기업이 관리하는 데이터센터Decentralized : 분산공유 네트워크
Tomcat, Weblogic, ...누구나 참여 가능한 이더리움 네트워크에 참여한 노드들이
RDBMS, NOSQL, ...데이터를 공유

Dapp 개발.. 찍먹 한 번 해보자.


1. 준비물

npm install truffle -g


2. Truffle 시작하기

  • truffle init 명령어를 통해 기본 형식을 쉽게 구성할 수 있다.
truffle init

  • vs code로 열어보면 다음과 같은 파일들이 생성 된다.

  • contracts 디렉토리 : solidity를 이용한 스마트 컨트랙트 디렉토리

    • Migrations.sol : 컨트랙의 소유자를 지정하는 컨트랙트
  • migrations 디렉토리 : 배포 스크립트 디렉토리

    • {number}_{name}.js 형식
  • test 디렉토리 : 테스트 스트립트 디렉토리

  • truffle-config.js : 트러플 설정

    • 기본적인 설정들이 주석 처리 되어 있어서 쉽게 확인 할 수 있다.
module.exports = {

  // 네트워크 설정 (로컬, 테스트넷, 메인넷, ... 등등을 설정 한다.)
  networks: {
    dev: { // 이름은 아무거나 사용 가능
      host: "127.0.0.1",     // Localhost
      port: 8545,            // Standard Ethereum port
      network_id: "*",       // Any network
     },
  },

  // 컴파일러 설정
  compilers: {
    solc: {
      version: "0.8.9", // 컴파일러 버전
    }
  },
};

3. 컨트랙트 작성

  • 공부시작의 국룰 HelloWorld를 만들어보자.
  • contracts 안에 만들자.

HelloWorld.sol

  • 파일 맨 위에 SPDX 라이센스를 명시 하도록 한다.
  • 라이센스를 명시하지 않으려면 이렇게 적으면 된다.
	// SPDX-License-Identifier: UNLICENSED 
  • 자바 + 자바스크립트 같은 느낌이다ㅎㅎ
// SPDX-License-Identifier: UNLICENSED 

pragma solidity ^0.8.9; // 컴파일러 버전 명시

// 컨트랙트 명시
contract HelloWorld {
    string public greeting; // 문자열 타입 변수 선언

    // 생성자를 통해 값을 초기화 한다.
    constructor(string memory _greeting) { 
        greeting = _greeting;
    }
    
    // setter 함수를 통해 값을 변경 할 수있다.
    function setGreeting(string memory _greeting) public{
        greeting = _greeting;
        
    }
    
    // 변수값 출력
    function say() public view returns(string memory){
        return greeting;
    }
}

4. 배포 스크립트 작성

  • HelloWorld.sol 파일의 생성자를 통해 초기화 하도록 작성 했으므로 값을 전달해 주어야 한다.
const HelloWorld = artifacts.require("HelloWorld");

module.exports = function (deployer) {
  // 첫번째 파라미터는 배포할 솔리디티 파일을 명시
  // 두번째 파라미터는 HelloWorld.sol의 생성자의 매개변수에 전달한다. 
  deployer.deploy(HelloWorld, "Hello World!!");
};

5. Ganache에 배포하기

  • 로컬환경에 이더리움 네트워크를 구성해준다.

ganache-cli 실행

  • 테스트를 위한 100ETH를 가진 계정 10개를 자동으로 생성 해준다.
  • 8545 포트를 기본으로 사용한다.

컴파일

  • truffle compile 명령어를 통해 컴파일 한다. (또는 migrate 시 자동 컴파일 된다.)
  • 컴파일 후에 build/contracts 디렉토리 아래에 json 파일이 생성된다.
  • json파일에는 컨트랙에 대한 정보들이 들어있고 내부에 있는 bytecode가 블록체인에 올라간다.

배포

  • 네트워크가 구성되었으니 위에서 작성한 컨트랙을 배포해보자.
  • truffle migrate 명령어를 사용한다.
  • --network 옵션에 위에서 설정했던 네트워크를 선택한다.
	fruffle migrate --network dev

  • 두가지 컨트랙트가 배포 된 것을 확인 할 수 있다.
  • ganache-cli 실행 시 생성되었던 10개의 계정 중 0번 계정을 사용해서 배포되었다.
  • 배포 시에는 이더리움이 필요하다! 이더리움이 없으면 배포 불가능!!

6. 스마트 컨트랙트 사용하기

  • truffle console에서 배포 된 컨트랙을 사용해보자.
	truffle console --network dev // 네트워크 이름 지정
  • {contract}.deployed() 함수를 통해 배포된 컨트랙에 접근할 수 있다.
  • setGreeting(), say() 함수를 사용해 보자.

테스트 코드 작성

  • 매번 console 에서 함수 하나하나 실행 해보는 것은 오바오바다.
  • 테스트 코드를 작성하여 컨트랙트를 테스트 해보자.

test_helloworld.js

const helloWorld = artifacts.require("HelloWorld"); 

contract("HelloWorld", function(accounts){

    // HelloWorld 컨트랙트에 접근
    before(async () =>{
        this.instance = await helloWorld.deployed();
    });

    // say() 테스트
    it("should be initialized with correct value", async () => {
        const greeting = await this.instance.greeting();

        assert.equal(greeting, "Hello World!!", "Wrong initialized value!");
    });

    // setGreeting() 테스트
    it("should change the greeting", async () => {
        const val = "Hello, Ethereum!";

        // 상태를 바꾸는 함수는 계정이 필요하다
        await this.instance.setGreeting(val, {from: accounts[0]});
        const greeting = await this.instance.say();

        assert.equal(greeting, val, "dose not change the value!");
    });

});

테스트

  • truffle test 명령어를 통해 테스트 스크립트를 실행 한다.
  • 성공
  • 실패

7. testnet에 배포하기

  • 이더리움 네트워크(메인넷)이 아닌 테스트용 이더리움 네트워크를 운영하는 곳이 여러군데 있다.
    • Ropsten, Kovan, Rinkeby, 등등..
  • Ropsten에 배포해보자.

MetaMask 설치

  • 컨트랙트를 배포, 사용하기 위해서는 계정(지갑)이 필요하다.
  • ganache에 배포할 때는 ganache가 실행 될때 생성 된 계정을 사용했었지만 테스트넷에 배포하기 위해서 계정을 생성해야 한다.
  • MetaMask는 계정을 생성하고 관리하는 툴이다. (chrome extension)
  • 여러 네트워크가 있다.

  • 보기확장을 눌러 큰 화면으로 볼 수 있다!

테스트용 이더 받기

  • Ropsten 네트워크에 배포하려면 이더가 필요하다.

노드에 프로젝트 만들기

  • 테스트넷을 구성하는 여러 노드들 중 infura 노드를 사용한다.
  • https://infura.io/
  • 로그인 후 프로젝트 생성

  • 프로젝트를 생성하면 project id 가 생성 된다.

네트워크 추가

  • infura 노드에 접근하기 위해 HDWalletProvider이 필요하다.
  npm init
  npm install @truffle/hdwallet-provider

  • truffle-config.js 에 Ropsten 네트워크를 추가하자.
  • YOUR-PROJECT-ID란에 위에서 생성한 project id를 적는다.
truffle-config.js
const HDWalletProvider = require('@truffle/hdwallet-provider');

const fs = require('fs');
const mnemonic = fs.readFileSync(".secret").toString().trim(); // private 키 불러오기

module.exports = {

  networks: {
  
  ...
    
    ropsten: {
      provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
      network_id: 3,       // Ropsten's id
      gas: 5500000,        // Ropsten has a lower block limit than mainnet
      confirmations: 2,    // # of confs to wait between deployments. (default: 0)
      timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50)
      skipDryRun: true     // Skip dry run before migrations? (default: false for public nets )
    },
  },

  ...
  
};
  • 메타마스크 계정의 private 키는 계정세부정보 -> 비공개키 내보내기를 통해 가져올 수있다.
  • 메타마스크 계정의 private 키를 .secret 파일 안에 적어서 불러오도록 한다. (gitignore 필수!)

배포하기

  • 두근두근
  truffle migrate --network ropsten
  • 배포 성공!

  • 소중한 이더가 소모되었다..

  • ropsten 이더스캔으로 가서 확인할 수 있다.
    https://ropsten.etherscan.io/

  • HelloWorld 의 해시값으로 검색!!

컨트랙트를 써보자!

  • truffle console을 이용
  • setGreeting 함수는 값을 변경하므로 트랜잭션을 생성한다.

8. Truffle Boxes

  • 지금까지는 솔리디티와 트러플을 이용해 컨트랙트 개발을 했다. 이제 클라이언트에서 이 컨트랙트를 사용하려면 어떻게 해야할까?
  • 클라이언트에서 이더리움 노드를 쉽게 사용하기 위해 Web3.js 라이브러리를 사용한다.
  • Truffle Boxes는 다양한 환경에서 사용할 수 있도록 템플릿을 제공한다.
  • truffle + webpack + react 템플릿을 써보자.
	npx truffle unbox react
  • 이러한 기본 구성이 생기고 개발을 시작 할 수 있다.

  • App.js 에서 프로그램이 실행 될 때 SimpleStorage 컨트랙트의 set 함수를 호출하도록 되어있다.

  • truffle-config.js 를 살펴보자.

const path = require("path");

module.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
  // to customize your Truffle configuration!
  contracts_build_directory: path.join(__dirname, "client/src/contracts"), // 빌드 디렉토리
  networks: {
    develop: {
      host: "127.0.0.1",     
      port: 8545,          
      network_id: "*",  
    }
  }
};
  • 컴파일 시 지정된 위치에 json 파일이 생성된다. (client/src/contracts)
  • 로컬에 배포를 해보자.
	truffle migrate --network develop

  • client 디렉토리 안에서 react 실행
	npm run start

  • 그러면 메타마스크에서 다음과 같이 연결할 계정을 선택하라는 창이 뜬다.

  • 실행
  • 컨트랙트에 5가 잘 저장되어 있는지 확인해보자.

9. 참고


코드

profile
물흐르듯 개발하다 대박나기

0개의 댓글