文章原文来自:Code your own blockchain in less than 200 lines of Go!,原始文章是通过 Go 语言来实现自己的区块链的,这里我们参照该文章来使用 C# + Asp.Net Core 实现自己的区块链。在这里我也参考了 这篇译文

1.项目配置

首先新建一个 Asp.Net Core 项目,然后选择 Empty Project(空项目) 类型,建立完成后无需进行任何配置。

2.数据模型

这里我们来创建一个具体的区块数据模型,使用的是 Struct 结构体。

  1. public struct Block
  2. {
  3. /// <summary>
  4. /// 区块位置
  5. /// </summary>
  6. public int Index { get; set; }
  7. /// <summary>
  8. /// 区块生成时间戳
  9. /// </summary>
  10. public string TimeStamp { get; set; }
  11. /// <summary>
  12. /// 心率数值
  13. /// </summary>
  14. public int BPM { get; set; }
  15. /// <summary>
  16. /// 区块 SHA-256 散列值
  17. /// </summary>
  18. public string Hash { get; set; }
  19. /// <summary>
  20. /// 前一个区块 SHA-256 散列值
  21. /// </summary>
  22. public string PrevHash { get; set; }
  23. }

这里各个字段的含义已经在注释上方标明了,这里不在过多赘述。

之后我们新建一个 BlockGenerator 静态类用于管理区块链,并且使用一个 List 保存区块链数据。

  1. public static class BlockGenerator
  2. {
  3. public static List<Block> _blockChain = new List<Block>();
  4. }

我们使用散列算法(SHA256)来确定和维护链中块和块正确的顺序,确保每一个块的 PrevHash 值等于前一个块中的 Hash 值,这样就以正确的块顺序构建出链:

4.散列与生成区块

使用散列是因为可以使用极少的控件生成每一个区块的唯一标识,而且可以维持整个区块链的完整性,通过每个区块存储的前一个链的散列值,我们就可以确保区块链当中每一个区块的正确性,任何针对区块的无效更改都会导致散列值的改变,也就破坏了区块链。

那么我们就在 BlockGenerator 当中添加一个函数用于计算 Block 的 Hash 值:

  1. /// <summary>
  2. /// 计算区块 HASH 值
  3. /// </summary>
  4. /// <param name="block">区块实例</param>
  5. /// <returns>计算完成的区块散列值</returns>
  6. public static string CalculateHash(Block block)
  7. {
  8. string calculationStr = $"{block.Index}{block.TimeStamp}{block.BPM}{block.PrevHash}";
  9. SHA256 sha256Generator = SHA256.Create();
  10. byte[] sha256HashBytes = sha256Generator.ComputeHash(Encoding.UTF8.GetBytes(calculationStr));
  11. StringBuilder sha256StrBuilder = new StringBuilder();
  12. foreach (byte @byte in sha256HashBytes)
  13. {
  14. sha256StrBuilder.Append(@byte.ToString("x2"));
  15. }
  16. return sha256StrBuilder.ToString();
  17. }

这里的 CalculateHash 函数接收一个 Block 实例,通过该实例当中的 Index、TimeStamp、BPM、PrevHash 的值来计算出当前块的 SHA256 Hash 值,之后我们就可以来编写一个生成块的函数:

  1. /// <summary>
  2. /// 生成新的区块
  3. /// </summary>
  4. /// <param name="oldBlock">旧的区块数据</param>
  5. /// <param name="BPM">心率</param>
  6. /// <returns>新的区块</returns>
  7. public static Block GenerateBlock(Block oldBlock, int BPM)
  8. {
  9. Block newBlock = new Block()
  10. {
  11. Index = oldBlock.Index + 1,
  12. TimeStamp = CalculateCurrentTimeUTC(),
  13. BPM = BPM,
  14. PrevHash = oldBlock.Hash
  15. };
  16. newBlock.Hash = CalculateHash(newBlock);
  17. return newBlock;
  18. }

这个函数需要接收前一个块对象的值,用于新区块的 Index 递增以及 新的 SHA256 Hash 计算。

这里掺入了一个 CalculateCurrentTimeUTC 函数,该函数主要是用于将 DateTime.Now 时间转换为 UTC 时间,如下:

  1. /// <summary>
  2. /// 计算当前时间的 UTC 表示格式
  3. /// </summary>
  4. /// <returns>UTC 时间字符串</returns>
  5. public static string CalculateCurrentTimeUTC()
  6. {
  7. DateTime startTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
  8. DateTime nowTime = DateTime.Now;
  9. long unixTime = (long)Math.Round((nowTime - startTime).TotalMilliseconds, MidpointRounding.AwayFromZero);
  10. return unixTime.ToString();
  11. }

