블로그 아이덴티티블로그
글 개요
2019년 01월 10일 20:20다른 분야 공부/블록체인
본문

이 글은 Hexo 기반의 블로그에서 옮겨온 글이며, 원본 글은 2018년 7월 25일에 작성되었다.

이번 학교의 DPNM 연구실에서 여름 방학에 블록체인 관련 공부를 하고 있는데, 간단한 이더리움 활용 과제가 나와 수행하던 도중 난데없이 사설 네트워크와 "genesis"라는 단어가 나와 그에 대해 간단히 정리해본다.

아래의 글은 이미 서버에 이더리움이 설치되어 geth 명령어를 실행할 수 있다고 가정하고 작성하였다. 작성 당시 geth 버전은 1.8.12-stable이다.

이더리움 사설 네트워크와 Genesis 파일

이더리움은 사설 이더리움 네트워크를 만들 수 있게 되어 있는데, genesis 파일이란 이 개인 네트워크의 초기 설정이라 할 수 있다. "the genesis"는 발생, 창시 등의 뜻이 있다고 한다. 이더리움뿐 아니라, 다른 암호 화폐에서도 최초의 블록을 "Genesis block" 이라고 한다고 한다. 뭐... 그런 느낌이다. Genesis의 표기에 대해서는 첫 글자가 대문자이면 좀 더 멋져 보이므로, 내 맘대로 첫 글자를 대문자로 하기로 한다.

Genesis 파일 구조

Genesis 파일은 JSON 형식으로 네트워크 설정을 저장하고, 이 파일을 먼저 만들어야 나만의 이더리움 네트워크를 가동할 수 있다. 일단 그 태를 보면 아래와 같다.

{
    "config" : {
        "chainId"        : 0,
        "homesteadBlock" : 0,
        "eip155Block"    : 0,
        "eip158Block"    : 0
    },
    "alloc"      : {},
    "coinbase"   : "0x0000000000000000000000000000000000000000",
    "difficulty" : "0x10000",
    "extraData"  : "",
    "gasLimit"   : "0xffffff",
    "nonce"      : "0x0000000000000000",
    "mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "timestamp"  : "0x00000000"
}

