보다 더 생생한 기록

[GO] [코드리뷰] 블록체인 구축 코드 리뷰 - (1) 본문

Go

[GO] [코드리뷰] 블록체인 구축 코드 리뷰 - (1)

viviviviviid 2023. 8. 31. 23:34
노마드코드 강의를 들으며 클론코딩을 하고 있습니다. 강의가 끝난 뒤, 제 입맛대로 여러 기능을 가진 체인을 구축할 예정이지만, 수강중에 있으므로 코드리뷰는 노마드코더 클론코드를 위주로 진행합니다.

리뷰의 추가적인 목적으로는, 스스로 깨닫고 여타 큰 도움 없이 현 진도와 비슷한 체인을 구축하는것에 목적을 둡니다.  (리뷰 후 자체 체인 구축에는 클라이언트단 없이, DB와 백엔드만 들어갈 예정입니다.)

 

Overview

  • 강의 진도 : 8강 PERSISTENCE (36%)
  • 기술스택 : go, boltDB, gorilla-mux, cli 관련 (os, flag, etc)

Whole Flow ( 클라이언트 제외  )

백엔드 실행 

  1. CLI 커맨드로 서버 실행
  2. blockchain의 포인터가 
    1. nil 값이면 : 서버를 킨 것이므로 비어있을 수 밖에 없다. 그래서 DB에서 block들을 저장한 내용이 있는지 확인한다
      1. DB에 저장한 내용이 있다면 불러온다.
      2. DB에 저장한 내용이 없다면 Genesis Block을 생성해서 DB에 블록 내용을 추가해준다.
    2. nil 값이 아니면 : 이미 서버가 실행되고 있었다는 뜻이므로 아무런 제스쳐가 필요없음

 

블록 추가

1. AddBlock(data string)을 이용해 createBlock()에 데이터와 이전 해시값, 블록높이를 넣어 보낸다.

createBlock(data string, prevHash string, height int) *Block

그러면 Block struct 형태를 가진 block을 생성해, 그 포인터에 값을 넣어준다. (hash값은 다음단계에서 채워질 예정)

block := &Block{
    Data:     data,
    Hash:     "",
    PrevHash: prevHash,
    Height:   height,
}

그 뒤, 3가지 값을 payload로 묶고 sha256 암호화를 거쳐, 블록의 해시값을 구한 뒤, 이를 block의 hash값에 넣어준다. 

payload := block.Data + block.PrevHash + fmt.Sprint(block.Height)
block.Hash = fmt.Sprintf("%x", sha256.Sum256([]byte(payload)))

 

이제 block을 AddBlock으로 반환해서 해시값과 블록높이를,
체인의 현 블록과 관련된 데이터인 blockchain struct 포인터에 업데이트 해준다.

type blockchain struct {
    NewestHash string 
    Height     int    
}

func (b *blockchain) AddBlock(data string) {
    block := createBlock(data, b.NewestHash, b.Height+1)
    b.NewestHash = block.Hash
    b.Height = block.Height
    b.persist()
}

이후 blockchain struct의 포인터값을 db에 저장시켜준다.

// 직전 사용한 b.persist()

func (b *blockchain) persist() {
    db.SaveBlockchain(utils.ToBytes(b))	
}

 

전체 블록 조회

Blocks() 함수내에서, blocks라는 Block struct 형태의 빈 slice를 생성한다.

그 뒤, 저장된 NewestHash를 가져온다. 

type blockchain struct {
    NewestHash string 
    Height     int   
}

이제 이걸 타켓화해서 DB Block에서 해시 컬럼을 조회한다. 

 {
    "data": "Data for my block",
    "hash": "c57fca35b986fc973b8f1b535ae9970c081606d5bffde0c3def73cba9cf50bf9",
    "prevHash": "110e8eb40de97b0929e53a3b0cd2d697a4bd25a38fe1a5f069d6d35a40976e17",
    "height": 5
  },

조회하면 위와 같은 Block Object가 나오는데, blocks slice에 append로 저장하고, prevHash를 타겟으로 지정한다.

이걸 반복하면 Genesis Block 이 나올텐데, 그때는 prevHash가 빈 문자열이므로 중지한다.
지금까지 조회하면서 축적된 slice를 반환하여 전체블록을 화면에 뿌려준다.

 

특정 블록 조회

현재는 hash 값으로 검색하는 함수만 구현되어있다. 이 해시를 DB hash 컬럼에서 조회한다. 

그러면 전체 블록 조회처럼 Block Object가 나오는데 이를 반환하여, 화면에 뿌려준다.