而後咱們嘗試多添加幾個以後,訪問 BlockChain 來查看已經存在的區塊鏈結構:
8.結語
經過以上代碼咱們完成了一個簡陋的區塊鏈,雖然十分簡陋,可是已經具有了塊生成,散列計算,塊校驗這些基本能力,你能夠參考 GitHub 上面各類成熟的區塊鏈實現來完成工做量證實、權益證實這樣的共識算法,或者是智能合約、Dapp、側鏈等等。
首先新建一個 Asp.Net Core 項目,而後選擇 Empty Project(空項目) 類型,創建完成後無需進行任何配置。html
這裏咱們來建立一個具體的區塊數據模型,使用的是 Struct 結構體。web
public struct Block { /// <summary> /// 區塊位置 /// </summary> public int Index { get; set; } /// <summary> /// 區塊生成時間戳 /// </summary> public string TimeStamp { get; set; } /// <summary> /// 心率數值 /// </summary> public int BPM { get; set; } /// <summary> /// 區塊 SHA-256 散列值 /// </summary> public string Hash { get; set; } /// <summary> /// 前一個區塊 SHA-256 散列值 /// </summary> public string PrevHash { get; set; } }
這裏各個字段的含義已經在註釋上方標明瞭,這裏不在過多贅述。
以後咱們新建一個 BlockGenerator 靜態類用於管理區塊鏈,而且使用一個 List 保存區塊鏈數據。算法
public static class BlockGenerator { public static List<Block> _blockChain = new List<Block>(); }
咱們使用散列算法(SHA256)來肯定和維護鏈中塊和塊正確的順序,確保每個塊的 PrevHash 值等於前一個塊中的 Hash 值,這樣就以正確的塊順序構建出鏈:markdown
使用散列是由於可使用極少的控件生成每個區塊的惟一標識,並且能夠維持整個區塊鏈的完整性,經過每一個區塊存儲的前一個鏈的散列值,咱們就能夠確保區塊鏈當中每個區塊的正確性,任何針對區塊的無效更改都會致使散列值的改變,也就破壞了區塊鏈。
那麼咱們就在 BlockGenerator 當中添加一個函數用於計算 Block 的 Hash 值:app
/// <summary> /// 計算區塊 HASH 值 /// </summary> /// <param name="block">區塊實例</param> /// <returns>計算完成的區塊散列值</returns> public static string CalculateHash(Block block) { string calculationStr = $"{block.Index}{block.TimeStamp}{block.BPM}{block.PrevHash}"; 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(); }
這裏的 CalculateHash 函數接收一個 Block 實例,經過該實例當中的 Index、TimeStamp、BPM、PrevHash 的值來計算出當前塊的 SHA256 Hash 值,以後咱們就能夠來編寫一個生成塊的函數:async
/// <summary> /// 生成新的區塊 /// </summary> /// <param name="oldBlock">舊的區塊數據</param> /// <param name="BPM">心率</param> /// <returns>新的區塊</returns> public static Block GenerateBlock(Block oldBlock, int BPM) { Block newBlock = new Block() { Index = oldBlock.Index + 1, TimeStamp = CalculateCurrentTimeUTC(), BPM = BPM, PrevHash = oldBlock.Hash }; newBlock.Hash = CalculateHash(newBlock); return newBlock; }
這個函數須要接收前一個塊對象的值,用於新區塊的 Index 遞增以及 新的 SHA256 Hash 計算。
這裏摻入了一個 CalculateCurrentTimeUTC 函數,該函數主要是用於將 DateTime.Now 時間轉換爲 UTC 時間,以下:函數
/// <summary> /// 計算當前時間的 UTC 表示格式 /// </summary> /// <returns>UTC 時間字符串</returns> public static string CalculateCurrentTimeUTC() { DateTime startTime = new DateTime(1970, 1, 1, 0, 0, 0, 0); DateTime nowTime = DateTime.Now; long unixTime = (long)Math.Round((nowTime - startTime).TotalMilliseconds, MidpointRounding.AwayFromZero); return unixTime.ToString(); }
每個區塊都是不可信的,因此咱們須要在生成新的區塊的時候對其進行校驗,校驗規則以下:post
有了上述幾種條件,咱們能夠編寫一個校驗函數以下:區塊鏈
/// <summary> /// 檢驗區塊是否有效 /// </summary> /// <param name="newBlock">新生成的區塊數據</param> /// <param name="oldBlock">舊的區塊數據</param> /// <returns>有效返回 TRUE,無效返回 FALSE</returns> public static bool IsBlockValid(Block newBlock, Block oldBlock) { if (oldBlock.Index + 1 != newBlock.Index) return false; if (oldBlock.Hash != newBlock.PrevHash) return false; if (CalculateHash(newBlock) != newBlock.Hash) return false; return true; }
除開區塊校驗的問題以外,若是有兩個節點被分別添加到各自的區塊鏈上,咱們應該始終以最長的那一條爲主線,由於最長的那一條意味着他的區塊數據始終是最新的。ui
So,咱們還須要一個更新最新區塊的函數:
/// <summary> /// 若是新的區塊鏈比當前區塊鏈更新,則切換當前區塊鏈爲最新區塊鏈 /// </summary> /// <param name="newBlockChain">新的區塊鏈</param> public static void SwitchChain(List<Block> newBlockChain) { if (newBlockChain.Count > _blockChain.Count) { _blockChain = newBlockChain; } }
如今整個區塊鏈的基本操做已經完成,如今咱們須要讓他運轉起來,咱們來到 StartUp 當中,添加兩個新的路由:
app.Map("/BlockChain", _ => { _.Run(async context => { if (context.Request.Method == "POST") { // 增長區塊鏈 if (BlockGenerator._blockChain.Count == 0) { Block firstBlock = new Block() { Index = 0, TimeStamp = BlockGenerator.CalculateCurrentTimeUTC(), BPM = 0, Hash = string.Empty, PrevHash = string.Empty }; BlockGenerator._blockChain.Add(firstBlock); await context.Response.WriteAsync(JsonConvert.SerializeObject(firstBlock)); } else { int.TryParse(context.Request.Form["BPM"][0], out int bpm); Block oldBlock = BlockGenerator._blockChain.Last(); Block newBlock = BlockGenerator.GenerateBlock(oldBlock, bpm); if (BlockGenerator.IsBlockValid(newBlock, oldBlock)) { List<Block> newBlockChain = new List<Block>(); foreach (var block in BlockGenerator._blockChain) { newBlockChain.Add(block); } newBlockChain.Add(newBlock); BlockGenerator.SwitchChain(newBlockChain); } await context.Response.WriteAsync(JsonConvert.SerializeObject(newBlock)); } } }); }); app.Map("/BlockChains", _ => { _.Run(async context => { await context.Response.WriteAsync(JsonConvert.SerializeObject(BlockGenerator._blockChain)); }); });
咱們先經過 PostMan 來構建一個創世塊:
而後咱們嘗試多添加幾個以後,訪問 BlockChain 來查看已經存在的區塊鏈結構:
經過以上代碼咱們完成了一個簡陋的區塊鏈,雖然十分簡陋,可是已經具有了塊生成,散列計算,塊校驗這些基本能力,你能夠參考 GitHub 上面各類成熟的區塊鏈實現來完成工做量證實、權益證實這樣的共識算法,或者是智能合約、Dapp、側鏈等等。
原文地址:http://www.cnblogs.com/myzony/p/8478789.html