728x90

작업(을 통한)증명 Proof of Work

https://newpouy.github.io/jekyll/update/2018/03/20/naivecoin-kr-translate-2.html

 

Naivecoin Korean Translate Version #2

navie코인 번역 원문: lhartikk.github.io

newpouy.github.io

 

#1에서는 누구나 블록추가할 수 있었지만 이제는 계산을 푸는 작업을 해야 블록추가할 수 있게할거야. 이 계산 푸는 거를 채굴이라고 함. 또한 퍼즐의 난이도를 통해 블록 조절할거야. 좀 있다가는 트랜잭션(거래내역)에 대해서도 다룰거야. 이걸 통해서 보상받고 거래주고받고 하는거겠지

 

 

블록에 추가할 두 가지 속성 (-> 작업증명 퍼즐(블록의 해쉬값 찾기)을 풀기 위한 값)

  • difficulty 난이도  (=유효한 블록의 해쉬값은 얼마나 많은 0으로 시작해야하는가, 작은값찾기임)

해쉬값을 2진수로 표현한 다음 시작부분0의 갯수세어보는 것.

난이도 difficulty 가 4이면 임계값인 nonce가 1,2,3 올라가면서 해쉬값을 찾는다. 해쉬값계산 함수를 보면 

전체값을 합쳐서 hash화한걸 볼 수 있어 

 //다합쳐서 해시로 만들고 리턴
  const hash = cryptojs.SHA256(blockString).toString();
  return hash;

참고로 우리 코드에서도 다음블록찾는 nextBlock함수안에 findBlock함수가 있는데 거기서 nonce++로 수 올리고 있음.

 

 

 

블록의 해시값이 난이도를 만족하는지 

  • nonce 난이도를 만족하는 해시값을 찾기위해 반복한 값

 

//naive코드와 우리 팀플코드의 차이점

naive - 난이도를 만족하는지 확인하는 코드에서 hexToBinary 함수를 썼음 

