#!/usr/bin/env node
const ethers = require('ethers');
const http = require('http');
require('dotenv').config();
const config = {
host: process.env.ETH_RPC_HOST || 'localhost',
rpc_port: process.env.ETH_RPC_PORT || 8545,
network: process.env.ETH_NETWORK || 'homestead',
local_port: process.env.ETH_MONITOR_PORT || 50000,
max_difference: process.env.MAX_BLOCK_DIFFERENCE || 3,
server_name: process.env.SERVER_NAME || 'test-geth',
server_ip: process.env.SERVER_IP || '127.0.0.1',
};
const provider = ethers.getDefaultProvider(config.network);
const localProvider = new ethers.providers.JsonRpcProvider(`http://${config.host}:${config.rpc_port}`);
localProvider.connection.timeout = 5000;
function setCORSHeaders(res) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
}
async function getBlockNumbers() {
try {
const localBlockNum = await localProvider.getBlockNumber();
const networkBlockNum = await provider.getBlockNumber();
return { localBlockNum, networkBlockNum };
} catch (e) {
console.error(e);
return null;
}
}
function createHealthcheckResponse(localBlockNum, networkBlockNum, responseStatus) {
const difference = (localBlockNum - networkBlockNum).toString();
return JSON.stringify({
difference,
serverIpString: config.server_ip,
netWork: config.network,
responseStatus,
server_name: config.server_name,
});
}
const onHealthcheckRequest = async (req, res) => {
setCORSHeaders(res);
console.log(`>> checking ${config.host}:${config.rpc_port} (${config.network})`);
const { localBlockNum, networkBlockNum } = await getBlockNumbers();
if (!localBlockNum || !networkBlockNum) {
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end();
return;
}
const responseStatus = networkBlockNum - localBlockNum > config.max_difference ? 500 : 200;
res.writeHead(responseStatus, { 'Content-Type': 'application/json' });
const healthcheckResponse = createHealthcheckResponse(localBlockNum, networkBlockNum, responseStatus);
res.end(healthcheckResponse);
};
console.log(`Starting eth monitoring service for ${config.host}:${config.rpc_port} on ${config.local_port}...`);
http.createServer(onHealthcheckRequest).listen(config.local_port);
환경 변수 설정 및 기본값 지정
프로젝트에 필요한 환경 변수와 기본값을 설정한다. 이를 위해 config 객체를 사용하여 Ethereum 노드와 관련된 정보를 저장한다. 예를 들어, ETH_RPC_HOST, ETH_RPC_PORT, ETH_NETWORK 등의 정보를 설정할 수 있다.
dotenv를 활용하여 환경변수를 관리하는 것도 가능하다.
const config = {
host: process.env.ETH_RPC_HOST || 'localhost',
rpc_port: process.env.ETH_RPC_PORT || 8545,
network: process.env.ETH_NETWORK || 'homestead',
local_port: process.env.ETH_MONITOR_PORT || 50000,
max_difference: process.env.MAX_BLOCK_DIFFERENCE || 3,
server_name: process.env.SERVER_NAME || 'test-geth',
server_ip: process.env.SERVER_IP || '127.0.0.1',
};
Ethereum JSON-RPC 프로바이더 초기화
ethers.js 라이브러리를 사용하여 기본 Ethereum 프로바이더(provider)와 로컬 JSON-RPC 프로바이더(localProvider)를 설정한다. 이 프로바이더들은 Ethereum 블록체인과 상호 작용하는 데 필요한 기능을 제공한다.
const provider = ethers.getDefaultProvider(config.network);
const localProvider = new ethers.providers.JsonRpcProvider(`http://${config.host}:${config.rpc_port}`);
localProvider.connection.timeout = 5000;
CORS 헤더 설정 함수
setCORSHeaders 함수를 사용하여 모든 클라이언트가 서버에 요청할 수 있도록 CORS 헤더를 설정한다. 이렇게 하면 다양한 도메인에서 서버로 요청을 보낼 수 있게 된다.
function setCORSHeaders(res) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
}
블록 번호 가져오기
getBlockNumbers 함수를 사용하여 로컬 노드와 기본 Ethereum 노드의 현재 블록 번호를 가져온다. 이를 통해 로컬 노드의 동기화 상태를 확인할 수 있다.
async function getBlockNumbers() {
try {
const localBlockNum = await localProvider.getBlockNumber();
const networkBlockNum = await provider.getBlockNumber();
return { localBlockNum, networkBlockNum };
} catch (e) {
console.error(e);
return null;
}
}
Healthcheck 응답 생성
createHealthcheckResponse 함수를 사용하여 healthcheck 응답을 JSON 형식으로 생성한다. 응답에는 블록 번호 차이, 서버 IP, Ethereum 네트워크, 응답 상태, 서버 이름이 포함된다. 이 정보는 클라이언트가 요청한 경우에 응답으로 반환된다.
function createHealthcheckResponse(localBlockNum, networkBlockNum, responseStatus) {
const difference = (localBlockNum - networkBlockNum).toString();
return JSON.stringify({
difference,
serverIpString: config.server_ip,
netWork: config.network,
responseStatus,
server_name: config.server_name,
});
}
Healthcheck 요청 처리
onHealthcheckRequest 함수는 healthcheck 요청을 처리하고 CORS 헤더를 설정한 다음, 상태 코드를 설정하고 응답을 반환한다. 블록 차이가 설정된 최대 허용치를 초과하면 상태 코드는 500을 반환하고, 그렇지 않으면 200을 반환한다.
const onHealthcheckRequest = async (req, res) => {
setCORSHeaders(res);
console.log(`>> checking ${config.host}:${config.rpc_port} (${config.network})`);
const { localBlockNum, networkBlockNum } = await getBlockNumbers();
if (!localBlockNum || !networkBlockNum) {
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end();
return;
}
const responseStatus = networkBlockNum - localBlockNum > config.max_difference ? 500 : 200;
res.writeHead(responseStatus, { 'Content-Type': 'application/json' });
const healthcheckResponse = createHealthcheckResponse(localBlockNum, networkBlockNum, responseStatus);
res.end(healthcheckResponse);
};
HTTP 서버 시작
http.createServer(onHealthcheckRequest).listen(config.local_port)를 사용하여 지정된 포트에서 HTTP 서버를 시작한다. 서버는 healthcheck 요청을 처리하는 데 사용되는 onHealthcheckRequest 함수를 사용한다.
console.log(`Starting eth monitoring service for ${config.host}:${config.rpc_port} on ${config.local_port}...`);
http.createServer(onHealthcheckRequest).listen(config.local_port);
이렇게 구성하면 간단한 Node.js HTTP 서버가 Ethereum 노드의 상태를 모니터링할 수 있게 된다. 클라이언트는 이 서버에 요청을 보내서 노드의 동기화 상태를 확인할 수 있다.
'Blockchain > Ethereum' 카테고리의 다른 글
[이더리움] 샤펠라(Shapella) 업그레이드란? (0) | 2023.05.16 |
---|---|
[이더리움] 블록 '17034872'에서 이더리움 동기화가 왜 멈췄을까? 원인 분석 및 해결 방법 (0) | 2023.05.09 |
[이더리움] 이더리움 2.0: 최신 업데이트 및 개발 동향 분석 (2) | 2023.03.17 |
[이더리움] 이더리움 클라이언트의 역할과 종류 (0) | 2023.03.09 |
[이더리움] 스마트 컨트랙트와 Express.js를 사용하여 API 서버 만들기 (0) | 2023.03.07 |