5.校验区块

每一个区块都是不可信的,所以我们需要在生成新的区块的时候对其进行校验,校验规则如下:

  • 校验新区块与旧区块的 Index 是否正确递增
  • 校验新区块的 Hash 值是否正确
  • 校验新区块的 PrevHash 值是否与旧区块的 Hash 值匹配

    有了上述几种条件,我们可以编写一个校验函数如下:
  1. /// <summary>
  2. /// 检验区块是否有效
  3. /// </summary>
  4. /// <param name="newBlock">新生成的区块数据</param>
  5. /// <param name="oldBlock">旧的区块数据</param>
  6. /// <returns>有效返回 TRUE,无效返回 FALSE</returns>
  7. public static bool IsBlockValid(Block newBlock, Block oldBlock)
  8. {
  9. if (oldBlock.Index + 1 != newBlock.Index) return false;
  10. if (oldBlock.Hash != newBlock.PrevHash) return false;
  11. if (CalculateHash(newBlock) != newBlock.Hash) return false;
  12. return true;
  13. }

除开区块校验的问题之外,如果有两个节点被分别添加到各自的区块链上,我们应该始终以最长的那一条为主线,因为最长的那一条意味着他的区块数据始终是最新的。



So,我们还需要一个更新最新区块的函数:

  1. /// <summary>
  2. /// 如果新的区块链比当前区块链更新,则切换当前区块链为最新区块链
  3. /// </summary>
  4. /// <param name="newBlockChain">新的区块链</param>
  5. public static void SwitchChain(List<Block> newBlockChain)
  6. {
  7. if (newBlockChain.Count > _blockChain.Count)
  8. {
  9. _blockChain = newBlockChain;
  10. }
  11. }

6.集成到 Web 当中

现在整个区块链的基本操作已经完成,现在我们需要让他运转起来,我们来到 StartUp 当中,添加两个新的路由:

  1. app.Map("/BlockChain", _ =>
  2. {
  3. _.Run(async context =>
  4. {
  5. if (context.Request.Method == "POST")
  6. {
  7. // 增加区块链
  8. if (BlockGenerator._blockChain.Count == 0)
  9. {
  10. Block firstBlock = new Block()
  11. {
  12. Index = 0,
  13. TimeStamp = BlockGenerator.CalculateCurrentTimeUTC(),
  14. BPM = 0,
  15. Hash = string.Empty,
  16. PrevHash = string.Empty
  17. };
  18. BlockGenerator._blockChain.Add(firstBlock);
  19. await context.Response.WriteAsync(JsonConvert.SerializeObject(firstBlock));
  20. }
  21. else
  22. {
  23. int.TryParse(context.Request.Form["BPM"][0], out int bpm);
  24. Block oldBlock = BlockGenerator._blockChain.Last();
  25. Block newBlock = BlockGenerator.GenerateBlock(oldBlock, bpm);
  26. if (BlockGenerator.IsBlockValid(newBlock, oldBlock))
  27. {
  28. List<Block> newBlockChain = new List<Block>();
  29. foreach (var block in BlockGenerator._blockChain)
  30. {
  31. newBlockChain.Add(block);
  32. }
  33. newBlockChain.Add(newBlock);
  34. BlockGenerator.SwitchChain(newBlockChain);
  35. }
  36. await context.Response.WriteAsync(JsonConvert.SerializeObject(newBlock));
  37. }
  38. }
  39. });
  40. });
  41. app.Map("/BlockChains", _ =>
  42. {
  43. _.Run(async context =>
  44. {
  45. await context.Response.WriteAsync(JsonConvert.SerializeObject(BlockGenerator._blockChain));
  46. });
  47. });

7.最终效果

我们先通过 PostMan 来构建一个创世块:



然后我们尝试多添加几个之后,访问 BlockChain 来查看已经存在的区块链结构:

8.结语

通过以上代码我们完成了一个简陋的区块链,虽然十分简陋,但是已经具备了块生成,散列计算,块校验这些基本能力,你可以参考 GitHub 上面各种成熟的区块链实现来完成工作量证明、权益证明这样的共识算法,或者是智能合约、Dapp、侧链等等。

