이더리움

본문 바로가기
사이트 내 전체검색


이더리움
이더리움

2. 이더리움 실습(2)

페이지 정보

작성자 관리자 댓글 3건 조회 1,024회 작성일 21-07-03 23:53

본문

2. 이더리움 실습(2)

geth = go + ethereum 


geth는 이더리움 클라이언트 소프트웨어로, 이더리움 블록체인 네트워크의 풀노드를 구축하기 위해 사용된다.


Go 언어를 기반으로 이더리움 풀노드를 구현하고 작동시키기 위한 명령어 라인 인터페이스를 제공한다.


클라이언트 소프트웨어 중에서 가장 유명하고 많이 쓰이는게 geth이다.


geth 역할은 다음과 같다.


○ 채굴자나 어플리케이션 개발자들의 프로그램 인터페이스 역할

- geth를 통해 이더리움 블록체인의 노드로써 참여

- 채굴, 암호화폐 전송, 스마트 컨트랙트의 작성, 트랜젝션 브로드캐스팅 가능


○ 풀 블록 데이터 베이스를 다운

- 블록 전체의 거래 내역 탐색 가능


○ 풀 노드로서 블록 검증

- 이더리움 블록체인에 기여 가능



1. git 설치하고 go-ethereum 소스 가져오기


$ sudo apt install git 



ethereum 폴더를 먼저 하나 만든다.


$ mkdir ~/ethereum && cd ~/ethereum


앞으로 ethereum 폴더는 실습의 root 폴더라고 생각하면 된다.


git 설치가 끝났으니 git을 통해 원격에 있는 github/ethereum/go-ethereum 의 geth 클라이언트를 다운받는다.

소스버전이고 컴파일 버전 전이다.



$ git clone https://github.com/ethereum/go-ethereum.git



git repository에서 go-ethereum 소스를 내려 받는다. 


user@leelab:~/ethereum$ ll

합계 12 

drwxrwxr-x  3 user user 4096  7월  3 23:49 ./ 

drwxr-x--- 14 user user 4096  7월  3 23:49 ../ 

drwxrwxr-x 36 user user 4096  7월  3 23:50 go-ethereum/ 

user@leelab:~/ethereum$  


go-ethreum 폴더로 이동 후 빌드에 필요한 Go 언어와 컴파일러 등등 필수 라이브러리를 설치한다.

설치가 완료되면 이제 make 로 go 소스를 build 한다.


user@leelab:~/ethereum$ cd go-ethereum

user@leelab:~/ethereum/go-ethereum$ sudo apt-get install -y build-essential golang 



user@leelab:~/ethereum/go-ethereum$ make all



빌드된 파일들 확인과 geth 버전을 확인한다.


user@leelab:~/ethereum/go-ethereum$ cd build/bin

user@leelab:~/ethereum/go-ethereum/build/bin$ ./geth version 


Geth

Version: 1.10.5-unstable 

Git Commit: 3b053185254959b2c52129b8d146d300a78eb1ad 

Git Commit Date: 20210702 

Architecture: amd64 

Go Version: go1.16.2 

Operating System: linux 

GOPATH= 

GOROOT=go 

user@leelab:~/ethereum/go-ethereum/build/bin$  



우선, 환경변수를 설정해야한다.


user@leelab:~/ethereum/go-ethereum/build/bin$ pwd

/home/user/ethereum/go-ethereum/build/bin 

user@leelab:~/ethereum/go-ethereum/build/bin$ cd 


  


$ sudo apt-get install vim


vi 에디터를 설치 후 아래와 같이 .bash_profile 안에 path 내용에 GETH 위치를 추가해준다.


user@leelab:~$ vi .bash_profile


export GETH=/home/user/ethereum/go-ethereum

export PATH="$PATH:$GETH/build/bin" 


~                                


user@leelab:~$ source ~/.bash_profile

user@leelab:~$ env 


