9 UTXO优化

9.1 查找未花费输出

之前我们要查询 某个地址的余额需要遍历整个数据库,随着数据量的增大,这个工作量会很大,我们现在来尝试优化

/Users/xxx/go/src/publicChain/part63-UTXOSet/BLC/UTXO_Set.go

const utxoTableName = "utxoTableName"type UTXOSet struct {Blockchain *Blockchain
}func (utxoSet *UTXOSet) ResetUTXOSet() {err := utxoSet.Blockchain.DB.Update(func(tx *bolt.Tx) error {b := tx.Bucket([]byte(utxoTableName))if b != nil {tx.DeleteBucket([]byte(utxoTableName))b, _ := tx.CreateBucket([]byte(utxoTableName))if b != nil {}}return nil})if err != nil {log.Panic(err)}
}

/Users/xxx/go/src/publicChain/part62-UTXOSet/BLC/Transaction_TXOutputs.go

type TXOutputs struct {TxOutputs []*TXOutput
}

/Users/xxx/go/src/publicChain/part62-UTXOSet/BLC/Blockchain.go

func (blockchain *Blockchain) FindUTXOMap() map[string]*TXOutputs {//define an Iterator variable to attain blockblockchainIterator := blockchain.Iterator()//store all UTXOs have been spentspentableUTXOsMap := make(map[string][]*TXInput)utxoMaps := make(map[string]*TXOutputs)for {//attain blocksblock := blockchainIterator.Next()//range all index of Txs slicefor i := len(block.Txs) - 1; i >= 0; i-- {//attain Txstx := block.Txs[i]//judging if tx is in coinbase and put all txInput into sliceif tx.IsCoinbaseTransaction() == false {for _, txInput := range tx.Vins {//convert []byte to stringtxHash := hex.EncodeToString(txInput.TxHash)spentableUTXOsMap[txHash] = append(spentableUTXOsMap[txHash], txInput)}}//define an instance of &TXOutputstxOutputs := &TXOutputs{[]*TXOutput{}}//convert []byte to stringtxHash := hex.EncodeToString(tx.TxHash)workOutLoop://range if a value has been spentfor index, out := range tx.Vouts {//convert []byte to stringtxHash := hex.EncodeToString(tx.TxHash)//attain []*TXInputtxInputs := spentableUTXOsMap[txHash]//judging and put out into sliceif len(txInputs) > 0 {isSpent := falsefor _, in := range txInputs {outPublicKey := out.Ripemd160HashinPublicKey := in.PublicKeyif bytes.Compare(outPublicKey, Ripemd160Hash(inPublicKey)) == 0 {if index == in.Vouts {isSpent = truecontinue workOutLoop}}}if isSpent == false {txOutputs.TxOutputs = append(txOutputs.TxOutputs, out)}} else {txOutputs.TxOutputs = append(txOutputs.TxOutputs, out)}}//set key-value pairsutxoMaps[txHash] = txOutputs}var hashInt big.InthashInt.SetBytes(block.PreBlockHash)if hashInt.Cmp(big.NewInt(0)) == 0 {break}}return utxoMaps
}

相应的命令行工具也改一下,编译并运行,结果能够正常输出

./bc test
map[8e578e4d1d1ef2f5101bdd72e5bd922cb8d85956333977e03c4260975db0223c:0xc00000ca50]
./bc send -from '["1Eubsorq2zfZ1vmuA8NRcNxPwptSG6c8BJ"]' -to '["1B5y2naPTzkXLztVk2ffLPd3wbpoQg6723"]' -amount '["2"]'
./bc getBalance -address "1Eubsorq2zfZ1vmuA8NRcNxPwptSG6c8BJ"
1Eubsorq2zfZ1vmuA8NRcNxPwptSG6c8BJ has 18 token
./bc send -from '["1Eubsorq2zfZ1vmuA8NRcNxPwptSG6c8BJ","1B5y2naPTzkXLztVk2ffLPd3wbpoQg6723"]' -to '["1B5y2naPTzkXLztVk2ffLPd3wbpoQg6723","1Eubsorq2zfZ1vmuA8NRcNxPwptSG6c8BJ"]' -amount '["3","4"]'

尝试进行多笔转账会出错,我们下一节会详细讲解

9.2 多笔交易中的数字签名

我们完善一下相关函数

