溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

區(qū)塊鏈簡(jiǎn)易公鏈從0到1開發(fā)手冊(cè)

發(fā)布時(shí)間:2020-07-12 12:56:06 來(lái)源:網(wǎng)絡(luò) 閱讀:30474 作者:暗黑魔君 欄目:編程語(yǔ)言

從0到1簡(jiǎn)易區(qū)塊鏈開發(fā)手冊(cè)V0.1

從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),所以本文面向的群體是:

  • 對(duì)比特幣原理不了解,但沒(méi)時(shí)間看太多的資料文獻(xiàn)的初學(xué)者
  • 對(duì)比特幣原理有所了解,但是停留在理論階段的研究者
  • 沒(méi)有對(duì)比特幣進(jìn)行研究,想直接研究以太坊,超級(jí)賬本的實(shí)戰(zhàn)者(大神除外)
  • 對(duì)Golang熟悉,但是不知道如何入手區(qū)塊鏈的開發(fā)者或者是像我一樣的運(yùn)維 :-)

本文中,我們先通過(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)單演示一下如上功能

區(qū)塊鏈簡(jiǎn)易公鏈從0到1開發(fā)手冊(cè)

關(guān)于效果圖,大家先大致看下即可,不需要刻意研究,在后期的課程中都會(huì)涉及。

二. 實(shí)現(xiàn)命令行功能

區(qū)塊鏈簡(jiǎn)易公鏈從0到1開發(fā)手冊(cè)

1.定義結(jié)構(gòu)體

定義一個(gè)空結(jié)構(gòu)體

type CLI struct {

}

2.結(jié)構(gòu)體方法

重要!初學(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ù)的作用。

2.1 創(chuàng)建錢包CreateWallet
func (cli *CLI) CreateWallet() {
    _, wallets := GetWallets() //獲取錢包集合對(duì)象
    wallets.CreateNewWallets() //創(chuàng)建錢包集合

}
2.2 獲取錢包地址GetAddressLists
func (cli *CLI) GetAddressLists() {
    fmt.Println("錢包地址列表為:")
        //獲取錢包的集合,遍歷,依次輸出
    _, wallets := GetWallets() //獲取錢包集合對(duì)象
    for address, _ := range wallets.WalletMap { 
        fmt.Printf("\t%s\n", address)
    }
}
2.3 創(chuàng)建創(chuàng)世區(qū)塊CreateBlockChain
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()
}
2.4 創(chuàng)建轉(zhuǎn)賬交易Send
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()
}
2.5 查詢余額GetBalance
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)
}
2.6 打印區(qū)塊PrintChains
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()
}

3. 相關(guān)函數(shù)

3.1 判斷參數(shù)是否合法 isValidArgs
func isValidArgs() {
    if len(os.Args) < 2 {
        printUsage()
        os.Exit(1)
    }
}

判斷終端命令是否有參數(shù)輸入,如果沒(méi)有參數(shù),則提示程序使用說(shuō)明,并退出程序

3.2 程序使用說(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-- 查詢余額")
}
3.3 JSON解析的函數(shù)
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)賬的功能。

3.4 校驗(yà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)

  • 創(chuàng)建創(chuàng)世區(qū)塊
  • 轉(zhuǎn)賬交易
  • 查詢余額

4.命令行主要方法Run

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.Argsflag

關(guān)于這兩個(gè)功能,此處不再贅述,否則篇幅會(huì)無(wú)限臃腫。

代碼塊均在方法體Run中,下文將分步驟對(duì)代碼實(shí)現(xiàn)進(jìn)行體現(xiàn)

func (cli *CLI) Run() {
}
4.1 判斷命令行參數(shù)是否合法
isValidArgs()
4.2 創(chuàng)建flagset命令對(duì)象
    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ì)象

固定用法,掌握即可。

4.3 設(shè)置命令后的參數(shù)對(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ì)象

  • createblockchain命令后的參數(shù)對(duì)象:address
  • send命令后的參數(shù)對(duì)象: from | to |amount
  • getbalance命令后的參數(shù)對(duì)象: address

其中createwallet,getaddresslists,printchain命令沒(méi)有參數(shù)對(duì)象。

4.4 解析命令對(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.5 執(zhí)行對(duì)應(yīng)功能
    //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()
    }

5. 測(cè)試代碼

在main.go中中添加測(cè)試代碼

package main
func main() {
    cli:=BLC.CLI{}
    cli.Run()
}

編譯運(yùn)行

$ go build -o mybtc main.go

測(cè)試思路

  1. 查看命令行列表是否可以正常顯示
  2. 輸入非法字符查看是否有錯(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
向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI