Grass miner 만들기
Grass 코인을 서버에서 항시 채굴해보자
Grass
약 3달 전쯤 유튜브를 보다가 우연히 발견한 코인이다. 내 네트워크 대역폭을 제공하고 그 댓가로 해당 코인을 지급해주는 개념이다. (AI 학습을 위한 데이터 획득을 위함이라나...) 때문에 컴퓨팅 파워를 무지막지하게 활용해야하는 다른 코인보다 손쉽게 채굴할 수 있다.
나름 방식도 간단할 뿐더러 아직 활성화가 되지 않아 실제로 트래픽을 잡아먹지 않았다. 채굴 보상은 대략 3 만원 / ip 정도로 잡고 있어, 홈 서버가 굴러가는데 소요되는 전기세를 손쉽게 얻어낼 수 있다고 생각이 들었다.
작동 방식
Grass 의 채굴방식은 간단하다. 그냥 Chrome extension 을 설치하고 로그인하면 터널이 형성되어 내 디바이스의 네트워크를 통해서 데이터를 획득할 수 있다.
Miner 만들기
사실 기존에 Grass miner 로 제공된 코드들이 github 에 있었다. 따로 개발하기는 귀찮아서 해당 프로그램을 사용해서 채굴을 했다. Chrome extension 을 통해서만 채굴이 가능하기 때문에 대부분의 채굴 프로그램은 다 webdriver 를 load 하고 crx 파일을 통해서 확장 프로그램을 로드하며, 접속을 확인하는 정도로 작동한다.
그런데 이번에 확장 프로그램의 새 버전을 출시하며 1.25x 의 보상을 주었고, 기존의 프로그램의 경우 제대로 대응이 되지 않았다. 코드를 조금 변경하면 되기는 하는데, 단순한 작업인지라 코드가 굉장히 지저분했다.
또한 이번에 모니터링을 옮기면서 Grass 가 제대로 채굴되고 있는지에 대해서도 정보를 받아와보고 싶었다. 그래서 그냥 취미겸 한번 만들어보기로 했다.
구상
Grass 의 경우 이렇게 따로 올려서 채굴하는 방식은 다 동일할 수 밖에 없다. 단순히 어떤 언어로 작성하냐의 차이 정도이다. 다만, 이번에 Prometheus 를 통한 모니터링이 가능하도록 하는 기능을 추가할 것이며, 추후에 변경사항이 있을 때 조금 더 편리하게 코드를 고치고자 깔끔하게 리팩토링하는 과정이 될 것이다.
대략 정리하면 이렇게 구성해서 프로그램을 만들 수 있다.
- Chrome webdriver 를 통해 확장 프로그램을 로드
- Selenium 을 통해서 로그인 / 정보획득 자동화
- FastAPI + Prometheus Client 를 통해서 Prometheus metric 제공
리팩토링하기
위 레포에 있는 코드의 경우, main.py
에 다 때려박은 형태이다. 코드를 변경할 수는 있었지만 너무 더러워서 수정할 때 귀찮음이 있었다. 그래서 기능적으로 모듈로 분리해보고자 했다. 위 코드를 보면 다음과 같이 움직인다.
- 환경 변수로부터 유저 로그인 정보를 획득한다.
- 확장 프로그램을 다운받는다.
- Chrome webdriver 를 확장 프로그램과 함께 로드한다.
- webdriver 를 통해서 로그인한다.
- webdriver 를 통해서 연결 상태를 검증한다.
- 연결 상태를 api 를 통해서 받아오기 위해 Flask 를 시작한다.
이를 각각 기능적으로 나눠서 생각해봤다.
- 환경변수를 로드하는 기능
- 확장 프로그램을 가져오는 기능
- webdriver 를 로드하는 기능
- grass 페이지 내에서 작업을 하기 위해 webdriver 를 조작하는 기능
- API
그런데, 이 중에서 확장 프로그램을 다운받는 기능은 제외했다. 굳이 URL 로 받아올 이유가 딱히 없다. 미리 local 에 받아두고 이를 그냥 바로 주입하는 편이 나았다. 결과적으로 다음과 같이 다시 나누었다.
Config
- 환경 변수를 가져오고 관리
Util
- 프로그램 내 기타 유틸리티 기능
GrassHandler
- webdriver 를 통해 app.getgrass.io 에서 핸들링하는 기능 집합
Grass
- Grass miner 를 시작 / 관리 / 데이터 획득을 위해 driver / handler 를 제공받아 작동하는 최종 인터페이스
API
- FastAPI 의 controller code 들을 담음
Grass
와 GrassHandler
의 경우 굳이 구분을 한 이유는 복잡성 때문이었다. 프로그램 특성상 webdriver
를 변경하거나 handler
를 변경할 이유는 잘 없기에 GrassHandler
코드와 통합되어 작성해도 별 문제는 없다. 다만, 이렇게 때려박아버리니 기존의 코드와 다를 바가 없었고 기능 구분이 되지 않았다.
그래서 Grass
는 내 프로그램 입장에서 필요한 기능들의 집합한 인터페이스 느낌으로 활용하도록 했다. GrassHandler
의 경우 webdriver
를 조작하는데만 집중하도록 했다. 이렇게 코드를 작성할 경우 webdriver
를 다른 것으로 교체하거나 webdriver
가 아닌 다른 방식으로 채굴이 가능해졌을 때 handler
만 교체해서 사용하면 된다.
Util
부분의 경우 사실 애매한 method 들의 집합이다. 시간을 변환한다거나, Chrome driver 를 획득한다거나 하는 기능이다. 좋은 코드라고는 할 수 없겠으나 따로 나눠둘 곳도 마땅하지 않아 그냥 묶어뒀다.
그대로 나름 나누고 나니 코드를 읽고 수정하는데 간편해졌다. (나만 그럴지도)
Prometheus client
Metric을 받아와서 Grafana 로 보고 싶었다. 모니터링 서버의 경우 Prometheus를 통해 메트릭을 모두 수집하고 있어, 여기서도 Prometheus 를 통해서 pull 하도록 했다. 이는 prometheus-client
라이브러리의 활용을 통해서 쉽게 해결할 수 있다.
겪었던 문제
FastAPI :코드를 작성하면서 FastAPI
를 괜히 사용했다는 것을 알게됐다. FastAPI
의 경우 asyncio
를 사용하는데, selenium
을 통해서 webdriver
를 조작하는 과정은 블로킹 될 수 밖에 없어 이점을 취하지 못했다.
또한 프로그램 로드 과정에서 main.py
에서 실행하는 로직 그대로 프로그램이 시작되는 것이 아니었다. 이 때문에 프로그램을 종료하는 과정이 복잡해졌으며, 원하는 에러 코드로 exit 할 수도 없었고, 객체를 조작함에 있어서도 좀 고생을 했다. (python에 대한 이해 부족이다...)
요리조리 해결 방안을 찾아내기는 했으나 적절하지 못했던 선택이었다. Flask
로 전환을 좀 고려해봐야겠다.
Selenium : app.getgrass.io 의 서버가 꽤 불안정하다. 로그인 요청을 했을 때 바로 요청을 받아주면 좋겠으나 그냥 무한 대기를 해버리는 경우가 빈번했다. 또한 로그인을 하더라도, 로드가 제대로 되지 않는 경우도 많았다. 이런 경우 마땅히 방법이 없어, 프로그램을 재시작하는 수 밖에 없었다.
Python : Grass 객체나 Prometheus 객체의 경우 프로그램 전반에서 인스턴스가 하나만 존재해야한다. Python 으로 코드를 제대로 작성해본적이 없어서 언제 인스턴스가 만들어지고, 코드가 실행되는지, 클래스 생성자에 대한 이해가 부족했다. 지금 해결책이라고 한 방법들이 좋은 방법은 아닐 것 같다.
Grafana Dashboard 만들기
Grafana Dashboard 의 경우 매번 있는 것을 사용했었다. 이번에 처음 만들어보는데 그렇게 어렵지는 않았다. 다음과 같은 구성으로 대시보드를 구성했다.
- 전체 노드 상태 확인
- Summary
- 네트워크 퀄리티 기록 (range)
- 채굴량
- 시간별 채굴량
- 각 노드 상태
- 위와 거의 동일
생각한대로 잘 결과를 받아온다. grass 홈페이지에서도 이미 보여주는 정보들이라 필요한가 싶긴하다 ㅋㅋ. 그래도 Grafana 내에서 확인할 수 있으니 나름 의미는 있겠다. 노드가 많았으면 조금 더 활용도가 있었을텐데 아쉽다.
현재는 실제로 트래픽이 발생하지 않아 큰 의미는 없지만, 트래픽 모니터링은 기능에 추가하는게 어떨까싶다.
후기
재미삼아서 만들어본 프로젝트였다. 크게 뭔가 한 것은 없고 다음과 같은 것들을 가볍게 경험했다.
- 나름의 OOP 하기
- Selenium 으로 webdriver 조작
- Prometheus client 만들기
- Grafana dashboard 만들기
허접하지만, 누군가 github 에서 보고 referal 을 해서 부자가 됐으면 좋겠다. ㅋㅋ
끝~