728x90
https://stickode.tistory.com/1016
https://stickode.tistory.com/1023
이전 게시글들에 이어 이더리움 익스플로러에 비트코인 조회 기능을 추가해서 여러 블록체인을 조회할 수 있는 블록익스플로러로 확장해보겠습니다. infura key 같은 경우는 위 게시글을 참고하시면 쉽게 하실 수 있습니다.
여기부터는 프로젝트 파일 구조 및 코드입니다
index.html
<!--public/index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cryptocurrency Block Explorer</title>
</head>
<body>
<h1>Cryptocurrency Block Explorer</h1>
<!-- 이더리움 블록 조회 섹션 -->
<h2>Ethereum Block Lookup</h2>
<input type="number" id="ethBlockNumber" placeholder="Ethereum Block Number" />
<button onclick="getEthBlock()">Get Ethereum Block</button>
<br>
<!-- 이더리움 트랜잭션 및 계정 조회 섹션 -->
<h2>Ethereum Transaction and Account Lookup</h2>
<input type="text" id="ethTransactionHash" placeholder="Ethereum Transaction Hash" />
<button onclick="getEthTransaction()">Get Transaction</button>
<br>
<input type="text" id="ethAccountAddress" placeholder="Ethereum Account Address" />
<button onclick="getEthBalance()">Get Balance</button>
<br>
<button onclick="getEthGasPrice()">Get Current Ethereum Gas Price</button>
<br>
<!-- 비트코인 블록 조회 섹션 -->
<h2>Bitcoin Block Lookup</h2>
<input type="number" id="btcBlockHeight" placeholder="Bitcoin Block Height" />
<button onclick="getBtcBlock()">Get Bitcoin Block</button>
<br>
<!-- 비트코인 트랜잭션 및 주소 조회 섹션 -->
<h2>Bitcoin Transaction and Address Lookup</h2>
<input type="text" id="btcTransactionHash" placeholder="Bitcoin Transaction Hash" />
<button onclick="getBtcTransaction()">Get Bitcoin Transaction</button>
<br>
<input type="text" id="btcAddress" placeholder="Bitcoin Address" />
<button onclick="getBtcBalance()">Get Bitcoin Balance</button>
<br>
<pre id="result"></pre>
<script>
async function getEthBlock() {
// 입력 필드에서 블록 번호를 가져옴
const blockNumber = document.getElementById('ethBlockNumber').value;
// 블록 번호가 입력되지 않았다면 경고 메시지 출력 후 함수 종료
if (!blockNumber) {
alert('Please enter a block number');
return;
}
try {
// 서버로부터 블록 정보를 조회하는 HTTP 요청
const response = await fetch(`/ethereum/block/${blockNumber}`);
// HTTP 응답 본문을 텍스트로 읽음
const blockString = await response.text();
// 응답 텍스트를 JSON 객체로 파싱
const block = JSON.parse(blockString, (key, value) => {
// 문자열이 'n'으로 끝나면 BigInt로 변환
if (typeof value === 'string' && value.endsWith('n')) {
return BigInt(value.slice(0, -1));
}
return value;
});
// 블록 정보를 콘솔에 출력
console.log(" block : ");
console.log(block);
// 결과 영역에 블록 정보를 표시
document.getElementById('result').textContent = JSON.stringify(block, null, 2);
} catch (error) {
// 오류 발생 시 콘솔에 오류 메시지 출력 및 사용자에게 알림
console.error('Error fetching block:', error);
alert('Error fetching block. Check the console for more details.');
}
}
async function getEthTransaction() {
const ethTransactionHash = document.getElementById('ethTransactionHash').value;
if (!ethTransactionHash) {
alert('Please enter a transaction hash');
return;
}
try {
const response = await fetch(`/ethereum/transaction/${ethTransactionHash}`);
const transaction = await response.json();
document.getElementById('result').textContent = JSON.stringify(transaction, null, 2);
} catch (error) {
console.error('Error fetching transaction:', error);
alert('Error fetching transaction. Check the console for more details.');
}
}
async function getEthBalance() {
const ethAccountAddress = document.getElementById('ethAccountAddress').value;
if (!ethAccountAddress) {
alert('Please enter an account address');
return;
}
try {
const response = await fetch(`/ethereum/balance/${ethAccountAddress}`);
const balance = await response.json();
document.getElementById('result').textContent = `Balance: ${balance.balance}`;
} catch (error) {
console.error('Error fetching balance:', error);
alert('Error fetching balance. Check the console for more details.');
}
}
async function getEthGasPrice() {
try {
const response = await fetch('/ethereum/gasPrice');
const gasPrice = await response.json();
document.getElementById('result').textContent = `Current Gas Price: ${gasPrice.gasPrice}`;
} catch (error) {
console.error('Error fetching gas price:', error);
alert('Error fetching gas price. Check the console for more details.');
}
}
async function getBtcBlock() {
const blockHeight = document.getElementById('btcBlockHeight').value;
if (!blockHeight) {
alert('Please enter a Bitcoin block height');
return;
}
try {
const response = await fetch(`/bitcoin/block/${blockHeight}`);
const blockData = await response.json();
document.getElementById('result').textContent = JSON.stringify(blockData, null, 2);
} catch (error) {
console.error('Error fetching Bitcoin block:', error);
alert('Error fetching Bitcoin block. Check the console for more details.');
}
}
async function getBtcTransaction() {
const btcTransactionHash = document.getElementById('btcTransactionHash').value;
if (!btcTransactionHash) {
alert('Please enter a Bitcoin transaction hash');
return;
}
try {
const response = await fetch(`/bitcoin/transaction/${btcTransactionHash}`);
const transaction = await response.json();
document.getElementById('result').textContent = JSON.stringify(transaction, null, 2);
} catch (error) {
console.error('Error fetching Bitcoin transaction:', error);
alert('Error fetching Bitcoin transaction. Check the console for more details.');
}
}
async function getBtcBalance() {
const address = document.getElementById('btcAddress').value;
if (!address) {
alert('Please enter a Bitcoin address');
return;
}
try {
const response = await fetch(`/bitcoin/address/${address}`);
const balance = await response.json();
document.getElementById('result').textContent = `Balance: ${balance.balance}`;
} catch (error) {
console.error('Error fetching Bitcoin balance:', error);
alert('Error fetching Bitcoin balance. Check the console for more details.');
}
}
</script></body>
</html>
app.js
// app.js
const express = require('express'); // Express 모듈 불러오기
const app = express(); // Express 애플리케이션 생성
const { Web3 } = require('web3'); // Web3 모듈 불러오기
const web3 = new Web3('https://mainnet.infura.io/v3/발급받은 키 삽입'); // Infura를 통해 이더리움 메인넷에 연결
// BigInt 값을 문자열로 변환하여 JSON으로 직렬화하는 함수
function serializeBigInt(key, value) {
return typeof value === 'bigint' ? value.toString() : value; // 만약 값이 BigInt 타입이면 문자열로 변환
}
app.use(express.static('public')); // 'public' 디렉토리의 정적 파일을 제공
// 블록 번호를 이용해 블록 정보를 조회하는 라우트
app.get('/ethereum/block/:blockNumber', async (req, res) => {
try {
console.log(" blockNumber : " + req.params.blockNumber); // 로그에 블록 번호 출력
const block = await web3.eth.getBlock(req.params.blockNumber); // 비동기적으로 블록 정보 조회
console.log(" block : "); // 로그에 블록 정보 시작을 알림
console.log(block); // 조회한 블록 정보를 로그에 출력
const blockString = JSON.stringify(block, serializeBigInt); // BigInt 처리를 위한 직렬화 함수와 함께 JSON으로 변환
res.setHeader('Content-Type', 'application/json'); // 응답 헤더에 컨텐츠 타입 설정
res.send(blockString); // 직렬화된 블록 정보를 응답으로 전송
} catch (error) {
console.error(error); // 에러 발생시 콘솔에 에러 출력
res.status(500).send(error.toString()); // 클라이언트에 500 상태 코드와 에러 메시지 전송
}
});
// 트랜잭션 해시를 이용해 트랜잭션 정보를 조회하는 라우트
app.get('/ethereum/transaction/:transactionHash', async (req, res) => {
const transactionHash = req.params.transactionHash; // 요청에서 트랜잭션 해시 추출
console.log(`[Transaction Request] Hash: ${transactionHash}`); // 로그에 트랜잭션 요청 해시 출력
try {
const transaction = await web3.eth.getTransaction(req.params.transactionHash); // 트랜잭션 정보 조회
// BigInt 처리를 위한 직렬화 함수와 함께 JSON으로 변환
const transactionString = JSON.stringify(transaction, serializeBigInt);
res.setHeader('Content-Type', 'application/json'); // 응답 헤더에 컨텐츠 타입 설정
res.send(transactionString); // 직렬화된 트랜잭션 정보를 응답으로 전송
} catch (error) {
console.error(error); // 에러 발생시 콘솔에 에러 출력
res.status(500).send(error.toString()); // 클라이언트에 500 상태 코드와 에러 메시지 전송
}
});
// 계정 주소를 이용해 계정 잔액을 조회하는 라우트
app.get('/ethereum/balance/:accountAddress', async (req, res) => {
const accountAddress = req.params.accountAddress; // 요청에서 계정 주소 추출
console.log(`[Balance Request] Account address: ${accountAddress}`); // 로그에 계정 잔액 요청 주소 출력
try {
const balance = await web3.eth.getBalance(req.params.accountAddress); // 계정 잔액 조회
// BigInt 처리를 위한 직렬화 함수와 함께 JSON으로 변환
const balanceString = JSON.stringify({ balance }, serializeBigInt);
res.setHeader('Content-Type', 'application/json'); // 응답 헤더에 컨텐츠 타입 설정
res.send(balanceString); // 직렬화된 계정 잔액을 응답으로 전송
} catch (error) {
console.error(error); // 에러 발생시 콘솔에 에러 출력
res.status(500).send(error.toString()); // 클라이언트에 500 상태 코드와 에러 메시지 전송
}
});
// 현재 가스 가격을 조회하는 라우트
app.get('/ethereum/gasPrice', async (req, res) => {
console.log(`[Gas Price Request] Request for current gas price`); // 로그에 현재 가스 가격 요청 출력
try {
const gasPrice = await web3.eth.getGasPrice(); // 현재 가스 가격 조회
// BigInt 처리를 위한 직렬화 함수와 함께 JSON으로 변환
const gasPriceString = JSON.stringify({ gasPrice }, serializeBigInt);
res.setHeader('Content-Type', 'application/json'); // 응답 헤더에 컨텐츠 타입 설정
res.send(gasPriceString); // 직렬화된 가스 가격을 응답으로 전송
} catch (error) {
console.error(error); // 에러 발생시 콘솔에 에러 출력
res.status(500).send(error.toString()); // 클라이언트에 500 상태 코드와 에러 메시지 전송
}
});
// 비트코인 블록 조회 라우트
app.get('/bitcoin/block/:blockHeight', async (req, res) => {
try {
const blockHeight = req.params.blockHeight;
console.log(`[Bitcoin Block Request] Height: ${blockHeight}`); // 로그에 블록 높이 출력
const response = await fetch(`https://blockchain.info/block-height/${blockHeight}?format=json`);
const blockData = await response.json();
console.log("Bitcoin block data: ", blockData); // 조회한 블록 데이터 로그에 출력
res.json(blockData);
} catch (error) {
console.error('Error fetching Bitcoin block:', error);
res.status(500).send(error.toString());
}
});
// 비트코인 트랜잭션 조회 라우트
app.get('/bitcoin/transaction/:transactionHash', async (req, res) => {
try {
const transactionHash = req.params.transactionHash;
console.log(`[Bitcoin Transaction Request] Hash: ${transactionHash}`); // 로그에 트랜잭션 해시 출력
const response = await fetch(`https://blockchain.info/rawtx/${transactionHash}`);
const transactionData = await response.json();
if (response.status !== 200) {
throw new Error('Transaction not found');
}
console.log("Bitcoin transaction data: ", transactionData); // 조회한 트랜잭션 데이터 로그에 출력
res.json(transactionData);
} catch (error) {
console.error('Error fetching Bitcoin transaction:', error);
res.status(500).send(error.toString());
}
});
// 비트코인 주소 잔액 조회 라우트
app.get('/bitcoin/address/:address', async (req, res) => {
try {
const address = req.params.address;
console.log(`[Bitcoin Address Request] Address: ${address}`); // 로그에 주소 출력
const response = await fetch(`https://blockchain.info/rawaddr/${address}`);
const addressData = await response.json();
if (response.status !== 200) {
throw new Error('Address not found');
}
console.log("Bitcoin address data: ", addressData); // 조회한 주소 데이터 로그에 출력
res.json({ balance: addressData.final_balance });
} catch (error) {
console.error('Error fetching Bitcoin address:', error);
res.status(500).send(error.toString());
}
});
const PORT = 3000; // 서버가 리스닝할 포트 번호
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`); // 서버 시작시 로그에 실행 주소 출력
});
package.json
{
"name": "js-search-block-info-ethereum",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"express": "^4.18.2",
"web3": "^4.2.1"
}
}
'JavaScript' 카테고리의 다른 글
[JavaScript] OpenWeatherMap API 사용하여 입력한 도시의 향후 5일 동안의 날씨 예보 정보 가져오기 (0) | 2024.02.21 |
---|---|
[JavaScript] OpenWeatherMap API 사용하여 간단한 날씨 정보 대시보드 만들기 (0) | 2024.02.12 |
[JavaScript] DeepLink 사용해서 유튜브 앱 열기 (0) | 2024.01.06 |
[JavaScript] 이더리움 익스플로러에 조회 기능 추가하기 (2) | 2024.01.04 |
[JavaScript] 이더리움 블록 조회하는 간단한 사이트 만들기 (0) | 2023.12.26 |