目录
1.main.go文件
package main
func main() {
/*
todo 4、对osCli 结构体,实例化
*/
// 实例化
osCli := OsCli{}
// 调用
osCli.Init()
}
2.block.go文件
package main
import (
"bytes"
"crypto/sha256"
"math/rand"
"time"
)
/*
todo 13、新建block文件
新建
*/
/*Block
todo 14、创建Block结构体
*/
type Block struct {
Version uint64 // 区块版本号
blockHeight int // 区块高度
PrevBlockHash []byte // 前hash
MerKleRoot []byte // 默克尔根
TimeStamp uint64 // 时间戳
Difficulty uint64 // 难度值
Nonce uint64 // 随机数,挖矿找的就是它
Data []byte // 数据
Hash []byte // 当前区块hash
}
const VERSION = 1
/*NewBlock
todo 18新建区块方法
参数:
返回 区块
*/
func NewBlock(data string, blockHeight int, prevBlockHash []byte) *Block {
block := Block{
Version: VERSION,
blockHeight: blockHeight,
PrevBlockHash: prevBlockHash,
MerKleRoot: []byte{},
TimeStamp: uint64(time.Now().Unix()),
Difficulty: 1,
Nonce: uint64(rand.Intn(1000)),
Hash: []byte{},
Data: []byte(data),
}
block.setBlockHash()
return &block
}
/*setBlockHash
todo 19、设置区块hash
*/
func (block *Block) setBlockHash() {
bts := [][]byte{
uintToByte(block.Version),
block.PrevBlockHash,
block.MerKleRoot,
uintToByte(block.Difficulty),
uintToByte(block.TimeStamp),
uintToByte(block.Nonce),
block.Data,
}
data := bytes.Join(bts, []byte{})
hash := sha256.Sum256(data)
block.Hash = hash[:]
}
3.blockChain.go文件
package main
import (
"bytes"
"crypto/elliptic"
"encoding/gob"
"fmt"
"io/ioutil"
)
/*todo 15 新建blockChain.go 文件
*/
/*
BlockChain
todo 16、新建区块链结构体
区块数组切片
*/
type BlockChain struct {
Blocks []*Block
}
const INFO = "知链区块链人才培养摇篮"
const BlockChainName = "blockChain.dat"
/*NewBlockChain
todo 17、创建区块链方法
返回值 BlockChain
*/
func NewBlockChain() *BlockChain {
/*todo 25、加载区块链文件
*/
var bc BlockChain
var isSaveFile = bc.LoadBlockChainFile()
if !isSaveFile { // 未保存文件
// 创建创世区块
firstBlock := NewBlock(INFO, 0, []byte{})
// 把创世区块放到区块列表中
bc = BlockChain{
Blocks: []*Block{
firstBlock,
},
}
}
// 把区块列表返回
return &bc
}
/*saveBlockChainFile
todo 20、存储区块链文件
返回 bool
*/
func (bc *BlockChain) saveBlockChainFile() bool {
var buffer bytes.Buffer
gob.Register(elliptic.P256())
encoder := gob.NewEncoder(&buffer)
err := encoder.Encode(bc.Blocks)
fmt.Printf("存储列表结构\n")
if err != nil {
fmt.Printf("钱包序列化失败")
return false
}
content := buffer.Bytes()
// 保存到本地文件
err = ioutil.WriteFile(BlockChainName, content, 0600)
if err != nil {
fmt.Printf("钱包创建失败")
return false
}
return true
}
/*LoadBlockChainFile
todo 23、读取区块链文件
*/
func (bc *BlockChain) LoadBlockChainFile() bool {
// 判断文件是否存在
if !IsFileExist(BlockChainName) {
fmt.Printf("钱包文件不存在,请创建\n")
return false
}
// 1、读取文件
contet, err := ioutil.ReadFile(BlockChainName)
if err != nil {
fmt.Printf("读取文件不成功\n")
return false
}
// 2、gob解密
gob.Register(elliptic.P256())
decoder := gob.NewDecoder(bytes.NewBuffer(contet))
// 3、读取文件内容-赋值给区块链列表中
var bclist []*Block
err = decoder.Decode(&bclist)
bc.Blocks = bclist
if err != nil {
fmt.Printf("转义不成功\n")
return false
}
return true
}
/*PrintBlockChainList
todo 24、打印区块链列表
*/
func (bc *BlockChain) PrintBlockChainList() {
for i, block := range bc.Blocks {
fmt.Printf("I: %d\n", i)
fmt.Printf("PrevBlockHash: %x\n", block.PrevBlockHash)
fmt.Printf("Hash: %x\n", block.Hash)
fmt.Printf("Data: %s\n", block.Data)
fmt.Printf("blockHeight: %d\n", block.blockHeight)
fmt.Println("====================")
}
}
/*addBlock
todo 28、添加区块
*/
func (bc *BlockChain) addBlock(data string) {
// 取出最后一个区块
lastBlock := bc.Blocks[len(bc.Blocks)-1]
// 最后的区块的hash ,作为当前区块的前置hash
prevHash := lastBlock.Hash
newBlock := NewBlock(data, len(bc.Blocks), prevHash)
bc.Blocks = append(bc.Blocks, newBlock)
// 保存到区块文件中
bc.saveBlockChainFile()
}
4.commands.go文件
package main
import "fmt"
/*
todo 8、新建commands 文件
*/
/*
todo 9、通过命令行新建区块链
*/
func (OsCli *OsCli) osCreatBlock() {
fmt.Println("通过命令行新建区块链")
/*todo 21、调用区块链方法,存储文件
*/
bc := NewBlockChain()
bc.saveBlockChainFile()
/*todo 22、运行打包
*/
}
/* todo 10、通过命令行添加区块
*/
func (OsCli *OsCli) osAddBlock(data string) {
fmt.Printf("通过命令行新建添加区块 %s", data)
/*todo 29、调用区块链方法,添加区块
*/
bc := NewBlockChain()
bc.addBlock(data)
bc.PrintBlockChainList()
/*todo 30、运行打包
*/
}
/* todo 11、通过命令行打印区块列表
*/
func (OsCli *OsCli) osPrintBlockList() {
fmt.Println("通过命令行打印区块列表")
/*todo 26、调用区块链方法,打印区块列表
*/
bc := NewBlockChain()
bc.PrintBlockChainList()
/*todo 27、运行打包
*/
}
5.osCli.go文件
package main
import (
"fmt"
"os"
)
/*
todo 1、新建 osCli.go 文件
*/
/*
OsCli
todo 2、声明os结构体
*/
type OsCli struct {
}
/*
todo 3、对于os结构体的封装
*/
func (OsCli *OsCli) Init() {
// s1 接受命令行参数
cads := os.Args
if len(cads) < 2 {
fmt.Printf("无效的命令")
os.Exit(1)
}
switch cads[1] {
// todo 1====区块相关======
case "CreatBlockChain":
fmt.Printf("创建区块链命令被调用\n")
OsCli.osCreatBlock()
case "addBlock":
if len(cads) != 3 {
fmt.Printf("无效的命令,请输入需要添加的内容")
os.Exit(1)
}
fmt.Printf("添加区块AddBlock命令被调用\n")
OsCli.osAddBlock(cads[2])
case "BlockChainList":
fmt.Printf("打印区块链列表BlockChainList被调用\n")
OsCli.osPrintBlockList()
default:
fmt.Printf("打印错误")
}
}
6.utils.go文件
package main
import (
"bytes"
"encoding/binary"
"log"
"os"
)
// 工具函数文件
func uintToByte(num uint64) []byte {
//TODO uint 转 byte
// 使用binary.Write 来进行编码
var buffer bytes.Buffer
err := binary.Write(&buffer, binary.BigEndian, num)
if err != nil {
log.Panic(err)
}
return buffer.Bytes()
}
func IsFileExist(fileName string) bool {
_, err := os.Stat(fileName)
if os.IsNotExist(err) {
return false
}
return true
}