区块链UTXO集源码分析

资源

go实现区块链

前提

在未实现UTXO集之前,假设系统需要查询某个钱包地址的余额,系统需要遍历区块链的所有区块,当区块链非常长时,这种做法的成本太高了。

UTXO集是未花费交易输出的集合,它存储区块链中所有未花费交易输出。在实现UTXO集后,系统只需要遍历UTXO集就可以得到某个钱包地址的余额(或者其他操作)。

它的结构体如下:

// UTXOSet represents UTXO set
type UTXOSet struct {Blockchain *Blockchain
}

可以看到,UTXOSet的结构体中有一个区块链的指针,实际上我们需要通过这个区块链的指针来获得数据库连接(因为UTXO集合的内容是存储在数据库中的)。

源码分析

Reindex

下面是UTXOSet的Reindex方法,该方法将为区块链中所有的未花费交易输出建立Key-Value的索引。(其中,Key是交易的ID,Value是该交易ID下未花费交易输出的集合)

func (u UTXOSet) Reindex() {db := u.Blockchain.dbbucketName := []byte(utxoBucket)err := db.Update(func(tx *bolt.Tx) error {err := tx.DeleteBucket(bucketName)_, err = tx.CreateBucket(bucketName)})UTXO := u.Blockchain.FindUTXO()err = db.Update(func(tx *bolt.Tx) error {b := tx.Bucket(bucketName)for txID, outs := range UTXO {key, err := hex.DecodeString(txID)err = b.Put(key, outs.Serialize())}})
}

FindSpendableOutputs

FindSpendableOutputs这个方法是在发币的时候调用的,代码的逻辑比较清晰直接看源码即可。

func (u UTXOSet) FindSpendableOutputs(pubkeyHash []byte, amount int) (int, map[string][]int) {unspentOutputs := make(map[string][]int)accumulated := 0db := u.Blockchain.dberr := db.View(func(tx *bolt.Tx) error {b := tx.Bucket([]byte(utxoBucket))c := b.Cursor()for k, v := c.First(); k != nil; k, v = c.Next() {txID := hex.EncodeToString(k)outs := DeserializeOutputs(v)for outIdx, out := range outs.Outputs {if out.IsLockedWithKey(pubkeyHash) && accumulated < amount {accumulated += out.ValueunspentOutputs[txID] = append(unspentOutputs[txID], outIdx)}}}})return accumulated, unspentOutputs
}

FindUTXO

FindUTXO方法用来查询指定钱包地址的余额,它是通过遍历UTXO集的方式来完成余额查询的,代码的逻辑比较清晰直接看源码即可。

func (u UTXOSet) FindUTXO(pubKeyHash []byte) []TXOutput {var UTXOs []TXOutputdb := u.Blockchain.dberr := db.View(func(tx *bolt.Tx) error {b := tx.Bucket([]byte(utxoBucket))c := b.Cursor()for k, v := c.First(); k != nil; k, v = c.Next() {outs := DeserializeOutputs(v)for _, out := range outs.Outputs {if out.IsLockedWithKey(pubKeyHash) {UTXOs = append(UTXOs, out)}}}return nil})return UTXOs
}

Update

Update方法是用来更新UTXO集的,这个方法在新区块上链后被调用,以保证区块链和UTXO的数据同步更新。

func (cli *CLI) send(from, to string, amount int) {...newBlock := bc.MineBlock(txs)UTXOSet.Update(newBlock)
}

Update方法的执行步骤可分为两步:

  • 将被交易输入中引用的未花费交易输出从UTXO集中删除
  • 将新产生的交易输出更新到UTXO集中
func (u UTXOSet) Update(block *Block) {db := u.Blockchain.dberr := db.Update(func(tx *bolt.Tx) error {b := tx.Bucket([]byte(utxoBucket))for _, tx := range block.Transactions {if tx.IsCoinbase() == false {for _, vin := range tx.Vin {updatedOuts := TXOutputs{}outsBytes := b.Get(vin.Txid)outs := DeserializeOutputs(outsBytes)for outIdx, out := range outs.Outputs {if outIdx != vin.Vout {updatedOuts.Outputs = append(updatedOuts.Outputs, out)}}if len(updatedOuts.Outputs) == 0 {err := b.Delete(vin.Txid)} else {err := b.Put(vin.Txid, updatedOuts.Serialize())}}}newOutputs := TXOutputs{}for _, out := range tx.Vout {newOutputs.Outputs = append(newOutputs.Outputs, out)}err := b.Put(tx.ID, newOutputs.Serialize())}})
}

