httpServer.js
import express from 'express';
import bodyParser from 'body-parser';
import { getBlocks, createBlock } from './block.js';
import { connectionToPeer, getPeers, sendMessage } from './p2pServer.js';
import path from 'path';
const initHttpServer = (myHttpPoryt) => {
const app = express();
const __dirname = path.resolve();
app.use(bodyParser.json());
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, './index.html'));;
})
app.get('/blocks', (req, res) => {
res.send(getBlocks());
})
app.post('/createblock', (req, res) => {
res.send(createBlock(req.body.data));
})
app.post('/peers', (req, res) => {
res.send(getPeers())
})
app.post('/addPeer', (req, res) => {
console.log('/addrPeer : ', req.body.message);
res.send(connectionToPeer(req.body.data));
})
app.post('/sendMessage', (req, res) => {
res.send(sendMessage(req.body.data))
})
app.listen(myHttpPoryt, () => {
console.log('listening httpServer Port : ', myHttpPoryt);
})
}
export { initHttpServer }
p2pServer.js
import WebSocket from 'ws'
import { WebSocketServer } from 'ws';
const MessageType = {
RESPONSE_MESSAGE : 0,
SENT_MESSAGE : 1
}
const sockets = [];
const getPeers = () =>{
return sockets;
}
const initP2PServer = (p2pPort) => {
const server = new WebSocketServer({port:p2pPort})
server.on('connection', (ws) => {
initConnection(ws);
})
console.log('listening P2PServer Port : ', p2pPort);
}
const initConnection = (ws) => {
sockets.push(ws);
initMessageHandler(ws);
}
const connectionToPeer = (newPeer) => {
console.log(newPeer)
const ws = new WebSocket(newPeer)
ws.on('open', () => { initConnection(ws); console.log('Connect peer : ', newPeer ); })
ws.on('error', () => { console.log('Fail to Connection peer : ', newPeer); })
}
const initMessageHandler = (ws) => {
ws.on('message', (data) => {
const message = JSON.parse(data);
switch(message.type)
{
case MessageType.SENT_MESSAGE:
console.log(message.message);
break;
}
})
}
const write = (ws, message) => {
console.log('write()', message);
ws.send(JSON.stringify(message))
}
const sendMessage = (message) => {
sockets.forEach( (socket) => {
write(socket, message);
});
}
export { initP2PServer, connectionToPeer, getPeers, sendMessage }
import CryptoJS from 'crypto-js'
class Block {
constructor(index, data, timestamp, hash, previousHash, difficulty, nonce)
{
this.index = index;
this.data = data;
this.timestamp = timestamp;
this.hash = hash;
this.previousHash = previousHash;
this.difficulty = difficulty;
this.nonce = nonce;
}
}
const getBlocks = () => {
return blocks;
}
const calculateHash = (index, data, timestamp, previousHash, difficulty, nonce) => {
return CryptoJS.SHA256((index + data + timestamp + previousHash + difficulty + nonce).toString()).toString();
}
const createGenesisBlock = () => {
const genesisBlock = new Block(0, 'The Times 03/Jan/2009 Chancellor on brink of second bailout for banks', new Date().getTime() / 1000, 0, 0, 0, 0);
genesisBlock.hash = calculateHash(genesisBlock.index, genesisBlock.data, genesisBlock.timestamp, genesisBlock.previousHash, genesisBlock.difficulty, genesisBlock.nonce);
return genesisBlock;
}
const createBlock = (blockdata) => {
const previousBlock = blocks[blocks.length - 1];
const nextIndex = previousBlock.index + 1;
const nextTimestamp = new Date().getTime() / 1000;
const nextDifficulty = 1;
const nextNonce = findNonce(nextIndex, blockdata, nextTimestamp, previousBlock.hash, nextDifficulty);
const nextHash = calculateHash(nextIndex, blockdata, nextTimestamp, previousBlock.hash, nextDifficulty, nextNonce);
const newBlock = new Block(nextIndex, blockdata, nextTimestamp, nextHash, previousBlock.hash, nextDifficulty, nextNonce);
if (isValidNewBlock(newBlock, previousBlock))
{
blocks.push(newBlock);
return newBlock;
}
console.log('fail to create newblock');
return null;
}
const isValidBlockStructure = (newBlock) => {
if (typeof (newBlock.index) === 'number'
&& typeof (newBlock.data) === 'string'
&& typeof (newBlock.timestamp) === 'number'
&& typeof (newBlock.hash) === 'string'
&& typeof (newBlock.previousHash) === 'string'
&& typeof (newBlock.difficulty) === 'number'
&& typeof (newBlock.nonce) === 'number') {
return true;
}
return false;
}
const isValidNewBlock = (newBlock, previousBlock) => {
if (newBlock.index !== previousBlock.index + 1)
{
console.log('invalid index');
return false;
}
else if (newBlock.previousHash !== previousBlock.hash)
{
console.log('invalid previous hash');
return false;
}
else if(isValidBlockStructure(newBlock) == false) {
console.log('invalid previous structure')
return false;
}
return true;
}
const hashMatchDifficulty = (hash, difficulty) => {
const binaryHash = hexToBinary(hash);
const requiredPrefix = '0'.repeat(difficulty);
return binaryHash.startsWith(requiredPrefix);
}
const hexToBinary = (hex) => {
const lookupTable = {
'0' : '0000', '1' : '0001', '2' : '0010', '3' : '0011',
'4' : '0100', '5' : '0101', '6' : '0110', '7' : '0111',
'8' : '1000', '9' : '1001', 'a' : '1010', 'b' : '1011',
'c' : '1100', 'd' : '1101', 'e' : '1110', 'f' : '1111'
}
let binary = '';
for(let i =0; i < hex.length; i++)
{
if(lookupTable[hex[i]]) {
binary += lookupTable[hex[i]]
}
else {
console.log('invalid hex : ', hex);
return null;
}
}
return binary;
}
const findNonce = (index, data, timestamp, previousHash, difficulty) => {
let nonce = 0;
while(true)
{
let hash = calculateHash(index, data, timestamp, previousHash, difficulty, nonce);
if (hashMatchDifficulty(hash, difficulty)) {
return nonce;
}
nonce++;
}
}
const blocks = [createGenesisBlock()];
export { getBlocks, createBlock };