Javascript로 Blockchain 맛보기 (1) 블록 생성하기

sungjin6576·2022년 4월 28일
0

jsblockchain

목록 보기
1/2

1. 블록체인이란?

블록체인은 관리 대상 데이터를 '블록'이라고 하는 소규모 데이터들이 P2P 방식을 기반으로 생성된 체인 형태의 연결고리 기반 분산 데이터 저장 환경에 저장하여 누구라도 임의로 수정할 수 없고 누구나 변경의 결과를 열람할 수 있는 분산 컴퓨팅 기술 기반의 원장 관리 기술이다

참고 : 블록체인 - 위키백과

2. 자바스크립트로 블록체인 기술을 구현할 수 있다

필요한 파일 목록

  • block.js
    • blockchain 관련 function 선언
    • block 구조 설계
  • httpServer.js
    • 웹에 명령어를 입력해서 내 노드를 제어하는 서버
  • p2pServer.js
    • 다른 노드와 통신을 위한 서버
  • main.js
    • p2p 서버 초기화
    • http 서버 초기화
    • blockchain 함수 사용

2-1 httpServer.js

express 모듈을 통해 httpserver를 만들어주는 function 작성
변수로 port를 받아 localhost:port에서 서버를 연다

const initHttpServer = (myHttpPort) => {
    const app = express();
    app.use(express.json()); // express에 bodyparser 내장됨
    app.use(express.urlencoded({extended : true}));

    app.get("/", (req, res) => {
        res.send("Hello world!")
    })

    app.listen(myHttpPort, ()=>  {
        console.log("listening httpServer... Port : ",myHttpPort)
    })
}
export { initHttpServer };

2-2 p2pServer.js

웹소켓을 이용해 다른 노드와 통신 할 것이다
웹소켓 서버 열어주는 function 작성
변수로 port번호를 받아 웹소켓 서버를 연다

import WebSocket from "ws";
import { WebSocketServer } from "ws";

const sockets = []; //배열 시작점의 주소를 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);
}

export { initP2PServer };

2-3 main.js

각각 서버 열어주는 function을 불러와 서버 초기화를 해준다

import {initHttpServer} from "./httpServer.js"; 
import { initP2PServer } from "./p2pServer.js";

const httpPort = parseInt(process.env.HTTP_PORT) || 3001; 
const p2pPort = parseInt(process.env.HTTP_PORT) || 6001; 
// 직접 숫자를 집어넣는 것은 프로그래머만 vscode를 통해수정 할 수 있다 
// 하지만 .env파일을 참조하게 해놓으면 외부에서 수정할 수 있음

initHttpServer(httpPort);
initP2PServer(p2pPort);

2-4 block.js

class를 이용해 block의 기본 구조를 만든다

class Block {
    constructor(index, data, timestamp, hash, previousHash) {
        this.index = index;
        this.data = data;
        this.timestamp = timestamp;
        this.hash = hash;
        this.previousHash = previousHash;
    }
}

만들어진 block들을 가지고 있는 배열 blocks가 있다
이를 외부(예를 들면 httpServer.js에서 blocks를 쓰려고 할 때)에 노출할 수 있는 함수 getBlocks()를 만든다

const getBlocks = () => { // 외부에 노출할 수 있게
    return blocks;
}

block구조에서 hash는 직접 계산해야 하기 때문에 이를 계산하는 함수를 만든다

import CryptoJS from "crypto-js"

const calculateHash = (index, data, timestamp, previousHash) => {
    return CryptoJS.SHA256(`${index + data + timestamp + previousHash}`).toString(); 
  // toString() 한 것이 우리가 원하는 형태
}

첫번째 genesisblock을 만드는 함수를 짠다

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);
    
    genesisBlock.hash = calculateHash(genesisBlock.index, genesisBlock.data, 
    genesisBlock.timestamp, genesisBlock.previousHash);
    return genesisBlock;
}

블록의 무결성을 검증하는 function을 만든다

  • 블록의 인덱스가 이전 블록 인덱스보다 1크다
  • 블록의 previousHash가 이전 블록의 hash이다
  • 블록의 구조가 일치해야 한다.
const isValidBlockStructure = (newBlock) => {
    return(
        typeof (newBlock.index) === "number"
        && typeof (newBlock.data) === "string"
        && typeof (newBlock.timestamp) === "number"
        && typeof (newBlock.hash) === "string"
        && typeof (newBlock.previousHash) === "string"
    )
    
}

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)) {
        console.log("invalid block structure");
        return false;
    }
    return true;
}

블록의 무결성을 확인하고 다음 블락을 만드는 코드를 작성한다

// blockdata는 변수로 받는다
const createBlock = (blockData) => {
    const previousBlock = blocks[blocks.length - 1];
    const nextIndex = previousBlock.index + 1;
    const nextTimestamp = new Date().getTime() / 1000;
    const nextHash = calculateHash(nextIndex, blockData ,nextTimestamp, previousBlock.hash);
    const newBlock = new Block(nextIndex, blockData, nextTimestamp, nextHash, previousBlock.hash);
    if(isValidNewBlock(newBlock,previousBlock)){ // 블록의 무결성이 확인되면
        blocks.push(newBlock) // blocks 배열에 해당 block을 추가한다
        return newBlock;
    }
    
    console.log("fail to create newblock");
    return null;
}

blocks 배열을 확인하고 새로운 block을 추가하는 코드를 작성한다

// httpServer.js에서 추가

app.get("/blocks", (req, res) => {
        res.send(getBlocks());
    })

app.post("/createBlock",(req, res) => {
  res.send(createBlock(req.body.data))
})

node main.js로 서버를 실행시키고
localhost:3001/blocks에 접속하면 제네시스 블록이 들어가있는 blocks 배열을 확인할 수 있다

현재는 post를 할 수 있는 방법이 따로 없으므로 postman에서 post를 테스트해본다
body.data에 string을 담아 post를 해보면 새로 생긴 newBlock을 확인할 수 있다

다시 localhost:3001/blocks에 접속해보면 newBlock이 추가된 blocks 배열을 확인 할 수 있다

0개의 댓글