main.go
package main
import "coin/exam03/blockchain"
func main() {
chain := blockchain.GetBlockchain()
}
blockchain/blockchain.go
package blockchain
import "sync"
type block struct {
data string
hash string
prevHash string
}
type blockchain struct {
blocks []block
}
// 블록체인을 공유하고 초기화하는 작업
// Singleton pattern
// blockchain의 단 하나의 instance만을 공유하는 방법
// 공유하지 않으므로 private 선언
var b *blockchain
// 위 변수의 instance를 대신해서 드러내는 function 생성
// -> 다른 패키지에서 우리의 blockchain이 어떤식으로 생성될지 제어 가능하다는 의미
func GetBlockchain() *blockchain {
// b가 초기화되었는지 확인 후 처음이자 마지막으로 초기화 진행
// nil이면 아직 생성되지 않아 새로 생성한다는 의미
// 두번째로 부르는 순간부터 생성, 초기화는 진행되지 않는다.
if b == nil {
// "=" 를 통해 b를 새로 생성하지 않고 대입해준다.
b = &blockchain{}
}
return b
}
package main
import "coin/exam04/blockchain"
func main() {
chain := blockchain.GetBlockchain()
}
package blockchain
import (
"crypto/sha256"
"fmt"
"sync"
)
type block struct {
data string
hash string
prevHash string
}
type blockchain struct {
// block 타입의 포인터 슬라이스
blocks []*block
}
var b *blockchain
// 단 한번만 실행되게 하기 위함
var once sync.Once
// Hash를 계산해주는 함수
func (b *block) calculateHash() {
hash := sha256.Sum256([]byte(b.data + b.prevHash))
b.hash = fmt.Sprintf("%x", hash)
}
// 이전 해시값을 생성해서 가져오는 함수
func getLastHash() string {
totalBlocks := len(GetBlockchain().blocks)
// 블록의 개수가 0개면 마지막 Hash 값이 없기 떄문에 아무것도 반환하지 않는다.
if totalBlocks == 0 {
return ""
}
// 마지막 블록체인의 Hash를 반환해준다.
return GetBlockchain().blocks[totalBlocks-1].hash
}
func createBlock(data string) *block {
newBlock := block{data, "", getLastHash()}
newBlock.calculateHash()
return &newBlock
}
func GetBlockchain() *blockchain {
if b == nil {
// 단 한번만 실행된다.
// 병렬적으로 처리하든 뭘하든 해당 함수는 한번만 실행됨을 의미
once.Do(func() {
// 블록체인을 하나 생성하고
b = &blockchain{}
// 하나의 블록을 추가한다.
b.blocks = append(b.blocks, createBlock("Genesis Block"))
})
}
return b
}
앞서 만든 코드를 이용하여 blockchain에 block을 등록하고 block 정보를 가져오는 기능 구현
package main
import (
"coin/exam05/blockchain"
"fmt"
)
func main() {
chain := blockchain.GetBlockchain()
chain.AddBlock("Second Block")
chain.AddBlock("Third Block")
chain.AddBlock("Fourth Block")
for _, block := range chain.AllBlocks() {
fmt.Printf("Data: %s\n", block.Data)
fmt.Printf("Hash: %s\n", block.Hash)
fmt.Printf("Prev Hash: %s\n", block.PrevHash)
}
}
package blockchain
import (
"crypto/sha256"
"fmt"
"sync"
)
type block struct {
Data string
Hash string
PrevHash string
}
type blockchain struct {
// block 타입의 포인터 슬라이스
blocks []*block
}
var b *blockchain
var once sync.Once
func (b *block) calculateHash() {
hash := sha256.Sum256([]byte(b.Data + b.PrevHash))
b.Hash = fmt.Sprintf("%x", hash)
}
func getLastHash() string {
totalBlocks := len(GetBlockchain().blocks)
if totalBlocks == 0 {
return ""
}
return GetBlockchain().blocks[totalBlocks-1].Hash
}
func createBlock(data string) *block {
newBlock := block{data, "", getLastHash()}
newBlock.calculateHash()
return &newBlock
}
// export 함수
func (b *blockchain) AddBlock(data string) {
b.blocks = append(b.blocks, createBlock(data))
}
func GetBlockchain() *blockchain {
if b == nil {
once.Do(func() {
b = &blockchain{}
b.AddBlock("Genesis Block")
})
}
return b
}
// 사용자에게 field를 드러내주는 function(singleton의 철학)
func (b *blockchain) AllBlocks() []*block {
return b.blocks
// return GetBlockchain().blocks
}
기존에 private하게 만들어둔 block 정보를 public하게 만들어 준 후 AllBlocks() 함수를 통해 데이터를 읽어왔다. 이부분은 추후 수정