Golang|区块链UTXO集源码分析相关推荐

  1. php构建一个区块链(含源码)

    php构建一个区块链(含源码) 我们要用PHP编程语言构建区块链,区块链本身就是一个非常简单的概念,它是一个非常简单的数据结构,数字货币是很复杂,但区块链不是,它们复杂的原因是共识算法,挖矿机制和运行 ...

  2. Golang日志框架lumberjack包源码分析

    github地址:  https://github.com/natefinch/lumberjack 获取源码 go get gopkg.in/natefinch/lumberjack.v2 介绍 l ...

  3. golang学习之negroni/gizp源码分析

    在 Go 语言里,Negroni 是一个很地道的 Web 中间件,它是一个具备微型.非嵌入式.鼓励使用原生 net/http 库特征的中间件.利用它地Use功能,我们可以很简单地自定义中间件并使用.其 ...

  4. element ui表单校验prop的链式写法----源码分析

    <el-form :model="dynamicValidateForm" ref="dynamicValidateForm" label-width=& ...

  5. python timestamp转string_Python仿真区块链【含源码】

    在区块链或数字货币领域,Python并不是主流的开发语言.但是如果 你的目的是研究区块链技术的原理,或者需要在自己的笔记本上仿真一个 区块链网络并进行一些研究性的实验,比如完成自己的毕业设计项目 或科 ...

  6. golang RWMutex读写互斥锁源码分析

    针对Golang 1.9的sync.RWMutex进行分析,与Golang 1.10基本一样除了将panic改为了throw之外其他的都一样. RWMutex是读写互斥锁.锁可以由任意数量的读取器或单 ...

  7. 带你挖矿之旅!Python从零开始创建区块链!提供源码哦!月薪十万

    环境准备 确保已经安装Python3.6+, pip , Flask, requests,安装方法: pip install Flask==0.12.2 requests==2.18.4 同时还需要一 ...

  8. go-ethereum-code-analysis 以太坊源码分析

    分析go-ethereum的过程,我希望从依赖比较少的底层技术组件开始,慢慢深入到核心逻辑. 目录 go-ethereum代码阅读环境搭建 以太坊黄皮书 符号索引 rlp源码解析 trie源码分析 e ...

  9. Spring事务源码分析责任链事务链事务不生效

    文章目录 前言 带着问题分析源码 事务源码分析 寻找Spring事务源码类 TransactionInterceptor调用栈 分析Spring AOP责任链 分析TransactionInterce ...

最新文章

  1. C++知识点8——函数的返回值
  2. Windows批处理
  3. php mysql 云虚拟机_虚拟机+apache+php+mysql 环境安装配置
  4. bootstrap 模态框无法使用_模态窗 Modal Window - 产品中的??注意力设计
  5. 调整谷歌reCAPTCHA大小 How to resize the Google noCAPTCHA reCAPTCHA
  6. HashSet、LinkedHashSet、TreeSet 简明解释
  7. 国内各地图API坐标系统比较与转换
  8. 【Hadoop】MapReduce的配置 ---配置历史服务器
  9. 如何使用代理服务器上网,从基础到高手--转
  10. ParaView的简单用法
  11. Hbase 二级索引
  12. wps 安装字体手册
  13. csv格式导出,身份证号码显示不全
  14. Service Test1
  15. 构建数据思维从认知事物的基本方法开始!
  16. ec20 复位命令_Quectel EC20 R2.1 AT指令集(基础部分)未完
  17. 学习记录-Simpack生成车轮不圆的几种示例
  18. Office多版本共存,设置打开的版本
  19. 谨防上当:3月1日微信支付宝个人收款码是可以继续使用的-附图
  20. java ssm企业车辆汽车信息管理系统

热门文章

  1. lableimg闪退_打标工具labelme或者labelimg遇到图片闪退的完美解决方案
  2. 最大公约数gcd函数简介
  3. 计算机毕设Python+Vue业俊宾馆客房管理系统(程序+LW+部署)
  4. 什么是范式?第一范式、第二范式、第三范式的区别?
  5. 求会嵌入式软件的伙伴
  6. C++11 左值 右值
  7. JAVA:初级项目之 基于Swing界面的仿QQ(二)
  8. 空心少年的伤感QQ日志:放弃你,不代表放弃爱你
  9. Springboot连接Access2003数据库
  10. 城市选择控件文本框【纯javascript打造】兼容IE6以及以上、谷歌、Firefox