GETH=/home/user/ethereum/go-ethereum

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:/home/user/ethereum/go-ethereum/build/bin 



이렇게 하면 Geth 가 글로벌 환경변수에 등록 되면서 빌드된 파일을 실행할 수 있게 된다.



2. geth 계정 생성하기


geth를 실행하기 전 먼저 geth의 계정을 생성해 보도록 하겠다.


현재 ethereum 폴더 위치에서 test_data 폴더를 하나 만든다.


user@leelab:~$ cd ethereum/

user@leelab:~/ethereum$ mkdir test_data 


user@leelab:~/ethereum$ cd test_data && touch password


패스워드 파일을 test_data 폴더에 만들어 놓는다. 


user@leelab:~/ethereum/test_data$ cd ~/ethereum

user@leelab:~/ethereum$  


이제 geth 명령어 중 account new를 해보도록 하겠다. 

실제 geth 옵션은 -h 로 어떤것들이 있는지 확인해 볼 수 있다 


user@leelab:~/ethereum$ geth --help



우선 옵션들이 다양하다. 이더리움, 마이닝, 네트워킹, RPC 등 다양한 옵션들이 나오는 것을 확인할 수 있는데 이 모든 것들 다 알아야 하는 것은 아니니 우선 참고만 한다.


user@leelab:~/ethereum$ geth --datadir test_data account new --password test_data/password

INFO [07-04|09:25:00.468] Maximum peer count                       ETH=50 LES=0 total=50 

INFO [07-04|09:25:00.469] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory" 


Your new key was generated 


Public address of the key:   0x48A51D5Cf189476d61AC0c9Ca7c930Af16Dee91A 

Path of the secret key file: test_data/keystore/UTC--2021-07-04T00-25-00.469292620Z--48a51d5cf189476d61ac0c9ca7c930af16dee91a 


- You can share your public address with anyone. Others need it to interact with you. 

- You must NEVER share the secret key with anyone! The key controls access to your funds! 

- You must BACKUP your key file! Without the key, it's impossible to access account funds! 

- You must REMEMBER your password! Without the password, it's impossible to decrypt the key! 


user@leelab:~/ethereum$  



위의 명령어는 password 파일(실제 내용은 아무것도 없다)을 토대로 account 를 새로 생성하겠다는 의미이다. 패스워드를 따로 설정하지 않기 위해 만들어 놓았다.


10번을 실행하면 10개의 계정 생성된다. 송금 테스트를 위해 여러개 만들어 놓는다.



user@leelab:~/ethereum$ cd test_data/

user@leelab:~/ethereum/test_data$ ls -al 

합계 12 

drwxrwxr-x 3 user user 4096  7월  4 09:25 . 

drwxrwxr-x 4 user user 4096  7월  4 09:21 .. 

drwx------ 2 user user 4096  7월  4 09:25 keystore 

-rw-rw-r-- 1 user user    0  7월  4 09:21 password 

user@leelab:~/ethereum/test_data$  


위의 명령어를 치게 되면 못보던 keystore 폴더가 생긴 것을 볼 수 있다.


user@leelab:~/ethereum/test_data$ cd keystore/

user@leelab:~/ethereum/test_data/keystore$ ls 

UTC--2021-07-04T00-25-00.469292620Z--48a51d5cf189476d61ac0c9ca7c930af16dee91a 


user@leelab:~/ethereum/test_data/keystore$ cat UTC--2021-07-04T00-25-00.469292620Z--48a51d5cf189476d61ac0c9ca7c930af16dee91a 


{"address":"48a51d5cf189476d61ac0c9ca7c930af16dee91a","crypto":{"cipher":"aes-128-ctr","ciphertext":"45b123ded7e2ab19b4988f44fd5ff48000eb3c5b1f68db5f1c97504f71be20e6","cipherparams":{"iv":"71c9ce6e2bec37ad80c11bb8ae2cba60"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"25866a0645ac96a01bbdd2ef7d9c269da6889f856cae14a23bcab54caeb2863e"},"mac":"904129bf6e00eb2ac922b60d62cc38ae6fcbe8b6d87ddfc6f5301b8113b67f90"},"id":"df18c2a6-3c5d-4f37-a366-0e5b12c820fb","version":3}user@leelab:~/ethereum/test_data/keystore$ 



