[C#]200 行代码使用 C# 实现区块链
文章原文来自:Code your own blockchain in less than 200 lines of Go!,原始文章是通过 Go 语言来实现自己的区块链的,这里我们参照该文章来使用 C# + Asp.Net Core 实现自己的区块链。在这里我也参考了 这篇译文 。
1.项目配置
首先新建一个 Asp.Net Core 项目,然后选择 Empty Project(空项目) 类型,建立完成后无需进行任何配置。
2.数据模型
这里我们来创建一个具体的区块数据模型,使用的是 Struct 结构体。
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 值,这样就以正确的块顺序构建出链:
4.散列与生成区块
使用散列是因为可以使用极少的控件生成每一个区块的唯一标识,而且可以维持整个区块链的完整性,通过每个区块存储的前一个链的散列值,我们就可以确保区块链当中每一个区块的正确性,任何针对区块的无效更改都会导致散列值的改变,也就破坏了区块链。
那么我们就在 BlockGenerator 当中添加一个函数用于计算 Block 的 Hash 值:
/// <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 值,之后我们就可以来编写一个生成块的函数:
/// <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();
}
5.校验区块
每一个区块都是不可信的,所以我们需要在生成新的区块的时候对其进行校验,校验规则如下:
- 校验新区块与旧区块的 Index 是否正确递增
- 校验新区块的 Hash 值是否正确
- 校验新区块的 PrevHash 值是否与旧区块的 Hash 值匹配
有了上述几种条件,我们可以编写一个校验函数如下:
/// <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;
}
除开区块校验的问题之外,如果有两个节点被分别添加到各自的区块链上,我们应该始终以最长的那一条为主线,因为最长的那一条意味着他的区块数据始终是最新的。
So,我们还需要一个更新最新区块的函数:
/// <summary>
/// 如果新的区块链比当前区块链更新,则切换当前区块链为最新区块链
/// </summary>
/// <param name="newBlockChain">新的区块链</param>
public static void SwitchChain(List<Block> newBlockChain)
{
if (newBlockChain.Count > _blockChain.Count)
{
_blockChain = newBlockChain;
}
}
6.集成到 Web 当中
现在整个区块链的基本操作已经完成,现在我们需要让他运转起来,我们来到 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));
});
});
7.最终效果
我们先通过 PostMan 来构建一个创世块:
然后我们尝试多添加几个之后,访问 BlockChain 来查看已经存在的区块链结构:
8.结语
通过以上代码我们完成了一个简陋的区块链,虽然十分简陋,但是已经具备了块生成,散列计算,块校验这些基本能力,你可以参考 GitHub 上面各种成熟的区块链实现来完成工作量证明、权益证明这样的共识算法,或者是智能合约、Dapp、侧链等等。
[C#]200 行代码使用 C# 实现区块链的更多相关文章
- 200 行代码使用 C# 实现区块链
文章原文来自:Code your own blockchain in less than 200 lines of Go!,原始文章是通过 Go 语言来实现自己的区块链的,这里我们参照该文章来使用 C ...
- 200行代码实现简版react🔥
200行代码实现简版react
- 不到 200 行代码,教你如何用 Keras 搭建生成对抗网络(GAN)【转】
本文转载自:https://www.leiphone.com/news/201703/Y5vnDSV9uIJIQzQm.html 生成对抗网络(Generative Adversarial Netwo ...
- 200行代码,7个对象——让你了解ASP.NET Core框架的本质
原文:200行代码,7个对象--让你了解ASP.NET Core框架的本质 2019年1月19日,微软技术(苏州)俱乐部成立,我受邀在成立大会上作了一个名为<ASP.NET Core框架揭秘&g ...
- 200行代码实现Mini ASP.NET Core
前言 在学习ASP.NET Core源码过程中,偶然看见蒋金楠老师的ASP.NET Core框架揭秘,不到200行代码实现了ASP.NET Core Mini框架,针对框架本质进行了讲解,受益匪浅,本 ...
- SpringBoot,用200行代码完成一个一二级分布式缓存
缓存系统的用来代替直接访问数据库,用来提升系统性能,减小数据库复杂.早期缓存跟系统在一个虚拟机里,这样内存访问,速度最快. 后来应用系统水平扩展,缓存作为一个独立系统存在,如redis,但是每次从缓存 ...
- 200 行代码实现基于 Paxos 的 KV 存储
前言 写完[paxos 的直观解释]之后,网友都说疗效甚好,但是也会对这篇教程中一些环节提出疑问(有疑问说明真的看懂了 ),例如怎么把只能确定一个值的 paxos 应用到实际场景中. 既然 Talk ...
- 200行Go代码实现自己的区块链——区块生成与网络通信
go启动后,可以用telnet登录访问. 注意端口配置写在.env里面. 源码:https://github.com/mycoralhealth/blockchain-tutorial/tree/ma ...
- JavaScript开发区块链只需200行代码
用JavaScript开发实现一个简单区块链.通过这一开发过程,你将理解区块链技术是什么:区块链就是一个分布式数据库,存储结构是一个不断增长的链表,链表中包含着许多有序的记录. 然而,在通常情况下,当 ...
随机推荐
- 解决exlicpe以debug模式启动或运行速度非常慢的问题
该问题可能是由于eclipse和tomcat的交互而产生的, 在以debug模式启动tomcat时,发生了读取文件错误, eclipse自动设置了断点,导致tomcat不能正常启动. 解决方法如下:以 ...
- lua向文件中写入数据,进行记录
function readfile(path) local file = io.open(path, "r") if file then local content = file: ...
- 四则运算题目生成(python版)
四则运算题目生成-基于控制台 项目托管在码云:飞机票 需求分析 根据控制台提示信息,输入题目生成相关配置参数 题目生成数量 数字范围 式子中是否有分数 .... 程序支持 10000 题目生成 题目与 ...
- spring学习笔记二 注解及AOP
本节需要导入spring-aop包 注解 使用注解的目的是为了代替配置,在使用注解时,省略键时,则是为value赋值. 扫描某个包下的所有类中的注解 <?xml version="1. ...
- 2018上C语言程序设计(高级)作业- 第0次作业
准备工作(10分) 1.在博客园申请个人博客. 2.加入班级博客(2班班级博客链接地址)(1班班级博客链接地址) 3.关注邹欣老师博客.关注任课老师博客. 4.加入讨论小组,学习过程中遇到问题不要随意 ...
- Alpha第八天
Alpha第八天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...
- C语言指针作业
一.PTA实验作业 题目1:6-5 判断回文字符串 1. 本题PTA提交列表 2. 设计思路 3.代码截图 4.本题调试过程碰到问题及PTA提交列表情况说明. 第一次做的时候我j直接等于count,其 ...
- Beta版本展示
Beta版本展示 开发团队:MyGod 团队成员:程环宇 张芷祎 王田路 张宇光 王婷婷 源码地址:https://github.com/WHUSE2017/MyGod MyGod团队项目的目标: 让 ...
- 201621123035 《Java程序设计》第1周学习总结
1.本周学习总结 本周学习内容:Java平台概论.认识JDK规范与操作.了解JVM.JRE与JDK.撰写Java原始码.path是什么 关键词:JVM.JRE.JDK 联系:JVM是Java虚拟机的缩 ...
- 2018上c语言第0次作业
随笔: 1.翻阅邹欣老师博客关于师生关系博客,并回答下列问题,每个问题的答案不少于500字: (1)最理想的师生关系是健身教练和学员的关系,在这种师生关系中你期望获得来自老师的哪些帮助? 答:对此问题 ...