프라이빗 메인넷 구축(Geth puppeth).

김진경·2022년 5월 4일
0

원리, 환경

목록 보기
2/5
post-thumbnail

  본 글은 Ethereum 기반의 private network를 구축하기 위한 기본적인 내용을 담고 있다. 클라이언트는 Geth(go-ethereum)이 사용되었다.

서론

프라이빗 네트워크를 왜 빌드하는가?

  1. 보안
    블록체인을 사용하는 많은 이들은 프라이빗한 정보를 공개된 퍼블릭 체인에 보관하는 것보다 안전한 곳에 보관하려고 한다. 이것이 기업들이 자체 메인넷을 구축하는 이유이다. 동시에 메인넷을 구축한 이들은 누가 네트워크에 접근하는지 알고자 한다. 또한 이들은 원활한 네트워크 환경조성을 위해 때에 따라 네트워크와 상호작용하는 노드들을 제어하고자 한다.

  2. 네트워크 환경
    기존의 블록체인은 확인과 검증에 집중하여 마이닝 속도는 느린 편이었다. 비트코인은 블록당 10분, 이더리움은 12~13초가 걸린다. 이는 송출금 혹은 dApp 작동에 있어 상당한 불편을 초래할 수 있다. 시장이 더 빠른 속도를 원하는 것은 자연스러운 수순이었다. 또한 기업, 개인마다 원하는 네트워크 환경은 조금씩 다를 수 있고 . 스스로 마이닝 시간, 난이도, 접근가능한 노드의 수 등을 설정할 수 있는 점이 프라이빗 네트워크를 구축하는 이유이기도 하다.

용어 설명

  • 노드(node)
    노드(node)는 이더리움 네트워크에 참여하는 한대의 컴퓨터를 말한다. 네트워킹이 가능한 기기이다.

  • 피어(peer)
    노드가 네트워크에 참여할 때 자신을 제외한 상대방 노드(node)를 말한다. 즉 자신과 같이 네트워크를 구성하는 다른 구성원.

  • 이더리움 클라이언트(Etherum Clients)
    이더리움 클라이언트(Ethereum Clients)는 이더리움 블록체인 네트워크를 구성하는 개별 클라이언트 노드(node)이다. 이더리움은 중앙 집중형 서버 프로그램이 따로 존재하지 않는다. 오로지 클라이언트 프로그램만 존재한다. 이더리움 클라이언트는 멀티 플랫폼 환경을 지원하기 위해 다양한 프로그래밍 언어로 개발되고 있다.

  • Geth(Go-ethereum)
    게스(geth)는 이더리움 재단(Ethereum Foundation)이 제공하는 공식 클라이언트 소프트웨어로서, Go 언어로 개발되었다. 게스(Geth)를 처음 시작하면 네트워크 내의 다른 이더리움 클라이언트(노드)에 연결하는 작업을 먼저 시작하고 블록체인의 전체 사본을 내려받게 된다. 게스(Geth)는 블록체인의 복사본을 최신 상태로 유지하기 위해 끊임없이 다른 노드와 통신한다. 또한 블록을 채굴하고, 블록체인에 트랜잭션을 추가하고 블록의 트랜잭션을 검증하며 트랜잭션을 실행할 수도 있다.

  • Puppeth
    puppeth는 새로운 이더리움 네트워크를 생성하는데 도움을 주는 CLI 관리 툴이다. genesis, boot node, signer, ethstats, faucet, dashboard 등을 제공한다. 이런 네트워크 구축에 필요한 모든 서비스를 하나씩 구성할 필요 없이 한번에 제공한다.




본론

Private Network(ethereum chain) 구축

프라이빗 네트워크를 구축하기 위한 초기 설정은 다음과 같다.

  1. Custom Data Directory 생성
    1-1. Account 생성.
  2. Custom Genesis File 생성
  3. Custom Network ID 생성
    network id는 network의 privacy를 보장해준다. network id는 ethereum에서 사용하는 것을 제외하고 임의로 입력하면 된다.
  1. Custom Data Directory 생성

디렉토리 구조는 네트워크(상위 디렉토리) 전체와 블록체인을 구성할 구성원들(하위 디렉토리)로 이루어진다. 먼저 상위 디렉토리를 생성하고, 차례로 하위 디렉토리를 생성한다.
이 글에선 1개의 네트워크와 그 구성원 3개를 생성했다.

디렉토리 생성 명령어

$ mkdir 디렉토리이름

실행결과


1개의 상위 디렉토리(네트워크)와 3개의 하위 디렉토리(네트워크 구성 노드)가 생성되었다.