func NewSimpleTransaction(from, to string, amount int, blockchain *Blockchain, txs []*Transaction) *Transaction {--//signatureblockchain.SignTransaction(tx, wallet.PrivateKey, txs)return tx
}
func (blockchain *Blockchain) SignTransaction(tx *Transaction, privateKey ecdsa.PrivateKey, txs []*Transaction) {--for _, vin := range tx.Vins {prevTX, err := blockchain.FindTransaction(vin.TxHash, txs)--
}
func (blockchain *Blockchain) FindTransaction(ID []byte, txs []*Transaction) (Transaction, error) {for _, tx := range txs {if bytes.Compare(tx.TxHash, ID) == 0 {return *tx, nil}}bci := blockchain.Iterator()for {block := bci.Next()for _, tx := range block.Txs {if bytes.Compare(tx.TxHash, ID) == 0 {return *tx, nil}}var hashInt big.InthashInt.SetBytes(block.PreBlockHash)if big.NewInt(0).Cmp(&hashInt) == 0 {break}}return Transaction{}, nil
}

最后重新编译运行

./bc send -from '["1Eubsorq2zfZ1vmuA8NRcNxPwptSG6c8BJ"]' -to '["1B5y2naPTzkXLztVk2ffLPd3wbpoQg6723"]' -amount '["2"]'
./bc getBalance -address "1Eubsorq2zfZ1vmuA8NRcNxPwptSG6c8BJ"
1Eubsorq2zfZ1vmuA8NRcNxPwptSG6c8BJ has 29 token
./bc getBalance -address "1B5y2naPTzkXLztVk2ffLPd3wbpoQg6723"
1B5y2naPTzkXLztVk2ffLPd3wbpoQg6723 has 1 token

9.3 遍历并存储UXTO

/Users/xxx/go/src/publicChain/part63-UTXOSet/BLC/Transaction_TXOutputs.go

//SerializeBlockfunc (txOutput *TXOutputs) Serialize() []byte {var result bytes.Bufferencoder := gob.NewEncoder(&result)err := encoder.Encode(txOutput)if err != nil {log.Panic(err)}return result.Bytes()
}//DeserializeBlockfunc DeserializeTXOutputs(txOutputsBytes []byte) *TXOutputs {var txOutputs TXOutputsdecoder := gob.NewDecoder(bytes.NewReader(txOutputsBytes))err := decoder.Decode(&txOutputs)if err != nil {log.Panic()}return &txOutputs
}

/Users/xxx/go/src/publicChain/part63-UTXOSet/BLC/UTXO_Set.go

const utxoTableName = "utxoTableName"type UTXOSet struct {Blockchain *Blockchain
}func (utxoSet *UTXOSet) ResetUTXOSet() {err := utxoSet.Blockchain.DB.Update(func(tx *bolt.Tx) error {b := tx.Bucket([]byte(utxoTableName))if b != nil {err := tx.DeleteBucket([]byte(utxoTableName))if err != nil {log.Panic(err)}}b, _ = tx.CreateBucket([]byte(utxoTableName))if b != nil {txOutputMap := utxoSet.Blockchain.FindUTXOMap()for keyHash, outs := range txOutputMap {txHash, _ := hex.DecodeString(keyHash)b.Put(txHash, outs.Serialize())}}return nil})if err != nil {log.Panic(err)}
}

在终端中运行,程序能够正常运行

9.3 FindUTXOMap方法优化

我们直接通过utxoSet来获取余额

func (cli CLI) getBalance(address string) {fmt.Println("Address:" + address)blockchain := BlockChainObject()defer blockchain.DB.Close()utxoSet := &UTXOSet{blockchain}amount := utxoSet.GetBalance(address)fmt.Printf("%s has %d token\n", address, amount)
}

我们再来完善一下需要调用的方法

func (utxoSet *UTXOSet) FindUTXOForAddress(address string) []*UTXO {}
func (utxoSet *UTXOSet) GetBalance(address string) int64 {//
}

我们再改为下列结构体,其他文件相应的也变更

type TXOutputs struct {UTXOS []*UTXO
}

/Users/xxx/go/src/publicChain/part63-UTXOSet/BLC/UTXO_Set.go