이게 바로 JSON 형태의 Account 계정들의 private key json 파일이다. 

아마 거래소는 고객의 EOA 계정을 본인들이 운영하는 Geth 에서 생성하고 위와 같은 Key 파일을 내부망 안에다 두고 관리할 것이다. 


JSON 형태이다. 저 안에는 우선 Address 정보와 내부적인 여러 Private key와 관련된 여러 정보들이 존재해 보이는 듯하다. 



3. genesis 블록 생성하기


geth 를 띄워서 console 창에 거래를 해보는 실습을 해보겠다. 

먼저 geth를 띄우기 전에 블록체인을 설정하는 작업을 해야하는데 test_data 폴더에 genesis.json 파일을 생성하고 파일 안에 다음과 같은 내용을 집어 넣어보겠다.


user@leelab:~/ethereum/test_data/keystore$ cd ~/ethereum

user@leelab:~/ethereum$ cd test_data/ 

user@leelab:~/ethereum/test_data$ vi genesis.json 

{

  "config": {

        "chainId": 8484,

        "homesteadBlock": 0,

 "eip150Block": 0,

        "eip155Block": 0, 

        "eip158Block": 0

    },

  "alloc"      : {},

  "coinbase"   : "0x0000000000000000000000000000000000000000",

  "difficulty" : "0x20",

  "extraData"  : "",

  "gasLimit"   : "0x47e7c5",

  "nonce"      : "0x0000000000000042",

  "mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",

  "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",

  "timestamp"  : "0x00"

}



user@leelab:~/ethereum/test_data$ cd ~/ethereum 

user@leelab:~/ethereum$  



이제 init을 한다.


user@leelab:~/ethereum$ geth --datadir test_data init test_data/genesis.json
INFO [07-04|09:48:34.533] Maximum peer count                       ETH=50 LES=0 total=50
INFO [07-04|09:48:34.534] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory"
INFO [07-04|09:48:34.538] Set global gas cap                       cap=50,000,000
INFO [07-04|09:48:34.538] Allocated cache and file handles         database=/home/user/ethereum/test_data/geth/chaindata cache=16.00MiB handles=16
INFO [07-04|09:48:34.565] Writing custom genesis block 
INFO [07-04|09:48:34.566] Persisted trie from memory database      nodes=0 size=0.00B time="10.34µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [07-04|09:48:34.569] Successfully wrote genesis state         database=chaindata hash=39f8fb..b1176e
INFO [07-04|09:48:34.569] Allocated cache and file handles         database=/home/user/ethereum/test_data/geth/lightchaindata cache=16.00MiB handles=16
INFO [07-04|09:48:34.586] Writing custom genesis block 
INFO [07-04|09:48:34.586] Persisted trie from memory database      nodes=0 size=0.00B time="4.004µs" gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [07-04|09:48:34.586] Successfully wrote genesis state         database=lightchaindata hash=39f8fb..b1176e
 
실행을하게 되면 위와 같이 나오는데 Successfully 가 나오면 성공적으로 프라이빗 네트워크의 제네시스 블록이 생성이 되었다. 

4. geth 명령어 실습

이제 geth를 실행해본다.

user@leelab:~/ethereum$ geth --networkid 8484 --allow-insecure-unlock --nodiscover --datadir test_data --rpcaddr 0.0.0.0 --rpc --rpcport 8545 --rpccorsdomain "*" --rpcapi="db,eth,net,web3,personal,web3,miner,admin" --miner.threads 1 console 2>> test_data/geth.log
Welcome to the Geth JavaScript console!

