当前位置:   article > 正文

Golang|区块链Transaction实现源码分析_golang 区块链获取transtion里面的from

golang 区块链获取transtion里面的from

区块链Transaction实现源码分析

资源

go实现区块链

程序运行结果

在这里插入图片描述

源码分析

当程序解析到命令行参数时,将调用结构体CLI的createBlockchain方法。这个方法的作用是在本地数据库中创建一个含有创世区块的区块链。(如果在本地数据库中已经含有区块链,则不执行创建)

在这里插入图片描述

进入到该方法的源码部分。

// CreateBlockchain creates a new blockchain DB
func CreateBlockchain(address string) *Blockchain {
	if dbExists() {
		fmt.Println("Blockchain already exists.")
		os.Exit(1)
	}

	var tip []byte
	db, err := bolt.Open(dbFile, 0600, nil) // 打开数据库
	// 打开一个数据库读写事务
	err = db.Update(func(tx *bolt.Tx) error {
		// 尝试获取存储区块的bucket
		b := tx.Bucket([]byte(blocksBucket))
			// 产生一个挖出创世区块的奖励事务
			cbtx := NewCoinbaseTX(address,genesisCoinbaseData)
			// 构造新区块来存储记录该事务
			genesis := NewGenesisBlock(cbtx)
			// 在数据库中创建一个bucket
			b, err := tx.CreateBucket([]byte(blocksBucket))
			// 将传世区块存储到bucket中
			err = b.Put(genesis.Hash, genesis.Serialize())
			// 更新bucket中存储的区块链最后一个区块的哈希值
			err = b.Put([]byte{1}, genesis.Hash)
			tip = genesis.Hash
			return err
		return nil
	})
	if err != nil {
		log.Panic(err.Error())
	}
	bc := Blockchain{tip, db}
	return &bc
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

观察上面的源码,其中比较关键的有两个方法。

一个方法是NewCoinbaseTX,另一个方法是NewGenesisBlock。在这段代码中,程序将产生一个挖出创世区块的Transaction,然后将Transaction存储在创世区块上面,最后将创世区块添加到区块链中(存到本地数据库)。

先进入NewCoinbaseTX方法,观察它做了什么操作。

func NewCoinbaseTX(to,data string)*Transaction {
	if data == "" {
		data = fmt.Sprintf("Reward to %s", to)
	}
	// 任意交易输入
	txin := TXInput{[]byte{}, -1, data}
	// 交易输出:奖励旷工虚拟货币
	txout := TXOutput{subsidy, to}
	// 构造交易
	tx := Transaction{nil, []TXInput{txin}, []TXOutput{txout}}
	tx.SetID() // 设置交易ID
	return &tx
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在NewCoinbaseTX中,它构造了一组输入交易、一组输出交易并且设置了Transaction的ID,完成Transaction的构造后,该方法将Transaction指针返回。

以下是SetID的源码。

func (tx *Transaction)SetID(){
	var result bytes.Buffer
	encoder := gob.NewEncoder(&result)
	encoder.Encode(tx)
	// 对tx的序列化结果进行sha256运算
	hash := sha256.Sum256(result.Bytes())
	// 将运算的32位结果作为tx的ID
	tx.ID = hash[:]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

可以看到,该方法将Transaction进行了序列化,然后将序列化的结果进行了哈希运算,并且将哈希运算的值作为了Transaction的ID。这样做的目的是,我们可以通过Transaction的ID值来校验Transaction的内容(一组输入交易以及一组输出交易)是否发生了篡改。

NewCoinbaseTX方法执行完毕后,将进入到NewGenesisBlock方法中。

// 产生一个挖出创世区块的奖励事务
	cbtx := NewCoinbaseTX(address,genesisCoinbaseData)
// 构造新区块来存储记录该事务
	genesis := NewGenesisBlock(cbtx)
  • 1
  • 2
  • 3
  • 4

现在进入到NewGenesisBlock中,观察它做了什么操作。

func NewGenesisBlock(coinbase *Transaction) *Block {
	return NewBlock([]*Transaction{coinbase}, []byte{})
}

func NewBlock(transactions []*Transaction, prevBlockHash []byte) *Block {
	block := Block{}
	block.Transactions = transactions
	block.Timestamp = time.Now().Unix()
	block.PrevBlockHash = prevBlockHash
	// 工作量证明
	pow := NewProofOfWork(&block)
	nonce, hash := pow.Run()
	block.Hash = hash[:]
	block.Nonce = nonce
	return &block
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

可以看到,在NewGenesisBlock方法中,调用NewBlock构造了一个Block,在NewBlock中,比较重要的是工作量证明部分。现在进入到pow.Run()方法中,观察这个方法做了什么操作。

func (pow *ProofOfWork) prepareData(nonce int) []byte {
	data := bytes.Join(
		[][]byte{
			pow.block.PrevBlockHash,
			pow.block.HashTransactions(),
			IntToHex(pow.block.Timestamp),
			IntToHex(int64(targetBits)),
			IntToHex(int64(nonce)),
		},
		[]byte{},
	)

	return data
}

// Run performs a proof-of-work
func (pow *ProofOfWork) Run() (int, []byte) {
	var hashInt big.Int
	var hash [32]byte
	nonce := 0

	for nonce < maxNonce {
		data := pow.prepareData(nonce)

		hash = sha256.Sum256(data)
		fmt.Printf("\r%x", hash)
		hashInt.SetBytes(hash[:])

		if hashInt.Cmp(pow.target) == -1 {
			break
		} else {
			nonce++
		}
	}
	fmt.Print("\n\n")

	return nonce, hash[:]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

工作量证明部分,程序通过枚举nonce来寻找符合系统难度的一串哈希值。当工作量证明完成后(得到nonce与当前区块的hash值),也就相当于挖出了一个新的区块了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/900053
推荐阅读
相关标签
  

闽ICP备14008679号