블록체인
[블록체인] 블록체인만들기 (4) P2P 서버 (p2pServer.js)
코드코코
2021. 12. 31. 17:22
사전작업
p2pServer.js파일 생성
touch p2pServer.js
모듈설치
Ws
npm i ws
웹소켓 모듈 ws 사용
모듈불러오기
chainedBlock
getLastBlock, getBlocks
const WebSocket = require('ws');
const { getLastBlock, getBlocks } = require('./chainedBlock');
const p2p_port = process.env.P2P_PORT || 6001
const WebSocket = require("ws")
function initP2PServer(test_port) {
const server = new WebSocket.Server({ port: test_port })
//console.log(server);
server.on("connection", (ws) => { initConnection(ws); })
console.log("Listening webSocket port : " + test_port)
}
initP2PServer(6001);
initP2PServer(6002);
initP2PServer(6003);
let sockets = []
function initConnection(ws) {
//console.log(ws._socket.remotePort)
sockets.push(ws)
initMessageHandler(ws)
initErrorHandler(ws)
}
function getSockets() {
return sockets;
}
function write(ws, message) {
ws.send(JSON.stringify(message))
}
function broadcast(message) {
sockets.forEach(
// function (socket) {
// write(socket, message);
// }
(socket) => {
write(socket, message);
}
)
}
function connectToPeers(newPeers) {
newPeers.forEach(
(peer) => {
const ws = new WebSocket(peer)
console.log(ws);
ws.on("open", () => { console.log("open"); initConnection(ws); })
ws.on("error", (errorType) => { console.log("connetion Failed!" + errorType) })
}
)
}
// Message Handler
const MessageType = {
QUERY_LATEST: 0,
QUERY_ALL: 1,
RESPONSE_BLOCKCHAIN: 2
}
function initMessageHandler(ws) {
ws.on("message", (data) => {
const message = JSON.parse(data)
switch (message.type) {
case MessageType.QUERY_LATEST:
write(ws, responseLatestMsg());
break;
case MessageType.QUERY_ALL:
write(ws, responseAllChainMsg());
break;
case MessageType.RESPONSE_BLOCKCHAIN:
handleBlockChainResponse(message);
break;
}
})
}
function responseLatestMsg() {
return ({
"type": RESPONSE_BLOCKCHAIN,
"data": JSON.stringify([getLastBlock()])
})
}
function responseAllChainMsg() {
return ({
"type": RESPONSE_BLOCKCHAIN,
"data": JSON.stringify(getBlocks())
})
}
function handleBlockChainResponse(message) {
const receiveBlocks = JSON.parse(message.data)
const latestReceiveBlock = receiveBlocks[receiveBlocks.length - 1]
const latestMyBlock = getLastBlock()
//1. 데이터로 받은 블럭 중에 마지막 블럭의 인덱스가 내가 보유 중인 마지막 블럭의 인덱스보다 클 때 / 작을 때
//내가 가진 것 보다 짧은 것은 의미가 없음
if (latestReceiveBlock.header.index > latestMyBlock.header.index) {
//받은 마지막 블록의 이전 해시값이 내 마지막 블럭일 때 : addBlock
if (createHash(latestMyBlock) === latestReceiveBlock.header.previousHash) {
if (addBlock(latestReceiveBlock)) {
//나를 아는 주변 노드에게 변경사항을 전파
//서로의 피어을 다 공유하고 있는 상황?
broadcast(responseLastestMsg())
}
else {
console.log("Invaild Block!!");
}
}
//받은 블럭의 전체 크기가 1일 때(제네시스 블럭 인 경우와 같다)
else if (receiveBlocks.length === 1) {
//블럭을 전체 다 달라고 요청하기
broadcast(queryAllMsg())
}
else {
//내 전체 블럭이 다른 블럭들보다 동기화가 안된 상황이므로 갈아끼우기
//내 원장이랑 다른 원장들과의 차이가 매우 큰 경우 : 원장간의 불일치를 해소해야 하는 상황
replaceChain(receiveBlocks)
}
}
else {
console.log("Do nothing.");
}
}
function queryAllMsg() {
return ({
"type": QUERY_ALL,
"data": null
})
}
function queryLatestMsg() {
return ({
"type": QUERY_LATEST,
"data": null
})
}
function initErrorHandler(ws) {
ws.on("close", () => { closeConnection(ws) })
ws.on("error", () => { closeConnection(ws) })
}
function closeConnection(ws) {
console.log(`Connection close${ws.url}`);
//소켓을 복사하는 데, 뒤에 있는 데이터를 넣어서 복사 : 즉 , 초기화 하는 것임
sockets.splice(sockets.indexOf(ws), 1)
}
module.exports = {
connectToPeers, getSockets
}