如何建立NEO輕客戶端

NEOGO發表於2019-01-04

目前很多開發者身體力行的投入到NEO技術社群生態的建設當中,比如neo-swift,它是一個可實現與NEO區塊鏈互動功能的輕客戶端,主要用Swift-4語言編寫。儘管它目前是一個輕客戶端,但不代表以後就不會擴充套件為全節點客戶端。

本文梳理了neo-swift的運作需要哪些支援,希望大家在讀完這篇部落格後能瞭解區塊鏈的內裡運作機制,也希望本文能激勵開發者在NEO區塊鏈上建立下一個專案。

為什麼?

對於任何專案而言,第一個問題永遠是專案的建立目的的是什麼,neo-swift專案建立主要出於4個原因。

1.開發者想要開發分散式iOS應用,且應用廣度越來越廣。

2. 建立一個開發者友好社群,其中一個方法就是建立便於非區塊鏈開發者使用的SDK。

3.有的開發者很喜歡Swift。

4.移動裝置的開發與部署日益重要。

如何建立NEO輕客戶端

如何建立NEO輕客戶端

以下為它的實質內容

讀取操作

首先需要實現區塊鏈的讀取操作。區塊鏈是一個公開的分散式賬本,使用者無需通過任何形式的鑑定即可自由讀取資訊。實現此類讀取操作的一個途徑是在機器上執行全節點,全節點可以儲存完全同步的區塊鏈備份,但移動裝置上顯然還沒有足夠的空間儲存區塊鏈的全部資訊備份。在這種情況下,讀取資料的方式是通過RPC與執行全節點的人進行交流。

    public func getBlockBy(index: Int64, completion: @escaping (NeoClientResult<Block>) -> ()) {
        sendRequest(.getBlock, params: [index, 1]) { result in
            switch result {
                case .failure(let error):
                    completion(.failure(error))
                case .success(let response):
                    let decoder = JSONDecoder()
                    guard let data = try? JSONSerialization.data(withJSONObject: (response["result"] as! JSONDictionary), options: .prettyPrinted),
                        let block = try? decoder.decode(Block.self, from: data) else {
                            completion(.failure(.invalidData))
                            return
                    }
                
                let result = NeoClientResult.success(block)
                completion(result)
            }
        }
    }複製程式碼

這一組程式碼可以實現從鏈上的特定高度獲取一個區塊,寫這篇文章時的區塊高度為1,348,910,可以檢索並檢視任何低於該高度的區塊。感興趣的話可以在鏈上搜尋交易、區塊以及地址等資訊,從而更深入瞭解資料結構的運作機制。https://neotracker.io/

建立錢包

儘管從區塊鏈讀取資料便於收集資料,但將資料寫入區塊鏈更有意思。本文將探討NEO區塊鏈目前正在使用的兩個主要的寫入操作,即傳送資產與認領GAS。希望大家在通讀本文後能對目前使用頻率最高的幾個區塊鏈操作有清楚的瞭解。要想把資訊寫入NEO區塊鏈,首先需要獲得一對有效的公私鑰授權你的寫入操作。

“錢包實際上並不儲存任何資產,它的功能只是使用私鑰將寫入需求傳送給區塊鏈。”

這是錢包軟體使用者最可能出現理解誤區的一個地方。實際上,NEO資產是儲存在區塊鏈上的;錢包只是一個互動介面,使用者可以通過這個互動介面輸入私鑰並移動資產,即:將資訊寫入分散式賬本。

那麼如何生成這對公私鑰呢?首先得生成私鑰,私鑰是由64個字元組成的十六進位制字串,可以是0與2^256(1.15792089e77)之間的任一數字。“賬戶”的其餘資訊都是根據這串數字派生而來,賬戶資訊包括私鑰、WIF(錢包匯入格式)、公鑰與地址。

WIF

這是一個私鑰

0C28FCA386C7A227600B2FE50B7CAEEC86D3BF1FBE471BE89827E19D72AA1D複製程式碼

由於過於複雜,把私鑰轉變為WIF(錢包匯入格式)。

5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ複製程式碼

雖然仍未達到完全可讀的程度,但肯定比原字串更易讀。WIF還有基本錯誤檢查功能,所以如果把資產傳送給WIF格式地址,就更有可能檢查出錯誤。

公鑰

成功獲得私鑰和WIF後,操作才開始複雜起來。將整個客戶端搭建在Swift上很難,Swift沒有加密方法庫來實現橢圓曲線加密,而NEO需要使用secp256r1橢圓曲線來派生公鑰。

可以通過下方連結深入瞭解有關資訊:

ellipticcurves - Is secp256r1 more secure than secp256k1? - Cryptography Stack Exchange

https://github.com/neo-project/neo/blob/master/neo/Cryptography/Crypto.cs

使用btckeygenie,修改後就可以匯入到golang錢包生成器中,並使用gomobile編譯。未來可能能用Swift語言編寫一個成熟的ECDSA(橢圓曲線數字簽名演算法)庫,但現階段還不能達到。

地址

獲取公鑰後,只要再獲取地址就可以擁有一個“完整賬戶”了。在此階段,將十六進位制或WIF私鑰放入go語言程式包中,生成一個完整的賬戶。

public init?(wif: String) {
    var error: NSError?
    guard let wallet = GoNeowalletGenerateFromWIF(wif, &error) else { return nil }
    self.wif = wif
    self.publicKey = wallet.publicKey()
    self.privateKey = wallet.privateKey()
    self.address = wallet.address()
    self.hashedSignature = wallet.hashedSignature() //We'll discuss this later
}
複製程式碼