instance: Geth/v1.10.5-unstable-3b053185-20210702/linux-amd64/go1.16.2
coinbase: 0x48a51d5cf189476d61ac0c9ca7c930af16dee91a
at block: 0 (Thu Jan 01 1970 09:00:00 GMT+0900 (KST))
 datadir: /home/user/ethereum/test_data
 modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

To exit, press ctrl-d


콘솔 창이 나오게 되고 이제부터는 console 에 직접 우리가 API를 보고 Geth에게 명령을 내리면 된다.
API 명령어 는 기본적인 Geth 명령어와 web3 명령어 둘로 나뉠 수 있다.



먼저 마이닝을 해보겠다. 

console 에 miner.start(1)를 하기 전 먼저 coinbase가 존재하는지 확인해 보자

> eth.coinbase          // 존재한다면 address 하나가 나올 것이다. 확인 후 
"0x48a51d5cf189476d61ac0c9ca7c930af16dee91a"

> miner.start()
null

 
터미널 창을 하나 더 열어서 로그를 확인한다.

user@leelab:~$ cd ethereum/test_data/
user@leelab:~/ethereum/test_data$ tail -f geth.log
 
INFO [07-04|09:55:10.502] Updated mining threads                   threads=1
INFO [07-04|09:55:10.503] Transaction pool price threshold updated price=1,000,000,000
INFO [07-04|09:55:10.503] Commit new mining work                   number=1 sealhash=4eaed0..21d0bb uncles=0 txs=0 gas=0 fees=0 elapsed="174.739µs"
INFO [07-04|09:55:16.056] Generating DAG in progress               epoch=0 percentage=0 elapsed=4.656s
INFO [07-04|09:55:20.434] Generating DAG in progress               epoch=0 percentage=1 elapsed=9.035s
 
이제부터 DAG가 가동된다. 채굴을 하려면 좀 기다려야 되는데 본인의 PC의 경우 DAG 생성 시간은 대략적으로 7분정도 걸릴 것이다.
설정의 minethread를 1로 세팅했기 때문에 약간 느리게 될 것이다. 
이 옵션은 풀어도 상관은 없다.

DAG가 다 생성이 되고 아래와 같이 콘솔에다 명령어를 치면 block number가 지속적으로 증가하는 것을 확인 할 수 있다.

마이닝 상태는 web3.eth.mining 명령어로 알 수 있고, eth.blockNumber는 현재 latest 상태의 블록의 height를 확인할 수 있는 것이다.

> web3.eth.mining
true
> eth.blockNumber
6
> eth.blockNumber
16


이제 가장 기초적인 coinbase 에서 아까 위에서 만들었던 다른 계좌까지 송금 트랜잭션을 날려보도록 하겠다. 
먼저 coinbase 에 잔고를 확인한다.


> web3.fromWei(eth.getBalance(eth.coinbase),'ether')
85

현재 계속 변하고 있지만 85 이더가 쌓였다. 
자 이제 특정 계좌로 송금을 해보도록 하겠다 송금 전 먼저 마이닝을 중지한다.

> miner.stop()
null
> web3.eth.mining
false

아래와 같이 1 이더를 송금 해보도록 하겠다.

> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')
0
> eth.sendTransaction({from : eth.coinbase, to : eth.accounts[1], value : web3.toWei(1,'ether')});
Error: authentication needed: password or unlock
at web3.js:6357:37(47)
at web3.js:5091:62(37)
at <eval>:1:20(19)

아마 위와같이 실행하면 계정이 잠겨있다고 나올 것이다. 
계정을 풀어준다.

> personal.unlockAccount(eth.coinbase,'',0);
true

그리고 다시 위에 있는 sendTransaction을 다시 실행한다.

> eth.sendTransaction({from : eth.coinbase, to : eth.accounts[1], value : web3.toWei(1,'ether')});

"0x14dde2b400b14fb132f5f7335571f32c56b6df6f2b8b42169e1c58591343614d"


