본문 바로가기

블록체인 기반 핀테크 및 응용 SW개발자 양성과정 일기

[117일차] 블록체인 제네시스 블록 만들기 with JavaScript

반응형

 

 

블롴체인 개념 설명

 

- 네트워크 (http, socket..) 

- 분산원장 (데이터를 저장하는 코드) 

  - hash sha 256 -> JWT 

  - 단반향 암호화 ( 자리수는 고정되어 있다.) 

  - 머클 (Merkle) 

  - 작업증명 (pow) = 마이닝 

Merkle

 

Merkle 사용 이유 : 너무 많은 노드(블록)들을 찾기에 리소스의 낭비가 크고 효율성이 떨어짐 (완전탐색) => merkle 사용으로 연결된 데이터 중 찾고자하는 데이터를 효율적으로 찾을 수 있음. 

 

 

 

 

 

 

이제 위의 내용대로 하나하나 만들어보기 

 

 

1) version 가져오기 

 

src 폴더 생성

src 폴더 cd 들어가기 전,  (src의 상위 폴더 경로에서) 아래 명령어 실행

npm init

src > block.js 생성

package.json 파일을 불러와서 console.log 찍어보기 

// file system package 
const fs = require('fs')

function getVersion(){
    const package = fs.readFileSync("../package.json")
    console.log('package=',package.toString('utf8'))
}

getVersion()

toString('utf8') 이 없으면 binary 형태로 나옴 

 

 

// file system package 
const fs = require('fs')

function getVersion(){
    const package = fs.readFileSync("../package.json")
    // console.log('package=',package.toString('utf8'))
    console.log('JSON.parse(package)=',JSON.parse(package))
    console.log('JSON.parse(package) version=',JSON.parse(package).version)
}

getVersion()

↓↓↓

// file system package 
const fs = require('fs')

function getVersion(){
    const {version} = JSON.parse(fs.readFileSync("../package.json"))
    console.log(version)
    return version
}

getVersion()

 

 

 

2) timestamp  (유닉스 기준일 1970년 1월 1일)

// file system package 
const fs = require('fs')

function getVersion(){
    const {version} = JSON.parse(fs.readFileSync("../package.json"))
    // console.log('package=',package.toString('utf8'))
    // console.log('JSON.parse(package)=',JSON.parse(package))
    // console.log('JSON.parse(package) version=',JSON.parse(package).version)
    console.log(version)
    return version
}   

function getCurrentTime(){
    console.log( new Date())
}

getCurrentTime()
getVersion()

 

현재 날짜를 시간으로 바꿔주기 = .getTime()

function getCurrentTime(){
    console.log( new Date().getTime())
}

getCurrentTime()

1000 = 1초 *** 

 

console.log( new Date().getTime()/1000)   // 1000으로 나누기

return Math.ceil(new Date().getTime()/1000)    // 올리기

시간 구하기 끝 

 

 

 

 

 

3) Merkle 

 

sha 256, merkel을 만드는 package 설치  (경로 : src) 

npm i merkletreejs crypto-js

 

src > merkle.js 파일 생성 + 위에서 가져온 packages 가져오기 

const { MerkleTree } = require('merkletreejs')
const SHA256 = require('crypto-js/sha256')

 

 

이제 sha256 사용하기 

const { MerkleTree } = require('merkletreejs')
const SHA256 = require('crypto-js/sha256')

// SHA256 은 함수 (노랑색!) 
// 

console.log( SHA256('emily'))

node merkle

 

text로 만들어주기 .toStirng() 만 붙여주기 

console.log( SHA256('emily').toString())

여기까지 sha256를 string으로 암호화 한 것 ! 

 

 

이제 배열로 만들 것 (a,b,c를 배열에 담아 암호화 ) 각각 256암호화 해서 배열에 넣기 

const { MerkleTree } = require('merkletreejs')
const SHA256 = require('crypto-js/sha256')

// SHA256 은 함수 (노랑색!) 

console.log( SHA256('emily').toString())

const testSet = ['a','b','c'].map((v)=>SHA256(v))
console.log(testSet)

 

a,b,c 를 머클에 적용해보기 

const { MerkleTree } = require('merkletreejs')
const SHA256 = require('crypto-js/sha256')

// SHA256 은 함수 (노랑색!) 

console.log( SHA256('emily').toString())

const testSet = ['a','b','c'].map((v)=>SHA256(v))
console.log(testSet)


const tree = new MerkleTree(testSet, SHA256)
console.log(tree)

 

 

 

Merkle에는 최상위 노드 (root)를 가져오는 매서드가 있음 ! 

const { MerkleTree } = require('merkletreejs')
const SHA256 = require('crypto-js/sha256')

// SHA256 은 함수 (노랑색!) 

console.log( SHA256('emily').toString())

const testSet = ['a','b','c'].map((v)=>SHA256(v))
console.log(testSet)


const tree = new MerkleTree(testSet, SHA256)
console.log(tree)

const root = tree.getRoot()
console.log('root=',root)

tree.getRoot().toString() 도 안되고 toString('utf8')도 안됌 ! 

const root = tree.getRoot().toString('hex')
console.log('root=',root)

 

const { MerkleTree } = require('merkletreejs')
const SHA256 = require('crypto-js/sha256')

// SHA256 은 함수 (노랑색!) 

console.log( SHA256('emily').toString())

const testSet = ['a','b','c'].map((v)=>SHA256(v))
console.log(testSet)


const tree = new MerkleTree(testSet, SHA256)
console.log(tree)

const root = tree.getRoot().toString('hex')
console.log('root=',root)

const testRoot = 'a'
const leaf = SHA256(testRoot)

