이더리움 프라이빗 네트워크 구축 및 스마트 컨트랙트 실습



Geth 사용


  1. Go Ethereum (Geth) 설치 - https://geth.ethereum.org/downloads/

  1. 터미널에서 geth 실행

  1. 계정 생성: geth --datadir "드라이브명:\폴더명" account new
    • 이후 해당 폴더에 keystore 파일과 공개키가 생성됨

  1. Genesis block 코드 작성 (임의의 .json 파일 생성)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"config": {
"chainId": 1008,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc": {
"개인 퍼블릭 키 주소": {"balance": "보유 금액"
},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x20000",
"extraData": "",
"gasLimit": "0x2fefd8",
"nonce": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00"
}

  1. Genesis Block 생성: 계정 폴더로 이동한 후 geth --datadir 드라이브명:\계정 폴더명 init 파일명.json

  1. 노드 실행: geth --datadir 드라이브명:\폴더명

  1. 노드 실행 및 네트워크 접속: geth --datadir 드라이브명:\폴더명 --networkid 숫자 console
    • 숫자에는 메인넷과 테스트넷에서 사용하는 1~4번을 제외하고 아무 숫자나 대입



Geth eth 명령어


명령어 이름 명령 내용
eth.blockNumber 블록 개수 확인
eth.getBlock(블록번호) 블록 정보 확인
eth.accounts 계정 조회
eth.getBalance(“지갑 주소”) 또는 eth.getBalance(지갑 인덱스) 계정 잔액 조회



Geth 모듈


  • admin
  • debug
  • eth
  • ethash
  • miner
  • net
  • personal
  • rpc
  • txpool
  • web3



  1. 계정 생성: personal.newAccount()

  2. 계정 확인: personal.listWallets


  1. 트랜잭션 발생: eth.sendTransaction({from:"보내는 주소", to:"받는 주소", value:전송량}) 또는 eth.sendTransaction({from:보내는 계정 인덱스, to:받는 계정 인덱스, value:전송량})
    • 초기 설정 시 계정이 잠겨 있음 (11번에서 해결)

  1. 계정 잠금 해제: personal.unlockAccount(계정 인덱스, '비밀번호') 또는 personal.unlockAccount("지갑 주소", '비밀번호')
    • 아직 블록이 생성되지 않았기 때문에 반영되지 않음

  1. 트랜잭션 조회: eth.getTransaction("트랜잭션 해시값")
  • Pending 트랜잭션 조회: eth.pendingTransactions
    • 아직 블록에 포함되지 않은 상태를 Pending이라고 함

  1. 마이닝 보상받을 지갑 확인: eth.coinbase
  • 마이닝 보상받을 지갑 변경: eth.setEtherbase("지갑 주소")

  1. 마이닝 시작: miner.start()

  2. 마이닝 종료: miner.stop()



