GO语言实现区块链-coinbase交易2

238 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情

coinbase交易2

上文链接

如何使用CoinBase交易

3、修改创世块创建函数。

NewGenesiBlock的修改主要是参数以及NewBlock的调整

// 创世块创建,返回创世块Block指针
func NewGenesisBlock(coinbase *Transaction) *Block {
	return NewBlock([]*Transaction{coinbase}, []byte{})
}

4、修改NewBlockchain函数。

NewBlockchain函数的作用是创建区块链和初始化创世区块。我们先将它的名字修改为CreatBlockchain。对其的改造主要有两点。其一:出于安全性考虑,创世块一旦存在就不能在被创建。 其二:在创世块中,需要把CoinBase交易加入到里面。

当我们更新数据库时,需要加入CoinBase交易

/ 判断区块链是否已经存在
func dbExists() bool {
	if _, err := os.Stat(dbFile); os.IsNotExist(err) {
		return false
	}
	return true
}

// 创建区块链结构,初始化只有创世块
func CreateBlockchain() *Blockchain {
	// 只能第一次创建
	if dbExists() {
		fmt.Println("Blockchain already exists.")
		os.Exit(1)
	}
	var tip []byte
	// 没有则创建文件
	db, _ := bolt.Open(dbFile, 0600, nil)
        	//更新数据库
	db.Update(func(tx *bolt.Tx) error {
		//获取bucket
		buck := tx.Bucket([]byte(blocksBucket))
		if buck == nil {
			// 第一次使用,创建创世块
			fmt.Println("No existing blockchain found. Creating a new one...")
			cbtx := NewCoinbaseTX(miner, genesisCoinbaseData)
			genesis := NewGenesisBlock(cbtx)
			//区块数据编码
			block_data := genesis.Serialize()
			// 创建新bucket,存入区块信息
			bucket, _ := tx.CreateBucket([]byte(blocksBucket))
			bucket.Put(genesis.Hash, block_data)
			bucket.Put([]byte("last"), genesis.Hash)
			tip = genesis.Hash

		} else {
			// 不是第一次使用,之前有块
			tip = buck.Get([]byte("last"))
		}
		return nil
	})
	//3. 记录Blockchain 信息
	return &Blockchain{tip, db}
}

NewCoinBaseTX在使用时需要传入一个接口地址和Data,可以提前定义两个常量,其中genesisCoinbaseData就是中本聪在比特币创世块中写入的内容。

//定义矿工地址
const miner = "小明"

//创世块留言
const genesisCoinbaseData = "2022.6.25,小明再此一挖两个币"

5、修改main函数

func main() {
	//创世块初始化区块链
	bc := CreateBlockchain()
	//创建2个块记录2笔交易
	// bc.AddBlock("Send 1 BTC to Yekai")
	// bc.AddBlock("Send 2 more BTC to Fuhongxue")

	bci := bc.Iterator()
	for {
		block, next := bci.PreBlock()
		fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash)
		fmt.Printf("Data: %s\n", block.Transactions[0].Vin[0].FromAddr)
		fmt.Printf("Hash: %x\n", block.Hash)
		fmt.Printf("Nonce: %d\n", block.Nonce)
		pow := NewProofOfWork(block)
		fmt.Printf("Pow: %t\n", pow.Validate())
		fmt.Println()
		if !next {
			//next为假 代表已经到创世块了
			break
		}
	}
        }

经此一遭,矿工已经奋发图强的挖矿了·····