[연재] bootnode로 ethereum 네트웍 동기화하기

bootnode로 ethereum 네트웍 동기화하기

앞 연재에서는 개별 node의 enode 주소를 bootnodes 에 할당하여 네트웍을 구성하였다.

하지만 노드 수가 늘어나고, 네트웍이 점차 커지면 이렇게 노드를 연결할 순 없다. 뭔가 중앙에서 전체 노드들을 연결해주는 무엇인가가 필요한데, 이더리움에서는 이를 bootnode라고 한다.

이 장에서는 bootnode가 무엇이며, 어떻게 사용하는지 살펴보겠다.


bootnode란 무엇인가?

bootnode 소스코드를 보면 다음과 같이 나와있다.

bootnode runs a bootstrap node for the Ethereum Discovery Protocol.

좀 거칠게 우리말로 바꿔보면 "부트노드는 이더리움 식별 프로토콜을 실행하는 부트스트립 노드"다. 

좀 풀어서 얘기하자면 특정 이더리움 네트웍에 참여하고자 하는 노드들을 서로 연결시켜 주는 프로그램 정도가 아닐까 한다.

실생활을 예를 들자면 부트노드는 중매쟁이 또는 부동산 중개업소, 잡코리아 등이 가장 비슷한 예가 아닐까 한다. 같은 목적을 가진 사람들을 서로 엮어주니 말이다.

부트노드를 그림으로 표현하면 아래와 같다. 예를 들어 node4가 bootnode에 붙으면 bootnode는 현재 붙어 있는 노드 정보(node1...node3)를 node4에 알려 준다.

node4는 이 정보에 바탕해서 다른 노드들과 통신하며 p2p 망을 이룬다. 아울러 node4는 수시로 bootnode에 붙어 이 정보를 갱신 받는다.

즉 bootnode로 부터 정기적으로 node 목록을 받고, 이 목록에 기초해서 block 정보를 동기화 한다.



bootnode는 geth를 설치하면 함께 설치되므로 따로 설치할 필요는 없다.

먼저 아래 테스트를 위해 설치된 geth 버전은 다음과 같다.

 $ geth version
Geth
Version: 1.8.6-stable
Git Commit: 12683feca7483f0b0bf425c3c520e2724f69f2aa
Architecture: amd64
Protocol Versions: [63 62]
Network Id: 1
Go Version: go1.10
Operating System: linux
GOPATH=
GOROOT=/usr/lib/go-1.10


bootnode 키 생성

bootnode를 실행하기 위해서는 제일 먼저 key를 생성해야 한다.

아래는 "부트노드 식별자인 주소를 만들기 위한 키를 만들어 이를 boot.key 라는 파일에 저장하라" 라는 명령어다.
 $ bootnode -genkey boot.key
$ cat boot.key
36d3684b765b2b0d69afbeba61f46dad6b0cb84dc10e71228601b6d9b3c82bb6


bootnode 실행

키를 만들었으면 이 키를 가지고 bootnode를 실행하자.

 $ bootnode -nodekey boot.key -verbosity 9
INFO [07-05|11:32:21] UDP listener up                          self=enode://50dc...중략...7336326ae12@[::]:30301

bootnode를 실행하면 bootnode 주소가  콘솔에 나온다.

enode로  시작하는 이 부분이 바로 해당 노드의 이더리움 주소다.

enode://50dc...중략...ae12@[::]:30301

여기서 [::] 부분에 서버 IP 주소를 넣으면 된다. 도메인 주소는 안된다.

enode://50dc...중략...ae12@127.0.0.1:30301


이제 이 전용 이더리움 망(private network)에 붙을 모든 노드들은 이 주소를 부트노드로 해서 접속하면 된다. 방법은 bootnodes 옵션에 이 주소를 추가하면 된다. bootnode가 여러 개일 경우 , 로 구분한다.

기본 포트는 30301이고, 만약 포트를 바꾸고 싶다면 -addr :30310 과 같이 -addr 옵션으로 변경할 수 있다.

-verbosity 9로 준 것은 개별 노드와 정보를 ping/pong 하는 로그를 확인하기 위한 것으로 실 운용에서는 없어도 된다.


노드 구성

이제 노드를 구성해보자.

2개 노드를 만들어 bootnode에 어떻게 붙는지, 각각이 어떻게 마이닝 해나가는지 확인해보도록 하자.

