0
点赞
收藏
分享

微信扫一扫

区块链项目 - 4 命令行工具

4.命令行工具

截至目前我们区块链的基本逻辑已经构建完毕,现在我们使用命令行工具按照我们想要的目的进行输出

4.1 flag基本使用

在此之前,我们先来看看flag的基本使用方法

/Users/xxx/go/src/publicChain/part21-cli-flag/main.go

package main

import (
	"flag"
	"fmt"
)

func main() {
	flagString := flag.String("printChain", "", "output all details of blocks")

	flagInt := flag.Int("number", 6, "output an int")

	flagBool := flag.Bool("open", false, "Judging true and false")
	flag.Parse()

	fmt.Printf("%s\n", *flagString)
	fmt.Printf("%d\n", *flagInt)
	fmt.Printf("%t\n", *flagBool)
}

在终端构建程序并运行

cd /Users/xxx/go/src/publicChain/part21-cli-flag
go build main.go
./main

输出结果

6
false

通过-输出指定内容,指定的顺序可以变化

./main -printChain "jech" -open -number 10
jech
10
true

4.2 os

我们再来看一个os包下面的变量args

/Users/xxx/go/src/publicChain/part22-cli-osArgs/main.go

func main() {

	args := os.Args

	fmt.Printf("%v\n", args)
}
go build main.go
./main printChain -data "jech.org"
[./main printChain -data jech.org]

它能够将输入连接成一个数组,这个数组中的元素可以随着输入无限增长

./main how are you
[./main how are you]

当然我们可以对这个动态数组求长度、访问里面的元素等

4.3 命令行解释器

现在我们结合os包下的变量args和flag实现我们自定义的命令行工具。args可以获取输入,通过一定的解析可以实现自定义的命令行工具,我们来看看具体代码实现:

/Users/xxx/go/src/publicChain/part23-cli/main.go

func printUsage() {
	fmt.Println("Usage:")
	fmt.Println("\taddBlock -data DATA - transaction data")
	fmt.Println("\tprintChain -- output block's information")
}
func isValidArgs() {
	if len(os.Args) < 2 {
		printUsage()
		os.Exit(1)
	}
}

func main() {
	isValidArgs()
	//custom command
	addBlockCmd := flag.NewFlagSet("addBlock", flag.ExitOnError)
	printChainCmd := flag.NewFlagSet("printChain", flag.ExitOnError)

	flagAddBlockData := addBlockCmd.String("data", "jech.org", "transaction data...")

	switch os.Args[1] {
	case "addBlock":
		err := addBlockCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	case "printChain":
		err := printChainCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	default:
		printUsage()
		os.Exit(1)
	}
	if addBlockCmd.Parsed() {
		if *flagAddBlockData == "" {
			printUsage()
			os.Exit(1)
		}
		fmt.Println(*flagAddBlockData)
		cli.addBlock(*flagAddBlockData)
	}
	if printChainCmd.Parsed() {
		//fmt.Println("output all blocks' information")
		cli.printChain()
	}
}

4.4 数据持久化

现在我们要实现命令行工具将区块添加至数据库,并且根据需要打印区块链

把/Users/xxx/go/src/publicChain/part16-persistence-iteration复制一份并命名为part24-persistence-cli

我们先把上述代码放到独立文件中

/Users/xxx/go/src/publicChain/part24-persistence-cli/BLC/CLI.go

type CLI struct {
	Blockchain *Blockchain
}

func printUsage() {
	fmt.Println("Usage:")
	fmt.Println("\taddBlock -data DATA - transaction data")
	fmt.Println("\tprintChain -- output block's information")
}
func isValidArgs() {
	if len(os.Args) < 2 {
		printUsage()
		os.Exit(1)
	}
}

func (cli CLI) addBlock(data string) {
	cli.Blockchain.AddBlockToBlockchain(data)
}

func (cli CLI) printChain() {
	cli.Blockchain.PrintChain()
}

