摘要:原文鏈接如何設(shè)計一個比特幣錢包服務(wù)概述總所周知,比特幣全節(jié)點的實現(xiàn)目前有兩個版本,一個是中本聰寫的原版,一個是語言寫的。查詢最新區(qū)塊高度,錢包轉(zhuǎn)賬后通過區(qū)塊高度來計算交易是否已經(jīng)確認,比特幣是個區(qū)塊確認。
原文鏈接 https://github.com/liyue201/b...
如何設(shè)計一個比特幣錢包服務(wù) 概述總所周知,比特幣全節(jié)點的實現(xiàn)目前有兩個版本,一個是中本聰c++寫的原版bitcoin core,一個是go語言寫的btcd。這兩個版本從功能上并沒有多大差異,都實現(xiàn)了比特幣協(xié)議。從理論上講,比特幣網(wǎng)絡(luò)中的每個全節(jié)點只要遵循相同的比特幣協(xié)議,至于用什么語言實現(xiàn),用什么方式存儲都是無所謂的。bitcoin core和btcd都沒有實現(xiàn)通用的錢包服務(wù),這里說的錢包服務(wù)指的是一個可以給錢包app提供所數(shù)據(jù)的服務(wù),私鑰保存在錢包app中,用戶交易在錢包app中簽名,再將簽名數(shù)據(jù)發(fā)給錢包服務(wù),再由錢包服務(wù)轉(zhuǎn)發(fā)到全節(jié)點上鏈,如圖:
所幸的是全節(jié)點提供了一些JSON RPC接口,通過這些接口可以讀取區(qū)塊數(shù)據(jù)和發(fā)起轉(zhuǎn)賬交易。但是能讀到的數(shù)據(jù)還是太原始了,就連獲取某個地址的余額都做不到。因為比特幣使用的是UTXO賬號體系,并沒有一個統(tǒng)一的地方存儲地址余額,只有UTXO。而UTXO是分散在每個區(qū)塊中的,要想知道某個地址的UTXO,需要從第一個區(qū)塊開始遍歷。有些人說這樣設(shè)計可以更好的并發(fā)執(zhí)行,這個鄙人真的不敢茍同。說可以更好的溯源倒是真的,因為每一筆交易都可以追溯到上一筆交易。
錢包服務(wù)功能好了,廢話不多說,我們看一下一個錢包服務(wù)應(yīng)該具備什么樣的功能。
(1)查詢?nèi)我庖粋€地址的余額,錢包需要知道自己地址的余額。
(2)查詢?nèi)我庖粋€地址的UTXO,錢包轉(zhuǎn)賬時需要UTXO來簽名打包。
(3)發(fā)起轉(zhuǎn)賬交易。錢包需要調(diào)服務(wù)發(fā)起轉(zhuǎn)賬交易。
(4)查詢?nèi)我庖粋€地址的歷史交易記錄。
(5)查詢最新區(qū)塊高度,錢包轉(zhuǎn)賬后通過區(qū)塊高度來計算交易是否已經(jīng)確認,比特幣是6個區(qū)塊確認。
第(1)(2)點實際上是一個問題,知道UTXO自然就知道余額了。第(3)(5)可以直接調(diào)全節(jié)點接口。所以錢包服務(wù)的難點只剩下(2)(4)這兩個功能。錢包服務(wù)要做的就是從全節(jié)點從第一個區(qū)塊開始遍歷讀取所有的交易記錄,并推導(dǎo)出每個地址當前區(qū)塊高度的UTXO,再將這個信息保存到數(shù)據(jù)庫中方便錢包使用。
全節(jié)點選擇bitcoin core 雖然是原版的比特幣全節(jié)點,但是他只提供了http接口,沒有websocket接口,不能實時推送未上鏈的交易。一個體驗好的錢包不僅要獲取已經(jīng)上鏈的交易記錄,也要知道未上鏈的交易。btcd不僅提供了http接口,還有websocket,所以btcd應(yīng)該是更好的選擇。
數(shù)據(jù)庫選型到目前為止(2018-12-26)比特幣的交易量是3.6億,因為一筆交易涉及到多個輸入和多個輸出地址(如果你研究過區(qū)塊鏈瀏覽器上的數(shù)據(jù),會發(fā)現(xiàn)一筆交易幾千個輸入和幾千個輸出都是很正常的,這樣可以省礦工費,可能是交易所轉(zhuǎn)賬),解析出來后大約是16.6億條(這個我自己跑的數(shù)據(jù))。若是用傳統(tǒng)的關(guān)系型數(shù)據(jù)庫肯定扛不住的,所以一般人都會往nosql或者列式數(shù)據(jù)庫方向考慮,比如用mongo或cassandra等。雖然能夠解決問題,但是面對這么大的數(shù)據(jù),這類型的數(shù)據(jù)庫都需要部署分片集群。對于一個小創(chuàng)業(yè)公司來說,如果用戶不是很多,從運維成本上來看,是不是都點殺雞用牛刀大感覺呢。有沒有經(jīng)濟實惠的方案?當然有,比如leveldb和rocksdb這類kv嵌入式數(shù)據(jù)庫,只需要單個機器就可以滿足要求。在幾億數(shù)據(jù)量情況下,leveldb在普通硬盤上讀寫速度可以達到幾萬每秒,使用ssd硬盤更快,而且內(nèi)存占用極少。當然使用leveldb或rocksdb,也有其缺點,就是單機數(shù)據(jù)安全的問題,如果硬盤壞了怎么辦。恰好我們這個業(yè)務(wù)對數(shù)據(jù)的安全性要求并不高,因為所有數(shù)據(jù)都是從全節(jié)點來的,要是硬盤壞了,大不了重新跑一遍數(shù)據(jù)。rocksdb是facebook的開源產(chǎn)品,據(jù)說是對leveldb做了優(yōu)化,性能更強。rocksdb是c++寫的,而leveldb除了c++版本之外,還有g(shù)o語言版本,比特幣全節(jié)點btcd和以太坊全節(jié)點geth都是用的go版本的leveldb。最終我選擇了leveldb,因為我的服務(wù)是用go寫的,雖然go也可以通過cgo調(diào)用C++,但是代碼寫起來沒有純go那么舒服。
數(shù)據(jù)結(jié)構(gòu)leveldb是kv數(shù)據(jù)庫,沒有表的概念,所以數(shù)據(jù)結(jié)構(gòu)的設(shè)計非常關(guān)鍵。比如地址的歷史交易記錄,在關(guān)系型數(shù)據(jù)庫中可以建一個以地址為索引的歷史交易記錄表。而kv數(shù)據(jù)庫則沒有索引的概念。好在level的key是有序的,可以根據(jù)key的順序讀取內(nèi)容。根據(jù)這個特性,我們可以這樣設(shè)計索引,每個地址的交易是一組key,這組key在數(shù)據(jù)庫的所有key中是緊挨著的。這樣只要知道某個地址的第一個索引key就可以按順序讀到這個地址的其他交易。因為一個交易涉及到多個輸入地址和輸出地址所以需要索引跟數(shù)據(jù)分開,對于utxo只關(guān)聯(lián)到一個地址,就不需要多帶帶設(shè)計索引了,索引跟數(shù)據(jù)可以放在一起。
數(shù)據(jù)結(jié)構(gòu)設(shè)計好了,該怎么存。這個就是序列化的問題了,可以是json,或者go自帶的gob,也可以自己寫。最后從編碼難度,執(zhí)行效率和壓縮率等方面綜合考慮采用了protobuf。這是我的proto文件
syntax = "proto3"; package models; //key: utxo-{addr}-{Transaction.id}-{Transaction.vout} message Utxo { string txId = 1; uint32 vout = 2; int64 amount = 3; string scriptPubKey = 4; } //context //key: context message Context { int64 blockHeight = 1; // 當前處理的區(qū)塊高度 string blockHash = 2; // 當前處理的區(qū)塊hash int32 blockTotalTx = 3; // 當前區(qū)塊的交易數(shù) int32 BlockProcessedTx = 4; // 當前區(qū)塊已經(jīng)處理的交易數(shù) int64 totalTx = 5; // 總共的交易數(shù) int64 totalTxNode = 6; // } message TxInput { string txId = 1; //上一筆交易id uint32 vout = 2; //上一筆交易輸出的idx string addr = 3; //通過查詢獲得 int64 amount = 4; //通過查詢獲得 } message TxOutput { string addr = 1; int64 amount = 2; uint32 vout = 3; string scriptPubKey = 4; } //key: tx-{Transaction.txId} message Transaction { int64 id = 1; //自增di string txId = 2; int64 blockTime = 3; string blockHash = 4; int64 blockHeight = 5; repeated TxInput inputs = 6; repeated TxOutput outputs = 7; } //key: txnode-{addr}-{TxNode.id} message TxNode{ int64 id = 1; //自增di string txId = 2; uint32 type = 3; //1-intput 2-output 3-intput|output }總結(jié)
這個項目的難點不在編碼而是技術(shù)選型,當然還有調(diào)試。代碼寫完后經(jīng)過漫長的同步,大概半個月才同步完成。 只有同步完成才能進行完整的功能測試,若果有數(shù)據(jù)的bug還得從頭開始同步。需要注意的是這里只是設(shè)計了已經(jīng)確認的區(qū)塊,對于未確認的區(qū)塊和內(nèi)存池的交易要多帶帶考慮。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/24521.html
摘要:比特幣區(qū)塊鏈無疑是當今業(yè)界的最熱門的。目前,每個成功的礦工獲得可能每年更換一次或通過比特幣社區(qū)決策作為成功向區(qū)塊鏈添加一塊交易的獎勵。填寫其他詳細信息,例如比特幣金額和可選說明。 比特幣區(qū)塊鏈無疑是當今業(yè)界的最熱門的。通過這篇博客,我將盡力向大家介紹加密貨幣比特幣的概念,以及它如何創(chuàng)造我們稱之為區(qū)塊鏈的革命性技術(shù)。 這個問題經(jīng)常引起混淆。這篇文章可以快速解釋和清理這方面的混亂! 什么是...
摘要:創(chuàng)建比特幣錢包需要一組優(yōu)秀的程序員。如何使用流行的庫構(gòu)建自己的比特幣錢包應(yīng)用程序創(chuàng)建比特幣錢包應(yīng)用程序的一種方法是依賴現(xiàn)有工具。具有以下功能它允許開發(fā)人員使用密碼加密創(chuàng)建比特幣錢包應(yīng)用程序。 盡管目前加密貨幣市場相當黯淡,但比特幣和其他山寨幣繼續(xù)受歡迎。每天都有新的交易者加入市場,希望能夠在下一個價格高漲時獲利。 隨著市場的突飛猛進,開發(fā)商也在獲益。新交易者的首要任務(wù)是設(shè)置比特幣錢包。...
摘要:創(chuàng)建比特幣錢包需要一組優(yōu)秀的程序員。如何使用流行的庫構(gòu)建自己的比特幣錢包應(yīng)用程序創(chuàng)建比特幣錢包應(yīng)用程序的一種方法是依賴現(xiàn)有工具。具有以下功能它允許開發(fā)人員使用密碼加密創(chuàng)建比特幣錢包應(yīng)用程序。 盡管目前加密貨幣市場相當黯淡,但比特幣和其他山寨幣繼續(xù)受歡迎。每天都有新的交易者加入市場,希望能夠在下一個價格高漲時獲利。 隨著市場的突飛猛進,開發(fā)商也在獲益。新交易者的首要任務(wù)是設(shè)置比特幣錢包。...
摘要:側(cè)鏈側(cè)鏈協(xié)議允許資產(chǎn)在比特幣區(qū)塊鏈和其他區(qū)塊鏈之間互轉(zhuǎn)。實現(xiàn)了比特幣區(qū)塊鏈的擴展證明在比特幣系統(tǒng)中驗證交易時,涉及交易合法性檢查雙重花費檢查腳本檢查等。 比特幣項目簡介 比特幣是基于區(qū)塊鏈技術(shù)的一種數(shù)字貨幣實現(xiàn),比特幣網(wǎng)絡(luò)是歷史上首個經(jīng)過大規(guī)模、長時間檢查的數(shù)字貨幣系統(tǒng) 比特幣網(wǎng)絡(luò)在功能上具有如下特點: 去中心化: 意味著沒有任何獨立個體可以對網(wǎng)絡(luò)中的交易進行破壞,任何交易請求都需要...
閱讀 1901·2021-09-27 13:35
閱讀 3439·2019-08-30 14:16
閱讀 2491·2019-08-30 10:52
閱讀 871·2019-08-29 16:35
閱讀 1425·2019-08-29 15:22
閱讀 3651·2019-08-23 18:21
閱讀 3144·2019-08-23 18:00
閱讀 3129·2019-08-23 16:50