만들려는 전체 디렉토리 구조는 다음과 같다.

 $ tree -Ld 2 
.
├── node1
│   ├── geth
│   └── keystore
└── node2
    ├── geth
    └── keystore


genesis 파일은 앞 연재에서 만든 것을 chainId만 바꾸어서 그대로 사용하겠다.

{
    "config": {
        "chainId": 950,
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
    },
    "difficulty": "400",
    "gasLimit": "2100000",
    "alloc": {}
}


1번 노드 구성


1. 제네시스 블럭 생성

제일 먼저 아래 명령어로 최초 블럭, 제네시스 블럭을 생성한다.

 $ geth --datadir ./node1 init genesis.json


2. 계정 생성

두 번째로 채굴하기 위한 etherbase로 쓸 계정을 만든다.

 $ geth --datadir ./node1 account new

계정이 하나면 자동으로 etherbase로 설정한다. 로그에서 이 내용을 확인할 수 있다.



3. 노드 실행

이제 노드를 실행해서 bootnode가 해당 노드와 통신하는지 확인해보자.

geth --datadir node1 \
     --syncmode 'full' --port 30311 \
     --bootnodes 'enode://50dc1ae7b7b5b3b8cdb843dec53e43b677fca13afd2e46c04a1c1a83aa92fbc30f07a7495bae8a3a1deb6e44e6d36f5b3f83d90efb34bef0c118d7336326ae12@127.0.0.1:30301' \
     --networkid 950 --gasprice '1' console

앞에서도 얘기했지만, bootnodes 에 bootnode 주소를 넣어주면 된다. bootnode 주소는 환경마다 다를 것이다.

노드를 실행하면 bootnode와 아래와 같이 Ping/Pong 하며 서로 정보를 주고 받는 것을 볼 수 있다.

node1은 30311 포트에서 실행되기 때문에 나중에 여러 노드가 붙을 때는 포트 번호가 30311인 것으로 식별하면 된다.



4. 마이닝

자 마지막으로 마이닝을 해보자.

노드 콘솔 창에서 다음과 같이 입력하자.

> miner.start(1)

그러면 아래와 같이 마이닝이 진행되며 현재로서는 빈 블럭이 만들어질 것이다.



2번 노드 구성

2번 노드도 1번 노드와 동일한 순서로 구성한다.


1. 제네시스 블럭 생성

1번 노드와 동일하다.


2. 계정 생성

1번 노드와 동일하다.


3. 노드 실행

다만 노드를 실행할 때 디렉토리와 포트를 달리 주어야 한다.

데이터 디렉토리를 node2로 포트를 30312로 실행해보자.

geth --datadir node2 \
     --syncmode 'full' --port 30312 \
     --bootnodes 'enode://50dc1ae7b7b5b3b8cdb843dec53e43b677fca13afd2e46c04a1c1a83aa92fbc30f07a7495bae8a3a1deb6e44e6d36f5b3f83d90efb34bef0c118d7336326ae12@127.0.0.1:30301' \
     --networkid 950 --gasprice '1' console


부트노드 콘솔 창을 보자. 두번째 노드(30312포트)가 보이는가? node2가 제대로 붙은 것이다.



아울러 node2 실행 콘솔에 node1에서 마이닝한 블럭을 동기화하는 내용을 볼 수 있다.



> INFO [07-05|14:10:18] Block synchronisation started 
> INFO [07-05|14:10:19] Imported new chain segment blocks=18 txs=0 mgas=0.000 elapsed=1.277s mgasps=0.000 number=18 hash=ee4e10…f7edc4 cache=3.84kB

이 부분이 블럭을 동기화하고 있다는 콘솔 로그다.


4. 마이닝

Node2에서도 마이닝을 해보자. Node1과 함께 마이닝 작업을 시작한다.

> miner.start(1)


마이닝을 하면 "Successfully sealed new block" 라는 부분이 나오는데, 이 부분이 새로운 블럭을 만들었다는 것이고 "Commit new minging work" 은 다른 노드가 만든 블럭을 동기화했다는 의미이다.


즉 bootnode를 통해 node1에 붙어 데이터를 동기화하며, 아울러 마이닝 작업을 하고 있다.

결론

이번 연재에서는 bootnode를 통해 개별 노드들을 동기화하는 방법을 알아보았다.