完成了以上步驟,實際上也就完成了SDK開發的第一步,也是重要的一步。

傳送資產與認領GAS

生成錢包後,資產可以轉入錢包地址,但同時還需要Neon錢包一類的應用來傳送資產或認領GAS,當然我們還希望建立一個可以嵌入任何iOS移動應用的SDK。

這就需要實現sendrawtransaction RPC方法,參考文件。

RPC方法負載如下:

"params": [ "80000001195876cb34364dc38b730077156c6bc3a7fc570044a66fbfeeea56f71327e8ab0000029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500c65eaf440000000f9a23e06f74cf86b8827a9108ec2e0f89ad956c9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50092e14b5e00000030aab52ad93f6ce17ca07fa88fc191828c58cb71014140915467ecd359684b2dc358024ca750609591aa731a0b309c7fb3cab5cd0836ad3992aa0a24da431f43b68883ea5651d548feb6bd3c8e16376e6e426f91f84c58232103322f35c7819267e721335948d385fae5be66e7ba8c748ac15467dcca0693692dac"]複製程式碼

出處:

官方檔案->NetworkProtocol · neo-project/neo Wiki · GitHub

若結果為“
true
”,就意味著當前交易就已經成功向全網廣播,大功告成!

若結果為“
false
”,就意味著當前交易未能成功廣播,導致這種情況的原因有許多,如雙重支付、簽名不完整等。在此例中,交易經確認後已經成功廣播,但是由於存在雙重支付,因此未能進行第二次廣播。

最終javascript sdk輸出的十六進位制字串終於自己的字串會一致。

如何建立NEO輕客戶端

跟著javascript操作一遍後,就能為傳送資產交易的完整記憶體配置繪製一個一目瞭然的示意圖,如下:

如何建立NEO輕客戶端

如果詳細地瀏覽每一部分,就會發現交易從高度最低的記憶體地址(0x00)開始,一直到最高的記憶體地址(0xXX),在這裡XX是以十六進位制表示的交易長度。

  • 第一個後設資料:包括交易的種類、版本與屬性。交易種類是轉賬/80/,版本為/00/(可能需要升級?)這裡所說的交易不包含特定的屬性。

  • Input:Input才是真正有意思的部分。NEO或任一區塊鏈系統的餘額不同於傳統伺服器客戶端模型中資料庫的任何數字,在實際操作中,餘額是以以下形式呈現的。

"GAS": {
        "balance": 29.02751232,
        "unspent": [
            {
                "index": 1,
                "txid": "74cc80ffb1588a964fc6a656302bfe5c3465d2214c64211d8fe2f322cb342a29",
                "value": 28.0
            },
            {
                "index": 0,
                "txid": "819e00aeca6be42a436b9535b2c165670be9011bbd41afe5d475b0c858a7f6c5",
                "value": 1.0
            },
            {
                "index": 1,
                "txid": "3d96fb31185394147b237a987730fa2e4c1848744530842e468a6d9bdeec4069",
                "value": 0.02751232
            }
        ]
    }複製程式碼

餘額總數是某交易ID下“未消耗”數列中所有物件的總合。當我們傳送GAS等資產時,就需要使用這些未消耗的Input來生成一個結果。例如,如果需要傳送28個GAS,就需要一個值為28的Input,但如果需要傳送29個GAS,就需要兩個Input,一個值為28,另一個值為1。你看,所有的交易都會歸納為一個任意數值。目前能進行的最大的交易就是傳送30個GAS,這需要3個Input。

  • 第二個後設資料:表示Output的次數。例如,如果我們想要傳送28個GAS,僅會產生一個Output,因為我們會消耗所有Output,僅留下一個Output,這個Output即為傳送給接收人的新交易資訊。但如果想要傳送27個GAS呢,情況就會更加複雜,因為這時會產生兩個Output,一個Output是傳送至接收人的27個GAS,另一個是發回給傳送人的找零。所以每個交易都會產生1個或2個Output。

  • 資產ID:NEO網路裡的每個資產都有其獨一無二的識別符號,目前有兩個識別符號,但未來可能會有無數個識別符號。

  • 傳送資產數額:這是不言自喻的,需要乘以100000000驗證浮點數精度

  • 接收人地址雜湊值:這也是不言自喻的,代表接收人地址的雜湊值

  • Total-Send總計:這是發回給錢包地址的找零,如果找零為0,你就不需要填寫這個欄位或後面的傳送人地址雜湊值

  • 傳送人地址雜湊值:接收找零的地址雜湊值

如何建立NEO輕客戶端

簽名:繼續使用同一個p256橢圓曲線來為負載簽名,這就是第三個後設資料塊前的所有內容。

  • NEO公鑰:即為普通的公鑰,但包括字首與字尾位元組,我也不清楚字首和字尾的用處,可能有檢查錯誤的功能。

結論

區塊鏈是讓人興奮的,它並不只是一門簡單的技術,想要打通與未來世界的連線的橋樑,NEO是一個絕佳的切入點。NEO作為一個開源專案,開發者越來越多,生態越來越健康,希望能夠加入到NEO社群建設中來,NEO有機會成為dBFT共識機制與區塊鏈技術的黃金標準。


感謝本文原作者Salty Skip

原文


相關文章