3 분 소요

블록체인 플랫폼 중 하나인 Ethereum을 설치하고 Private Network를 구축해보았습니다.

Ubuntu 18.04 LTS(ubuntu-18.04-desktop-amd64)에서 진행되었습니다.

Geth 설치

geth는 이더리움 노드 실행을 위한 CLI(Command Line Interface)입니다.

golang

Go를 이용해 빌드하기 때문에 golang을 설치해야 합니다.

# 패키지를 이용한 설치
$ sudo apt-get install golang-go

# 바이너리를 이용한 설치
$ wget https://dl.google.com/go/go1.10.3.linux-amd64.tar.gz
$ tar zxvf go1.10.3.linux-amd64.tar.gz
$ cd go
$ export GOROOT=$(pwd)
$ export PATH=$PATH:$GOROOT/bin
$ go version
go version go1.10.3 linux/amd64

Building geth

$ git clone https://github.com/ethereum/go-ethereum.git
$ cd go-ethereum
$ make
$ sudo cp build/bin/geth /usr/local/bin/
$ geth version
Geth
Version: 1.8.14-unstable
Git Commit: 45eaef24319897f5b1679c9d1aa7d88702cce905
Architecture: amd64
Protocol Versions: [63 62]
Network Id: 1
Go Version: go1.10.3
Operating System: linux
GOPATH=
GOROOT=/home/jbshin/ehtereum-workspace/go

Private Network

위의 과정으로 geth가 설치되고 설치된 geth를 이용해 Private Network를 구축해보겠습니다.

우선 편의를 위해 privnet이라는 폴더를 만들게요.
편하신 경로에 편하신 폴더명으로 작명하셔도 됩니다!

$ mkdir -p ~/ethereum-workspace/privnet
$ cd ~/ethereum-workspace/privnet

Genesis Block

제네시스 블록을 생성하기 위해 genesis.json 파일을 작성합니다.
편하신 에디터를 이용해 아래의 내용을 입력해주세요.

{
  "config": {
    "chainId": 2018,
    "homesteadBlock": 0,
    "eip155Block": 0,
    "eip158Block": 0
  },
  "nonce": "0x0000000000000033",
  "timestamp": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "gasLimit": "0x8000000",
  "difficulty": "0x100",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x3333333333333333333333333333333333333333",
  "alloc": {}
}

Initialize

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

Node

제네시스 블록 생성까지 했으니 모든 준비가 완료된 것 같네요.
이제 노드를 실행해볼까요?

$ geth --rpc --datadir ./data --nodiscover --rpcapi db,eth,net,web3,admin.personal console

RPC address와 port는 각각 --rpcaddr, --rpcport 옵션을 이용해 지정할 수 있으며 default로 127.0.0.1:8545를 사용합니다.
--networkid를 이용해 네트워크ID를 지정할 수 있습니다. --nodiscover 옵션은 같은 제네시스 블록과 네트워크ID에 있는 노드들이 연결하는 것을 방지해줍니다.

Geth 사용하기

geth로 Private Network의 노드로 참여하는 것에 성공했습니다!
그렇다면 account를 만들고 mining을 하고 송금하는 등 간단한 사용법 몇가지를 알아볼까요?

account 목록을 조회해볼게요.

> eth.accounts
[]

명령어를 입력하니 빈 배열이 나오네요.
account가 없으니 하나 새로 만들어보죠.

> personal.newAccount('jb')
"0x260bf32fc4529a3167c73f02f06201c02f028205" # 출력되는 값이 다를거에요!

personal.newAccount()의 파라미터에 passphrase가 입력됩니다.
0x260bf32fc4529a3167c73f02f06201c02f028205의 passphrase는 jb에요.

> eth.accounts
["0x260bf32fc4529a3167c73f02f06201c02f028205"]

account 목록에 정상적으로 추가되었네요.

이 account에는 얼마의 ether가 있을까요?