프라이빗 네트워크 구축


  1. 각 노드를 구성할 새로운 폴더 node1 ~ node4를 만들고 각각 계정 생성

  1. Genesis block 코드 작성 (임의의 .json 파일 생성)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"config": {
"chainId": 1008,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc": {
"노드1 폴더의 개인 퍼블릭 키 주소": {"balance": "보유 금액"},
"노드2 폴더의 개인 퍼블릭 키 주소": {"balance": "보유 금액"},
"노드3 폴더의 개인 퍼블릭 키 주소": {"balance": "보유 금액"},
"노드4 폴더의 개인 퍼블릭 키 주소": {"balance": "보유 금액"}
},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x20000",
"extraData": "",
"gasLimit": "0x2fefd8",
"nonce": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x00"
}

  1. Genesis block 파일을 각 노드 폴더에 복사

  1. 터미널 상 노드1 폴더로 이동 후 geth --datadir 드라이브명:\노드1 폴더명 init 파일명.json

  1. 노드1 구동: geth --networkid 앞에서 설정한 숫자 --datadir 드라이브명:\노드1 폴더명 --rpc --rpcport 8545 --rpcaddr "0.0.0.0" --rpccorsdomain "*" --rpcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --port 30303 --allow-insecure-unlock console

  1. 새로운 터미널1에서 노드2 폴더로 이동 후, 4, 5번과 동일하게 입력
    • 단, 노드1 폴더명은 노드2 폴더명으로, rpcport는 8545에서 8546으로, port는 30303에서 30304 --ipcdisable로 교체

  1. 새로운 터미널2에서 노드3 폴더로 이동 후, 4, 5번과 동일하게 입력
    • 단, 노드1 폴더명은 노드3 폴더명으로, rpcport는 8545에서 8547으로, port는 30303에서 30305 --ipcdisable로 교체

  1. 새로운 터미널3에서 노드4 폴더로 이동 후, 4, 5번과 동일하게 입력
    • 단, 노드1 폴더명은 노드4 폴더명으로, rpcport는 8545에서 8548으로, port는 30303에서 30306 --ipcdisable로 교체

  1. 노드1 터미널로 이동한 후 admin

  1. admin 정보에서 나오는 enode 값 복사

  1. 노드2, 3, 4 터미널로 각각 이동하여 admin.addPeer("노드1의 enode값")

  2. 노드3, 4 터미널로 각각 이동하여 admin.addPeer("노드2의 enode값")

  3. 노드4 터미널로 이동하여 admin.addPeer("노드3의 enode값")


  1. 노드 간 트랜잭션 전송 및 블록 생성



스마트 컨트랙트


Remix를 통해 스마트 컨트랙트 배포 - https://remix.ethereum.org/



Solidity 변수 및 데이터 타입


데이터 타입 키워드 사용 범위
Boolean bool True or False True, False
Uint uint8 부호가 없는 정수 표현 0 ~ 255
uint16 부호가 없는 정수 표현 0 ~ 65,535
uint24 부호가 없는 정수 표현 0 ~ 16,777,216
uint256 부호가 없는 정수 표현 0 ~ 2^256
uint 부호가 없는 정수 표현 0 ~ 4,294,967,295
String string 문자열 -
Address address 주소 잔액 조회 -
address payable 이더리움 전송 -
Array DataType[] 배열 선언 -
push 가장 마지막 데이터 추가 -
pop 가장 마지막 데이터를 가져오고 제거 -
length 배열의 길이 -
struct 구조체 선언 -
Map Mapping
(key type=>value type)
-



Solidity 함수 및 옵션


1
2
3
Function 함수명() 옵션 {
기능 정의
}

  • view/pure를 사용하여 데이터 조회 시 수수료를 지불하지 않음

  • view는 변수 값을 조회하여 반환이 가능하나 pure는 변수에 접근이 불가능함

  • view/pure가 붙은 함수는 데이터 변경이 불가능함


View Pure
상태 변수 값 변경 상태 변수 읽기
이벤트 발생 this.balance 혹은 <주소>.balance로 접근
다른 계약 생성 Block, tx, msg 중 하나의 멤버 변수에 접근
(msg.sig와 msg.data) 제외
selfdestruct 사용
(해당 계약 계정을 삭제하고 모든 잔액을 지정된 주소로 이동)
pure로 정의되어 있지 않은 어떠한 함수라도 호출
이더리움 전송 특정 OPCODE를 포함한 인라인 어셈블리 사용
view 혹은 pure로 선언되지 않은 어떠한 함수라도 호출 -
로우 레벨 호출 -
특정 OP Code를 포함한 인라인 어셈블리 사용 -



함수의 호출 범위 (가시성)


  • public: 모든 영역 (상속받은 컨트랙트, 외부 컨트랙트, 내부)에서 함수 호출 가능

  • private: 해당 함수를 포함한 컨트랙트 내부에서만 호출 가능

  • external: 다른 컨트랙트에서 호출하거나 트랜잭션으로만 호출 가능

  • internal: private과 비슷하지만 internal은 상속받은 컨트랙트에서도 호출 가능



