
npm init : npm init으로 기본적인 package.json 설치npm i crypto-js merkle : 블록의 해시를 생성하기 위한 암호화 라이브러리인 crypto-js 및 블록의 머클과 머클루트를 만들기 위한 merkle 라이브러리 설치npm i -D jest : 개발 테스트를 위한 jest 라이브러리 설치

class TestClass{
#privateValue;
constructor(value){
this.#privateValue = value;
}
}
module.exports = TestClass;
const TestClass = require("./class.js");
describe("Class Test", ()=>{
it("private test", ()=>{
const test = new TestClass(5);
expect(test.#privateValue).toBe(5);
});
});

npx jest 로 테스트해보면 #privateValue에 접근 불가능하기 때문에 failed 가 출력된다.
get privateValue(){
return this.#privateValue;
}
const TestClass = require("./class.js");
describe("Class Test", ()=>{
it("private test", ()=>{
const test = new TestClass(5);
expect(test.privateValue).toBe(5); // 이렇게 접근해 사용할 수 있다.
});
});
npx jest 로 테스트
set privateValue(value){
this.#privateValue = value;
}
const TestClass = require("./class.js");
describe("Class Test", ()=>{
it("private test", ()=>{
const test = new TestClass(5);
test.privateValue = 200 // set 접근
expect(test.privateValue).toBe(200); // passed
});
});

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

const merkle = require("merkle");const SHA256 = require("crypto-js").SHA256;class BlockHeader{
// private으로 블록에 들어갈 Header 값 선언
#version;
#merkleRoot;
#timestamp;
#height;
#difficulty;
#nonce;
// 생성자 : class를 사용해 새로운 객체를 생성할 때 어떤 값을 집어넣을 지 미리 정의해둔다.
constructor(_data, _previousBlock){
// 버전
this.#version = "1.0.0";
// 머클루트 : data가 있으면 머클 라이브러리를 사용해 머클루트를 생성하고,
// 없으면 0으로 채운다.
this.#merkleRoot
= _data ? merkle("sha256").sync(_data).root() : "0".repeat(64);
// 체인에 추가될 때의 시점으로 블록 생성 시간을 정의하기 위해
// 하단에 setTimestamp() 메서드를 만들었으며 그것을 호출해 그대로 정의했다.
this.setTimestamp;
// 높이는 이전 블록이 있으면 이전 블록+1, 없으면 0으로 채운다.
this.#height = _previousBlock ? _previousBlock.height + 1 : 0;
// 난이도와 논스는 0으로 초기화한다.
this.#difficulty = 0;
this.#nonce = 0;
}
// 일단 클래스 외부에서 private 값에 접근할 수 있도록 get으로 정의
get version(){
return this.#version;
}
get merkleRoot(){
return this.#merkleRoot;
}
get timestamp(){
return this.#timestamp;
}
get height(){
return this.#height;
}
get difficulty(){
return this.#difficulty;
}
get nonce(){
return this.#nonce;
}
// 시간을 수정하는 데에 매개변수가 필요 없으므로 get 메서드가 아닌 일반 메서드로 만들었다.
setTimestamp() {
// Date : 클래스, now() : Date 클래스 내부에 static으로 정의되어 접근 가능한 메서드
this.#timestamp = Date.now();
}
}
class Block extends BlockHeader{
// private으로 블록에 들어갈 값 선언
#previousHash
#hash
#data
// 새로운 객체를 생성할 때 어떤 값을 집어넣을 지 생성자에 정의해둔다.
constructor(_data, _previousBlock){
// super() : 부모 클래스(BlockHeader)의 constructor를 호출해
// 부모의 생성자 값을 가져온다. 부모에게도 받은 data와 _previousBlock을 보내준다.
super(_data, _previousBlock);
this.#previousHash = _previousBlock ? _previousBlock.hash : "0".repeat(64);
// createHash(this) : 여기서 this는 현재 객체(Block 클래스) 자체를
// createHash 함수의 매개변수로 보내겠다는 의미이다.
// 만약 _data가 있으면서 _previousBlock(이전 블록)도 있으면 해시를
// 만들어주고, 아니면 0으로 채운다.
this.#hash = _data && _previousBlock ? Block.createHash(this) : "0".repeat(64);
this.#data = _data; // data 값은 매개변수로 받아와 저장한다.
}
// 클래스 외부에서 접근하기 위해 private 변수 각각의 get을 만들어준다.
get previousHash(){
return this.#previousHash;
}
get hash(){
return this.#hash;
}
get data(){
return this.#data;
}
// 블록으로 해시를 생성하는 static 메서드
static createHash(_block){
// 블록의 정보를 임시로 합칠 변수
let tempStr = "";
// 매개변수로 받은 블록의 정보를 합친다.
tempStr += _block.version;
tempStr += _block.merkleRoot;
tempStr += _block.timestamp;
tempStr += _block.height;
tempStr += _block.difficulty;
tempStr += _block.nonce;
tempStr += _block.previousHash;
// hash는 현재 만들고 있는 키이기 때문에 추가하지 않는다.
// data는 merkleRoot로 이미 합쳐져 있기 때문에 merkleRoot로 대체한다.
// crypto-js 라이브러리를 통해 SHA256 방식으로 암호화한 후 생성된 해시 리턴
return SHA256(tempStr).toString().toUpperCase();
}
}
const temp = new Block(["a"]);
const blockHash = Block.createHash(temp);
// 기존 제네시스 블록의 해시
console.log(temp.hash);
// createHash 메서드를 통해 생성된 해시
console.log(blockHash);

module.exports = Block;
const Block = require("./block.js");
const merkle = require("merkle");
describe("Block Test", ()=>{
// 블록의 머클루트와 테스트 환경에서
// 새로 만든 머클루트가 서로 일치하는지 확인한다.
it("merkle Test", () =>{
const data = ["a", "b", "c"];
const block = new Block(data);
const merkleRoot = merkle("sha256").sync(data).root();
expect(block.merkleRoot).toBe(merkleRoot);
});
// hash를 확인한다.
it("hash Test", () =>{
const data = ["a", "b", "c"];
// 블록 하나로 비교하면 이전 블록이 없어서 해시가
// 0으로 채워지기 때문에 블록 2개를 만들어 테스트한다.
const block1 = new Block(data);
const block2 = new Block(data, block1);
// 새로 만든 해시
const hash = Block.createHash(block2);
expect(block2.hash).toBe(hash);
});
});