이제 위에서부터 하나하나 말해보자면...

  • config
    새로 만들 개인 블록체인 네트워크의 설정을 담당하는 오브젝트이다. 이 오브젝트 이외의 설정값들은 대망의 첫 블록에 관한 것이다.
    • chainId : 현재 블록체인의 ID이다. 리플레이 공격을 막기 위해 사용된다. 그저 이더리움 네트워크를 공부할 때는 예약된 ID가 아닌 것으로 아무렇게나 적어도 괜찮다.
    • homesteadBlock : 이더리움은 네트워크의 발전 단계에 따라 버전을 미리 구상해 놓았다. 그 각 단계에 올림픽, 프론티어, 홈스테드 등 여러가지 코드 네임을 붙여놓았는데, 그 중 처음으로 "안정" 단계에 해당하는 단계가 바로 홈스테드 이다. 그 홈스테드 단계가 시작되는 블록의 ID를 적으면 된다. 그저 이더리움 네트워크를 공부할 때는 처음부터 홈스테드 단계로 들어가서 살펴보게 되므로, 0이라고 적으면 된다.
    • eip155Block : EIP는 Ethereum Improvement Proposal 의 약자로, 이더리움 네트워크를 개선하는 여러 제안들을 말한다. 그 중 리플레이 공격 방어에 관한 155번째 제안이 적용이 시작되는 블록 ID를 적으면 된다. 그저 이더리움 네트워크를 공부할 때는 처음부터 이 보안을 적용할 것이므로, 0이라고 적으면 된다.
  • alloc : 네트워크 초기에 특정한 계좌에 특정한 액수의 코인을 지급할 수 있다. 암호 화폐의 초기 부흥을 위해서 화폐를 사전 판매하는 경우가 있는데, 이 때 쓰일 수 있다. 예를 들면, 아래와 같다.
    "alloc" : {
        "19yadv8h2ebalnlrqszzlph54lci6d6pdvht5abi" : { "balance" : 10000 },
        "haq72tf9ldqzyavp3slocx55jb00hvldm4ai9iln" : { "balance" : 10000 }
    }

    이 경우 저 두 계좌로 각각 10,000 코인을 지급한 것이 된다. 그저 이더리움 네트워크를 공부할 때는 {}로 비워놔도 좋다.

  • coinbase : 지금 설정하고 있는 이 첫 블록의 채굴 보상이 돌아갈 계좌 주소이다. 이더리움에서 주소는 160비트로 이루어져 있다. 그저 이더리움 네트워크를 공부할 때는 0으로 해놔도 좋다.
  • difficulty : 첫 블록의 논스 값 범위의 난이도이다. 값이 낮을 수록 채굴이 쉬워진다. 첫 블록 이후에는 이전 블록의 difficultytimestamp를 참고하여 이더리움 소프트웨어가 자동으로 difficulty를 계산할 것이다. 그저 이더리움 네트워크를 공부하는 사람은 거대한 채굴 능력이 없기 때문에, 난이도를 낮게 설정하여 쉽게 채굴하도록 하는 것이 좋으므로, 0x10000 정도로 설정해놓는 것이 좋다.
  • extraData : 어떠한 데이터를 블록체인에 영구적으로 보존하기 위해 존재하는 32비트의 빈 공간이다. 보통 ""로 비워둔다.
  • gasLimit : 이더리움 거래 수수료 단위를 Gas 라 하는데, 이더리움 ETH 자체는 시장 가치의 변동폭이 매우 크므로, 그 대신 안정적으로 트랜잭션 비용을 지불하기 위해 만들어진 단위이다. 거래 별 거래 수수료는 해당 거래를 처리하기 위해 필요한 컴퓨터 연산의 정도로 책정된다. 따라서 한 블럭의 전체 거래 수수료 합이 매우 크다는 건 한 블럭을 처리하는데 엄청난 연산이 필요하다는 말이 된다. 그래서 한 블럭에 포함된 거래 수수료에 한도를 두어 한 블럭을 연산하는데 시간이 많이 걸리지 않도록 한다. 그저 이더리움 네트워크를 공부하는 사람은 굳이 여기에 제한을 둘 필요가 없으므로, 0xffffff로 설정해놓을 수 있다.
  • nonce : 64비트의 상수으로, mixhash와 합쳐져서 작업을 증명하는 데 사용된다. 블록 채굴자들은 이 nonce 값을 증가시켜가며 정답 범위에 들어가는 nonce값을 순차적으로 찾아나설 것이다. 그저 이더리움 네트워크를 공부할 때는 0으로 설정해놓아도 좋다.
  • mixhash : PoW의 핵심이 되는 값 중 하나로, 256비트의 해시값이며 nonce와 결합하여 작업을 증명하게 된다. 그저 이더리움 네트워크를 공부할 때는 그냥 간편히 0으로 설정해놓으면 된다.
  • parentHash : 이전 블록의 해시값이다. 이전 블록의 mixhash가 아니다. 이전 블록 전체에 관한 해시값이다. 첫 블록(Genesis block)은 이전 블록이란 게 없으므로, (parent...가 없으므로?) 0으로 설정해놓으면 된다.
  • timestamp : 블록이 받아들여진 시간을 유닉스 시각으로 나타낸다. 이 값은 블록의 순서를 검증할 때도 사용된다. 그저 이더리움 네트워크를 공부하는 사람은 크게 신경쓸 것 없이 0으로 설정해놓으면 된다.
위의 예시에 적히지 않은 설정 파라미터도 있고 생략가능한 파라미터도 있지만, 그저 이더리움 네트워크를 공부하는 입장에서 적당하게 적어놓았다.

