var Args []string
CLI에서 사용된 문자열 배열을 리턴합니다. 첫번째 인자는 실행프로그램의 이름package main
import (
"fmt"
"os"
)
func usage() {
fmt.Printf("Welcome to FDong Coin\n\n")
fmt.Printf("Please use the following commands:\n\n")
fmt.Printf("explorer: Start the HTML Explorer\n")
fmt.Printf("rest: Start the REST API (recommende)\n")
os.Exit(0)
}
func main() {
if len(os.Args) < 2 {
usage()
}
switch os.Args[1] {
case "explorer":
fmt.Println("Start Explorer")
case "rest":
fmt.Println("Start REST API")
default:
usage()
}
}
go run main.go 입력 시
> go run main.go
Welcome to FDong Coin
Please use the following commands:
explorer: Start the HTML Explorer
rest: Start the REST API (recommende)
go run main.go explorer 입력 시
> go run main.go explorer
Start Explorer
go run main.go rest 입력 시
> go run main.go rest
Start REST API
package main
import (
"flag"
"fmt"
"os"
)
func usage() {
fmt.Printf("Welcome to FDong Coin\n\n")
fmt.Printf("Please use the following commands:\n\n")
fmt.Printf("explorer: Start the HTML Explorer\n")
fmt.Printf("rest: Start the REST API (recommende)\n")
os.Exit(0)
}
func main() {
// FlagSet은 go에게 어떤 command가 어떤 flag를 가질 것인지 알려주는 역할을 한다.
if len(os.Args) < 2 {
usage()
}
rest := flag.NewFlagSet("rest", flag.ExitOnError)
portFlag := rest.Int("port", 4000, "Sets the port of the server")
switch os.Args[1] {
case "explorer":
fmt.Println("Start Explorer")
case "rest":
rest.Parse(os.Args[2:])
default:
usage()
}
if rest.Parsed() {
fmt.Println(*portFlag)
fmt.Println("Start Server")
}
}
package main
import "coin/exam23/cli"
func main() {
cli.Start()
}
package cli
import (
"coin/exam23/explorer"
"coin/exam23/rest"
"flag"
"fmt"
"os"
)
func usage() {
fmt.Printf("Welcome to FDong Coin\n\n")
fmt.Printf("Please use the following flags:\n\n")
fmt.Printf("-port: Set the PORT of the server\n")
fmt.Printf("-mode: Choose between 'html' and 'rest'\n")
os.Exit(0)
}
func Start() {
if len(os.Args) == 1 {
usage()
}
port := flag.Int("port", 4000, "Set port of the server")
mode := flag.String("mode", "rest", "Choose between 'html' and 'rest'")
flag.Parse()
switch *mode {
case "rest":
// start rest api
rest.Start(*port)
case "html":
// start html explorer
explorer.Start(*port)
default:
usage()
}
}
> go run main.go -mode=rest -port=2000
Listening on http://localhost:2000
> go run main.go -mode=html -port=8000
Listening on http://localhost8000
> go run main.go -mode=html -port=asdf
invalid value "asdf" for flag -port: parse error
Usage of /var/folders/5s/13x9ywys5wz_w321jgl_f_pw0000gn/T/go-build895749235/b001/exe/main:
-mode string
Choose between 'html' and 'rest' (default "rest")
-port int
Set port of the server (default 4000)
exit status 2
https://github.com/boltdb/bolt
bolt db는 Key/Value 형태의 저장소이다.
go get github.com/boltdb/bolt
package db
import (
"coin/exam24/utils"
"github.com/boltdb/bolt"
)
const (
dbname = "blockchain.db"
dataBucket = "data"
blocksBucket = "blocks"
)
var db *bolt.DB
// DB initialize, Singleton pattern형식
func DB() *bolt.DB {
if db == nil {
// init db
// path는 DB의 이름, 파일이 없으면 자동으로 생성해준다,
dbPointer, err := bolt.Open(dbname, 0600, nil)
utils.HandleErr(err)
db = dbPointer
// bucket이 존재하지 않으면 생성시켜주는 Transaction, 두개의 bucket을 만들어준다.
// bucket는 table 같은거다
err = db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(dataBucket))
utils.HandleErr(err)
_, err = tx.CreateBucketIfNotExists([]byte(blocksBucket))
return err
})
utils.HandleErr(err)
}
return db
}
package main
import (
"coin/exam26/blockchain"
)
func main() {
blockchain.Blockchain()
}
package db
import (
"coin/exam26/utils"
"fmt"
"github.com/boltdb/bolt"
)
const (
dbname = "blockchain.db"
dataBucket = "data"
blocksBucket = "blocks"
)
var db *bolt.DB
// DB initialize, Singleton pattern형식
func DB() *bolt.DB {
if db == nil {
// init db
// path는 DB의 이름, 파일이 없으면 자동으로 생성해준다,
dbPointer, err := bolt.Open(dbname, 0600, nil)
utils.HandleErr(err)
db = dbPointer
// bucket이 존재하지 않으면 생성시켜주는 Transaction, 두개의 bucket을 만들어준다.
// bucket는 table 같은거다
err = db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(dataBucket))
utils.HandleErr(err)
_, err = tx.CreateBucketIfNotExists([]byte(blocksBucket))
return err
})
utils.HandleErr(err)
}
return db
}
func SaveBlock(hash string, data []byte) {
fmt.Printf("Saving Block %s\nData: %b", hash, data)
err := DB().Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(blocksBucket))
err := bucket.Put([]byte(hash), data)
return err
})
utils.HandleErr(err)
}
func SaveBlockchain(data []byte) {
err := DB().Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(dataBucket))
err := bucket.Put([]byte("checkpoint"), data)
return err
})
utils.HandleErr(err)
}
package blockchain
import (
"bytes"
"coin/exam26/db"
"coin/exam26/utils"
"crypto/sha256"
"encoding/gob"
"fmt"
)
type Block struct {
Data string `json:"data"`
Hash string `json:"hash"`
PrevHash string `json:"prevhash,omitempty"`
Height int `json:"height"`
}
func (b *Block) toBytes() []byte {
var blockBuffer bytes.Buffer
encoder := gob.NewEncoder(&blockBuffer)
utils.HandleErr(encoder.Encode(b))
return blockBuffer.Bytes()
}
func (b *Block) persist() {
db.SaveBlock(b.Hash, b.toBytes())
}
func createBlock(data string, prevHash string, height int) *Block {
block := &Block{
Data: data,
Hash: "",
PrevHash: prevHash,
Height: height,
}
payload := block.Data + block.PrevHash + fmt.Sprint(block.Height)
block.Hash = fmt.Sprintf("%x", sha256.Sum256([]byte(payload)))
block.persist()
return block
}
package blockchain
import (
"sync"
)
type blockchain struct {
NewestHash string `json:"newestHash"`
Height int `json:"height"`
}
var b *blockchain
var once sync.Once
// AddBlock receiver
func (b *blockchain) AddBlock(data string) {
block := createBlock(data, b.NewestHash, b.Height)
b.NewestHash = block.Hash
b.Height = block.Height
}
func Blockchain() *blockchain {
if b == nil {
once.Do(func() {
b = &blockchain{"", 0}
b.AddBlock("Genesis Block")
})
}
return b
}
> go run main.go
Saving Block 8500b59bb5271135cd9bcbf0afd693028d76df3b9c7da58d412b13fc8a8f9394
Data: [111101 11111111 10000001 11 1 1 101 1000010 1101100 1101111 1100011 1101011 1 11111111 10000010 0 1 100 1 100 1000100 1100001 1110100 1100001 1 1100 0 1 100 1001000 1100001 1110011 1101000 1 1100 0 1 1000 1010000 1110010 1100101 1110110 1001000 1100001 1110011 1101000 1 1100 0 1 110 1001000 1100101 1101001 1100111 1101000 1110100 1 100 0 0 0 1010100 11111111 10000010 1 1101 1000111 1100101 1101110 1100101 1110011 1101001 1110011 100000 1000010 1101100 1101111 1100011 1101011 1 1000000 111000 110101 110000 110000 1100010 110101 111001 1100010 1100010 110101 110010 110111 110001 110001 110011 110101 1100011 1100100 111001 1100010 1100011 1100010 1100110 110000 1100001 1100110 1100100 110110 111001 110011 110000 110010 111000 1100100 110111 110110 1100100 1100110 110011 1100010 111001 1100011 110111 1100100 1100001 110101 111000 1100100 110100 110001 110010 1100010 110001 110011 1100110 1100011 111000 1100001 111000 1100110 111001 110011 111001 110100 0]
package blockchain
import (
"coin/exam27/db"
"coin/exam27/utils"
"sync"
)
type blockchain struct {
NewestHash string `json:"newestHash"`
Height int `json:"height"`
}
var b *blockchain
var once sync.Once
func (b *blockchain) persist() {
db.SaveBlockchain(utils.ToBytes(b))
}
// AddBlock receiver
func (b *blockchain) AddBlock(data string) {
block := createBlock(data, b.NewestHash, b.Height+1)
b.NewestHash = block.Hash
b.Height = block.Height
b.persist()
}
func Blockchain() *blockchain {
if b == nil {
once.Do(func() {
b = &blockchain{"", 0}
b.AddBlock("Genesis Block")
})
}
return b
}
package blockchain
import (
"coin/exam27/db"
"coin/exam27/utils"
"crypto/sha256"
"fmt"
)
type Block struct {
Data string `json:"data"`
Hash string `json:"hash"`
PrevHash string `json:"prevhash,omitempty"`
Height int `json:"height"`
}
func (b *Block) persist() {
db.SaveBlock(b.Hash, utils.ToBytes(b))
}
func createBlock(data string, prevHash string, height int) *Block {
block := &Block{
Data: data,
Hash: "",
PrevHash: prevHash,
Height: height,
}
payload := block.Data + block.PrevHash + fmt.Sprint(block.Height)
block.Hash = fmt.Sprintf("%x", sha256.Sum256([]byte(payload)))
block.persist()
return block
}
package utils
import (
"bytes"
"encoding/gob"
"log"
)
func HandleErr(err error) {
if err != nil {
log.Panic(err)
}
}
// 원하는 건 모든지 받을 수 있다.
func ToBytes(i interface{}) []byte {
var aBuffer bytes.Buffer
encoder := gob.NewEncoder(&aBuffer)
HandleErr(encoder.Encode(i))
return aBuffer.Bytes()
}