func (cli CLI) Run() {
	isValidArgs()
	//custom command
	addBlockCmd := flag.NewFlagSet("addBlock", flag.ExitOnError)
	printChainCmd := flag.NewFlagSet("printChain", flag.ExitOnError)

	flagAddBlockData := addBlockCmd.String("data", "jech.org", "transaction data...")

	switch os.Args[1] {
	case "addBlock":
		err := addBlockCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	case "printChain":
		err := printChainCmd.Parse(os.Args[2:])
		if err != nil {
			log.Panic(err)
		}
	default:
		printUsage()
		os.Exit(1)
	}
	if addBlockCmd.Parsed() {
		if *flagAddBlockData == "" {
			printUsage()
			os.Exit(1)
		}
		fmt.Println(*flagAddBlockData)
		cli.addBlock(*flagAddBlockData)
	}
	if printChainCmd.Parsed() {
		//fmt.Println("output all blocks' information")
		cli.printChain()
	}
}

main函数当然也得改一下

/Users/xxx/go/src/publicChain/part24-persistence-cli/main.go

func main() {
	//creat a Genesis Block
	Blockchain := BLC.CreatBlockchainWithGenesisBlock()
	defer Blockchain.DB.Close()

	cli := BLC.CLI{Blockchain: Blockchain}
	cli.Run()
}

由于当前每次运行都会从创建创世区块开始,现在我们来重新更新下这里的代码

/Users/xxx/go/src/publicChain/part24-persistence-cli/BLC/Blockchain.go

//1 creat a blockchain with Genesis Block

func CreatBlockchainWithGenesisBlock() *Blockchain {
	if dbExists() {
		fmt.Println("The genesis block already exists")

		//open a database
		db, err := bolt.Open(dbName, 0600, nil)
		if err != nil {
			log.Fatal(err)
		}

		var blockchain *Blockchain

		err = db.Update(func(tx *bolt.Tx) error {
			b := tx.Bucket([]byte(blockTableName))

			hash := b.Get([]byte("l"))

			blockchain = &Blockchain{Tip: hash, DB: db}
			return nil
		})
		if err != nil {
			log.Panic(err)
		}
		return blockchain
	}

	//creat/open a database
	db, err := bolt.Open(dbName, 0600, nil)
	if err != nil {
		log.Fatal(err)
	}

	var blockHash []byte

	err = db.Update(func(tx *bolt.Tx) error {
		//creat a table
		b, err := tx.CreateBucket([]byte(blockTableName))

		if err != nil {
			log.Panic(err)
		}
		if b != nil {
			genesisBlock := CrateGenesisBlock("Genesis Data......")

			//Store the genesis block into a table
			err := b.Put(genesisBlock.Hash, genesisBlock.Serialize())
			if err != nil {
				log.Panic(err)
			}
			//Store the hash of current block
			err = b.Put([]byte("l"), genesisBlock.Hash)
			if err != nil {
				log.Panic(err)
			}
			blockHash = genesisBlock.Hash
		}
		return nil
	})
	return &Blockchain{blockHash, db}
}

在终端中构建并使用命令行运行

go build -o bc main.go
./bc
0000eef7e34b794745f53c69c83a9b8a6f0462efb7acb55a6b72d5837dabf620
Usage:
        addBlock -data DATA - transaction data
        printChain -- output block's information
./bc printChain
The genesis block already exists
Height:1
PreBlockHash:0000000000000000000000000000000000000000
Data:Genesis Data......
Timestamp:2022-02-27 12:59:50 PM
Hash:0000eef7e34b794745f53c69c83a9b8a6f0462efb7acb55a6b72d5837dabf620
Nonce:36226
./bc addBlock -data "2022"
The genesis block already exists
2022
0000680e7def40960635ee3fe08fc7a879cea562b5f566f08a5ea28b9c4b51e0
./bc printChain
The genesis block already exists
Height:2
PreBlockHash:0000eef7e34b794745f53c69c83a9b8a6f0462efb7acb55a6b72d5837dabf620
Data:2022
Timestamp:2022-02-27 01:01:55 PM
Hash:0000680e7def40960635ee3fe08fc7a879cea562b5f566f08a5ea28b9c4b51e0
Nonce:8328

Height:1
PreBlockHash:0000000000000000000000000000000000000000
Data:Genesis Data......
Timestamp:2022-02-27 12:59:50 PM
Hash:0000eef7e34b794745f53c69c83a9b8a6f0462efb7acb55a6b72d5837dabf620
Nonce:36226

非常完美,我们可以在终端中添加输入data来生成区块,并且输出

举报

相关推荐

0 条评论