1-1. Account 생성.

디렉토리를 생성했다면, 노드들에게 이더리움 어카운트를 생성해주어야 한다. 다음의 명령어를 실행하여 어카운트를 생성할 수 있다.

$ geth --datadir "./디렉토리이름" account new

비밀번호를 입력하고 나면 어카운트는 2개의 정보를 준다.
public addresssecret key.
이 2개의 정보는 중요하므로 안전한 곳에 기록해놓는 것을 추천한다.

3개의 노드에서 명령어를 전부 실행하였고, 3개의 어카운트를 생성하였다.



  1. Custom Genesis File 생성

Data Directory를 생성했다면, genesis file을 생성할 차례이다. genesis file은 private network의 모든 정보를 담고 있고, configuration(환경설정. 줄여서 config라고도 함)을 지정한다. 예를 들어, 채굴 난이도에 대한 정보나, 체인의 환경설정 같은 부분이 있다. genesis file에는 4가지 필드(config, difficulty, gasLimit, alloc)가 반드시 들어있어야 한다.

genesis file을 생성하기 위해 노드보다 상위 디렉토리(네트워크)에서 puppeth를 사용한다.
다음과 같이 명령어를 입력한다.

$ puppeth
  1. 사용할 네트워크 이름 입력
    입력하면 먼저 puppeth의 안내문구가 뜨고, 사용할 네트워크의 이름을 입력할 수 있다. 참고로 대문자는 사용할 수 없다.

    사용할 이름을 입력하면 --network=입력한이름 으로 설정되고 다음 단계로 넘어간다.

  2. 목적 입력
    네트워크의 이름을 입력하면 하고자 하는 행동의 선택지들을 제공한다. 지금은 genesis file을 생성하는 것이기에 2번을 선택했다.

  3. 1번의 연장선으로 선택지가 주어진다. 지금은 genesis file을 생성하는 것이기에 1번을 선택했다.

  4. 네트워크의 합의방식을 고르는 선택지가 주어진다. 지금은 프라이빗 네트워크에 더 적합한 PoA를 선택한다. PoA(권위증명) 방식은 프라이빗 네트워크에서 '전송' 및 '블록생성'을 담당하는 소수의 Validator(검증자) 노드를 지정한다. 이는 다른 증명방식에 비해 노드 수를 줄여 유효성 검사에 필요한 시간을 줄일 수 있고, 블록 생성주기를 짧게 하여 빠른 트랜잭션 처리를 가능하게 한다.PoA방식과 프라이빗 네트워크

  5. 블록 생성주기를 선택한다. 초단위를 입력하여 설정한다. 기본값은 15초이다.

  6. 권한을 줄 노드를 입력한다. 검증자로서의 역할을 하는 노드의 public address를 입력한다. 그 뜻은 지정된 노드에서 모든 블록이 채굴된다는 뜻이다. 여기선 첫번째 노드(node1)만 입력하여 권한을 주는 것으로 설정한다. 두번째, 세번째 노드는 채굴은 할 수 없지만 모든 트랜잭션에 대해 조회가 가능하다.

  7. pre-funded address를 입력하는 선택지가 주어진다. 3개의 계정 모두 입력한다.

  8. prefund하려는 금액을 입력한다. yes를 입력하면 1 Wei가 제공되고 그 외의 숫자도 입력 가능하다.

  9. Chain/Network id를 입력하게 된다. 위에서 설명한 대로 network id는 ethereum에서 사용하는 것을 제외하고 임의로 입력하면 된다.

여기까지 실행하면 genesis file이 생성된다. 그리고 처음으로 돌아가 새로운 선택지가 주어지는데, 처음과 다르게 2. Configure new genesis 항목이 2. Manage existing genesis 로 바뀌어 있다. 해당 항목을 선택해준다.

그리고 나서 설정한 genesis configurations 를 파일로 확인할 수 있도록 2. Export genesis configurations를 선택해준다.

마지막으로 생성하고자 하는 위치(디렉토리 이름)을 입력하면 디렉토리가 생성됨과 동시에 그 안에 genesis file도 같이 생성된다.

그러고 나면, puppeth 창은 처음으로 돌아가고, 생성된 genesis file을 확인할 수 있다.

genesis file 분석

