[연재] 이더스캔(etherscan.io)을 만들어 보자 - web3.js로 블럭 정보 저장 1

이더스캔(etherscan.io)을 만들어 보자 - web3.js로 블럭 정보 저장 1


블럭체인은 말 그대로 "블럭이 사슬처럼 엮어 있는 것"을 말한다.
즉 최초의 블럭인 제네시스 블럭부터 현재 블럭까지 차곡차곡 쌓여 있다.
블럭에 대해 살펴보면 모든 블럭은 블럭 번호와 해쉬값을 가지고 있다.


이번 연재에서는 제네시스 블럭부터 현재블럭까지 읽어 데이터베이스에 저장하는 것을 해보겠다.
각자 선호하는 DB가 있고, 이 부분은 이 글을 읽는 분들은 이미 많이 코딩하고 있으니 여기서는 다루지 않겠다.

Node.js에서 Mysql로 데이터를 저장하려면 mysql.js를 참조하기 바란다.


가장 최근에 만들어진 블럭 번호를 알아내자.

제일 먼저 할 일은 가장 최근에 만들어진 블럭 번호를 아는 것이다.
이 번호를 알아야 블럭 번호가 0 번인 제네시스 블럭부터 현재 블럭까지 읽어 데이터베이스에 저장할 수 있기 때문이다.

현재 블럭 번호를 읽어 오는 코드는 아래와 같다.

web3.eth.blockNumber
// or async
web3.eth.getBlockNumber(callback(error, result){ ... })

출처: https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethblocknumber


이 함수는 동기 방식 또는 비동기 방식 둘 다 사용할 수 있다.
하지만 RPC가 아닌 IPC 방식 Web3.providers.IpcProvider를 사용한다면 동기 방식을 사용할 수 없다.

따라서 가급적 비동기 방식으로 코딩해야 Provider를 변경하더라도 재사용이 가능하다.

web3.eth.getBlockNumber(function(err, rtn) {
    if(err) return console.log(err);
    var latest_block_number = rtn;
});


오류가 없다면 rtn에는 가장 최근에 쌓인 블럭 번호가 들어 온다.
이제 최초블럭 0번 부터 현재 블럭까지 순회하며 블럭 정보를 읽어 오면 된다.


블럭정보를 읽어오자.

블럭정보를 읽어 오는 함수는 다음과 같다.

web3.eth.getBlock(blockHashOrBlockNumber [, returnTransactionObjects] [, callback])

출처: https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethgetblock


이 함수는 블럭 번호 또는 해쉬값 어떤 것으로도 조회가 가능하다.
두번째 파라미터인 returnTransactionObjects는 블럭 내에 있는 트랜잭션 정보를 모두 읽어 올 것인지 여부를 묻는 것이다.
여기서는 블럭 정보만 읽을 것이기 때문에 false로 하겠다.


만일 블럭정보를 저장하면서 트랜잭션 정보도 함께 저장하고자 한다면 이 값을 true로 주던지 아니면 트랜잭션 해쉬값으로 트랜잭션 정보를 다시 읽어오던지 하면 된다.
web3.eth.getBlock으로 블럭 정보를 읽어 오는 코드를 추가하면 전체 코드는 다음과 같다.

web3.eth.getBlockNumber(function(err, rtn) {
    var latest_block_number = rtn;
    for(var i=0; i <= latest_block_number; i++){
        web3.eth.getBlock(i, false, function(err, block) {
            # TODO: DB에 insert하는 코드
            console.log(block);
        });
    }
});


데이터베이스에 저장하자.

전체 코드는 완성되었고 남은 것은 데이터베이스에 저장하는 부분만 만들면 된다.
이 부분은 각자 DB에 맞게 작성하면 된다.

참고로 몽고DB와 같은 JSON DB가 아니라 MySQL과 같은 관계형 데이터베이스에 저장한다면 block 구조를 알아야 테이블을 만들고 데이터를 저장할 것이다.

다음은 block을 출력한 한 예이다.

{
  "difficulty": "131136",
  "extraData": "0xd683010806846765746886676f312e3130856c696e7578",
  "gasLimit": 2104100,
  "gasUsed": 0,
  "hash": "0xb9bf6edbbb048f449ff85c36fba5c3ecd6f162400b3bed00cd609558085eca72",
  "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "miner": "0x0a5476a467ae58155f39bc30c1d2d3f85d2c7ffc",
  "mixHash": "0xa7d1f429decbb4929092f907c49adca5b9548201d545339d775b6c3095b420a0",
  "nonce": "0x34193c40bc186155",
  "number": 2,
  "parentHash": "0xd2742760a8bc9597bbd5055bd9680dcbefc02bddaf49c5656a664300cbe36f70",
  "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  "size": 534,
  "stateRoot": "0xf5f3ecbce6db46a87294e00d2b7e98a47fddb58a3892a5489e37749c9feada9c",
  "timestamp": 1525235536,
  "totalDifficulty": "262608",
  "transactions": [],
  "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  "uncles": []
}


이후로 계속 쌓이는 Block은 어떻게 저장할 것인가?

다음으로 알아볼 것은 현재 계속 쌓여지고 있는 블럭 정보는 어떻게 저장할 것인가하는 것이다. 위 코드에서 시작 블럭을 DB에 저장된 블럭 다음부터 해서 특정 시간 단위로 setInterval을 돌릴 수도 있지만...실재 저장되는 것하고는 시간 차가 난다.

다음 장에서는 RDBMS에서 제공하는 트리거와 비슷한 개념의 filter에 대해 알아보도록 하겠다.