
src/block.js
1. 1. AddBlock 새로운 block 추가하는 함수
<javascript />
// 새로운 block을 간단히 추가하는 함수
function addBlock(){
const newBlock = nextBlock(data);
if(isValieNewBlock(newBlock, getLastBlock())){
Blocks.push(newBlock);
return true;
}
return false;
}
2. 2. newBlock 새로운 블록을 생성하는 함수
<javascript />
// 다음 블럭(nextBlock)의 header와 body를 만들어주는 함수
function nextBlock(data){
// 이전 block 가져오기
const prevBlock = getLastBlock();
// Header
const version = getVersion();
const index = prevBlock.header.index + 1;
const previousHash = createHash(prevBlock);
const time = getCurrentTime();
// Mekle root를 가져오기 위해 tree 만들기
const merkleTree = merkle('sha256').sync(data)
const merkleRoot = merkleTree.root() || '0'.repeat(64);
const newBlockHeader = new BlockHeader(version, index, previousHash, time, merkleRoot)
// header + data(body) 로 new block return
return new Block(newBlockHeader, data)
}
3.
4. 3. createHash 함수 생성 - 이전 블록의 모든 header string값을 받아와 새 hash 암호화
<javascript />
function createHash(block){
// 이전 블록을 인자로 받아와 해당 블록 header의 요소들 가져오기
const {version, index, previousHash, time, merkleRoot} = block.header;
// 모든 string을 + 더하기
const blockString = version + index+previousHash+time+merkleRoot;
const Hash = CryptoJs.SHA256(blockString).toString();
return Hash;
}
5. 4. 새로 만든 블록 검증 -> 후에 add
함수가 많이 나오므로 잘 구별하기.
addBlock : 새로운 블록을 추가하는 함수
isValidNewBlock : 새로운 블록과, 이전 블록을 세트로 검증하는 함수
isValieType : 새로운 블록의 Type 을 검증하는 함수
<javascript />
// 새로운 block을 간단히 추가하는 함수
function addBlock(data){
const newBlock = nextBlock(data);
if(isValidNewBlock(newBlock, getLastBlock())){
Blocks.push(newBlock);
return true;
}
return false;
}
// 새로운 블록 검증
function isValidNewBlock(currentBlock, previousBlock){
// 1. 새로운 블록의 type 검증
isValidType(currentBlock)
return true;
}
function isValidType(block){
console.log(block)
}
addBlock(['asdf']);
6.
6.1. 1) type검증
<javascript />
// 새로운 블록 검증
function isValidNewBlock(currentBlock, previousBlock){
// 1. 새로운 블록의 type 검증
if(!isValidType(currentBlock)){
// "" or '' or `` string 값으로 만들 때 객체는[Object Object]로 나와서 JSON.stringify 붙여주기
console.log(`inValidType is found in currentBlock = ${currentBlock}`);
console.log(`inValidType is found in currentBlock = ${JSON.stringify(currentBlock)}`);
return false;
}
return true;
}
// 새로운 블록 type 검증
function isValidType(block){
return (
typeof(block.header.version)=="string" &&
typeof(block.header.index)=="numbr" &&
typeof(block.header.previousHash)=="string" &&
typeof(block.header.time)=="number" &&
typeof(block.header.merkleRoot)=="string" &&
typeof(block.body)=="object" )
}
6.2. 2) index 검증
<javascript />
// 새로운 블록 검증
function isValidNewBlock(currentBlock, previousBlock){
// 1. 새로운 블록의 type 검증
if(!isValidType(currentBlock)){
// "" or '' or `` string 값으로 만들 때 객체는[Object Object]로 나와서 JSON.stringify 붙여주기
console.log(`inValidType is found in currentBlock = ${currentBlock}`);
console.log(`inValidType is found in currentBlock = ${JSON.stringify(currentBlock)}`);
return false;
}
// 2. index 검증
if(previousBlock.header.index+1 !== currentBlock.header.index){
console.log(`invalid index found`)
return false;
}
return true;
}
6.3. 3) previous Hash
<javascript />
// 3. previousHash check
if(currentBlock.header.previousHash !== createHash(previousHash)){
console.log(`invalid previousHash found`)
return false;
}
6.4. 4) root
merkle 목적 : data 위조 방지 (+ 특정 노드 효율적으로 찾기)
<javascript />
// 4. merkleRoot check (root가 정확한지)
if(currentBlock.header.merkleRoot !== merkle('sha256').sync(currentBlock.body).root()){
console.log(`invalid body found`)
return false;
}
6.5. 5) body
<javascript />
// 5. body check (body에 내용이 반드시 있어야함 !)
if(currentBlock.body.length===0){
console.log(`invalid body found, it's empty`);
return false;
}
isValidNewBlock 함수 (새로 만들어진 블록 검증하는) 의 전체 코드
<javascript />
// 새로운 블록 검증
function isValidNewBlock(currentBlock, previousBlock){
// 1. 새로운 블록의 type 검증
if(!isValidType(currentBlock)){
// "" or '' or `` string 값으로 만들 때 객체는[Object Object]로 나와서 JSON.stringify 붙여주기
console.log(`inValidType is found in currentBlock = ${currentBlock}`);
console.log(`inValidType is found in currentBlock = ${JSON.stringify(currentBlock)}`);
return false;
}
// 2. index 검증
if(previousBlock.header.index+1 !== currentBlock.header.index){
console.log(`invalid index found`)
return false;
}
// 3. previousHash check
if(currentBlock.header.previousHash !== createHash(previousBlock)){
console.log(`invalid previousHash found`)
return false;
}
// 4. merkleRoot check (root가 정확한지)
if(currentBlock.header.merkleRoot !== merkle('sha256').sync(currentBlock.body).root()){
console.log(`invalid body found`)
return false;
}
// 5. body check (body에 내용이 반드시 있어야함 !)
if(currentBlock.body.length===0){
console.log(`invalid body found, it's empty`);
return false;
}
return true;
}
6.6. 6. Blocks 안 전체 배열 검증
1) 제네시스 블록 유효한지, 데이터가 바뀐 적이 없는지 확인
2) Blocks 배열 안의 모든 요소들을 짝으로 검사 (10개 요소라면 -> 9번 검사)
1) 제네시스 블록 검증
JavaScript 특징 상, {} !== {} 이다. 제네시스 블록은 객체이므로 JSON.stringiyi() 로 string으로 만들어 비교를 진행해야 한다.
<javascript />
// 제네시스 블록 검증
function isValidBlock(Blocks){
if(JSON.stringify(Blocks[0]) !== JSON.stringify(createGenesisBlock())){
console.log(`Invalie Genesis Block found`);
return false;
}
}
2) Blocks 배열 요소 검증
<javascript />
// 6. 전체 검증 (제네시스블록 & 블록을 담은 Blocks 배열 전체)
function isValidBlock(Blocks){
// GENESIS BLOCK 검증
if(JSON.stringify(Blocks[0]) !== JSON.stringify(createGenesisBlock())){
console.log(`Invalie Genesis Block found`);
return false;
}
// BLOCKS ARRAY 검증
// tempBlocks 변수에 제네시스 블록 배열로 담기
let tempBlocks = [Blocks[0]];
for(let i=1; i<Blocks.length; i++){
if(isValidNewBlock(Blocks[i], tempBlocks[i-1])){
tempBlocks.push(Blocks[i])
}else{
console.log(`invalid Block found, located at ${i} in Blocks Array`)
return false;
}
}
return true;
}
3) 위의 isValidBlock() 함수를 addBlcok() 함수에 추가해주기
<javascript />
// 얘는 단순히 Push만 할 것 ! 인자값에 배열을 넣어주기 (data)
function addBlock(data) {
// new header 만들어서 => new block(header, body)
const newBlock = nextBlock(data) // return 다음 블록에 대한 객체
// newBlock과 마지막
if(isValidNewBlock(newBlock, getLastBlock()) && isValidBlocks(Blocks)){
Blocks.push(newBlock);
return newBlock; //함수가 여기서 끝나버리게
}
return false;
}
전체 코드
block.js
<html />const fs = require('fs') const merkle = require('merkle') const CryptoJs = require('crypto-js'); // 1. version 구하기 function getVersion(){ const package = fs.readFileSync('../package.json'); // console.log(package) // console.log(JSON.parse(package)) console.log('version=',JSON.parse(package).version) return JSON.parse(package).version; // 위와 같은 코드 // const {version} = JSON.parse(fs.readFileSync('../package.json')) // return version } // 2. StampTime 구하기 function getCurrentTime(){ console.log('TimeStamp = ', Math.ceil(new Date().getTime()/1000)) return Math.ceil(new Date().getTime()/1000) } // 3. merkle tree 연습 - > src > merkle.js 파일에 있음 // 4. Header 만들기 by Class class BlockHeader { constructor(version, index, previousHash, time, merkleRoot){ this.version = version this.index = index this.previousHash = previousHash this.time = time this.merkleRoot = merkleRoot } } class Block{ constructor(header, body){ this.header = header this.body = body } } // const blockchain = new Block(new BlockHeader(1,2,3,4,5), ['hello']) // 5. 제네시스 블록 만들기 function createGenesisBlock(){ const version = getVersion(); const time = getCurrentTime(); const index = 0; const previousHash = '0'.repeat(64) // 제네시스 블록 : 이전hash 없으므로 자리수만 64로 맞춰서 제공 // body는 배열 형태 *** const body = ['hello block I am body '] // body를 가지고 merkle tree 값을 구성하기 const tree = merkle('sha256').sync(body) const root = tree.root() || '0'.repeat(64) // 예외처리 const header = new BlockHeader(version, index, previousHash, time, root) //console.log('header=', header) //console.log(new Block(header, body)) return new Block(header,body) } // 6. 블록 생성할 때마다 -> 배열에 넣기 예정 / 마지막 블록 가져오기 let Blocks = [createGenesisBlock()] console.log('Blocks=', Blocks) function getLastBlock(){ return Blocks[Blocks.length-1] } //---------------------------------------------------------------------------------------- // 새로운 block을 간단히 추가하는 함수 function addBlock(data){ const newBlock = nextBlock(data); if(isValidNewBlock(newBlock, getLastBlock()) && isValidBlocks(Blocks)){ Blocks.push(newBlock); return true; } return false; } // 새로운 블록 검증 function isValidNewBlock(currentBlock, previousBlock){ // 1. 새로운 블록의 type 검증 if(!isValidType(currentBlock)){ // "" or '' or `` string 값으로 만들 때 객체는[Object Object]로 나와서 JSON.stringify 붙여주기 console.log(`inValidType is found in currentBlock = ${currentBlock}`); console.log(`inValidType is found in currentBlock = ${JSON.stringify(currentBlock)}`); return false; } // 2. index 검증 if(previousBlock.header.index+1 !== currentBlock.header.index){ console.log(`invalid index found`) return false; } // 3. previousHash check if(currentBlock.header.previousHash !== createHash(previousBlock)){ console.log(`invalid previousHash found`) return false; } // 4. merkleRoot check (root가 정확한지) if(currentBlock.header.merkleRoot !== merkle('sha256').sync(currentBlock.body).root()){ console.log(`invalid body found`) return false; } // 5. body check (body에 내용이 반드시 있어야함 !) if(currentBlock.body.length===0){ console.log(`invalid body found, it's empty`); return false; } return true; } // 새로운 블록 type 검증 function isValidType(block){ return ( typeof(block.header.version)=="string" && typeof(block.header.index)=="number" && typeof(block.header.previousHash)=="string" && typeof(block.header.time)=="number" && typeof(block.header.merkleRoot)=="string" && typeof(block.body)=="object" ) } // 6. 전체 검증 (제네시스블록 & 블록을 담은 Blocks 배열 전체) function isValidBlocks(Blocks){ // GENESIS BLOCK 검증 if(JSON.stringify(Blocks[0]) !== JSON.stringify(createGenesisBlock())){ console.log(`Invalie Genesis Block found`); return false; } // BLOCKS ARRAY 검증 // tempBlocks 변수에 제네시스 블록 배열로 담기 let tempBlocks = [Blocks[0]]; for(let i=1; i<Blocks.length; i++){ if(isValidNewBlock(Blocks[i], tempBlocks[i-1])){ tempBlocks.push(Blocks[i]) }else{ console.log(`invalid Block found, located at ${i} in Blocks Array`) return false; } } return true; } addBlock(['asdf']); // 다음 블럭(nextBlock)의 header와 body를 만들어주는 함수 function nextBlock(data){ // 이전 block 가져오기 const prevBlock = getLastBlock(); // Header const version = getVersion(); const index = prevBlock.header.index + 1; const previousHash = createHash(prevBlock); const time = getCurrentTime(); // Mekle root를 가져오기 위해 tree 만들기 const merkleTree = merkle('sha256').sync(data) const merkleRoot = merkleTree.root() || '0'.repeat(64); const newBlockHeader = new BlockHeader(version, index, previousHash, time, merkleRoot) // header + data(body) 로 new block return return new Block(newBlockHeader, data) } function createHash(block){ // 이전 블록을 인자로 받아와 해당 블록 header의 요소들 가져오기 const {version, index, previousHash, time, merkleRoot} = block.header; // 모든 string을 + 더하기 const blockString = version + index+previousHash+time+merkleRoot; const Hash = CryptoJs.SHA256(blockString).toString(); return Hash; }
'BlockChain' 카테고리의 다른 글
블록체인 지갑생성(공개키, 비밀키) (0) | 2022.01.01 |
---|---|
블록체인 네트워크 웹소켓 WebSocket http ws (0) | 2021.12.31 |
블록체인 제네시스 블록 만들기 by JavaScript (0) | 2021.12.30 |
블록체인 블록 만들어보기 (0) | 2021.12.29 |
blockchain 맛 보기 (0) | 2021.12.27 |