이더리움 프로그래밍 수업(2)
들어가며
지난 글에서는 이더리움 코어 엔진인 geth을 설치하고 다뤄보면서 이더리움 플랫폼과 프로그래밍의 개괄적인 내용에 대해 살펴 보았습니다. 사용자 계정을 만들고 이들 간에 가상화폐를 주고 받고 , 이 주고 받는 작업을 블록체인에 연결하기 위해 마이닝이라는 작업을 하였습니다. 이번에서 실제 이더리움이 제공하는 가장 유용한 기술이자 비트코인 플랫폼과 차별화되는 대표 기능인 스마트 컨트랙트를 솔리디티(Solodity) 개발 언어를 이용하여 프로그래밍하는 방법과 개발 환경 구축 등에 대해 살펴보겠습니다.
// 솔리디티(Solidity) 프로그래밍에 앞 서 기억해야 할 것들.
go-ethereum 1.6.0 이후 버전부터 geth 상에서 RPC API 호출을 사용하여 솔리디티 검파일러인 solc를 호출하여 Solidity 소스를 컴파일수 없습니다. 따라서 geth 엔진상에서 solidity compiler를 RPC로 호출하여 컴파일할 수 있는 getCompilers() API 1.6.0 버전 이후에는 작동하지 않습니다.
> web3.eth.getCompilers()
"Method does not exist/is not available" eth.getCompilers(), in geth console to eth_compilers, eth_compileSolidity are gone in go-ethereum 1.6.0
참고 : #3740에서 해당 기능 삭제되었고 #290에 그 이유가 설명이 되어 있습니다. web3에서 제공하는 객체중 eth 객체는 이더리움 노드의 코어 기능과 관련된 것들을 담당하는 데 solc 컴파일러 호출은 이 범위를 벗어나기 때문에 삭제했다고 합니다. 또한 이더리움은 저차원 EVM 바이트 코드를 처리해야 하는 데 고수준의 프로그래밍 언어와 관련된 API를 호출하는 것은 바람직하지 않다라는 입장입니다. 이해도 가는 만 이 기능은 아주 유용하고 편리한 기능한 기능이라 반드시 지원이 되었으면 합니다.
// 솔리디티 개발환경을 준비합니다.
솔리디티 프로그래밍을 위해서는 직접 로컬 컴퓨터상에 솔리디티 컴파일러를 설치하거나 Remix(aka.Brower-solidity) 같은 개발 도구를 사용하는 방법이 있습니다. Remix 외에도 Ethreum Studio 처럼 여러 개발 툴들이 있으나 Remix가 가장 편리합니다. 왜냐하면 다른 복잡한 것을 설치할 필요없이 웹 브라우져를 통해 항상 최신 버전을 사용할 수 있기 때문입니다.
Remix를 사용하기 위해 다음의 주소로 접속합니다. 참고로 OSX에서 사파리10.1.1.에서 작동이 원활치 않았고 , 크롬 59.0.3071.115 빌드에서는 사용하는 데 문제가 없었습니다. 여기서는 크롬을 기준으로 합니다.
https://remix.ethereum.org
만약 온라인으로 접속하지 않고 로컬 컴퓨터 상에 Remix를 설치하여 사용하고 싶으면 Remix 소스 코드를 다운로드를 받은 후 사용하면 됩니다. 다음은 Brower-solidity 의 다운로드 링크입니다.
https://github.com/ethereum/browser-solidity/archive/master.zip
// Remix 를 사용법을 익혀 봅니다.
모든 제품을 사용하기 전에 매뉴얼은 한번 읽어 보는 게 낭패를 당하거나 시간을 낭비하지 않는 지름길이라 생각합니다. 적어도 어디에 뭐가 있는지는 알아야 제대로 활용할 수 있듯이 Remix로 솔리디티 개발을 위해서는 Remix 개발 환경에 대한 이해가 반드시 필요하다 생각합니다. 차근차근 살펴보면서 동시에 Solidity 프로그램도 함께 익숙해져 보겠습니다.
[그림 2-1 ] Remix 접속 후 첫화면. 총 3개의 영역(컬럼)으로 구성되어 있다.
Remix는 3개 영역으로 구성되어 있습니다 - 가장 왼쪽이 소스코드 브라우져 , 가운데가 소스코드 에디터 , 그리고 오픈쪽이 컨트랙의 컴파일 및 배포, 디버깅, 분석 등 다양한 관련 옵션 등을 처리하는 영역입니다.
// 소스파일 브라우져 영역 알아보기
[그림2-2] 소스 파일 영역
소스 파일 영역에서 <<+버튼 메뉴>>는 신규 파일 생성 , 그리고 <<폴더 버튼>>은 로컬 파일 열기 , 그리고 마지막 <<체인 버튼>>은 특정 로컬 폴더을 연결하여 사용하는 기능입니다. 실제 작업을 하다보면 체인 버튼이 아주 유용한데 이 부분은 나중에 뒤에서 별도로 설명하겠습니다. 최초 설치 후 소스 파일 영약에 제공되는 Ballot.sol은 Remix에서 제공하는 기본 예제 파일입니다.
[그림2-3] 소스 코드 에디터 영역
-소스 코드 편집 영역
중간은 소스코드 편집 영역으로 <<+버튼>>은 폰트 크기를 크게 , <<- 버튼>> 폰트 크기를 작게 해줍니다. 멀티 파일을 열어서 작업할 수 있습니다.
-컨트렉 조정 영역
마지막은 컴파일 및 배포 등 컨트롤 영역입니다. 이 영역을 잘 이해해야 솔리디티 개발을 고생하지 않고 할 수 있습니다.
[그림2-4] 컨트랙 조정 영역
컨트랙 조정 영역중 Contract 탭에는 Environment 메뉴가 있는데 3개의 실행 환경 모드를 제공합니다 - Javescript VM , injected Web3 , Web3 provider.
다음은 각 실행 모드에 대한 설명입니다.
- Javescript VM - geth 노드 연결 없이 모든 개발이 로컬 컴퓨터의 Remix의 메모리상에서 이루어짐
- injected Web3 - Mist나 Metamask같이 Mist와 유사한 공급자에 의해 제공되는 실행 환경을 이용
- Web3 provider - 로컬 컴퓨터에서 작동되는 geth 노드에 연결하여 수행됩니다. 이 환경에서는 트렌젝션이 네트웍을 통해 전달될 수 있음.
위의 세가지 환경 중 가장 편리한 것이 Javascript VM입니다. 첫번째 수업해서 설명한 것처럼 보통 개발자가 컨트렉트를 만들고 이를 컴파일한 후 블록체인 상에 배포하고 작동시키기 위해서는 마이닝 작업을 통해 Ether와 Gas가 미리 준비되어 있어야 합니다. 또한 구동중인 Geth 노드에 RPC 로 연결하여 컴파일된 솔리디티 바이트코드를 EVM에 배포하고 이를 다시 이더리움 체인에 연결하기 위해 다시 마이닝하는 등 여러 작업들을 해야 만 트렌젝션의 실행 결과를 확인할 수 있습니다. 다행스럽게도 Remix의 Javascript VM 환경을 이용하면 이러한 모든 작업을 로컬 메모리상에서 Remix 에서 미리 준비해둔 자바스크립트 VM모듈을 통해 수행가능합니다. 따라서 본 수업에서는 Javascript VM 환경을 기본 환경으로 사용합니다. 실제 Javascript VM 환경으로 개발을 하고 이후 Web3 Provider 환경을 통해 실제 로컬에 설치된 geth 노드에 RPC로 연결하여 작업을 하면 편리합니다. 보통 개발자들이 개인 개발 환경에서 작업을 하고 이를 개발 이나 스테이징 환경에 올려서 테스트 하는 것과 동일한 하다고 생각하면 됩니다.
***************************************************
$$ 정확히 알고 가자. : Ether와 Gas
Remix 에서 <<Contract 메뉴>>를 보면 Gas Limit 이라는 항목이 있습니다. Gas는 한마디로 이더리움에서 트렌젝션을 실행시키기 위해 필요한 수수료입니다. 이더리움에서는 트렌젝션들이 모여 블럭이 되고 , 이 블럭을 체인에 연결하기 위해서는 마이닝 작업을 통해 해쉬 계산을 하고 합의 과정을 거쳐 가장 빨리 계산한 마이너가 해당 블록을 체인에 연결을 합니다. 이러한 블록 하나를 연결할 때 마이너는 현재 0.25 Ether를 받습니다. 또한 해당 블럭내에 있는 트렉젝션을 수행하기 위해 EVM 을 작동시키는 데 드는 대가를 Gas로 받습니다.
트렌젝션 수수료를 Ether로 주지 않고 Gsd라는 단위를 사용하는 이유는 무엇일가요? 바로 Ether는 가상 화폐이기 때문에 변동성이 생길 수 있으나 Gas는 거의 변동이 되지 않습니다. 따라서 트렌젝션을 수행하는 EVM은 계산량에 따라 고정된 Gas 값을 받습니다. 이더리움의 가스 가격의 변동 차트를 보면 거의 변동이 없습니다.
https://etherscan.io/chart/gasprice , 이더리움 가스 가격의 변동 차트
Gas Limit은 트렌젝션 처리에 쓸 수 있는 Gas 최대 한도비용입니다. 이 비용이 높을 수록 트렌젝션이 우선 처리가 될 수 있습니다. 그러나 트렌젝션 처리시 Gas Limit을 초과하면 트렌젝션이 중단되고 Gas는 그냥 소비되게 됩니다.
*****************************************************
// 컨트랙트 배포(Create)
Remix는 원격지에 있는 solc 컴파일러를 사용하여 컴파일을 합니다. <<Setting메뉴>>에 들어가면 기본값으로 컴파일 옵션이 <<Auto Compile>>로 설정되어 있습니다. 반복해서 주기적으로 컴파일을 하기 때문에 불편하면 해제해 놓아도 됩니다.
Contract 탭에서 <<Create 버튼>>는 작성된 컨트랙을 geth 노드에 배포합니다. 물론 Web3 provider 환경에서 배포를 하기 위해서는 RPC설정이 된 상태로 geth가 미리 작동이 되고 있어야 합니다. 또한 컨트렉을 배포할 때 잠시 생각을 해 보면 이런 의문점이 생깁니다. 이더리움은 어카운트가 기본인데 계정은 어떻게 되나? 그리고 컨트랙을 배포할 때는 당연히 비용을 지불해야 하는 데 어떻게 되는 거지?
잠시 생각해 보겠습니다. 먼저 Contract은 원래 Contrace Account 의 줄임말입니다. 따라서 컴파일 후 배포가 되면 자동으로 해당 컨트렉트 계정이 생기고 컨트랙트 주소가 만들어 집니다. 대신 일반 사용자 계정 ( EOAs , Externally Owned Accounts)과는 구별이 됩니다. 실제 컨트렉트 계정은 사용자 계정에 의해서만 작동되고, 작동되면 컴파일된 코드에 의해서만 컨트롤이 됩니다. 그리고 당연히 코드를 이더리움 상에 배포시 대가를 지불해야 합니다. 다행이도 Remix의 Javascript VM환경에서는 이 대가를 Remix 대신 처리를 해주니 별도의 마이닝 작업 등을 할 필요가 없습니다. 물론, Web3 provider 환경에서는 미리 Ether를 할당해 높거나 마이닝을 통해 직접 처리해야 합니다.
<<Create 버튼>>을 클릭하여 배포를 하면 아래 [그림2-5]처럼 ballot 컨트렉트를 컨트롤 할 수 있는 다양한 버튼들이 나타납니다. 분홍색으로 표시된 각 트렌젝션들은 실제 해당 값을 입력하여 실행하면 그 결과를 바로 확인할 수 있습니다.
[그림2-5] 컨트랙 배포 후 화면
// web3 provider 환경 사용하기
로컬 컴퓨터 상의 구동중인 geth 노드에 연결하여 사용하고 싶다면 web3 provider 환경 옵션을 선택해야 합니다. <<web3 provider >>옵션을 선택하면 다음과 같이 로컬에 있는 이더리움 노드와 연결을 원하는 지 다시 한번 묻는 팝업 윈도우가 나타납니다.
[그림2-6] <<web3 provider >>옵션 선택 후 팝업 화면
<<확인>>버튼을 선택합니다. 다음과 같이 이더리움 노드의 IP 주소와 RPC 포트를 묻는 팝업 윈도우가 나타납니다.
[그림2-7] <<web3 provider >>옵션에서 서버의 Endpoting 입력 화면
로컬 컴퓨터의 IP 주소와 RPC 포트인 8080을 입력합니다. 수업1에서 우리는 이미 다음과 같이 로컬컴퓨터상에서 이더리움 노드를 작동시켜 놓았습니다.
MacBook-Pro:go-ethereum jhpark$ geth167 --identity "JayBlockChain" --rpc --rpcaddr "127.0.0.1" --rpcport "8080" --rpccorsdomain "*" --datadir "/Users/jhpark/go-ethereum/go-ethereum-1.6.7/build/bin/privatechain" --port "30303" --nodiscover --rpcapi "db,eth,net,web3,personal" --networkid 1999 --mine console
// 개발시 로컬 폴더 연결하여 활용하기
Remix는 웹 기반이기 때문에 작업을 하다 보면 로컬상의 폴더를 연결해서 쓰면 편하겠다라는 생각이 듭니다. 앞서 살펴본 소스 파일 브라우져 영역에서 <<체인 버튼>>이 바로 로컬 파일을 연결하는 기능입니다.
해당 <<체인 버튼>>을 클릭하면 다음과 같이 로컬 파일을 연결하겠느냐라는 팝업 윈도우가 나타납니다.
[그림2-8] 로컬 폴더를 연결하겠느냐는 확인 팝업 윈도우
연결을 위해 <<Connect 버튼>>을 선택하면 다음과 같이 로컬 컴퓨터의 특정 폴더를 연결할 수 있습니다. 연결된 후에는 <<Connect 버튼>>이 녹색으로 변경됩니다.
[그림2-9] 로컬 호스트 상의 특정 폴더를 연결한 후의 모습
그런데 이렇게 특정한 로컬 폴더에 연결을 하기 위해서는 remixd라는 모듈을 설치하고 구동시켜야 만 합니다.
//로컬 폴더를 연결하기 위해 remixd 설치하기
remixd를 설치하기 위해서는 npm 이 필요합니다. Npm(Node.js package echosystem)은 오픈소스 자바 스크립트 패키지 관리툴입니다. node.js 를 설치하면 자동으로 함께 설치됩니다.
먼저 , http://nodejs.org 에서 설치 파일을 다운로드 합니다. 제 경우 macOS용 V6.11.2 LTS버전을 다운로드 받아 설치했습니다. 설치 후 npm으로 다음과 같이 remixd 설치합니다.
npm install -g remixd
MacBook-Pro:~ jhpark$ npm install -g remixd
remixd 설치 후 다음과 같이 Remix에서 연결하여 사용하고 싶은 공유 폴더를 -S옵션과 함께 지정하여 remixd 를 구동 시킵니다. 여기서는 /Users/jhpark/go-ethereum/contracts를 공유하였습니다.
remixd -S [로컬에서 공유할 폴더 위치]
cBook-Pro:contracts jhpark$ remixd -S /Users/jhpark/go-ethereum/contracts
[WARN] Any application that runs on your computer can potentially read from and write to all files in the directory.
[WARN] Symbolinc links are not forwarded to Remix IDE
Shared folder : /Users/jhpark/go-ethereum/contracts
Fri Aug 04 2017 09:23:45 GMT+0900 (KST) Remixd is listening on 127.0.0.1:65520
이제 Remix에서 공유한 폴더를 소스 파일 브라우져에서 연동하여 사용할 수 있습니다.
// 첫번째 솔리디티 프로그램 작성 : SimpleStorage.sol
자 이제 어느 정도 준비가 되었으니 첫번째 아주 간단한 프로그램을 하나 작성하여 작동시켜 보겠습니다.
먼저 , Remix의 파일 브라우져 영역의 <<+ 메뉴>>를 선택하여 새로운 파일을 생성하고 다음의 내용을 입력합니다.
이 경우 프로그램 파일은 로컬 브라우져 상에 저장이 됩니다. 가장 편리한 방법은 앞서 Remixd를 통해 공유한
로컬 폴더내에 해당 파일을 원하는 에디터로 작성하는 것 입니다. 일단 파일을 작성하면 자동으로 Remix가 Remixd를
통해 해당 파일을 읽어 옵니다. 제 경우 /Users/jhpark/go-ethereum/contracts 폴더 밑에
SimpleStorage.sol를 vi를 사용하여 작성하였습니다.
pragma solidity ^0.4.0;
contract SimpleStorage {
uint storedData;
function set(uint x)
{
storedData = x;
}
function get() constant returns (uint)
{
return storedData;
}
}
위의 예제는 솔리디티 가이드 문서에서 첫번째로 나오는 예제 파일입니다. 보다 자세한 내용은 아래 링크를 참고하세요.
참고 : 솔리디티 개발 문서 : https://media.readthedocs.org/pdf/solidity/develop/solidity.pdf
작성 후 컴파일시 문법적 오류가 없다면 아래와 같은 화면이 나타납니다. 앞서 설명드린 것처럼 Remix는 auto compile을 합니다 ( <<settings 메뉴>> ).
[그림2-10] SimpleStorage.sol 컴파일 후 화면
이 프로그램은 무척 단순합니다. solidity ^0.4.0은 솔리디티 0.4.0으로 작성되었으니 업그레이드된 컴파일러가 나오더라도 이 파일은 0.4.0 방식으로 처리해 달라는 의미이며 , SimpleStorage 라는 이름의 contract는 내부의 상태가 256비트 크기의 unsigned integer 타입인 storedData와 이 상태에 값을 추가하는 set 이라는 이름의 function과 상태의 값을 알려주는 get function으로 구성되어 있습니다. 특별한 사용자 계정에 의해 조작되는 것이 없기 때문에 누구나 SimpleStorage를 이용해서 상태 값을 설정하거나 조회할 수 있습니다.
작동을 시켜 보겠습니다!!.
오른쪽에 <<Create>> 버튼을 눌러 컴파일된 솔리디티 바이트코드를 배포하겠습니다. 배포 후 [2-11] 처럼 화면 하단에 SimpleStorage 컨트렌트의 트렌젝션과 실행 비용에 대한 Gas 비용, 그리고 컨트렉트 주소 등이 나타납니다.
[그림2-11] 배포 된 후 SimpleStorage 컨트렉트
그리고 재미나게도 함수 set은 트렌젝션, get은 Call이라고 합니다. 왜 같은 함수를 구별할까요? 제 생각에 트렌젝션은 상태의 변화를 가져오는 것이고 , Call은 상태변화가 없어서 구별하는 것이 아닐까 싶습니다. 이후 계속 맞는 지 확인해 보겠습니다.
set 트렌젝션에 1000 을 입력하고 버튼을 눌러 작동을 시킵니다.
[그림2-12] SimpleStorage 컨트렉트의 set 트렌젝션 실행
set함수 실행 후 get 버튼을 클릭하여 수행하면 다음과 같이 내부의 상태 값이 1000으로 바뀐 것을 확인할 수 있습니다.
[그림2-13] SimpleStorage 컨트렉트의 get 실행
마치는 말
지금까지 본격적인 스마크 컨트랙트 개발에 앞서 Remix를 사용하여 솔리디티 언어로 스마트 컨트랙트를 작성하고 이를 실행하는 등 기본 사항들을 살펴 보았습니다. 다음부터는 본격적으로 솔리디티를 통한 스마트 컨트렉트 프로그래밍에 대해 살펴 보겠습니다. 프로그래밍을 하면서 필요한 개념과 용어는 중간에 지속적으로 소개하도록 하겠습니다. 혹시, 잘못된 내용이나 추가할 내용있으면 지속적으로 알려주시면 수정하도록 하겠습니다.