genesis block에 만들었던 것처럼 똑같은 알고리즘으로 만들면 된다. 다만, 이전 이전 블록의 header값으로 previousHash값을 만든다는 점만 다를 뿐이다.
index만 이전 블록의 header.index의 값에 1만 추가해주면 된다.
const fs = require('fs');//filesystem
const merkle = require('merkle');
const CryptoJs = require('crypto-js');
const SHA256 = require('crypto-js/sha256');
let index=0;
function createGenesisBlock(aaaaa){
//1.header만들기(5개의 인자를 만들기)
const version = getVersion()
const time = parseInt(Date.now()/1000)
const previousHash = aaaaa || '0'.repeat(64)
//body의 내용으로 merkleroot를 만드는 것임. 그래서 먼저 body를 만듦
const body = ['hello block']
const tree = merkle('sha256').sync(body)
const root = tree.root() || '0'.repeat(64)
const header = new BlockHeader(version,index,previousHash,time,root)
return new Block(header,body)
}
function getVersion(){
const package = fs.readFileSync("../package.json");
return JSON.parse(package).version;
};
class BlockHeader {
constructor(version,index,previousHash,timestamp,merkleRoot){//header를 만들 인잣값들
this.version = version//
this.index = index
this.previousHash = previousHash
this.timestamp = timestamp
this.merkleRoot = merkleRoot
}
}
class Block{
constructor(header,body){
this.header = header
this.body = body
}
}
const block=createGenesisBlock();
let Blocks= [createGenesisBlock()]
return 부분을 보면 return new Block(header,body)
으로 되어 클래스로 되어있음을 알 수 있다. 즉, 각 블록은 class로 되어있음을 알 수 있다.
함수의 기본 원칙이 있다.
하나의 함수에 하나의 기능!
이번 코드는 이걸 적용해서 엄청 복잡한 코드가 되었다. 그러나 논리적으로는 그렇게 어렵지 않다.
function addBlock(data){
const newBlock = nextBlock(data)
Blocks.push(newBlock);
}
이 함수는 블록을 추가해주기 위해 만든 코드이다.
전체적인 블록을 만든다.
이전 genesis블록과 다른 점이 있다면
previousHash
부분과 index
부분이 있다.
function nextBlock(data){
//header
const prevBlock = getLastBlock()
const version = getVersion()
const index = prevBlock.header.index + 1
const previousHash = createHash(prevBlock)
const time = parseInt(Date.now()/1000);
const merkleTREE = merkle('sha256').sync(data)
const merkleRoot = merkleTREE.root() || '0'.repeat(64)
const header = new BlockHeader(version,index,previousHash,time,merkleRoot)
return new Block(header,data)
}
getLastBlock()
을 통해 지금 Blocks 안의 마지막 항목의 블록을 가져온다. 그래서 index
에 가져온 항목.header.index+1
의 값을 넣어준다.
function getLastBlock(){
return Blocks[Blocks.length-1]
}
우리가 만들고있는 블록체인 배열 Block의 현재의 마지막 블록을 반환해주는 역할을 한다.
무슨 정보를 가지고 암호화를 하는가?
바로 이전 블록의 header의 value값들을 가져와서 string으로 바꾼 다음에 다 합친 내용을 암호화를 한다.
인잣값으로는 이전 블록의 값을 넣어준다.
function createHash(data){
//header
const {
version,
index,
previoushash,
time,
merkleRoot
} = data.header
const blockString = version+index+previoushash+time+merkleRoot
const Hash = CryptoJs.SHA256(blockString).toString()
return Hash
}
const fs = require('fs');
const merkle = require('merkle');
const CryptoJs = require('crypto-js');
const SHA256 = require('crypto-js/sha256');
let index=0;
function createGenesisBlock(aaaaa){
//1.header만들기(5개의 인자를 만들기)
const version = getVersion()
const time = parseInt(Date.now()/1000)
const previousHash = aaaaa || '0'.repeat(64)
//body의 내용으로 merkleroot를 만드는 것임. 그래서 먼저 body를 만듦
const body = ['hello block']
const tree = merkle('sha256').sync(body)
const root = tree.root() || '0'.repeat(64)
const header = new BlockHeader(version,index,previousHash,time,root)
return new Block(header,body)
}
function getVersion(){
const package = fs.readFileSync("../package.json");
return JSON.parse(package).version;
};
class BlockHeader {
constructor(version,index,previousHash,timestamp,merkleRoot){//header를 만들 인잣값들
this.version = version//
this.index = index
this.previousHash = previousHash
this.timestamp = timestamp
this.merkleRoot = merkleRoot
}
}
class Block{
constructor(header,body){
this.header = header
this.body = body
}
}
const block=createGenesisBlock();
let Blocks= [createGenesisBlock()]
console.log(Blocks)
function getBlock(){
return Blocks
}
function getLastBlock(){
return Blocks[Blocks.length-1]
}
function nextBlock(data){
//header
const prevBlock = getLastBlock()
const version = getVersion()
const index = prevBlock.header.index + 1
const previousHash = createHash(prevBlock)
const time = parseInt(Date.now()/1000);
const merkleTREE = merkle('sha256').sync(data)
const merkleRoot = merkleTREE.root() || '0'.repeat(64)
/*이전 해쉬값의
SHA256(versiton+index+previousHash+timestamp+merkleRoot)*/
const header = new BlockHeader(version,index,previousHash,time,merkleRoot)
return new Block(header,data)
}
function createHash(data){
//header
const {
version,
index,
previoushash,
time,
merkleRoot
} = data.header
const blockString = version+index+previoushash+time+merkleRoot
const Hash = CryptoJs.SHA256(blockString).toString()
return Hash
}
function addBlock(data){
//header+body
//검증을 위한 미리 공간을 확보해 놓은 것
// 함수 하나에는 함수 하나의 기능만 할 수 있게끔
const newBlock = nextBlock(data)
Blocks.push(newBlock);
}
// addBlock();
// addBlock();
addBlock(["hello1"]);
addBlock(["hello2"]);
addBlock(["hello3"]);
console.log(Blocks);
아무런 검증없이 블럭을 넣어준다?
블럭체인은 절.대.로 그럴 수 없다.
블록을 올리면 모두가 검증하고 맞다고 검증한 수가 과반수가 넘었을 때에 비로소 등록이 되는 알고리즘이기 때문이다.
이제 검증하는 것을 하겠다.
검증할 것
- 올리려는 현재 블록
- 각 타입들이 맞게 잘 들어갔는지
- 암호화가 제대로 되어있는지(merkleroot부분)
- 인덱스가 이전 블록에서 +1이 되어있는지
- 이전 블록들
- 제네시스 블록이 맞는지
- 배열별로 각 항목이 제대로 되어있는지 확인
const fs = require('fs');//filesystem
const merkle = require('merkle');
const CryptoJs = require('crypto-js');
const SHA256 = require('crypto-js/sha256');
let index=0;
function createGenesisBlock(aaaaa){
const version = getVersion()
const time = parseInt(Date.now()/1000)
const previousHash = aaaaa || '0'.repeat(64)
const body = ['hello block']
const tree = merkle('sha256').sync(body)
const root = tree.root() || '0'.repeat(64)
const header = new BlockHeader(version,index,previousHash,time,root)
return new Block(header,body)
}
function getVersion(){
const package = fs.readFileSync("../package.json");
return JSON.parse(package).version;
};
class BlockHeader {
constructor(version,index,previousHash,timestamp,merkleRoot){//header를 만들 인잣값들
this.version = version//
this.index = index
this.previousHash = previousHash
this.timestamp = timestamp
this.merkleRoot = merkleRoot
}
}
class Block{
constructor(header,body){
this.header = header
this.body = body
}
}
const block=createGenesisBlock();
let Blocks= [createGenesisBlock()]
function getBlock(){
return Blocks
}
function getLastBlock(){
return Blocks[Blocks.length-1]
}
function nextBlock(data){
//header
const prevBlock = getLastBlock()
const version = getVersion()
const index = prevBlock.header.index + 1
const previousHash = createHash(prevBlock)
const time = Math.floor(Date.now()/1000);
const merkleTREE = merkle('sha256').sync(data)
const merkleRoot = merkleTREE.root() || '0'.repeat(64)
const header = new BlockHeader(version,index,previousHash,time,merkleRoot)
return new Block(header,data)
}
function createHash(data){
const {
version,
index,
previoushash,
time,
merkleRoot
} = data.header
const blockString = version+index+previoushash+time+merkleRoot
const Hash = CryptoJs.SHA256(blockString).toString()
return Hash
}
function addBlock(data){
const newBlock = nextBlock(data)
if(isValidBlock(newBlock,getLastBlock())){
Blocks.push(newBlock);
return true;
}
return false;
}
function isValidBlock(currentBlock,previousBlock){
if(!isValidType(currentBlock)){
console.log(`invalid block structure ${JSON.stringify(currentBlock)}`)
return false
};
if(previousBlock.header.index+1 !== currentBlock.header.index){
console.log(`invalid index`)
}
if(createHash(previousBlock) !== currentBlock.header.previousHash){
console.log(`invalid hash value`)
}
if(currentBlock.body.length ===0 || (merkle("sha256").sync(currentBlock.body).root() !== currentBlock.header.merkleRoot)){
console.log(`invalid body`)
}
isValidBlock2()
return true
}
function isValidType(block){
return(
typeof(block.header.index)==="number" &&//num
typeof(block.body)==="object" &&//obj
typeof(block.header.version)==="string" &&//str
typeof(block.header.previousHash)==="string" &&//str
typeof(block.header.timestamp)==="number" &&//num
typeof(block.header.merkleRoot)==="string"//str
)
}
addBlock(["hello1"]);
addBlock(["hello2"]);
addBlock(["hello3"]);
console.log(Blocks)
function isValidBlock2(){
if(JSON.stringify(Blocks[0]) !== JSON.stringify(createGenesisBlock())){
console.log(`invalid genesisBlock`)
console.log(JSON.stringify(Blocks[0]))
console.log(JSON.stringify(createGenesisBlock()))
console.log('보여줬다.')
return false
}
let tempBlocks = [Blocks[0]]
for (let i =1; i<Blocks.length; i++){
if(isValidBlock(Blocks[i],tempBlocks[i-1])){
tempBlocks.push(Blocks[i])
}else {
console.log('이것도 안됨')
return false
}
}
return true;
}
module.exports={
getBlock,getLastBlock,addBlock,getVersion
}
위의 코드는 오류가 있어서 잠시 보류하도록 하겠다. 그러나 위의 주의사항을 잘 숙지하면 된다.