您好,登錄后才能下訂單哦!
從0到1簡(jiǎn)易區(qū)塊鏈開發(fā)手冊(cè)V0.2-創(chuàng)建錢包
https://blog.51cto.com/clovemfong/2161923
從0到1簡(jiǎn)易區(qū)塊鏈開發(fā)手冊(cè)V0.3-數(shù)據(jù)持久化與創(chuàng)世區(qū)塊
https://blog.51cto.com/clovemfong/2162169
從0到1簡(jiǎn)易區(qū)塊鏈開發(fā)手冊(cè)V0.4-實(shí)現(xiàn)轉(zhuǎn)賬交易的思路分析
https://blog.51cto.com/clovemfong/2163057
從0到1簡(jiǎn)易區(qū)塊鏈開發(fā)手冊(cè)V0.5-實(shí)現(xiàn)余額查詢
https://blog.51cto.com/clovemfong/2163109
從0到1簡(jiǎn)易區(qū)塊鏈開發(fā)手冊(cè)V0.6-實(shí)現(xiàn)打印區(qū)塊
https://blog.51cto.com/clovemfong/2163211
這是我這段時(shí)間學(xué)習(xí)區(qū)塊鏈開發(fā)以來(lái)打造的第一個(gè)區(qū)塊鏈平臺(tái),之所以叫做簡(jiǎn)易區(qū)塊鏈,是因?yàn)樗_實(shí)比較簡(jiǎn)易,僅僅是實(shí)現(xiàn)了底層的一些功能,不足以作為一個(gè)真正的公鏈?zhǔn)褂?,但通過(guò)學(xué)習(xí),我們能夠通過(guò)代碼更加理解比特幣白皮書中描述的各種比特幣原理,區(qū)塊鏈?zhǔn)澜?,無(wú)論是研究理論的,還是實(shí)戰(zhàn)開發(fā)的,甚至炒幣玩資本的,都離不開比特幣的影子,區(qū)塊鏈技術(shù)畢竟是從比特幣中剝離抽象而來(lái),所以,作為一個(gè)技術(shù)人員,無(wú)論是研究以太坊,超級(jí)賬本,甚至是各種公鏈,包括某些山寨公鏈,都需要先去理解比特幣原理,而對(duì)于開發(fā)者而言,理解原理最好的方式就是將其通過(guò)代碼實(shí)現(xiàn),當(dāng)然,我們這里實(shí)現(xiàn)的一些原理只是應(yīng)用實(shí)戰(zhàn)范圍之內(nèi)可以實(shí)現(xiàn)的,比如橢圓加密算法,我們要實(shí)現(xiàn)的只是使用橢圓加密去實(shí)現(xiàn)某些加密功能,而非用代碼去實(shí)現(xiàn)一個(gè)完整的橢圓加密代碼庫(kù),這個(gè)不再本文的討論范圍內(nèi),所以本文面向的群體是:
本文中,我們先通過(guò)命令行的方式演示區(qū)塊鏈的工作流程以及相關(guān)原理,涉及到比較重要的內(nèi)容,比如Sha256哈希,橢圓加密,Base58編碼等內(nèi)容,我會(huì)根據(jù)時(shí)間以及后期的工作情況進(jìn)行適當(dāng)調(diào)整,這注定是一個(gè)短期內(nèi)沒(méi)有結(jié)尾的故事。
為表尊敬,寫在前面,建議先閱讀該文檔
本文的學(xué)習(xí)資料來(lái)自這位liuxhengxu前輩翻譯的資料
能將資料翻譯得如此完美,相比其技術(shù)功能也是相當(dāng)深厚的,感謝分享
建議大家可以先看該資料后再來(lái)看我的這系列文章,否則可能會(huì)有一些難度,由于該資料是通過(guò)循序漸進(jìn)的方式進(jìn)行版本迭代,慢慢引導(dǎo)開發(fā)者不斷對(duì)原有的代碼進(jìn)行優(yōu)化,拓展,非常認(rèn)真并細(xì)心,希望大家時(shí)間充裕的時(shí)候以及對(duì)某些本文并未寫清楚的地方,強(qiáng)烈建議閱讀該資料。
本文在此基礎(chǔ)上進(jìn)行了一些修改(談不上改進(jìn)),我摒棄一些過(guò)于基礎(chǔ)的以及后期需要大量重構(gòu)的代碼,直接通過(guò)該項(xiàng)目的執(zhí)行流程進(jìn)行代碼分析,這樣可以稍微節(jié)省一些大家的時(shí)間,把有限的精力放在對(duì)業(yè)務(wù)有更大提升的技術(shù)研究上。
Usage:
createwallet
-- 創(chuàng)建錢包
getaddresslists
-- 獲取所有的錢包地址
createblockchain -address address
-- 創(chuàng)建創(chuàng)世區(qū)塊
send -from SourceAddress -to DestAddress -amount Amount
-- 轉(zhuǎn)賬交易
printchain
-- 打印區(qū)塊
getbalance -address address
-- 查詢余額
本文圍繞著幾個(gè)功能進(jìn)行講解
創(chuàng)建錢包
通過(guò)橢圓加密算法創(chuàng)建錢包地址
獲取錢包地址
獲取區(qū)塊鏈中所有的錢包地址
創(chuàng)建創(chuàng)世區(qū)塊
實(shí)現(xiàn)創(chuàng)世區(qū)塊的創(chuàng)建,并生成區(qū)塊鏈
實(shí)現(xiàn)轉(zhuǎn)賬交易
通過(guò)轉(zhuǎn)賬交易,生成區(qū)塊,并存入?yún)^(qū)塊鏈
打印區(qū)塊
打印出所有的區(qū)塊信息,實(shí)現(xiàn)轉(zhuǎn)賬交易的溯源
查詢余額
查詢出對(duì)應(yīng)錢包的余額狀態(tài)
隨著代碼的不斷完善,我們將會(huì)對(duì)以上進(jìn)行改進(jìn),并提供更多的功能點(diǎn)進(jìn)行分析探討,我們先通過(guò)下圖簡(jiǎn)單演示一下如上功能
關(guān)于效果圖,大家先大致看下即可,不需要刻意研究,在后期的課程中都會(huì)涉及。
定義一個(gè)空結(jié)構(gòu)體
type CLI struct {
}
重要!初學(xué)者必看
這里提到的結(jié)構(gòu)體方法并不是真正實(shí)現(xiàn)功能的方法,而是命令行對(duì)象的方法,這些方法中會(huì)調(diào)用實(shí)際的功能對(duì)象方法進(jìn)行功能實(shí)現(xiàn),在本章節(jié)中,創(chuàng)建結(jié)構(gòu)體方法即可,功能代碼可以為空,如:
例子:
func (cli *CLI) CreateWallet() {
}
func (cli *CLI) GetAddressLists() {
}
.....
其他的可以在后期逐步實(shí)現(xiàn),為了讓有基礎(chǔ)的同學(xué)對(duì)項(xiàng)目整體提前有些印象,所以,代碼內(nèi)容我直接復(fù)制粘貼進(jìn)來(lái),不做刪減,在后期的內(nèi)容中,會(huì)逐步涉及到每個(gè)調(diào)用的對(duì)象方法或者函數(shù)的作用。
func (cli *CLI) CreateWallet() {
_, wallets := GetWallets() //獲取錢包集合對(duì)象
wallets.CreateNewWallets() //創(chuàng)建錢包集合
}
func (cli *CLI) GetAddressLists() {
fmt.Println("錢包地址列表為:")
//獲取錢包的集合,遍歷,依次輸出
_, wallets := GetWallets() //獲取錢包集合對(duì)象
for address, _ := range wallets.WalletMap {
fmt.Printf("\t%s\n", address)
}
}
func (cli *CLI) CreateBlockChain(address string) {
CreateBlockChainWithGenesisBlock(address)
bc :=GetBlockChainObject()
if bc == nil{
fmt.Println("沒(méi)有數(shù)據(jù)庫(kù)")
os.Exit(1)
}
defer bc.DB.Close()
utxoSet:=&UTXOSet{bc}
utxoSet.ResetUTXOSet()
}
func (cli *CLI) Send(from, to, amount []string) {
bc := GetBlockChainObject()
if bc == nil {
fmt.Println("沒(méi)有BlockChain,無(wú)法轉(zhuǎn)賬。。")
os.Exit(1)
}
defer bc.DB.Close()
bc.MineNewBlock(from, to, amount)
//添加更新
utsoSet :=&UTXOSet{bc}
utsoSet.Update()
}
func (cli *CLI) GetBalance(address string) {
bc := GetBlockChainObject()
if bc == nil {
fmt.Println("沒(méi)有BlockChain,無(wú)法查詢。。")
os.Exit(1)
}
defer bc.DB.Close()
//total := bc.GetBalance(address,[]*Transaction{})
utxoSet :=&UTXOSet{bc}
total:=utxoSet.GetBalance(address)
fmt.Printf("%s,余額是:%d\n", address, total)
}
func (cli *CLI) PrintChains() {
//cli.BlockChain.PrintChains()
bc := GetBlockChainObject() //bc{Tip,DB}
if bc == nil {
fmt.Println("沒(méi)有BlockChain,無(wú)法打印任何數(shù)據(jù)。。")
os.Exit(1)
}
defer bc.DB.Close()
bc.PrintChains()
}
func isValidArgs() {
if len(os.Args) < 2 {
printUsage()
os.Exit(1)
}
}
判斷終端命令是否有參數(shù)輸入,如果沒(méi)有參數(shù),則提示程序使用說(shuō)明,并退出程序
func printUsage() {
fmt.Println("Usage:")
fmt.Println("\tcreatewallet\n\t\t\t-- 創(chuàng)建錢包")
fmt.Println("\tgetaddresslists\n\t\t\t-- 獲取所有的錢包地址")
fmt.Println("\tcreateblockchain -address address\n\t\t\t-- 創(chuàng)建創(chuàng)世區(qū)塊")
fmt.Println("\tsend -from SourceAddress -to DestAddress -amount Amount\n\t\t\t-- 轉(zhuǎn)賬交易")
fmt.Println("\tprintchain\n\t\t\t-- 打印區(qū)塊")
fmt.Println("\tgetbalance -address address\n\t\t\t-- 查詢余額")
}
func JSONToArray(jsonString string) []string {
var arr [] string
err := json.Unmarshal([]byte(jsonString), &arr)
if err != nil {
log.Panic(err)
}
return arr
}
通過(guò)該函數(shù)將JSON字符串格式轉(zhuǎn)成字符串?dāng)?shù)組,用于在多筆轉(zhuǎn)賬交易中實(shí)現(xiàn)同時(shí)多個(gè)賬戶進(jìn)行兩兩轉(zhuǎn)賬的功能。
func IsValidAddress(address []byte) bool {
//step1:Base58解碼
//version+pubkeyHash+checksum
full_payload := Base58Decode(address)
//step2:獲取地址中攜帶的checkSUm
checkSumBytes := full_payload[len(full_payload)-addressCheckSumLen:]
versioned_payload := full_payload[:len(full_payload)-addressCheckSumLen]
//step3:versioned_payload,生成一次校驗(yàn)碼
checkSumBytes2 := CheckSum(versioned_payload)
//step4:比較checkSumBytes,checkSumBytes2
return bytes.Compare(checkSumBytes, checkSumBytes2) == 0
}
以下三個(gè)功能實(shí)現(xiàn)之前需要先調(diào)用該函數(shù)進(jìn)行地址校驗(yàn)
Usage:
createwallet
-- 創(chuàng)建錢包
getaddresslists
-- 獲取所有的錢包地址
createblockchain -address address
-- 創(chuàng)建創(chuàng)世區(qū)塊
send -from SourceAddress -to DestAddress -amount Amount
-- 轉(zhuǎn)賬交易
printchain
-- 打印區(qū)塊
getbalance -address address
-- 查詢余額
我們將如上功能展示的實(shí)現(xiàn)功能寫在Run方法中,實(shí)現(xiàn)命令行功能的關(guān)鍵是了解os.Args與flag
關(guān)于這兩個(gè)功能,此處不再贅述,否則篇幅會(huì)無(wú)限臃腫。
代碼塊均在方法體Run中,下文將分步驟對(duì)代碼實(shí)現(xiàn)進(jìn)行體現(xiàn)
func (cli *CLI) Run() {
}
isValidArgs()
createWalletCmd := flag.NewFlagSet("createwallet", flag.ExitOnError)
getAddresslistsCmd := flag.NewFlagSet("getaddresslists", flag.ExitOnError)
CreateBlockChainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError)
sendCmd := flag.NewFlagSet("send", flag.ExitOnError)
printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError)
getBalanceCmd := flag.NewFlagSet("getbalance", flag.ExitOnError)
testMethodCmd := flag.NewFlagSet("test", flag.ExitOnError)
如上,通過(guò)flag.NewFlagSet方法創(chuàng)建命令對(duì)象,如createwallet,getaddresslists,createblockchain等命令對(duì)象
固定用法,掌握即可。
flagCreateBlockChainData := CreateBlockChainCmd.String("address", "GenesisBlock", "創(chuàng)世區(qū)塊的信息")
flagSendFromData := sendCmd.String("from", "", "轉(zhuǎn)賬源地址")
flagSendToData := sendCmd.String("to", "", "轉(zhuǎn)賬目標(biāo)地址")
flagSendAmountData := sendCmd.String("amount", "", "轉(zhuǎn)賬金額")
flagGetBalanceData := getBalanceCmd.String("address", "", "要查詢余額的賬戶")
通過(guò)命令對(duì)象的String方法為命令后的參數(shù)對(duì)象
其中createwallet,getaddresslists,printchain命令沒(méi)有參數(shù)對(duì)象。
switch os.Args[1] {
case "createwallet":
err := createWalletCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "getaddresslists":
err := getAddresslistsCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "createblockchain":
err := CreateBlockChainCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "send":
err := sendCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "getbalance":
err := getBalanceCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "printchain":
err := printChainCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
case "test":
err := testMethodCmd.Parse(os.Args[2:])
if err != nil {
log.Panic(err)
}
default:
printUsage()
os.Exit(1)
}
匹配對(duì)應(yīng)的命令,用命令對(duì)象的Parse方法對(duì)os.Args[2:]進(jìn)行解析。
//4.1 創(chuàng)建錢包--->交易地址
if createWalletCmd.Parsed() {
cli.CreateWallet()
}
//4.2 獲取錢包地址
if getAddresslistsCmd.Parsed() {
cli.GetAddressLists()
}
//4.3 創(chuàng)建創(chuàng)世區(qū)塊
if CreateBlockChainCmd.Parsed() {
if !IsValidAddress([]byte(*flagCreateBlockChainData)) {
fmt.Println("地址無(wú)效,無(wú)法創(chuàng)建創(chuàng)世前區(qū)塊")
printUsage()
os.Exit(1)
}
cli.CreateBlockChain(*flagCreateBlockChainData)
}
//4.4 轉(zhuǎn)賬交易
if sendCmd.Parsed() {
if *flagSendFromData == "" || *flagSendToData == "" || *flagSendAmountData == "" {
fmt.Println("轉(zhuǎn)賬信息有誤")
printUsage()
os.Exit(1)
}
//添加區(qū)塊
from := JSONToArray(*flagSendFromData) //[]string
to := JSONToArray(*flagSendToData) //[]string
amount := JSONToArray(*flagSendAmountData) //[]string
for i := 0; i < len(from); i++ {
if !IsValidAddress([]byte(from[i])) || !IsValidAddress([]byte(to[i])) {
fmt.Println("地址無(wú)效,無(wú)法轉(zhuǎn)賬")
printUsage()
os.Exit(1)
}
}
cli.Send(from, to, amount)
}
//4.5 查詢余額
if getBalanceCmd.Parsed() {
if !IsValidAddress([]byte(*flagGetBalanceData)) {
fmt.Println("查詢地址有誤")
printUsage()
os.Exit(1)
}
cli.GetBalance(*flagGetBalanceData)
}
//4.6 打印區(qū)塊信息
if printChainCmd.Parsed() {
cli.PrintChains()
}
在main.go中中添加測(cè)試代碼
package main
func main() {
cli:=BLC.CLI{}
cli.Run()
}
編譯運(yùn)行
$ go build -o mybtc main.go
測(cè)試思路
- 查看命令行列表是否可以正常顯示
- 輸入非法字符查看是否有錯(cuò)誤提示
業(yè)務(wù)功能此處暫未實(shí)現(xiàn),測(cè)試時(shí)忽略。
從0到1簡(jiǎn)易區(qū)塊鏈開發(fā)手冊(cè)V0.2-創(chuàng)建錢包
https://blog.51cto.com/clovemfong/2161923
從0到1簡(jiǎn)易區(qū)塊鏈開發(fā)手冊(cè)V0.3-數(shù)據(jù)持久化與創(chuàng)世區(qū)塊
https://blog.51cto.com/clovemfong/2162169
從0到1簡(jiǎn)易區(qū)塊鏈開發(fā)手冊(cè)V0.4-實(shí)現(xiàn)轉(zhuǎn)賬交易的思路分析
https://blog.51cto.com/clovemfong/2163057
從0到1簡(jiǎn)易區(qū)塊鏈開發(fā)手冊(cè)V0.5-實(shí)現(xiàn)余額查詢
https://blog.51cto.com/clovemfong/2163109
從0到1簡(jiǎn)易區(qū)塊鏈開發(fā)手冊(cè)V0.6-實(shí)現(xiàn)打印區(qū)塊
https://blog.51cto.com/clovemfong/2163211
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。