genesis file에는 많은 정보들이 있지만, 그중 몇가지 특정한 정보를 분석해보자.

  1. config : 해당 블록체인의 설정을 나타낸다.
    1-1. chainId : 현재 chain을 식별하는 값으로 사용된다. replay attack을 막기 위해서 사용되기도 한다.
    1-2. homesteadBlock : Homestead는 두 번째 Ethereum release 버전이다. 이값을 0으로 set하면 Homestead 첫번째 버전을 사용하는 것을 의미한다.
    1-3. eip155Block : eip는 Ethereum Improvement Proposal을 의미한다.

  2. difficulty : mining difficulty. 이 값을 낮게 줄수록 block이 mining하는데 걸리는 시간이 짧아진다.

  3. gasLimit : the limit of gas cost per block. 이 값을 높일수록 block 하나에 포함할 수 있는 gasLimit양이 늘어난다. 그만큼 많은 transaction을 block에 포함시킬 수 있게 된다.

  4. alloc : pre-funded address를 입력하는 곳이다. 이 문서에서 만든 네트워크에는 3개의 노드 모두가 pre-funded address에 해당한다.

Private Network 실행

Private Network 초기화

네트워크를 생성하기 위해 노드에 로그인한다. 그 전에 먼저 상위 디렉토리에 genesis file을 위치시켜야 한다.

그리고 나서 네트워크를 생성시키기 위해, 노드가 genesis.json 파일을 실행하도록 다음 명령어를 실행한다. 노드 진입 후, data폴더 확인하고 json파일 위치도 확인할 것.

// geth --datadir ./data init genesisfile위치
$ geth --datadir ./data init ../knives.json 

실행결과.

genesis 파일에서 설정한 configuration의 private network가 생성된다. 같은 명령어를 다른 노드들에서도 실행해준다. 실행하고 나면 동일한 genesis에 대한 여러 노드를 갖게 되는 것이다.



Boot Node 생성

네트워크에 참여할 노드들을 생성하고, 각각의 노드에서 genesis 파일을 실행도 했지만 아직 각각의 노드들은 연결된 상태가 아니다. 노드들을 연결하기 위해 Boot Node 를 사용한다.

Boot Node는 네트워크의 일부인 동시에 그 어떤 블록도 채굴하지 않는다. 부트노드의 주 목적은 모든 노드에 연결하는 것이다.
ex) 노드 1 ↔︎ 부트 노드 ↔︎ 노드 2

먼저 Boot Node를 설정할 디렉토리를 생성한다.

Boot Node 디렉토리에 진입 후, 부트 키를 생성하기 위해 명령어를 입력한다.

$ bootnode -genkey boot.key

실행하고 나면 다음과 같이 boot.key가 생성된다.

이제 생성된 boot.key로 boot node를 실행한다.

bootnode -nodekey boot.key

실행하고 나면 다음과 같이 enode가 생성된다.


이 enode는 네트워크 연결을 위해 다른 피어를 검색하고 허용하는 역할을 한다. 안전한 곳에 기록해놓는 것을 추천한다.

네트워크에 연결하기 전에 잠깐 팁을 주자면, 비밀번호를 매번 입력하지 않아도 되도록 미리 txt파일을 만들어 비밀번호를 입력해두면 편하다.



Private Network 실행

  1. Boot Node 실행
    다른 노드들을 실행하기 전에 먼저 부트노드를 실행한다.

$ bootnode -nodekey boot.key -verbosity 7 -addr :30301