// 첫번째 인자값 : 우리가 찾을 sha256 값 
const proof = tree.getProof(leaf)
console.log(tree.verify(proof,leaf, root))

= >

 

 

npm install merkle 

src > block.js 에 merkle & crypoJS 가져오기 

 

 

Header 

BlockHeader Class 사용해서 만들기 (붕어빵 틀 만들기) 

// file system package 
const fs = require('fs')
const merkle = require('merkle')
const cryptoJs = require('crypto-js')

// 암호화할 방법 넣어주기 
// sync  배열만 가능  
//const tree = merkle("sha256").sync([])   //tree 구조 
//tree.root()

class BlockHeader {
    // Header를 만들 인자값 5개 받기 
    constructor(version, index, previousHash, time, merkleRoot){
        // 현재 클래스의 version, index, hash, time, merkle은 내가 받은 값으로 하겠다. 
        this.version = version
        this.index = index 
        this.previousHash = previousHash
        this.time = time
        this.merkleRoot = merkleRoot 
    }
}

const header = new BlockHeader(1,2,3,4,5)
console.log('header=',header)

 

 

 

Block 이라는 class BlockHeader 사용해서 만들기 

// file system package 
const fs = require('fs')
const merkle = require('merkle')
const cryptoJs = require('crypto-js')

// 암호화할 방법 넣어주기 
// sync  배열만 가능  
//const tree = merkle("sha256").sync([])   //tree 구조 
//tree.root()

class BlockHeader {
    // Header를 만들 인자값 5개 받기 
    constructor(version, index, previousHash, time, merkleRoot){
        // 현재 클래스의 version, index, hash, time, merkle은 내가 받은 값으로 하겠다. 
        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'])
console.log('blockchain=',blockchain)

 

 

여기에 제대로 된 정보들만 넣으면 요 block이 최초의 제네시스 블록 

 

 

 

이제 제네시스 블록을 만드는 함수 만들기 

// file system package 
const fs = require('fs')
const merkle = require('merkle')
const cryptoJs = require('crypto-js')

// 암호화할 방법 넣어주기 
// sync  배열만 가능  
//const tree = merkle("sha256").sync([])   //tree 구조 
//tree.root()

class BlockHeader {
    // Header를 만들 인자값 5개 받기 
    constructor(version, index, previousHash, time, merkleRoot){
        // 현재 클래스의 version, index, hash, time, merkle은 내가 받은 값으로 하겠다. 
        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
    }   
}

function createGenesisBlock(){
    // header 만들기 - 5개의 인자값이 필요해! version, index, hash, time, merkle..
    const version = getVersion();
    const time = getCurrentTime();
    const index = 0 // 제네시스 블록은 index=0으로 설정 (최초의 블록이라 우리가 직접 하드코딩)
    const previousHash = '0'.repeat(64) // 제네시스 블록은 이전 hash가 없으므로 자리수만 0으로 맞춰서 제공 
    
    // body는 배열 형태로 
    const body = ['hello block']
    // body를 가지고 merkletree 값을 구성하기 
    
    const tree = merkle('sha256').sync(body)
    const root = tree.root() || '0'.repeat(64) // ||사용해서 예외처리

    // header 완성시키기 
    const header = new BlockHeader(version, index, previousHash, time, root)
    console.log(header)
    console.log('asdf',new Block(header,body))
    // header 만들어진 결과 가지고 block class에 넣어주기 
    return new Block(header,body)

}

const BBLOCKK = createGenesisBlock()
console.log('completed', BBLOCKK)


function getVersion(){
    const {version} = JSON.parse(fs.readFileSync("../package.json"))
    // console.log('package=',package.toString('utf8'))
    // console.log('JSON.parse(package)=',JSON.parse(package))
    // console.log('JSON.parse(package) version=',JSON.parse(package).version)
    return version
}   

function getCurrentTime(){
    return Math.ceil(new Date().getTime()/1000)
}

 

 

 

 

 

다음 사용자 / 블록이 생길 때 

블록을 생성할 때마다 -> 배열에 넣기 

전역변수로 배열 만들기 

 

블록을 추가해주는 구조 간단히 틀만 

 

 

마지막 블록 가져오기 

let Blocks = [createGenesisBlock()]

function getLastBlock() {
    return Blocks[Blocks.length - 1]
}

 

 

전체 코드 (교수님 코드) 

const fs = require('fs')
const merkle = require('merkle')
const CryptoJs = require('crypto-js')
const { runInThisContext } = require('vm')

/* 사용법 */
// const tree = merkle("sha256").sync([]) // tree 구조 
// tree.root()

class BlockHeader { 
    constructor(version ,index ,previousHash, time, merkleRoot){
        this.version = version 
        this.index = index  // 포인트
        this.previousHash = previousHash // 마지막 블럭 -> header -> string 연결  -> SHA256
        this.time = time  //
        this.merkleRoot = merkleRoot 
    }
}

class Block {
    constructor(header,body){
        this.header = header
        this.body = body
    }
}

let Blocks = [createGenesisBlock()] 

function getBlocks(){
    return Blocks
}

function getLastBlock() {
   return Blocks[Blocks.length - 1]
}

function createGenesisBlock(){
    // 1. header 만들기 
    // 5개의 인자값을 만들어야되여.
    const version = getVersion() // 1.0.0
    const index = 0
    const time = getCurrentTime() 
    const previousHash = '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 addBlock(){
    // new header -> new block ( header , body)
}

function getVersion(){
    const {version} = JSON.parse(fs.readFileSync("../package.json"))
    return version
}

function getCurrentTime(){
    return Math.ceil(new Date().getTime()/1000) 
}

// class 
// { header body } 1차 목표는 제네시스 블럭을 만드는것 
console.log(Blocks)

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형