func (utxoSet *UTXOSet) GetBalance(address string) int64 {UTXOS := utxoSet.FindUTXOForAddress(address)var amount int64for _, utxo := range UTXOS {amount += utxo.Output.Value}return amount
}
func (utxoSet *UTXOSet) FindUTXOForAddress(address string) []*UTXO {var utxos []*UTXOutxoSet.Blockchain.DB.View(func(tx *bolt.Tx) error {//assume bucket exists and has keysb := tx.Bucket([]byte(utxoTableName))c := b.Cursor()for k,v := c.First();k != nil; k,v = c.Next() {fmt.Printf("key=%s, value=%s\n",k,v)txOutputs := DeserializeTXOutputs(v)for _,utxo := range txOutputs.UTXOS {if utxo.Output.UnlockScriptPublicKeyWithAddress(address) {utxos = append(utxos,utxo)}}}return nil})return utxos
}

在终端中的重新创建区块并查询余额,结果能够正常输出,现在我们每次查询余额就不需要遍历数据库了

./bc creatBlockChain -address "1JfaJ6AtBCSop8npzv1UBhayhM9AxNnu9N"
./bc getBalance -address "1JfaJ6AtBCSop8npzv1UBhayhM9AxNnu9N"
1JfaJ6AtBCSop8npzv1UBhayhM9AxNnu9N has 10 token

9.4 修改CoinbaseTransaction交易哈希导致的bug

我们修改一下如下代码,调用ResetUTOXSet方法重置UTOX

func (cli *CLI) testMethod() {//attain blockchainblockchain := BlockChainObject()defer blockchain.DB.Close()//attain utxoSetutxoSet := &UTXOSet{blockchain}//call method utxoSet.ResetUTXOSet()
}

​ 接着我们在终端中编译并运行

./bc send -from '["1Dh46KP31Gfkd55wqdmnpqy2TQh1cvwpzY"]' -to '["17pGGPVzFrzvLLoHWJoJ926Eemwm1DJKRN"]' -amount '["2"]'

我们发现在终端转账不能正常运行,我们修改一下部分代码

func (tx *Transaction) HashTransaction() {var result bytes.Bufferencoder := gob.NewEncoder(&result)err := encoder.Encode(tx)if err != nil {log.Panic(err)}resultBytes := bytes.Join([][]byte{IntToHex(time.Now().Unix()), result.Bytes()}, []byte{})hash := sha256.Sum256(resultBytes)tx.TxHash = hash[:]
}

改好之后在次编译重置即可查询余额

./bc getBalance -address "17pGGPVzFrzvLLoHWJoJ926Eemwm1DJKRN"
17pGGPVzFrzvLLoHWJoJ926Eemwm1DJKRN has 2 token
./bc getBalance -address "1Dh46KP31Gfkd55wqdmnpqy2TQh1cvwpzY"
1Dh46KP31Gfkd55wqdmnpqy2TQh1cvwpzY has 18 token
./bc send -from '["1Dh46KP31Gfkd55wqdmnpqy2TQh1cvwpzY","17pGGPVzFrzvLLoHWJoJ926Eemwm1DJKRN"]' -to '["17pGGPVzFrzvLLoHWJoJ926Eemwm1DJKRN","1Dh46KP31Gfkd55wqdmnpqy2TQh1cvwpzY"]' -amount '["3","4"]'
17pGGPVzFrzvLLoHWJoJ926Eemwm1DJKRN has 1 token
1Dh46KP31Gfkd55wqdmnpqy2TQh1cvwpzY has 29 token

一次性转多笔也是能够实现的

区块链项目 - 9 UTXO优化相关推荐

  1. 区块链项目ICO评估模型

    一哲奶奶: ICO项目很多,骗子很多,傻逼也多. 币圈新,阿猫阿狗利用信息势能差暴力敛财. 币圈牛鬼蛇神良莠不齐,有技术极客,也有睿智的投资新贵,也有龌龊的小混混. 传统行业个别潦倒的阿猫阿狗只要进场 ...

  2. 密码极客经济学博士揭秘,2020年哪个区块链项目最值期待?

    2020年哪个区块链项目最值期待? 文章来源:密码极客 2019年12月13日,密码极客投资总监江鹏联合密码极客经济学顾问秋叶,一起分享从业以来的投资心路历程.以下是本次分享会节选. 分享嘉宾:秋叶 ...

  3. 一览印度区块链项目Matic Network的应用场景

    近日,Coinbase发布了一则公告,称其正在评估上线Matic,并也公开宣布将增加其对Matic的技术和商务发展的资源分配.随着公告的发出,这个印度区块链项目逐步走进了大家的视野.能够得到Coinb ...

  4. 1月共有49个区块链项目进行ICO,卖牛肉的都来玩区块链了!

    2018年1月份已经过去,愈演愈烈的区块链也诞生了很多新项目.HiBlock编辑整理了国外网站上关于区块链项目ICO的49个项目,虽然金融相关项目还是占大多数,但区块链也已经开始应用在直播.视频流媒体 ...

  5. 【AI TOP 10】马化腾:AI技术沦为网络黑产新工具;网易区块链项目被传夭折; 人工智能可以让狗跟人说话

    原文链接:点击打开链接 摘要: 产业观察 马化腾:AI技术沦为网络黑产新工具 SpaceX的龙飞船完成补给任务成功返回地球 松下或与特斯拉在中国建超级电池工厂 英特尔:修复芯片漏洞的补丁也有漏洞 Fa ...

  6. 【AI TOP 10】马化腾:AI技术沦为网络黑产新工具;网易区块链项目被传夭折; 人工智能可以让狗跟人说话...

    产业观察 马化腾:AI技术沦为网络黑产新工具 SpaceX的龙飞船完成补给任务成功返回地球 松下或与特斯拉在中国建超级电池工厂 英特尔:修复芯片漏洞的补丁也有漏洞 Facebook:调整信息流市值一夜 ...

  7. 寒冬来临,它却屡屡拿奖,成为国家认可的区块链项目

    10月9日(上周二),一条重磅新闻在链圈和币圈发酵,在工信部直属中国信息通信研究院.中国通信标准化协会联合主办的"可信区块链峰会"上,主办方郑重宣布:DDN区块链平台通过可信区块链 ...

  8. 区块链惊现山寨万融链 怎样判断一个区块链项目的真假

    区块链惊现山寨万融链 怎样判断一个区块链项目的真假 "区块链实质上是一种集体式记录方式.特别之处在于它别出心裁地采用一组技术,实现了记录结果的真实可信,难以毁坏也无法篡改."张孝荣 ...

  9. 密码极客波卡生态系列分享会第一期:如何基于波卡开发区块链项目

    2020年10月20日,密码极客发起了第一期[波卡生态系列分享会].我们非常荣幸邀请到了Parity亚洲区技术总监贾瑶琪博士做客密码极客大咖直播间,为大家讲解<如何基于波卡开发区块链项目> ...

最新文章

  1. 企业架构的过去、现在与未来
  2. LimeSDR性能参数介绍及如何用它实现通信过程
  3. counter()函数和most_common()函数
  4. php接收post过来的json数据
  5. 【.NET Core 跨平台 GUI 开发】第一篇:编写你的第一个 Gtk# 应用
  6. 数学的意蕴与价值(建议收藏)
  7. 【转】.NET平台开发Mongo基础知识
  8. 要素集获取要素_Excel点文件转面要素
  9. 微信退款参数格式错误
  10. leetcode933.NumberofRecentCalls
  11. Linux之telnet命令
  12. Spring Boot 消息
  13. AjaxPro实现方法
  14. leetcode 28 实现strStr()
  15. EUV光刻!宇宙最强DDR4内存造出
  16. php yml,YAML、YML在线编辑器(格式化校验)
  17. 副产品举例_CMA知识点:联产品和副产品成本计算法
  18. 坚守13年的极飞,终靠“务农”拿下12亿融资!专访彭斌:要为行业找技术,而不是为技术找行业...
  19. 计算机硬盘的文件怎么删除文件,电脑硬盘删除文件怎么恢复
  20. iP138版 iP地址 离线iP数据库 ip.dat详解

热门文章

  1. 计算机英语ppt演讲稿,英语ppt演讲稿(精选多篇).doc
  2. Android Volley完全解析(一),初识Volley的基本用法
  3. react 全选反选_react解决checkbox全选checked的问题
  4. visualSVN Server的下载和安装
  5. 如何在Mac上清理磁盘空间?这些方法你必须要懂
  6. java springBoot 对接阿里云短信
  7. 高通骁龙骁龙780G和麒麟990有多大差别 骁龙骁龙780G和麒麟990选哪个好
  8. 各种软件的常用快捷键(for mac 持续更新)
  9. 7-8 哈利·波特的考试 (25 分)
  10. 当web前端架构方案遇上《金瓶梅》?!