Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
Tags
- 트러블슈팅
- 코드스테이츠
- 인센티브 기반 커뮤니티
- 옵저버패턴
- 업그레이더블 컨트랙트
- 팀 프로젝트
- 팩토리패턴
- 일시정지
- 프록시패턴
- git add
- 디자인 패턴
- 스테이트머신패턴
- 코드리뷰
- 싱글톤패턴
- 블록체인
- 토큰노믹스
- solidity
- 재진입
- 부트캠프
- 솔리디티
- 투표
- RBAC
- 멀티시그
- 웹툰
- 회로차단
- 배팅
- github 에러
- git commit
- github
Archives
- Today
- Total
보다 더 생생한 기록
[GO] [코드리뷰] 블록체인 구축 코드 리뷰 (PoW) - (2) 본문
Overview
- 강의 진도 : 9강 Mining (41%)
Added Contents
Proof of Work 합의 알고리즘을 추가하였다. 채굴자는 최근 생성된 블록에서 논스만 조절하고 해시화한다.
이제 생성된 해시가 체인이 제공하는 문제의 목표기준에 부합하면, 해당 블록의 마이닝이 종료되고 블록이 체인에 추가된다.
난이도와 블록간 시간차를 계산하기 위해 여러 내용들이 추가되었다.
const (
defaultDifficulty int = 2
difficultyInterval int = 5 // 5 블록마다 걸린 시간을 측정할것임
blockInterval int = 2 // 2분마다 한개 생성하는것을 목표로 잡음
allowedRange int = 2 // expectedTime과의 Gap차이 허용 구간
)
type blockchain struct {
NewestHash string
Height int
CurrentDifficulty int
}
이를 이용하여 매 5블록(프로젝트에서 임의로 정한 기준)이 생성될때까지 걸린 사이시간을 구하고,
이게 우리가 목표로 잡은 10분(2분차이허용: allowedRange 상수) 이하라면 난이도를 높인다.
만약 10분(2분차이허용) 이상이라면 난이도를 낮춰 목표시간에 근접하도록 조절해주는 함수를 구현하였다.
func (b *blockchain) recalculateDifficulty() int {
allBlocks := b.Blocks()
newestBlock := allBlocks[0] // chain.go에서 Blocks를 보면, 우리는 최근 해시부터 찾아들어갔다는 것을 확인할 수 있다. 즉 0번 인덱스를 조회해야 최근 블록내용이 나온다.
lastRecalculatedBlock := allBlocks[difficultyInterval-1] // 가장 최근 업데이트된 블록
actualTime := (newestBlock.Timestamp / 60) - (lastRecalculatedBlock.Timestamp / 60) // unix라서 60을 나눠줌으로 분단위
expectedTime := difficultyInterval * blockInterval // 우린 블록당 2분으로 예상을 했고, 5블록마다 측정한다면 이 둘의 곱은 10분이어야함.
if actualTime < (expectedTime - allowedRange) {
return b.CurrentDifficulty + 1
} else if actualTime > (expectedTime + allowedRange) {
return b.CurrentDifficulty - 1
}
return b.CurrentDifficulty
}
func (b *blockchain) difficulty() int {
if b.Height == 1 {
return defaultDifficulty
} else if b.Height%difficultyInterval == 0 { // 우리는 매 5블록마다 걸린 시간 측정
// 비트코인은 2016 블록마다 측정 -> 2주간 측정했을때 24 * 14 (2주시간) == 2016 / 60 (한시간마다 1블록이라고 치면)
// 즉 2주보다 더 걸렸으면 난이도를 낮추고, 덜 걸렸으면 난이도를 높임.
return b.recalculateDifficulty()
} else { // 첫번째 블록이 아니면서, 난이도 조절이 필요 없을때
return b.CurrentDifficulty
}
}
비트코인은 2016 블록마다 측정하는데, 이는 2주간 블록을 10분마다 하나씩 해결하면 딱 들어맞는 블록개수이다.
(숫자가 정말 이쁘지 않은가)
Mining Process
1. 가장 최근 생성된 블록의 pointer값을 가져온다.
type Block struct {
Data string
Hash string
PrevHash string
Height int
Difficulty int
Nonce int
Timestamp int
}
2. 그 포인터 값을 해시화한다.
func Hash(i interface{}) string {
s := fmt.Sprintf("%v", i) // v: default formmater
hash := sha256.Sum256([]byte(s))
return fmt.Sprintf("%x", hash)
}
3. 체인은 해시값의 맨 앞 문자들이 0으로 시작하길 원한다. (difficulty의 개수에 따라 0이 몇개 있어야할지 정해짐)
difficulty = 4 라면
체인이 원하는 해시값은 "0000dkjwje21ejlk32saj1241adksadjl" 이런 값이다
즉 해시의 맨 첫 4자리가 0으로 구성되어야 한다는 것이다.
func (b *Block) mine() {
target := strings.Repeat("0", b.Difficulty)
for {
b.Timestamp = int(time.Now().Unix())
hash := utils.Hash(b)
fmt.Printf("\n\n\nTarget: %s\nHash: %s\nNonce: %d\n\n\n", target, hash, b.Nonce)
if strings.HasPrefix(hash, target) {
b.Hash = hash
break
} else {
b.Nonce++
}
}
}
HasPrefix(a, b)는 a의 앞부분에 b가 있는지 확인하는 strings 패키지.
4. 아니라면 1번에서 가져온 Block의 nonce 값을 1 올려서 다시 해싱한다. (즉 채굴자는 nonce의 값만 조절이 가능하다)
5. 그 뒤 새로 생성된 해시를 3번과정을 거친다 의 반복
아직 채굴자에 대한 보상 체계는 구축되지 않았다.
'Go' 카테고리의 다른 글
[GO] Method VS Function 선언 선택 공식, 함수 또는 메서드가 어떤 역할 하는지 선언만 보고 간단하게 파악하기 (0) | 2023.09.08 |
---|---|
[GO] once.Do() + 데드락 (0) | 2023.09.08 |
[GO] [코드리뷰] 블록체인 구축 코드 리뷰 - (1) (0) | 2023.08.31 |
[GO] go get VS go install (zsh: command not found) (0) | 2023.08.30 |
[Go] ERROR : command-line-arguments, gopls - go 초기 에러 (0) | 2023.06.14 |