// bootnode는 기본으로 30301 포트로 실행되므로 -addr 옵션을 생략해도 된다.
-verbosity 7 옵션에 대해서는 geth 공식 홈페이지(https://geth.ethereum.org/docs/interface/command-line-options) 와 구글링에도 나오지 않아 더 찾아볼 예정이다.

Boot node의 실행결과는 다음과 같다.

이제 나머지 노드들도 실행해준다.
먼저 node1에서 네트워크를 실행하는데, node1에서 네트워크를 실행하는 명령어는 다음과 같다.

geth --networkid 19444 --datadir "./data" --bootnodes enode://68d9ae9d7752d25ca00d11b682877d0be6ec4e47d49857c4f01596649f0b693a6ff1f0d87ca5e144b894bbaee14b7f0eb8b1f74160103b4945ac8a151f4b41b3@127.0.0.1:30301 --port 30303 --rpcport 8545 --unlock 0x08d4cEE4075b1BBEd80Ec815896C516f4A169447 --password password.txt --mine console 

명령어 옵션을 살펴보자.

geth --networkid : 네트워크 번호 

--datadir : data 폴더위치를 말한다.

--bootnodes : enode를 value로 입력한다. 
@127.0.0.1:30301(enode의 포트번호) 를 붙여준다.

--port 포트번호 : 해당 노드가 네트워크를 시작하는 포트번호를 value로 입력한다.

--rpcport value : HTTP-RPC 서버 포트이다.

--unlock : 잠금을 해제하고 네트워크를 실행시킬 노드의 public address를 value로 입력한다.

password : 비밀번호를 value로 입력한다. 미리 만들어둔 assword.txt를 입력한다.

--mine : 블록 마이닝을 시작한다.

console : 콘솔창에 결과를 표시한다.

실행화면은 다음과 같다.

그리고 부트노드에서도 반응을 관찰할 수 있다.

이제 node 2와 node 3도 명령어를 입력하여 네트워크를 실행한다.

// node2 네트워크 명령 실행
$ geth --networkid 19444 --datadir "./data" --bootnodes enode://68d9ae9d7752d25ca00d11b682877d0be6ec4e47d49857c4f01596649f0b693a6ff1f0d87ca5e144b894bbaee14b7f0eb8b1f74160103b4945ac8a151f4b41b3@127.0.0.1:30301 --port 30304 --rpcport 8546 --unlock 0x3e2dE119df49057C1625FF220Fbf75338Bf4c37C --password password.txt console 
// node3 네트워크 명령 실행
$ geth --networkid 19444 --datadir "./data" --bootnodes enode://68d9ae9d7752d25ca00d11b682877d0be6ec4e47d49857c4f01596649f0b693a6ff1f0d87ca5e144b894bbaee14b7f0eb8b1f74160103b4945ac8a151f4b41b3@127.0.0.1:30301 --port 30305 --rpcport 8547 --unlock 0x6c934286e7F518864109d9a188B2D16a68d1b05a --password password.txt console 

node1과 다른 점만 확인해보자.

--port : 각 노드마다 다른 포트를 부여한다.
--rpcport : rpcport 역시 노드마다 다르게 부여해준다.
--unlock : 각 노드의 public address를 입력한다.
--mine : node1과 다르게 mine 옵션은 쓸 수 없다. 나머지 노드들에게 권한이 부여되지 않았으므로 채굴할 수 없기 때문이다.

실행 결과, 각 노드들도 잘 작동하는 모습이다.

node2 실행결과.

node3 실행결과.




테스트 (프라이빗 네트워크에 스마트 컨트랙트 배포)

리믹스에서 제공하는 스마트 컨트랙트 'StorageExample.sol' 을 Web3.Provider로 나의 프라이빗 네트워크(127.0.0.1:8545)에 배포가 되는지 테스트해보기로 한다.

먼저 메타마스크의 네트워크 환경설정에서 localhost 8545를 추가해준다.

이후, ENVIRONMENT 항목을 Web3.Provider로 선택한다.

테스트 환경을 바꾸고 deploy를 실행하면, 다음과 같이 정상적으로 배포되는 걸 확인할 수 있다. 이때, 설정한 난이도 주기에 따라 약 5초 정도 시간이 소요된다.

확인된 블록 넘버는 605, 블록 해쉬는 '0x34b...59c11' 이다.
프라이빗 네트워크의 노드에서 확인해보자.

위의 사진처럼 프라이빗 네트워크의 노드에서 해당 블록넘버와 해쉬값을 확인할 수 있다.
이로서 테스트까지 무사히 완료했다.




결론(후기)

  프라이빗 네트워크를 구축하게 된 계기는 단순히 교수님의 추천으로 하게 되었다. 무작정 구글링하고 관련 블로깅과 강의자료를 따라했다. 그렇게 네트워크를 구축하면서 배운 것은, '프라이빗 네트워크 구축'은 블록체인이라는 거대한 네트워크를 이해하는 시작점이라는 것이다. 자체 네트워크를 구축하고, 노드를 형성해 블록체인을 만드는 것으로 내가 테스트하고 배포할 공간이 형성된다.

  그렇게 나는 내가 만든 dApp을 배포하거나 테스트할 때 생기는 오류가, 네트워크와 어떤 불협화음이 있어서 생긴 것 인지 한번 더 생각해보게 되었다. 단순히 '내가 짠 코드가 오타났구나' 가 아니라 '내가 만든 dApp이 내 프라이빗 네트워크에서 돌아가기 수월하게 만들어졌는가', '이런 형태의 블록체인에선 어떤 구조의 dApp이 어울리고 비용이 적게 드는가'라는 생각까지 미치게 되었다.

  아직 하고 있는 고민을 모두 해결할 정도의 실력은 아니지만, 우선은 구축부터 시작하자. 익숙해지면 빠르게 성장할 수 있다.

profile
Maktub.

0개의 댓글