> eth.getBalance(eth.accounts[0]) # eth.getBalance('0x260bf32fc4529a3167c73f02f06201c02f028205')
0

0이네요… 당연한거겠죠?

블록을 마이닝하고 보상을 받는 과정을 해보겠습니다.

> miner.start()
INFO [08-10|17:35:09.128] Updated mining threads                   threads=0
INFO [08-10|17:35:09.128] Transaction pool price threshold updated price=18000000000
INFO [08-10|17:35:09.128] Etherbase automatically configured       address=0x260BF32FC4529a3167c73f02F06201C02F028205
null
INFO [08-10|17:35:09.128] Commit new empty mining work             number=1 uncles=0
INFO [08-10|17:35:09.128] Commit new full mining work              number=1 txs=0 uncles=0 elapsed=261.395µs
INFO [08-10|17:35:12.791] Generating DAG in progress               epoch=0 percentage=0 elapsed=2.844s
INFO [08-10|17:35:15.767] Generating DAG in progress               epoch=0 percentage=1 elapsed=5.819s
...
INFO [08-10|17:39:54.978] Successfully sealed new block            number=1 hash=5a2077…0eb665
INFO [08-10|17:39:54.979] 🔨 mined potential block                  number=1 hash=5a2077…0eb665
INFO [08-10|17:39:54.979] Commit new empty mining work             number=2 uncles=0
INFO [08-10|17:39:54.979] Commit new full mining work              number=2 txs=0 uncles=0 elapsed=316.197µs

마이닝까지의 시간이 꽤 걸릴거에요~
🔨 표시와 함께 1번 블록이 마이닝되었습니다!

(참고) account가 여러 개 있는데 그 중 하나를 지정해 보상을 받고 싶으시다면 miner.setEtherbase()를 활용해보세요!

> miner.setEtherbase(eth.accounts[1])
> eth.getBalance(eth.accounts[0])
5000000000000000000

5ether(5,000,000,000,000,000,000wei)를 보상으로 받은 것을 확인할 수 있습니다.

이번엔 송금을 해봐야겠죠?
송금을 위해 account를 하나 더 생성합시다!

> personal.newAccount('foo')
"0xc07f222c6312473fc5694fd2ae1cf1e78410b58c"

처음 만들었던 account에서 1ether를 새로 만든 account로 송금해보죠!
트랜잭션을 발생하기 위해서는 account unlock 과정이 필요합니다.

> personal.unlockAccount(eth.accounts[0])
Unlock account 0x260bf32fc4529a3167c73f02f06201c02f028205
Passphrase:
true
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, 'ether')})
INFO [08-10|19:59:50.985] Submitted transaction                    fullhash=0x1a5fa277634a504a10ff4f33a6a29c208e90c113d54b40c5b4bcc99e84fd1a63 recipient=0xc07f222C6312473FC5694fD2ae1cf1E78410b58C
"0x1a5fa277634a504a10ff4f33a6a29c208e90c113d54b40c5b4bcc99e84fd1a63"

accounts의 0번(jb)에서 1번(foo)로 1ether를 송금하는 트랜잭션이 발생하였습니다.

이 트랜잭션의 정보를 볼까요?
eth.pendingTransactionseth.getBlock('pending').transactions는 현재 마이닝 중인 블록에 있는 트랜잭션을 볼 수 있습니다.

> eth.pendingTransactions
[{
    blockHash: null,
    blockNumber: null,
    from: "0x260bf32fc4529a3167c73f02f06201c02f028205",
    gas: 90000,
    gasPrice: 18000000000,
    hash: "0x1a5fa277634a504a10ff4f33a6a29c208e90c113d54b40c5b4bcc99e84fd1a63",
    input: "0x",
    nonce: 0,
    r: "0xfee8ec5ab640f3a37c27b569966f9ec8a43199b2c8ef197ee49cf3cf67aa6df8",
    s: "0x6ca469673ec1e00d1e00d0954b0d8db49285b0dac418c8582d0dbb7b9237bad",
    to: "0xc07f222c6312473fc5694fd2ae1cf1e78410b58c",
    transactionIndex: 0,
    v: "0xfe8",
    value: 1000000000000000000
}]
> eth.getBlock('pending').transactions
["0x1a5fa277634a504a10ff4f33a6a29c208e90c113d54b40c5b4bcc99e84fd1a63"]