생성자


  • constructor 키워드를 사용

  • 함수와 동일한 방법으로 사용

  • 스마트 컨트랙트를 배포할 때 가장 처음 호출되는 함수

  • return 키워드 사용 불가



Payable


  • 외부로부터 이더리움을 받았을 때 호출하도록 하는 키워드

  • payable이 붙어 있으면 이더리움을 받았을 때 호출하라는 의미가 있음

  • payable이 붙은 경우 함수는 external이어야 함


  • msg.sender: 함수를 호출한 지갑 주소를 가져옴

  • msg.value: 전송된 이더리움 개수



함수 변경자


  • 함수 변경자는 함수를 실행할 때 미리 실행되는 함수

  • modifier 키워드 사용

  • 특정 지갑 주소만 함수를 호출할 수 있도록 설정할 때 사용



예외처리


require, assert를 이용



이벤트


  • event 키워드를 사용

  • 스마트 컨트랙트에서 특정한 일이 발생했을 때 외부에 알려주는 역할



Address 타입의 자료형


  • Address 타입의 자료형은 balance와 transfer 사용 가능

  • Balance는 특정 지갑 주소의 이더 보유량을 조회할 때 사용

  • Transfer는 스마트 컨트랙트가 보유중인 이더리움을 다른 지갑 주소로 전송 가능



조건문과 반복문


  • 조건문: if / if else / else

  • 반복문: for



상속


  • is 키워드 사용

  • public, internal일 때 사용 가능



delegatedcall, call


다른 컨트랙트를 호출하기 위해 사용



ERC-20


  • Ethereum Request for Comments (ERC)

  • ERC-20 기반으로 토큰을 생성할 수 있음



스마트 컨트랙트 실습


  1. 메타마스크 설치 - https://metamask.io

  1. 메타마스크 계정 생성 후 Ropsten 테스트넷 faucet 사이트로부터 1 이더리움 수령 - https://faucet.ropsten.be/

  1. Remix - Deploy & Run Transactions - Environment에서 Injected Web3 선택

  1. Solidity 파일 작성 후 컴파일러를 선택하고 컴파일

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
pragma solidity >=0.4.22 <0.6.0;

contract SogangBaselab_Token {
string public constant name = "BaseLab";
string public constant symbol = 'SBL';
uint8 public constant decimals = 18;

uint256 public totalSupply;

mapping (address => uint256) public balanceOf;

event Transfer (address indexed from, address indexed to, uint256 value);
event Burn (address indexed from, uint256 value);

address owner;

modifier onlyOwner() {
require (msg.sender == owner);
_;
}

constructor (
uint256 _totalSupply
) public {
owner = msg.sender;
totalSupply = _totalSupply * 10 ** uint256(decimals);
balanceOf[msg.sender] = totalSupply;
emit Transfer (address(this), msg.sender, totalSupply);
}

function transfer(address to, uint amount) public {
require (balanceOf[msg.sender] >= amount);
balanceOf[msg.sender] -= amount;
balanceOf[to] += amount;
emit Transfer(msg.sender, to, amount);
}

function burn(uint amount) onlyOwner public {
require(totalSupply >= amount);
balanceOf[msg.sender] -= amount;
totalSupply -= amount;
emit Burn (msg.sender, amount);
}

function addPublish(uint amount) onlyOwner public {
totalSupply += amount * 10 ** uint(decimals);
balanceOf[msg.sender] += amount * 10 ** uint(decimals);
}
}









강의 자료 출처: 서강대학교 컴퓨터공학과 서중원 박사과정

이더리움 프라이빗 네트워크 구축 및 스마트 컨트랙트 실습

https://y8ncastle.world/2020/02/25/education/ethereum/ethereum-private-network/

Author

Alec J

Posted on

2020-02-25

Updated on

2021-02-09

Licensed under