Genesis 파일 만들고 개인 네트워크 시작하기

  1. 먼저, 작업 디렉토리를 만들었다.

    ~ $ mkdir tessup #테스트 서버 (...)
    ~ $ cd tessup
  2. 위의 내용을 참고하여 아래의 내용으로 genesis.json 파일을 만들어 작업 디렉토리 안에 저장했다.

    {
    "config" : {
    "chainId" : 2010010611011415,
    "homesteadBlock" : 0,
    "eip155Block" : 0,
    "eip158Block" : 0
    },
    "alloc" : {},
    "coinbase" : "0x0000000000000000000000000000000000000000",
    "difficulty" : "0x20000",
    "extraData" : "",
    "gasLimit" : "0x300000",
    "nonce" : "0x0000000000000000",
    "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "timestamp" : "0x00000000"
    }
  3. 작업 디렉토리 안에 블록이 저장될 디렉토리로 data 디렉토리를 생성했다.

    ~/tessup $ mkdir data
  4. bootnode 명령어를 사용하여 부트 노드를 시작했다. bootnode는 부트스트랩 노드를 구현한 소프트웨어이다. 여기서 부트스트랩 노드는 일종의 시동 노드로, 다른 노드들의 목록을 저장하여 네트워크를 유지하는 노드를 말한다.

    ~/tessup $ bootnode -genkey=tessup.key
    ~/tessup $ bootnode -nodekey=tessup.key

    개인적으로는 위 마지막 명령을 백그라운드에서 관리하기 위해 아래와 같이 pm2라는 패키지를 활용했다. pm2NPM이 설치되어 있는 상황에서 sudo npm i pm2 -g 명령을 통해 설치할 수 있다.

    ~/tessup $ pm2 start bootnode -- -nodekey=tessup.key

    위 명령을 다 실행하면 내 부트스트랩 노드의 주소가 콘솔에 (pm2의 경우, pm2 log bootnode 명령어를 입력하면) 나타남을 볼 수 있다.

  5. geth 명령어를 사용하여 네트워크에 시동을 건다.

    ~/tessup $ geth --datadir="./data/" init genesis.json
    ~/tessup $ geth --bootnodes="(enode://로 시작하는 노드 주소)" --datadir="./data/" --networkid=(genesis.json 파일에 적었던 chainId) console

    이 과정이 성공적으로 완료되었다면 Geth Javascript Console이 나타남을 볼 수 있다.

  6. 노드 정보를 확인해본다.
    일이 다 끝나면 아래와 같이 자바스크립트 콘솔에 입력하여 내가 실행 중인 노드 정보를 알아볼 수 있다.

    > admin.nodeInfo

    여기서 내가 설정한 Genesis 파일과 동일하게 돌아가는지, 나의 부트스트랩 노드와 연결했는지 확인해보자.

    확인을 끝냈다면, 이제부터 나만의 네트워크를 즐겨보자!

    나의 이더리움 네트워크에서 해볼 수 있는 예시 활동은 이 글에 적어놓았다.

문제 해결

유효하지 않은 IP 주소 문제

Fatal: Error starting protocol stack: bad bootstrap/fallback node "enode://...@[::]:30301" (invalid IP (multicast/unspecified))

이 문제는 bootnode의 output을 그대로 가져다 붙여서 geth를 실행했을 때 나타나는 문제인데, bootnode에서 제공하는 주소 끝의 IP (0.0.0.0 혹은 ::)는 받는 IP의 종류로, 외부에서 들어오는 접속을 IP 가리지 않고 받는다는 뜻이다. 여기서 의도하는 것은 어디로 접속해야 할 지가 중요하므로, 0.0.0.0 혹은 :: 대신 아까 bootnode를 실행한 서버의 IP, 혹여 같은 서버라면 127.0.0.1을 적어주자. 30301 포트가 막혀 있다면 꼭 포트를 열어주자.

계속 뭔가가 나오는 문제

INFO [07-26|12:57:49.005] Imported new state entries               count=1152 elapsed=4.020ms   processed=99887672 pending=21784 retry=2   duplicate=0 unexpected=192
INFO [07-26|12:57:49.400] Imported new state entries count=953 elapsed=7.046ms processed=99888625 pending=21836 retry=0 duplicate=0 unexpected=192

아무것도 하지 않았는데 무언가 계속 통신이 이루어지는 듯한, 위와 같은 로그가 1초에 한 번 이상의 빈도로 반복적으로 나타난다면, 혹시 위의 geth 실행 과정에서 지정한 --datadir 옵션이 잘못되어있을 수 있다. 꼭 새로운 전용 작업 디렉토리와 새로운 데이터 디렉토리를 만들고, 그 디렉토리를 그대로 적어주자.

참고한 글

다들 필력이 대단하다. 나는 쨉도 안 된다.


가장 위로