트랜잭션이 발생되고 블록이 마이닝 된 후 ether를 확인해봅니다.

> eth.getBalance(eth.accounts[1])
1000000000000000000

1ether(1,000,000,000,000,000,000wei)가 입금되었습니다!

Private Network

다시 Private Network입니다.
이름이 Network인데 노드가 하나만 있다면 아쉽겠죠?

노드의 정보를 확인해볼게요.

> admin.nodeInfo
{
  enode: "enode://9bb90c172175f636faa6d1670607c88d23524080ee38f63a6d9347f5fa8d1e931a4a9e0423e7fab9f7816883d4a818474118aa41039e495f7f172d285d7a4df7@[::]:30303?discport=0",
  id: "9bb90c172175f636faa6d1670607c88d23524080ee38f63a6d9347f5fa8d1e931a4a9e0423e7fab9f7816883d4a818474118aa41039e495f7f172d285d7a4df7",
  ip: "::",
  listenAddr: "[::]:30303",
  name: "Geth/v1.8.14-unstable-45eaef24/linux-amd64/go1.10.3",
  ports: {
    discovery: 0,
    listener: 30303
  },
  protocols: {
    eth: {
      config: {
        chainId: 2018,
        eip150Hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
        eip155Block: 0,
        eip158Block: 0,
        homesteadBlock: 0
      },
      difficulty: 918208,
      genesis: "0x5704d029fe80f4fb605c0cb5e31d591511f10a46a0cb8166f97d8d559f9bc5b0",
      head: "0xe74d827b527f35d9de71bd113ccdbc8498e36cedd9db9cb1b0ebc1c0390456b1",
      network: 1
    }
  }
}

이 데이터의 enode를 이용해 다른 노드에서 이 노드를 네트워크에 추가 할 수 있습니다.

기존 노드를 종료하고 rpcaddr을 지정해서 다시 실행시켜볼게요.

> exit
$ geth --rpc --rpcaddr 0.0.0.0 --datadir ./data --nodiscover --rpcapi db,eth,net,web3,admin.personal console

다른 PC에서 노드를 하나 더 실행해 준 후 아래처럼 node를 추가할 수 있습니다.

# 위와 다른 PC의 노드입니다.
> admin.addPeer('enode://9bb90c172175f636faa6d1670607c88d23524080ee38f63a6d9347f5fa8d1e931a4a9e0423e7fab9f7816883d4a818474118aa41039e495f7f172d285d7a4df7@[::]:30303?discport=0')
true
> admin.peers
[{
    caps: ["eth/62", "eth/63"],
    id: "9bb90c172175f636faa6d1670607c88d23524080ee38f63a6d9347f5fa8d1e931a4a9e0423e7fab9f7816883d4a818474118aa41039e495f7f172d285d7a4df7",
    name: "Geth/v1.8.14-unstable-45eaef24/linux-amd64/go1.10.3",
    network: {
      inbound: false,
      localAddress: "[::1]:52530",
      remoteAddress: "[::1]:30303",
      static: true,
      trusted: false
    },
    protocols: {
      eth: {
        difficulty: 918208,
        head: "0xe74d827b527f35d9de71bd113ccdbc8498e36cedd9db9cb1b0ebc1c0390456b1",
        version: 63
      }
    }
}]
> INFO [08-10|20:23:19.741] Block synchronisation started

블록 동기화가 이루어지고 피어가 2개인 PrivateNetwork가 만들어졌습니다. 더 추가도 되겠죠?

카테고리:

업데이트:

댓글남기기