function hexToBinary(s) {
  //헤더부분을 sha256 암호화한 결과
  //16진수 64자리를 2진수로 변환하기
  const lookupTable = {
    0: "0000",
    1: "0001",
    2: "0010",
    3: "0011",
    4: "0100",
    5: "0101",
    6: "0110",
    7: "0111",
    8: "1000",
    9: "1001",
    A: "1010",
    B: "1011",
    C: "1100",
    D: "1101",
    E: "1110",
    F: "1111",
  };

상단의 이미지로 예시를 들면 

난이도가 4일 때 hash:08f3... 이거를 binaryHash 2진수로 변환한거임 0: "0000", 8:"1000", f:"1111",3:"0011"

(숫자형태아니고 문자열 string형태라서 옆에 붙는다)

우리는 hexToBinary 함수를 안썼어. 그래서 nonce추가되는걸로 난이도 따라 해시값찾는걸로 나와. naive는 binaryHash기준으로 난이도 비교적 쉽게 통과되고 우리는 hash대로. 그니까 난이도 8일때 hash값 지금 0027..나오면 우린 안돼 더 돌려서 hash값 앞에 0이 최소한 8개여야 통과되는 거임. 

 

 

 

 

아무튼 다시 naive코드로 와서

 

블록의 해시값이 난이도 difficulty를 만족하는지 확인하는 코드

const hashMatchesDifficulty=(hash, difficulty)=>{

해시값을 이진수화해.

난이도만큼 0을 반복해.

이진수화한 거가. 지정한문자로 시작하는지 확인. 0이 8개인 문자로. 

}

 

난이도를 만족하는 해시값찾기 위해 같은 블록에서 여러번 계산해줘야한다. 이때 nonce값을 쓰는데 sha256라는 해시함수를 쓴다. 채굴이 바로 매번 다른 nonce값을 시도해보는 과정을 뜻한다. 

 

블록구조, 최초의 블록 구조에 difficulty와 nonce추가

class Block{

난이도 추가

넌스값 추가

}

 

 

블록찾기 

nonce값은 언제 증가시키는 findBlock 함수. 해시값을 찾을 때까지 반복문 돌릴거임.

const findBlock{

초기넌스값은 0

hash를 해시계산함수 안에 블록애들 넣어서 찾아.

만약에 난이도 확인하는 함수에 (해시랑, 난이도)보내서 통과되면

블록을 뱉어내(블록내용들을 담아서)

}

 

그렇게 블록이 채굴되면 네트워크통해서 발송(broadcast)되겠지

 

 

 

난이도(difficulty)를 어떻게 결정할건가

 

난이도값을 계산하는 로직필요해서 상수를 몇 개 정의하면서 만들었어. 하드코딩한거임. 물론 naive에서..ㅋㅋ

  • BLOCK_GENERATION_INTERVAL: 블록은 얼마나 자주 채굴되는가(Bitcoin의 경우 10분 간격이죠.)
  • DIFFICULTY_ADJUSTMENT_INTERVAL: 난이도difficulty는 얼마나 자주 조정되는가(Bitcoin은 2016블록마다 조정돼요.)
// in seconds
const BLOCK_GENERATION_INTERVAL: number = 10;

// in blocks
const DIFFICULTY_ADJUSTMENT_INTERVAL: number = 10;

신기한게 여기서는 그냥 임의로 지정한 숫자 10을 넣었는데 이게 어떻게 10초, 10블록으로 인식하나 싶었거든. 이게 같이 비교되는 애들따라서 인식을 하는거래.  코드를 보자

 

난이도가져오는함수

const getDifficulty=(블록체인)={

가장 마지막 블록= 블록체인.길이-1

만약에

마지막블록.index % BLOCK_GENERATION_INTERVAL(10블록으로 인식됨) 이 0이면 그리고 마지막블록.index가 0이 아니면

난이도 조절함수로 (마지막블록, 블록체인) 보내

 

아니면, 마지막블록의 난이도 뱉어내.

}

 

 

난이도 조절함수 

const getAdjustedDifficulty=(마지막블록,블록체인)=>{

이전조절블록 = 블록체인.길이- BLOCK_GENERATION_INTERVAL(10블록으로 인식됨)

예상시간= BLOCK_GENERATION_INTERVAL(10) 곱하기 DIFFICULTY_ADJUSTMENT_INTERVAL(10) //100이라는 숫자

걸린시간 = 마지막블록.timestamp -이전조절블록.timestamp     //그니까 10블록 생성될동안 걸린시간

 

만약 (걸린시간이 < 100 /2 ){

이전조절블록.난이도 +1  

아니면, (걸린시간 > 100* 2) {

이전조절블록.난이도 -1}

아니면, {

이전조절블록. 난이도 그대로 뱉어내

}

}

 

 

timestamp 

이전에는 아무 역할도 안해서 무슨값이든 상관없었는데 이제 난이도 조절하면서 블록 유효성 검증되는지 사용할거야.

 

유효한 타임스탬프인지 확인하는 함수

const isValidTimestamp = (새블록, 이전블록)=>{

이전블록.생성시간 - 60 < 새 블록.생성시간 그리고 새블록.생성시간 - 60 < 현재타임스탬프함수getCurrentTimestamp()

면 true

}

 

//현재 타임스템프 찍어주는 함수
function getCurrentTimestamp() {
  //Math.round 반올림함수
  return Math.round(new Date().getTime() / 1000);
}
 
new Date().getTime() / 1000이게 1970 년 1 월 1 일 자정 이후의 초를 알려준다고 함.

 

 

 

누적난이도

#1에서는 가장 긴 체인이 옳은 체인이라고 했지만 사실 

difficulty 난이도가 가장 많이 누적된 체인이 옳은 체인이야. 

 

작업증명에서 가장 중요한 건 그 과정이 풀기는 어렵지만 증명하기는 쉬워야한다는 것! 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90
728x90

알아본다면 당신은 천재임 (못알아봐도 천재)

각 노드, 참여자 컴퓨터에

3001이 관리자 

6001이 노동자..

http서버는 모든 걸 보여주기 용으로 돌리는거

 

라고 대충이해했는데.. 이후에 db서버랑, 리액트서버랑 얘네가 어떻게 맞물리는지 사실 아직도 서버관계를 정확하게 모르겠다! 

 

일단 코드 여기요 (지금까지 한 것만 포크해놓음)

 

https://github.com/jsoyun/4th-project-YunminBlock

 

GitHub - jsoyun/4th-project-YunminBlock: 4th BlockChain Project

4th BlockChain Project. Contribute to jsoyun/4th-project-YunminBlock development by creating an account on GitHub.

github.com

 

 

각 컴퓨터 참여자로 노드 만들어서 

p2p서버 전달 확인해봄

 

참고로 실행할 때는 

node node1/r_httpServer.js

이렇게 했다

 

 

두 서버 각각 열고 

3001
3002

 

 

get 요청인 blocks로 들어가보면

둘다 제네시스 블록이 잘 들어가 있음요 

 

서버 연결!!

post addpeers로 

3002한테 요청하는거임 

 

3002가 6001 웹소켓으로  상대 웹소켓 주소 ws 6001로 연결

문 똑똑

 

 

 

 

peers로 연결된거 확인!

 

 

이제 둘이 연결됐으니

3002에서 채굴해보겠음 

3002 채굴돼서 들어왔지?

 

 

그렇다면 3001을 새로고침해보면 3002랑 연결되어있고 그블록의 길이가 더 길어서 추가됨

 

 

연결되어있으니까 3002에서 연속 2개 추가해도 업데이트 됨

 

 

 

 

 

 

 

3001에서 블록채굴해도 마찬가지로 3002에서 업뎃됨 

연속으로 4,5 값 넣어서 블록추가함


서버 통신 코드

 

 

 

httpServer.js

post로 보내면 

data로 이름지어서 "data" : 웹소켓 주소 가능한거임

 

이 웹소켓 주소 data가 connectToPeers함수로 들어감 얘가 웹소켓 연결해줌

P2PServer.js

 

소켓에 넣고 메세지 핸들러 함수쓰고

얘네가 보내주는거 관리하는거임 

 

 

메세지 핸들러는 이렇게 여기서 변수로 지정해줬음 

(그 검증할 때 변수 10으로 다 잡아서 블록10개 이전과 비교해서 생성시간 알아내는 거 있잖아

이거요 blockchain.js

걔랑 비슷한 원리인듯

신기한게 컴퓨터는 바보라서 걍 숫자 넣어서 계산하는 거기 때문에 시간인지 뭔지 안적어도 가능했음)

 

 

대신 쓸때는 위처럼 MessageType.QUERY_LATEST 이런식으로 해야 얘가 찾겠지?

 

 

연결됐을 때 채굴하면 broadcast로 연결되어있는애들 전부한테 뿌려주는 거

(근데 생각해보니까 마지막 최신블록 담아서 보내주는거 말고도 아예 많이 다르면 전체 교체해야되는 replace함수 써야되는데 broadcast(initMessageHandler(ws)) 이걸로 해줘야 되는거 아닌가....? 흠 정리하고 다시 수정해봐야겠다. )

 

 

 

중간에 맞이했던 에러들

브로드캐스트에 저 함수를넣지 않은 것 말고도 있음

 

갑자기 이거 뜸

(node:11496) Warning: Accessing non-existent property 'Blocks' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
(node:11496) Warning: Accessing non-existent property 'getLastBlock' of module exports inside circular dependency                                                                     cular dependency
(node:11496) Warning: Accessing non-existent property 'createHash' of module exports inside circular dependency                                                                       de circular dependency
(node:11496) Warning: Accessing non-existent property 'isValidTimestamp' of module exports  circular dependency
inside circular dependency

이게 찾아보니까 순환참조? a스크립트에서 만든 함수 내보내고 b에서 a의 함수 가져왔는데 또 가져와서? 생기는 뭐 중복돼서 그런거라고 했는데 

이전에 안뜨다가 갑자기 떠서 당황... 작동은 되는데 불안하죠잉

 

결국 전역변수에 있는 애들 다 지역변수로 넣어서 함... 

 

이런식으로.. 

 

 

 

 

 

 

아 그리고 블록체인 에 

 

이 부분 틀렸다는데 

흠 내가 이해한 거는 새블럭을 현재 시간이랑 어느정도 오차범위까지는 인정하는 코드라고 봤거든 책도 그 얘기고..

 

 

흠..어렵군!!

 

 

 

 

 

728x90

+ Recent posts