SCT 리치리스트 등 스팀엔진 데이터 가져다 쓰기 개발 방법론 및 샘플코드

in #sct6 years ago (edited)

SCT 리치리스트
https://coin-on.com/rich

어떻게 만들었나 노하우를 공유하는 포스팅입니다.

우리 개발자들이 만약 Facebook API 나 Twitter API 를 이용해서 뭘 만들려면 쉽습니다. Documentation 도 워낙 잘돼있고 막힐때면 구글링으로 stackoverflow.com 에 답변을 찾아보면 다 나옵니다.
그런식으로 블록체인 관련 개발업계에 와서 뭘 해보려고 하면 부족한 개발문서와 거의 없다시피 한 stackoverflow 검색결과 때문에 난감해지는데요.
블록체인 개발팀에게 있어서 3rd party 개발자들을 위한 개발문서 작성이란 우선순위가 한참 후순위고 다른 중요한 할일이 많기때문에 이바닥에 어쩔수없는 현실입니다.

스팀엔진측에서 제공하는 개발자 문서와 API 스펙같은게 있는지, 어디있는지, 얼만큼 잘 돼있는지 지금 이 글을 쓰는 순간에도 잘 모르겠으나
일단 https://steem-engine.com/?p=balances&a=morning 여기 지갑에 가보면 리치리스트를 만드는데 필요한 데이터가 잘 나와주고 있어서

account 를 입력하면 stake 와 balance 가 나와준다

여기서 사용된 API call 을 똑같이 가져다 쓰면 되겠죠

1.png
크롬에서 F12 눌러서 Developer Tools 들어가서 Network 탭, XHR 로 필터링 해놓고 F5 새로고침.
2.png
원하는걸 찾았습니다. JSON Response 에서 balance 와 stake 가 나오는군요

익숙한 언어 Node.js와 간단한 데이터베이스 NeDB 를 이용해서 최대한 빨리 결과물을 내놓기로 하고 만들었습니다.
두 부분으로 나뉩니다.
첫번째는 위에서 찾아낸 API 를 끊임없이 호출해서 최신 정보를 가져다가 DB에다가 저장시키는 코드.
두번째는 위에서 저장된 DB를 읽어다가 웹페이지에 뿌려주는 코드.
(두번째 거는 워낙 평범하므로 설명을 생략합니다.)

해당 request 에 오른클릭해서 cURL 포맷으로 복사해서 텍스트 에디터에 붙여넣고

curl 'https://api.steem-engine.com/rpc/contracts' 
-H 'Access-Control-Allow-Origin: *' 
-H 'Accept: application/json, text/plain, */*' 
-H 'Referer: https://steem-engine.com/?p=balances&a=morning' 
-H 'Origin: https://steem-engine.com' 
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36' 
-H 'Content-Type: application/json' 
--data-binary '{"jsonrpc":"2.0","id":12,"method":"find","params":{"contract":"tokens","table":"balances","query":{"account":"morning"},"limit":1000,"offset":0,"indexes":""}}' 
--compressed

그대로 request (https://www.npmjs.com/package/request) 이용해서 쓸 수 있도록 해보면 아래처럼 작성하니 같은결과가 나옵니다.

const options = {
    method: 'POST',
    url: 'https://api.steem-engine.com/rpc/contracts',
    headers: {
        'Access-Control-Allow-Origin': '*', 
        'Accept': 'application/json, text/plain, */*',
        'Referer': 'https://steem-engine.com/?p=balances&a=morning',
        'Origin': 'https://steem-engine.com',
        'User-Agent': 'request',
        'Content-Type': 'application/json'
    },
    gzip: true,
    json: true,
    body: {
        "jsonrpc":"2.0",
        "id":10,
        "method":"find",
        "params":{
            "contract":"tokens",
            "table":"balances",
            "query":{"account":"스팀아이디"},
            "limit":1000,
            "offset":0,
            "indexes":""
        }
    }
};

request(options, function(err, res, body) {
    console.log(body);
}

위 console.log(body) 에서 확인한 결과를 DB에 저장하는 코드

const Datastore = require('nedb');
const db = new Datastore({ filename: 'richlist.db', autoload: true, timestampData: true});

// ...

if (body.result.length > 0) {
    var i = body.result.length;
    while(i--) {
        var b = body.result[i];
        if (b.symbol == symbol) {
            var doc = {
                'account': account, 
                'balance': parseFloat(b.balance), 
                'stake': parseFloat(b.stake), 
                'stakeBalance': parseFloat(b.balance) + parseFloat(b.stake),
                'delegatedStake': parseFloat(b.delegatedStake),
                'receivedStake': parseFloat(b.receivedStake),
                'pendingUnstake': parseFloat(b.pendingUnstake)
            };
            db.count({'account': account}, function (err, count) {
                if (count) {
                    db.update({'account': account}, doc, {}, function(err, num) {
                        console.log('updated', num, doc);
                    });
                } else {
                    db.insert(doc, function(err, newDoc) {
                        console.log('inserted', newDoc);
                    });
                }
            });
        }
    }
}

위의 코드를

const grabBalance = function(symbol, account, done) {
} 

이런 함수 안에 넣어놓고 반복적으로 호출합니다.

const async = require('async');
// ...
var accountPool = [{'account': 'morning'}, {'account': 'ned'}];
const start = function() {
    async.eachSeries(accountPool, function(acc, callback) {
        grabBalance('SCT', acc.account, function() {
            setTimeout(function() {
                callback();
            }, 100); // 혹시 모를 rate limit 문제를 피하기 위해 약간의 시간차를 둡니다.
        });
    }, function(err) {
        setTimeout(function() {
            start();
        }, 60000); // accountPool 을 다 돌리고 나면 좀 쉬었다가 돌립니다.
    });
}

start();

이런식으로 하면 DB에 잘 쌓이겠죠?
DB에서 긁어다가 뿌려주면 리치리스트 완성.
grabBalance 파라미터값을 'SCT' 말고 다른걸로 하면 다른 스팀엔진토큰에도 응용 가능.

Sort:  

소스를 공유해주셔서 감사합니다. 👍

오 개발에 관심 있는데 좋은 정보 감사합니다

혹시 디커머스 진행은 어떻게 되고 있는지 알 수 있나요??? ^^

개발자의 세계는 참 놀라운 것 같습니다 ㅎㅎ 모닝님 오랜만입니다!

좋은 글 감사합니다~
저는 아직 이쪽으로는 문외한이지만 요즘 관심을 갖고 있으니... 언젠간 도움이 되겠지요~

우리 개발자들이

이 표현 왜 이렇게 웃긴가요ㅎㅎ

크롬 정말 대단한 툴인 것 같아요. 감사합니다.

좋은 정보 공유 감사드립니다.

좋은 글 감사드립니다. 풀봇이 모자라네요.

좋은 글 감사드려요.