요 몇달 간 회사일에 치어 글쓰기에 너무 소홀했던 듯 하다. 각성하고, 이제 진도를 뽑아보자~
얼마전, Vitalik Buterin 과 Martin이 한국에 다녀갔다. 국내 블록체인 업체인 코인플러그도 퍼블릭 블록체인 기반의 사업성과가 기대에 못미쳐서인지 기업용 블록체인에 눈을 돌린 듯 하다. 자체 블록체인을 발표하고, Ethereum 과 협업을 하고있는 모습이 국내 블록체인 기술의 업그레이드를 위해 노력하는 모습인것 같아 다행이라고 생각한다.
너무 오랜만의 글이라 갈길이 머니 마지막 글에 이어 일단 web3.js 를 사용하는 방법에 대해 본격적으로 이야기 해보자.
▌web3.js 소개
github.com/ethereum 의 repository 목록에서 보이는 내용이다. web3.js 는 Ethereum Compatible JavaScript API 이다.
일단 아래 그림을 보자.
예전에 외부에서 이더리움을 소개할 때 Ethereum 의 응용 구조에 대해 썼던 자료이다.현재 go Ethereum 의 경우, JSON RPC, IPC 외에도 그림에는 안나와있지만 WebSocket 을 지원한다.
위 구조를 보면 알겠지만, 이전 글까지는 Ethereum 의 JSON RPC 를 통해 어플리케이션이 Ethereum 을 사용하는 방법에 대해 소개 한 것이다.
그런데 JSON RPC 를 사용해서도 충분히 Ethereum 을 사용할 수 있겠지만, 응용 만드는 입장에서는 좀더 편하게 JSON RPC 를 호출해주는 라이브러리가 필요함을 느낀다. 특히 기본적인 Transaction 기반의 응용이 아니라 Smart Contract 를 사용하게 되면, Event 를 처리하거나 Smart Contract 에서 Return 되는 타입을 처리하여야 하는데, 이때 이러한 타입처리 또한 web3.js 라이브러리를 사용하면 편리하다.
web3.js 는 JavaScript 기반으로 Dapp 이나 서비스를 구현할 때 매우 유용하며, 현재는 EthereumJ 도 web3.js 를 지원하는 작업을 하고있다. 실질적으로 JSON RPC API 와 함께 Ethereum 의 표준 API 로 보면 되겠다. web3.js 는 내부적으로 HTTP 나 IPC 를 통해 JSON RPC API 를 호출하도록 되어있다.
▌JavaScript 코드에 web3.js 사용하기
web3.js 는 github/ethereum/web3.js 의 dist 내에 있는 web3.js 를 받아도 되지만,
Browser 에서 사용하려면 bower 를 사용하거나
Node.JS 를 사용한다면 npm 을 사용하면 된다.
이번에는 간단히 bower 로 install 한다.
[goodjoon eth_basic]$ bower install --save web3
crypto-js 와 bignumber.js 에 Dependency 가 걸려있으므로 두개를 추가로 받는다.
(npm 도 마찬가지로 web3 모듈을 설치하면 된다.)
이제 실제로 이전에 JSON RPC API 로 Transaction 보내기 했던 것을 web3.js 로 보내보도록 하고, 보너스로 블록 생성되는 이벤트를 받아보기 위한 Filter 를 하나 설치해보도록 하겠다.
화면은 간단히 아래와 같이 만들어 봤다.
일단 HTML 에서 web3.js 를 import 한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../bower_components/web3/dist/web3.js"></script>
<title>Simple Wallet</title>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="../bower_components/web3/dist/web3.js"></script>
<title>Simple Wallet</title>
그다음, web3.js 를 사용하여 Ethereum Node 에 접속하려면, 아래와 같이 Provider를 지정 해주어야 한다.
var Web3 = require('web3');
var web3 = new Web3();
web3.setProvider(new Web3.providers.HttpProvider('http://localhost:8551'));
var web3 = new Web3();
web3.setProvider(new Web3.providers.HttpProvider('http://localhost:8551'));
위 예제에서는 HttpProvider 를 지정해주었으나, IpcProvider 도 존재한다. Ethereum Node 와 같은 Machine 에서 동작한다면 IPC 로 Interface 하는것이 성능 측면에서 매우 유리하다.
▌Account 의 Balance 가져오기
Account 의 Balance 를 가져오기 위해서는 web3.eth.accounts 프로퍼티를 조사하면 된다.
function updateBalance() {
var address = web3.eth.accounts[0];
var balance = web3.fromWei(web3.eth.getBalance(address), 'ether');
$('#address').val(address);
$('#balanceAmount').val(balance);
}
var address = web3.eth.accounts[0];
var balance = web3.fromWei(web3.eth.getBalance(address), 'ether');
$('#address').val(address);
$('#balanceAmount').val(balance);
}
web3.eth.accounts[0]
web3.js API 들은 web3 라는 이름의 객체에 var web3 = new Web3(); 를 통해 할당하였다.
web3.eth 객체 내의 accounts 는 현재 Ethereum Node 에 생성된 계정들의 목록을 배열로 저장하고있다. 현재 내 Node 에 2개의 계정이 있으며, 이중 0 번 계정의 주소를 address 변수에 저장하였다.
web3.eth.getBalance(address)
특정 주소의 Balance 를 가져오는 함수이다. getBalance() 의 리턴값은 Wei 단위의 Balance 이다. address 의 Balance 를 가져와서 web3.fromWei() 함수를 통해 Wei 단위를 Ether 단위로 변경해서 balance 변수에 저장한다. 'ether' 를 지정하지 않아도 fromWei(), toWei() 함수의 기본 변환 단위는 'ether' 이다.
값을 가져와서 화면의 #address 와 #balanceAmount INPUT 필드의 value 로 표현한다.
▌Synchronous vs Asynchronous API
아마 위 함수들이 호출될 때 마다 브라우져나 Node.JS의 Console 에는 Synchronous XHR 은 deprecate 되었다고 경고가 출력될 것이다.
web3.js 에는 Synchronous 함수와 Property 들이 있으며, 이에 상응하는 Asynchronous 함수들이 있다. 원칙적으로는 Asynchronous API 를 호출해야 한다. accounts 프로퍼티 대신 web3.eth.getAccounts(address, callback) 을 주도록 되어있으며, web3.eth.getAccounts(address, function(err, addresses) { console.log(addresses)}); 처럼 Callback 을 통해 결과를 받아야 한다.
(RPC API 는 deprecate 된 Synchronous 호출을 아직 실행 해주지만, IPC 방식은 아예 호출이 불가능하다)
▌Transaction 보내기
Ether 의 이체, Smart Contract 의 Deploy (Creation), Smart Contract 의 함수 실행 (Message) 모두 하나의 Transaction 발생 함수를 통해 실행한다. 바로 web3.eth.sendTransaction() 함수이다.
sendTransaction() 함수는 앞으로 지속적으로 사용할 것이며 사용법은 매우 간단하다.
web3.personal.unlockAccount(web3.eth.accounts[0],'1111');
일단, Page 가 로드되는 시점 즈음에서 account 를 unlock 해두도록 한다. 이전 RPC API 편에서도 이야기 했듯이, Account 를 사용하기 전에는 Account 를 Unlock 해주어야 한다. 만약 Ethereum 실행 시에 --unlock 옵션을 주고 --password <패스워드파일> 을 주어서 Node 의 BootUp 시에 Unlock 을 이미 하였다면 unlockAccount() 를 실행 할 필요는 없다.
Send 버튼을 눌렀을 때에 실행되는 코드는 아래와 같다.
var toAddress = $('#toAddress').val();
var sendAmount = web3.toWei($('#sendAmount').val(), 'ether');
var txHash = web3.eth.sendTransaction({
from: web3.eth.accounts[0],
to: toAddress,
value: sendAmount
});
console.log(txHash);
var sendAmount = web3.toWei($('#sendAmount').val(), 'ether');
var txHash = web3.eth.sendTransaction({
from: web3.eth.accounts[0],
to: toAddress,
value: sendAmount
});
console.log(txHash);
web3.eth.sendTransaction(object) 함수에서 object 는 보낼 Transaction 의 내용이 정의 된 Object 이다.
- from : Transaction 을 보내는 from 주소
- to : Transaction 의 Destination 주소. 만약 Smart Contract Creation Transaction 인 경우, to 를 지정하지 않는다.
- value : 보낼 Balance 의 양 (Wei 단위)
- gas : 이번에는 Gas 양을 지정하지는 않았지만, Ethereum 은 기본적으로 90,000 Gas 를 적어 보내게 되어있다. data 필드를 사용하지 않는 기본 이체 Transaction 의 소모 Gas 는 현재 21,000 Gas 이다.
이 sendTransaction() 함수의 리턴값은 Transaction 의 Hash 값이다. Transaction 의 Hash 값은 Transaction 의 형식 자체에 오류만 없다면 Node 에서 즉시 리턴이 오는 값이다. Miner 나 타 Node 의 Validation 작업과는 무관하다.
Transaction 이 Block 에 잘 묶여졌는지 확인하기 위해서는
web3.eth.getTransactionReceipt(txHash) 로 Receipt 를 확인해야 한다. 만약 null 이 리턴되었다면 Transaction 은 Block 에 묶이지 않는 것이다.
▌Block Filter
Ethereum 에서 새로운 블록이 나오거나 Smart Contract 의 Method 내에서 Event 를 실행(Trigger) 시켰을 때, 특정 Address 나 Topic 에 해당하는 Log 를 알림 받으려고 할 때 사용할 수 있는 기능이 바로 Filter 객체이다. 그중 기본적으로 최신 블록이 생성되어 Mined/Import 되었을 때 이벤트를 받을 수 있도록 하여 좀더 동적인 느낌이 나도록 해보겠다.
var blockFilter = web3.eth.filter('latest');
blockFilter.watch(function(error, blockHash) {
var block = web3.eth.getBlock(blockHash);
appendLog('New Block('+block.number+')['+block.hash+'] / ' + block.transactions.length + ' TXs');
});
blockFilter.watch(function(error, blockHash) {
var block = web3.eth.getBlock(blockHash);
appendLog('New Block('+block.number+')['+block.hash+'] / ' + block.transactions.length + ' TXs');
});
위 처럼 web3.eth.filter() 함수를 통해 Block 에 대한 Filter 를 걸 수 있다. 'latest' 를 넣어주면 최신 생성된 블록이 있는 경우 Filter 로 잡히게 되며, 'pending' 을 적어주면 Pending 중인 블록 (마이닝 대상)을 보여준다. 또한 Smart Contract 의 Transaction Receipt 내의 Log 에 한하여 Address 나 Topic 을 옵션으로 하여 Filter 할 수도 있는데, 이건 다음번 Smart Contract 하면서 이야기 해보도록 하겠다.
이렇게 코드를 만들고 나면 최종 아래와 같은 화면을 볼 수 있다.
▌결과화면
이처럼 web3.js 를 사용하는 방법은 매우 간단하고 쉽다. 만약 Transaction 에 Custom 한 데이터를 포함하고 싶다면 sendTransaction() 시에 { data : '<HEX값>'} 을 추가하여 보내기만 하면 된다. Bitcoin 이 OP_RETUN 코드 실행으로 가져올 수 있는 40 Byte 의 임의의 데이터 공간만을 제공하는것에 비해 Gas 만 충분하다면 (1 Byte 당 5 Gas) 큰 데이터를 넣는것도 문제 없다. 실제로 수십KB 이상의 이미지 Binary 를 Homestead 와 같은조건으로 놓고 테스트해 본 결과 잘 들어간다.
다음은 Smart Contract 에 대한 개념과 개발 방법을 시작으로, Smart Contract 에 대하여 본격적으로 연재 해보도록 하겠다.
반응형
'Blockchain > Ethereum' 카테고리의 다른 글
Ethereum 응용 개발 - Smart Contract 의 응용 예시 (1/2) (4) | 2016.07.12 |
---|---|
Ethereum 응용 개발 - Smart Contract 의 이해 (3) | 2016.07.06 |
Ethereum 응용 개발 - JSON RPC 로 Transaction 발생 시키기 (2) | 2016.03.26 |
Ethereum 응용 개발 - JSON RPC API 기본 (1) | 2016.03.20 |
이더리움 Smart Contract - 개념 (1) | 2016.03.13 |