이제는 Tx Id가 Return 된 것을 볼 수 있는데 이게 바로 Transaction ID이다. 
이제 eth.accounts[1] 잔고를 확인해 보도록 한다.


> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')
0

아직 송금이 완료되지 않았다.

이더리움은 컨센서스가 PoW 이다. 
즉 Nonce의 값을 찾아내는 마이닝 과정을 통해서만 블록이 생성될 수 있고 해당 트랜잭션은 그 블록안에서 처리가 될 수 있는 것이다.
자 그럼 어느 공간에 트랜잭션이 있는지 확인해 본다.

> eth.pendingTransactions
[{ 
    blockHash: null,
    blockNumber: null,
    from: "0x48a51d5cf189476d61ac0c9ca7c930af16dee91a",
    gas: 21000,
    gasPrice: 1000000000,
    hash: "0x14dde2b400b14fb132f5f7335571f32c56b6df6f2b8b42169e1c58591343614d",
    input: "0x",
    nonce: 0,
    r: "0x79907e8b6c56961924fe295066f55a33f6a80c13a54699f155f233993bf9a18f",
    s: "0x7450c6078b7a9c8b6d6226a2dbffbbac558e4a12d0a0ea52823c09ebe6d7088f",
    to: "0x34c7d14533c224084fabb7f9add8fe2b3879b3c3",
    transactionIndex: null,
    type: "0x0",
    v: "0x426c",
    value: 1000000000000000000
}]
 

위와 같이 아직 처리가 되지 않고 Pending 된 상태로 존재한다는 것을 알 수 있다.
blockHash가 아직 null이고 Number도 null이기 때문이다.
이제 miner.start()를 실행해보면 알 수 있다.

> miner.start()
null
> eth.pendingTransaction 
undefined


이제는 사라지고 undefined 출력되는 것을 볼 수 있다.

eth.accounts[1] 잔고를 확인해 보도록 한다. 

> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')
1

송금이 완료 된 것을 확인할 수 있다.

> miner.stop()
null
> exit
user@leelab:~/ethereum$ 
 

댓글목록

관리자님의 댓글

관리자 작성일

> miner.stop()
null
> eth.pendingTransaction
undefined
> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')

1
> web3.fromWei(eth.getBalance(eth.coinbase),'ether')

454
> eth.sendTransaction({from : eth.coinbase, to : eth.accounts[1], value : web3.toWei(1,'ether')});
Error: authentication needed: password or unlock
at web3.js:6357:37(47)
at web3.js:5091:62(37)
at <eval>:1:20(19)

> personal.unlockAccount(eth.coinbase,'',0);

true
> eth.sendTransaction({from : eth.coinbase, to : eth.accounts[1], value : web3.toWei(1,'ether')});
"0x7a8d1cbbf4bca5a7f0f9b0f17206bdee6799dd7e0cdecf231ab7364253bf4632"
> eth.sendTransaction({from : eth.coinbase, to : eth.accounts[1], value : web3.toWei(1,'ether')});
"0xd189107498a26841d5964453314ad34f5390ad4450f35836e2b4ab93401d5ac3"
> eth.sendTransaction({from : eth.coinbase, to : eth.accounts[1], value : web3.toWei(1,'ether')});
"0x61c253ca28a2155dc9501a014f1c1f3b5a5e03e5c15bec8bf40e26d729d0bdb4"

> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')

