Puppeth 파헤치기

Jason Hwang
Tokamak Network
Published in
8 min readJul 12, 2018

들어가며..

이번 포스트는 Bootnode가 배포되는 코드가 실행되는 순서를 따라가며 puppeth가 어떻게 동작을 하는지 이해를 돕고자 작성 되었습니다. puppeth를 이용해 다양한 기능들을 개발하고자 하는 분들에게 도움이 되었으면 좋겠습니다.

main

Bootnode를 배포하는데 필요한 코드는 module_node.go wizard_node.go가 있습니다. wizard_node.go는 puppeth의 cli를 통해 배포에 필요한 파라미터를 입력 받는 역할을 담당하고, module_node.go는 cli를 통해 입력받은 값들을 통해 노드를 배포하는 역할을 담당하고 있습니다. module/wizard_node.go외에도 각 기능에 맞춰 배포하는 작업을 담당하는 코드들이 역할에 맞게 구성되어 있습니다. 자세한 내용은 go-ethereum github에서 확인하실 수 있습니다.

이제 본격적으로 puppeth가 노드를 배포하는 과정을 알아 보도록하겠습니다. 아래 그림은 wizard_network.go에 있는 deployComponent 함수에 대한 코드 입니다.

deployComponent 함수

위 코드는 puppeth 메인 화면에서 4. Deploy network components를 선택했을때 출력되는 화면입니다. switch case 문을 통해 선택을하면 각 컴포넌트를 배포하는 함수가 실행되는데, 다른 컴포넌트와 다르게 Bootnode와 Sealer는 entry point의 역할을 하는지 블록 생성을 담당 하는지 차이만 있을 뿐 크게 다를건 없기 때문에 true, false를 통해 구분이 됩니다.

원래는 1번 부터 순서대로 배포를 해야하지만 이번 글에서는 Bootnode를 배포하는 과정을 알아보기로 했기 때문에 deployNode 함수를 살펴보도록 하겠습니다.

wizard_node.go의 deployNode 함수

deployNode 함수는 wizard_node.go에도 있고 module_node.go에도 존재하는 함수입니다. 위 그림은 wizard_node.go에 있는 함수입니다. 위 코드를 보시면 제일 먼저 제네시스 파일이 생성되어 있는지 확인하고, ethstat이 배포되어 있는지 확인을 합니다. ethstat과 genesis 파일에 문제가 없어야 다음 단계인 Bootnode를 배포할 수 있습니다. 이상이 없을 경우 w.selectServer()에서 배포할 서버를 선택할 수 있습니다. 그 다음에는 노드의 상태를 확인하는 checkNode 함수가 실행됩니다. 배포하는 과정에서 checkNode 함수는 총 두번 실행되는데 위 그림에서 보이는 checkNode 함수는 다른 활성화된 노드 설정이 있는지 탐색하는 역할을 수행합니다. checkNode 함수는 뒤에 나올 때 자세히 살펴 보도록 하겠습니다.

checkNode 함수를 통해 노드들의 상태 확인이 완료되면 본격적으로 private network의 컴포넌트들을 배포할 준비를 시작합니다. &nodeInfos에 할당되는 값들은 puppeth cli에서 별다른 값을 입력하지 않았을 때 입력되는 default 값들 입니다.

default 값의 설정이 완료되면 이제 cli를 통해 배포에 필요한 파라미터들을 입력 받습니다. 아래 그림은 cli에서 배포에 필요한 파라미터를 받아오는 과정을 보여주는 그림입니다.

cli에서 파라미터를 받아오는 과정

puppeth를 다뤄 보셨다면 위 그림에 나온 문구들이 낯이 익을 것으로 생각됩니다. 코드를 보면 Bootnode를 배포 하는지 Sealer를 배포 하는지에 따라 cli에 출력되는 문구들이 조금씩 다르고 Sealer를 배포 하더라도 합의 알고리즘이 pow인지 poa인지에 따라 cli에 출력되는 문구가 다릅니다. cli를 통해 입력 되는 값들은 infos에 구조체 형태로 저장이 됩니다.