[C#]200 行代码使用 C# 实现区块链的更多相关文章

  1. 200 行代码使用 C# 实现区块链

    文章原文来自:Code your own blockchain in less than 200 lines of Go!,原始文章是通过 Go 语言来实现自己的区块链的,这里我们参照该文章来使用 C ...

  2. 200行代码实现简版react🔥

    200行代码实现简版react

  3. 不到 200 行代码,教你如何用 Keras 搭建生成对抗网络(GAN)【转】

    本文转载自:https://www.leiphone.com/news/201703/Y5vnDSV9uIJIQzQm.html 生成对抗网络(Generative Adversarial Netwo ...

  4. 200行代码,7个对象——让你了解ASP.NET Core框架的本质

    原文:200行代码,7个对象--让你了解ASP.NET Core框架的本质 2019年1月19日,微软技术(苏州)俱乐部成立,我受邀在成立大会上作了一个名为<ASP.NET Core框架揭秘&g ...

  5. 200行代码实现Mini ASP.NET Core

    前言 在学习ASP.NET Core源码过程中,偶然看见蒋金楠老师的ASP.NET Core框架揭秘,不到200行代码实现了ASP.NET Core Mini框架,针对框架本质进行了讲解,受益匪浅,本 ...

  6. SpringBoot,用200行代码完成一个一二级分布式缓存

    缓存系统的用来代替直接访问数据库,用来提升系统性能,减小数据库复杂.早期缓存跟系统在一个虚拟机里,这样内存访问,速度最快. 后来应用系统水平扩展,缓存作为一个独立系统存在,如redis,但是每次从缓存 ...

  7. 200 行代码实现基于 Paxos 的 KV 存储

    前言 写完[paxos 的直观解释]之后,网友都说疗效甚好,但是也会对这篇教程中一些环节提出疑问(有疑问说明真的看懂了 ),例如怎么把只能确定一个值的 paxos 应用到实际场景中. 既然 Talk ...

  8. 200行Go代码实现自己的区块链——区块生成与网络通信

    go启动后,可以用telnet登录访问. 注意端口配置写在.env里面. 源码:https://github.com/mycoralhealth/blockchain-tutorial/tree/ma ...

  9. JavaScript开发区块链只需200行代码

    用JavaScript开发实现一个简单区块链.通过这一开发过程,你将理解区块链技术是什么:区块链就是一个分布式数据库,存储结构是一个不断增长的链表,链表中包含着许多有序的记录. 然而,在通常情况下,当 ...

随机推荐

  1. c++ --> static关键字总结

    static关键字总结 C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static.前者应用于普通变量和函数,不涉及类:后者主要说明static在类中的作用. ...

  2. 如何解决js递归里面出现的堆栈溢出

    16.下面的递归代码在数组列表偏大的情况下会导致堆栈溢出.在保留递归模式的基础上,你怎么解决这个问题? var list = readHugeList(); var nextListItem = fu ...

  3. Java基础笔记(7)----三个修饰符

    abstract抽象 方法 抽象方法:abstract修饰的方法,只有声明 而没有方法的实现(连{}都没有). 语法:修饰符 返回值类型 方法名(形参列表); 注意:抽象方法 必须定义在 抽象类中. ...

  4. Linux下的进程与线程(二)—— 信号

    Linux进程之间的通信: 本文主要讨论信号问题. 在Linux下的进程与线程(一)中提到,调度器可以用中断的方式调度进程. 然而,进程是怎么知道自己需要被调度了呢?是内核通过向进程发送信号,进程才得 ...

  5. html5 input type="color"边框伪类效果

    html5为input提供了新的类型:color <input type="color" value="#999" id="color" ...

  6. Java基础学习笔记十一 Eclipse开发工具

    Eclipse是功能强大Java集成开发工具.它可以极大地提升我们的开发效率.可以自动编译,检查错误.在公司中,使用的就是Eclipse进行开发. Eclipse的下载.安装.卸载 下载 http:/ ...

  7. 如何从RxJava升级到RxJava2

    如何从RxJava升级到RxJava2. RxJava2已经推出有一年半的时间,由于之前RxJava已经在现有项目中广泛使用,而RxJava2在除了很多命名外并没有太多革新,所以相信有很多人跟我一样都 ...

  8. pip安装selenium报错:Read timed out

    今天打算把selenium降级重新安装,发现安装时总是失败,报如下错误: raise ReadTimeoutError(self._pool, None, 'Read timed out.') pip ...

  9. Bate敏捷冲刺每日报告--day4

    1 团队介绍 团队组成: PM:齐爽爽(258) 小组成员:马帅(248),何健(267),蔡凯峰(285)  Git链接:https://github.com/WHUSE2017/C-team 2 ...

  10. 冲刺No.3

    Alpha冲刺第三天 站立式会议 项目进展 今日团队对CSS与JS的基础知识进行了应用,并对网站的UI设计进行了讨论,对数据库设计进行了进一步的探讨,基本确立了各个表单的结构和内容.分割出项目基本模块 ...