1
> eth.pendingTransaction
undefined
> eth.pendingTransactions
[{
    blockHash: null,
    blockNumber: null,
    from: "0x48a51d5cf189476d61ac0c9ca7c930af16dee91a",
    gas: 21000,
    gasPrice: 1000000000,
    hash: "0x7a8d1cbbf4bca5a7f0f9b0f17206bdee6799dd7e0cdecf231ab7364253bf4632",
    input: "0x",
    nonce: 1,
    r: "0x70d53125df3680109bdba583235b222d648e57f65696c91ad98062cac5f6eae2",
    s: "0x6047e1a0474b32ef3562db7f5d63a49a91e850c1987c5b0198ca9a5e7563d862",
    to: "0x34c7d14533c224084fabb7f9add8fe2b3879b3c3",
    transactionIndex: null,
    type: "0x0",
    v: "0x426c",
    value: 1000000000000000000
}, {
    blockHash: null,
    blockNumber: null,
    from: "0x48a51d5cf189476d61ac0c9ca7c930af16dee91a",
    gas: 21000,
    gasPrice: 1000000000,
    hash: "0xd189107498a26841d5964453314ad34f5390ad4450f35836e2b4ab93401d5ac3",
    input: "0x",
    nonce: 2,
    r: "0x87b3ace5067ccd0c8501315f2702ded5fc0ae346c93e263b8aa819483082fa1e",
    s: "0x7b016c7fdaaf8bf090c451e1bb6309b5ae7db16f244a3fb2b6fcda196011def4",
    to: "0x34c7d14533c224084fabb7f9add8fe2b3879b3c3",
    transactionIndex: null,
    type: "0x0",
    v: "0x426b",
    value: 1000000000000000000
}, {
    blockHash: null,
    blockNumber: null,
    from: "0x48a51d5cf189476d61ac0c9ca7c930af16dee91a",
    gas: 21000,
    gasPrice: 1000000000,
    hash: "0x61c253ca28a2155dc9501a014f1c1f3b5a5e03e5c15bec8bf40e26d729d0bdb4",
    input: "0x",
    nonce: 3,
    r: "0x689a763bb2b6a41fb4d9e51c4460959d4eed2b593cf723a2fb6b2ae314c33b32",
    s: "0x41889a3041c5d4f95599c3173dc13d15a86ec8897893723818d994efce8bb36b",
    to: "0x34c7d14533c224084fabb7f9add8fe2b3879b3c3",
    transactionIndex: null,
    type: "0x0",
    v: "0x426b",
    value: 1000000000000000000
}]
>
> miner.start()
null
> eth.pendingTransactions
[]
> miner.stop()
null
> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')
4

> exit
user@leelab:~/ethereum$

관리자님의 댓글

관리자 작성일

트랜잭션들은 다음과 같은 필드로 구성됩니다.
nonce: EOA에 발급되는 트랜잭션 일련번호를 나타냅니다.
gas price: 가스의 가격입니다.
gas limit: 가스의 최대 사용량입니다.
from: 발신자 주소입니다.
to: 수신자 주소입니다.
value: 수신자에게 보내는 이더(ether) 개수입니다.
data: 가변길이의 바이너리 데이터(payload)입니다.
v, r, s: ECDSA 서명 구성 요소 입니다.

관리자님의 댓글

관리자 작성일

거래 영수증 항목들입니다.
blaockHash: 거래를 어떤 블록에 저장했는지 나타냅니다.
blockNumber: 거래를 몇 번째 블록에 저장했는지 나타냅니다.
contractAddress: 컨트랙트에 참여한 트랜잭션이라면 컨트랙트가 나타납니다.
cumulativeGasUsed: 트랜잭션에서 사용한 가스 사용량입니다.
from: 거래 발신자의 주소가 있습니다. 20바이트(160비트) 값입니다.
gasUsed: 사용한 가스 사용량입니다.
logsBloom: 블록 안에서 출력하는 로그 데이터를 블룸필터 형태로 저장한 것입니다
logs: 거래에서 생성된 로그들입니다.
root: 상태 트리를 바꾼 후의 상태 루트 값입니다.
to: 거래 수신자의 주소가 있습니다.
transactionHash: 32바이트의 거래 해시값을 나타냅니다.


개인정보취급방침 서비스이용약관 모바일 버전으로 보기 상단으로

TEL. 063-469-4551 FAX. 063-469-4560 전북 군산시 대학로 558
군산대학교 컴퓨터정보공학과

Copyright © www.leelab.co.kr. All rights reserved.