파라미터를 전부 입력한 후

배포에 필요한 파라미터들을 전부입력하면 deployNode 함수가 실행됩니다. 이번에 실행되는 deployNode 함수는 node_module.go에 있는 함수 입니다.

module_node.go의 deployNode 함수

module_node.go의 deployNode 함수가 실행 되면가장 먼저 배포되는 노드의 형태가 bootnode인지 sealnode인지 확인하는 작업이 수행됩니다. 배포되는 노드가 bootnode일 경우에는 bootnodes = make([]string, 0) 코드를 통해 기존에 저장되어 있던 enode값을 삭제하는 로직이 수행됩니다. 이 로직은 Onther의 공개채용공고의 25번 문제의 답변을 하기위해 알고 있어야 하는 로직입니다.

25. Puppeth를 이용해 여러개의 Bootnode를 갖고 있는 프라이빗 네트워크를 운영할 수 있는가? 그렇다면 혹은 그렇지 않다면 그 이유를 서술 하시오.

bootnode를 배포하려고 하면 bootnodes = make([]string, 0)를 통해 기존에 저장되어 있던 enode 값이 삭제 되기 때문에 bootnode 간의 연결이 되지 않기 때문에 별도의 작업 없이 puppeth만으로는 여러개의 bootnode를 운영할 수 없습니다.

Dockerfile 작성에 필요한 값들

puppeth는 Dockerfile과 docker-compose 파일을 배포해서 노드를 빌드하는 방식 입니다. 위 코드에서 보이는 값들이 Bootnode를 배포하는지 Sealer를 배포하는지에 따라 Dockerfile에 반영됩니다. 마찬가지로 아래 그림에 나타나있는 코드는 docker-compose 파일에 반영됩니다.

docker-compose 파일에 필요한 값들

여기까지 완료가 되었으면 노드를 배포할 준비가 끝이 났습니다. 아래 그림은 노드를 빌드하는 과정에 대한 내용입니다.

docker-compose 빌드 및 temp폴더 삭제

노드를 빌드하는 과정은 temp 폴더를 생성해서 도커 컨테이너를 배포한 후 docker-compose 명령어를 이용해 노드를 빌드합니다. 그 다음에는 rm -rf 명령으로 temp 폴더 삭제합니다. defer client.Run(“rm -rf” + workdir) 코드를 주석처리하거나 지우면 도커를 배포하는 서버에 dockerfile과 docker-compose 파일 등이 담겨있는 폴더가 남아있게 됩니다.

이렇게 deployNode 함수가 무사히 실행되면 네트워크의 상태를 점검하기 위해 w.networkStats() 함수가 실행됩니다.

networkStats 함수에서는 프라이빗 네트워크의 상태를 보여줍니다. 네트워크의 전반적인 상태를 점검한 다음 gatherStats() 함수를 호출해 배포되어 있는 각 노드들의 상태를 수집합니다.

gatherStats 함수는 배포되어 있는 모든 노드들의 상태를 모으는 역할을 수행하는 함수입니다. ethstat 부터 bootnode, sealer, wallet, faucet 노드의 상태를 전부 확인 합니다. 아래 그림은 그중에서도 bootnode의 상태를 수집하는 코드 입니다.

우선 checkNode함수를 이용해 노드의 상태를 수집합니다. checkNode 함수에서 수집하는 내용은 도커 컨테이너의 정보 등을 수집한 다음 infos.Report() 함수를 통해 stat.Service에 상태값을 저장 합니다. 맨 밑에 있는 append(bootnodes, infos.enode)는 Bootnode의 enode값을 저장해서 다른 노드들이 Bootnode에 연결할 수 있는 정보를 제공합니다.

마치며

이상으로 go-ethereum의 소스 코드를 통해 puppeth가 동작하는 과정을 살펴보았습니다. 충분한 설명이 되었는지는 모르겠지만, puppeth를 이용해 새로운것을 만들고자 하는 분들에게 도움이 되었으면 좋겠습니다.

--

--