使用C#編寫自己的區(qū)塊鏈挖礦算法
什么是加密貨幣挖掘?
一個加密貨幣的價值體現(xiàn)在它的稀缺性上,如果任何人都可以任意構(gòu)造一個比特幣,那么比特幣就毫無價值,所以比特幣的區(qū)塊鏈會讓參與者完成一項“工作”,根據(jù)這個工作的最終結(jié)果還分發(fā)比特幣,這個過程就被叫做“挖礦”。這就類似于一個黃金礦工花一些時間來工作,然后獲得一點黃金。
挖礦的原理
如果你百度/谷歌搜索 比特幣挖礦的原理 的話,都會給你說是計算一個復(fù)雜的數(shù)學問題而已,但是這么說的話太籠統(tǒng)而且也太簡單。采礦引擎如何工作這是一個重要的知識點,所以我們需要了解一些密碼學知識和哈希算法相關(guān)的知識,才能知道挖礦的基本原理。
哈希/散列介紹
單向加密人類能夠理解的輸入,例如 Hello World ,并將其扔到某個加密函數(shù)(即所謂的復(fù)雜的數(shù)學問題),加密函數(shù)的算法越復(fù)雜,逆向工程就越困難。
例如一個 SHA - 256 的例子,這個網(wǎng)站(鏈接: http://tool.oschina.net/encrypt?type=2 )可以很快的計算散列值,讓我們來散列 “Hello World” 看看會得到什么結(jié)果:
不管你試驗幾次都會得到一樣的散列值,在編程中這種被稱之為冪等性。
加密算法的一個基本特性就是,它們很難通過逆向工程來得到明文結(jié)果,但是十分容易驗證他們的加密結(jié)果,例如這里的 “Hello World” 很難通過逆向工程得到他的原明文結(jié)果,比特幣采用的是 Double SHA-256 也就是將明文通過 SHA-256 計算過一次之后,再拿 SHA-256 針對散列值再次進行計算,在這里我們只使用 SHA-256 來進行加密。
工作證明
比特幣通過讓參與者散列隨機的字母與數(shù)字的組合,直到計算出來的散列包含前導(dǎo) 0。
例如我們計算 886 的散列值可以得到如下結(jié)果:
000f21ac06aceb9cdd0575e82d0d85fc39bed0a7a1d71970ba1641666a44f530
它返回了 3 個 0 作為前綴的散列值,但是我們怎么知道 886 計算出來的散列結(jié)果產(chǎn)生了 3 個 0呢?
答案是我并不需要知道。我需要知道礦工給我的散列值前導(dǎo)有幾個零就好了,并不需要復(fù)雜的算法來驗證整個散列值的有效性。
比特幣則稍微復(fù)雜一點,它每隔 10 分鐘生成一個新的區(qū)塊,新區(qū)塊的散列值的難度它可以動態(tài)調(diào)整,就類似于 CLR 的 GC 一樣,它可以根據(jù)目前挖礦的人數(shù)來進行難度動態(tài)調(diào)整,如果挖礦的人多的話,則調(diào)高難度,少則調(diào)低。
動手開發(fā)
1.項目配置
首先新建一個 Asp.Net Core 項目,然后選擇 Empty Project(空項目) 類型,建立完成后無需進行任何配置。
2.數(shù)據(jù)模型
這里我們來創(chuàng)建一個具體的區(qū)塊數(shù)據(jù)模型,使用的是 Struct 結(jié)構(gòu)體。
public struct Block { /// <summary> /// 區(qū)塊位置 /// </summary> public int Index { get; set; } /// <summary> /// 區(qū)塊生成時間戳 /// </summary> public string TimeStamp { get; set; } /// <summary> /// 心率數(shù)值 /// </summary> public int BPM { get; set; } /// <summary> /// 區(qū)塊 SHA-256 散列值 /// </summary> public string Hash { get; set; } /// <summary> /// 前一個區(qū)塊 SHA-256 散列值 /// </summary> public string PrevHash { get; set; } /// <summary> /// 下一個區(qū)塊生成難度 /// </summary> public int Difficulty { get; set; } /// <summary> /// 隨機值 /// </summary> public string Nonce { get; set; } }
Difficulty 是一個整形,他定義了我們希望得到哈希前導(dǎo) 0 的數(shù)量,前導(dǎo) 0 越多,生成正確的散列值就越困難,我們現(xiàn)在從 1 開始。
Nonce 則是每次計算塊散列值所需要的隨機值。
3. 工作證明
我們首先添加一個新的方法來驗證生成的散列值是否包含指定數(shù)量的前導(dǎo) 0 :
/// <summary> /// 校驗 Hash 是否有效 /// </summary> /// <param name="hashStr">Hash 值</param> /// <param name="difficulty">難度</param> /// <returns></returns> public static bool IsHashValid(string hashStr, int difficulty) { var bytes = Enumerable.Range(0, hashStr.Length) .Where(n => n % 2 == 0) .Select(n => Convert.ToByte(hashStr.Substring(n, 2), 16)) .ToArray(); var bits = new BitArray(bytes); for (var i = 0; i < difficulty; i++) { if (bits[i]) return false; } return true; }
然后我們更改了之前區(qū)塊 Hash 的生成方法:
/// <summary> /// 計算區(qū)塊 HASH 值 /// </summary> /// <param name="block">區(qū)塊實例</param> /// <returns>計算完成的區(qū)塊散列值</returns> public static string CalculateHash(Block block) { string calculationStr = $"{block.Index}{block.TimeStamp}{block.BPM}{block.PrevHash}{block.Nonce}"; SHA256 sha256Generator = SHA256.Create(); byte[] sha256HashBytes = sha256Generator.ComputeHash(Encoding.UTF8.GetBytes(calculationStr)); StringBuilder sha256StrBuilder = new StringBuilder(); foreach (byte @byte in sha256HashBytes) { sha256StrBuilder.Append(@byte.ToString("x2")); } return sha256StrBuilder.ToString(); }
在這里我們新增新增了 Nonce 隨機值作為散列生成的依據(jù)。
那么我們生成新區(qū)塊的時候就順便來挖礦吧:
/// <summary> /// 生成新的區(qū)塊 /// </summary> /// <param name="oldBlock">舊的區(qū)塊數(shù)據(jù)</param> /// <param name="BPM">心率</param> /// <returns>新的區(qū)塊</returns> public static Block GenerateBlock(Block oldBlock, int BPM) { Block newnewBlock = new Block() { Index = oldBlock.Index + 1, TimeStamp = CalculateCurrentTimeUTC(), BPMBPM = BPM, PrevHash = oldBlock.Hash, DifficultyDifficulty = Difficulty }; // 挖礦 ing... for (int i = 0; ; i++) { newBlock.Nonce = i.ToString("x2"); if (!IsHashValid(CalculateHash(newBlock), Difficulty)) { Console.WriteLine($"目前結(jié)果:{CalculateHash(newBlock)} ,正在計算中..."); Task.Delay(1); continue; } else { Console.WriteLine($"目前結(jié)果:{CalculateHash(newBlock)} ,計算完畢..."); newBlock.Hash = CalculateHash(newBlock); break; } } // 原有代碼 // newBlock.Hash = CalculateHash(newBlock); return newBlock; }
效果
結(jié)語
其實代碼并不復(fù)雜,但是這幾十行代碼表明了區(qū)塊鏈挖礦的本質(zhì),后面你可以參考原文實現(xiàn) P2P 與 股權(quán)權(quán)益證明方法與智能合約。
總結(jié)
以上所述是小編給大家介紹的使用C#編寫自己的區(qū)塊鏈挖礦算法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對我們網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!
您可能感興趣的文章
- 01-10C#使用Dispose模式實現(xiàn)手動對資源的釋放
- 01-10C#3.0使用EventLog類寫Windows事件日志的方法
- 01-10C#使用windows服務(wù)開啟應(yīng)用程序的方法
- 01-10c# ArrayList的使用方法小總結(jié)
- 01-10C#使用ADO.Net部件來訪問Access數(shù)據(jù)庫的方法
- 01-10C#使用Mutex簡單實現(xiàn)程序單實例運行的方法
- 01-10使用Nopcommerce為商城添加滿XX減XX優(yōu)惠券功能
- 01-10C#中yield用法使用說明
- 01-10C#編程和Visual Studio使用技巧(下)
- 01-10C#編程和Visual Studio使用技巧(上)


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻 器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當前操作系統(tǒng)已
隨機閱讀
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-10delphi制作wav文件的方法
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10C#中split用法實例總結(jié)
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 04-02jquery與jsp,用jquery
- 01-10使用C語言求解撲克牌的順子及n個骰子