asomescan, 그 뒤에선 무슨 일이?
최근에 저희는 asomescan(https://asomescan.com) 이라는 새로운 서비스를 오픈하였습니다.
asomescan(이하 어썸스캔)은 이더리움 검색 서비스로 이용자들이 쉽고 편리하게 본인의 트랜잭션을 검색하는 목적으로 만들어졌습니다.
저희는 기존 이더리움 스캔 서비스 중 하나인 Etherscan (이하 이더스캔)은 영어밖에 지원이 되지 않는 점, 일반 사용자들에게 불필요한 데이터가 너무 많이 전달이 되는 점들이 일반 이더리움 사용자들에게 불편을 주고 있는 것 같았습니다. 그래서 저희는 불필요한 데이터는 지우고 일반 사용자들에게 필요한 데이터만 명확하게 전달하고자 하는 서비스를 만들고 싶었습니다.
이제 asomescan 뒤에서는 어떤 일이 벌어지고 있는지 알아보도록 하겠습니다.
들어가기 전에 앞서 저희 asomescan 에서 어떤 스택을 활용하여 개발이 되었고 왜 채택하였는지 설명드리겠습니다.
AWS 서버 — 현재 서비스되고 있는 서버 중 가장 안정적으로 운영이 되고 있으며 저희에게 가장 친숙한 서비스이기 때문에 채택하였습니다.
MongoDB — 저희에게 MySQL, PostgreSQL 과 같은 관계형 DB가 필요없다고 판단하였고 그에 따라 도큐멘트 저장형 MongoDB 를 선택하게 되었습니다.
Node.js — 아무래도 현재 이더리움 관련하여 패키지가 가장 많이 유지되고 있는 대부분의 Package 가 Javascript 기반이다 보니 Node.js 사용이 필수적이지 않나 싶습니다. 대표적으로 자바스크립트 위에의 가장 최신인 Web3.js 가 작동할 수 있다는게 매력인것 같습니다.
이 게시글은 Node.js v8.11.3 Web3.js 1.0.0-beta.34 를 사용하여 작성되었습니다.
가장 먼저 가장 최근에 싱크된 이더리움 블럭 번호를 DB에서 가져옵니다. 그리고 web3.js 를 이용하여 해당 블럭정보를 가져옵니다. 블럭정보를 가져올때는 web3.eth.getBlock 함수를 이용하여 트랜잭션 정보와 함께 가져옵니다.
그리고 이 트랜잭션 정보를 루프를 활용해 Transaction Receipt 를 가져오게 됩니다.
아래는 위 과정을 코드로 변환한 내용입니다.
좀 더 코드를 깊게 보도록 하겠습니다.
web3.js 1.0.0 에서 부터는 Promise 를 활용하기 때문에 .then 과 .catch 의 콜백 지옥을 해결하기 위해서 async/await 을 활용하였습니다.
또한 map 안에서도 async await 이 작동하기 때문에 map 이 끝난 이후에 저장을 하기 위해 Promise.all 을 이용해 저장을 모든 map 이 끝난 뒤에 할 수 있도록 하였습니다.
이제 Receipt 를 받았으니 한번 토큰 전송 정보를 읽어보도록 하겠습니다.
토큰 전송 데이터를 읽기 위해서는 먼제 ‘abi-decoder’ Package 가 필요합니다. 이 패키지는 ConsenSys 에서 만든 유틸로 Receipt 의 Logs 를 보기 좋게 ABI 로 해독해줍니다.
아래 처럼 활용이 가능합니다.
추가한 ABI 를 바탕으로 해독된 Logs 를 제공해줍니다. 만약에 ABI 에 없는 function 이 호출 된 경우 “undefined” 값을 Return 해줍니다.
저는 이더리움 표준 ERC20 ABI 를 사용하였기 때문에 “transfer” 함수가 있는 경우 From, To, Value 3가지 값을 리턴하게 됩니다. 리턴 받은 값은 Checksum, Wei 값이 아니기 때문에 DB에 넣기 전 한번 Filter 를 하시는 것을 권장드립니다.
이제 토큰 전송이 된 값은 Wei Value 가 아니기 때문에 Decimal 을 받아와야겠습니다.
Decimal 은 컨트랙 Method 를 활용하여 받아 올 수 있습니다.
아래는 코드와 설명입니다.
첫번째 줄은 컨트랙 을 호출하기전 ABI 와 컨트랙 주소를 입력함으로써 한번 최초 설정을 진행해줍니다.
두번째 줄은 컨트랙 함수를 호출합니다. 코드를 보시게 되면 ‘decimals’ 라고 적힌 부분이 있는데 표준 ERC20 ABI 를 지킨 대부분의 컨트랙은 decimals 로 호출이 가능합니다. 단, 표준을 지키지 않는 곳도 많이 있다는 것을 명심해주시고 Fallback 계획을 세워두시길 바라겠습니다.
그리고 저희 Crawler 는 이제 필요없는 데이터 일부를 삭제합니다.
삭제되는 데이터는 logs, v, r, s, input 등입니다.
데이터를 삭제한 후에 transaction, receipt, 토큰 정보 등을 모두 합하며 하나의 데이터로 만듭니다.
마지막으로, 똑같은 트랜잭션 정보를 복제하여 in/out 필드를 만듭니다.이 작업은 web에서 쿼리할 시의 필드를 줄이기 위해서 작업하였습니다.
asomescan 이 출시되기 전에는 web에서 총 4개의 필드를 쿼리하도록 되어있었습니다. (from/to/tokenTo/tokenFrom) 하지만, 이렇게 쿼리를 하게 되면 쿼리가 굉장히 복잡해지며 느려지게 되는 문제가 발생했습니다. 하지만 주 목적이 검색인 서비스인데 퍼포먼스가 늦어지면 안된다고 판단하였고 in/out 필드를 추가 함으로써 1개의 필드만을 쿼리 하도록 변경하였습니다. 현재는 from 필드 하나만 쿼리하면 되도록 변경되었으며 퍼포먼스는 이전 대비 500% 이상 상승했으며 <1초 이내에 query를 모두 합니다.(14870824 도큐먼트)
위 작업을 모두 마치면 트랜잭션 Array를 데이터베이스에 저장하고 끝나게됩니다. 이제 다음 블럭으로 넘어가서 다시 위 작업을 진행합니다.
원문 확인하기 >> https://bit.ly/2uNGYTS