[原]2.4 介面
CLI 命令列介面
直到現在,我們的實現還沒有提供任何操作介面給外界使用。我們先前的例子中在 main 函式中執行新建區塊鏈 NewBlockchain,還有新增區塊 bc.AddBlock 的方法。現在可以改善,增加命令列操作介面了。我們需要如下這樣的命令:
$ blockchain_go addblock “Pay 0.031337 for a coffee”
$ blockchain_go printchain
所有的命令列關聯的操作會被 CLI 結構處理:
type CLI struct { bc *Blockchain }
在 Run中加入CLI的接入點:
func (cli *CLI) Run() { cli.validateArgs() addBlockCmd := flag.NewFlagSet("addblock", flag.ExitOnError) printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError) addBlockData := addBlockCmd.String("data", "", "Block data") switch os.Args[1] { case "addblock": err := addBlockCmd.Parse(os.Args[2:]) case "printchain": err := printChainCmd.Parse(os.Args[2:]) default: cli.printUsage() os.Exit(1) } if addBlockCmd.Parsed() { if *addBlockData == "" { addBlockCmd.Usage() os.Exit(1) } cli.addBlock(*addBlockData) } if printChainCmd.Parsed() { cli.printChain() } }
使用標準的 flag 解析這些引數
addBlockCmd := flag.NewFlagSet("addblock", flag.ExitOnError) printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError) addBlockData := addBlockCmd.String("data", "", "Block data")
首先,建立兩個子命令, addblock 和 printfchain,用 -add 標記作為 addblock 的引數資料標識。printfchain 不用引數:
switch os.Args[1] { case "addblock": err := addBlockCmd.Parse(os.Args[2:]) case "printchain": err := printChainCmd.Parse(os.Args[2:]) default: cli.printUsage() os.Exit(1) }
檢測使用者輸入的引數和解析相關的 flag 子命令。
if addBlockCmd.Parsed() { if *addBlockData == "" { addBlockCmd.Usage() os.Exit(1) } cli.addBlock(*addBlockData) } if printChainCmd.Parsed() { cli.printChain() }
解析出的子命令該執行的相關函式:
func (cli *CLI) addBlock(data string) { cli.bc.AddBlock(data) fmt.Println("Success!") } func (cli *CLI) printChain() { bci := cli.bc.Iterator() for { block := bci.Next() fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash) fmt.Printf("Data: %s\n", block.Data) fmt.Printf("Hash: %x\n", block.Hash) pow := NewProofOfWork(block) fmt.Printf("PoW: %s\n", strconv.FormatBool(pow.Validate())) fmt.Println() if len(block.PrevBlockHash) == 0 { break } } }
現在的程式碼很像我們之些寫的那些。比較不同的是現在使用的是 BlockchainIterator去遍歷整個區塊鏈中的區塊。
最後修改 main 函式:
func main() { bc := NewBlockchain() defer bc.db.Close() cli := CLI{bc} cli.Run() }
注意,第一次執行時,如果BoltDB中沒有區塊鏈,則無論輸入什麼引數,都會建立一個區塊鏈。
現在可以檢測一下我們的程式碼是否工作OK了:
先安裝BoltDB
$ go get github.com/boltdb/bolt/…
執行程式:
$ blockchain_go printchain
No existing blockchain found. Creating a new one…
Mining the block containing “Genesis Block”
000000edc4a82659cebf087adee1ea353bd57fcd59927662cd5ff1c4f618109b
Prev. hash:
Data: Genesis Block
Hash: 000000edc4a82659cebf087adee1ea353bd57fcd59927662cd5ff1c4f618109b
PoW: true
$ blockchain_go addblock -data “Send 1 BTC to Ivan”
Mining the block containing “Send 1 BTC to Ivan”
000000d7b0c76e1001cdc1fc866b95a481d23f3027d86901eaeb77ae6d002b13
Success!
$ blockchain_go addblock -data “Pay 0.31337 BTC for a coffee”
Mining the block containing “Pay 0.31337 BTC for a coffee”
000000aa0748da7367dec6b9de5027f4fae0963df89ff39d8f20fd7299307148
Success!
$ blockchain_go printchain
Prev. hash: 000000d7b0c76e1001cdc1fc866b95a481d23f3027d86901eaeb77ae6d002b13
Data: Pay 0.31337 BTC for a coffee
Hash: 000000aa0748da7367dec6b9de5027f4fae0963df89ff39d8f20fd7299307148
PoW: true
Prev. hash: 000000edc4a82659cebf087adee1ea353bd57fcd59927662cd5ff1c4f618109b
Data: Send 1 BTC to Ivan
Hash: 000000d7b0c76e1001cdc1fc866b95a481d23f3027d86901eaeb77ae6d002b13
PoW: true
Prev. hash:
Data: Genesis Block
Hash: 000000edc4a82659cebf087adee1ea353bd57fcd59927662cd5ff1c4f618109b
PoW: true
本章總結
本章我們實現了區塊的持久化,還有完善了遍歷資訊來支援按序列印所有的區塊。下一章我們將會實現 address,wallet,transaction。敬請期待!
-
學院Go語言視訊主頁
ofollow,noindex" target="_blank">https://edu.csdn.net/lecturer/1928 -
掃碼獲取海量視訊及原始碼 QQ群:721929980