文章原文来自:Code your own blockchain mining algorithm in Go! ,原始文章通过 Go 语言来实现的,这里仍然是承接上一篇文章,来使用 C# + .Net Core 实现我们的挖矿算法。

强烈建议阅读前先阅读这篇文章

什么是加密货币挖掘?

一个加密货币的价值体现在它的稀缺性上,如果任何人都可以任意构造一个比特币,那么比特币就毫无价值,所以比特币的区块链会让参与者完成一项“工作”,根据这个工作的最终结果还分发比特币,这个过程就被叫做“挖矿”。这就类似于一个黄金矿工花一些时间来工作,然后获得一点黄金。

挖矿的原理

如果你百度/谷歌搜索 比特币挖矿的原理 的话,都会给你说是计算一个复杂的数学问题而已,但是这么说的话太笼统而且也太简单。采矿引擎如何工作这是一个重要的知识点,所以我们需要了解一些密码学知识和哈希算法相关的知识,才能知道挖矿的基本原理。

哈希/散列介绍

单向加密人类能够理解的输入,例如 Hello World ,并将其扔到某个加密函数(即所谓的复杂的数学问题),加密函数的算法越复杂,逆向工程就越困难。

例如一个 SHA - 256 的例子,这个网站可以很快的计算散列值,让我们来散列 “Hello World” 看看会得到什么结果:

不管你试验几次都会得到一样的散列值,在编程中这种被称之为幂等性

加密算法的一个基本特性就是,它们很难通过逆向工程来得到明文结果,但是十分容易验证他们的加密结果,例如这里的 “Hello World” 很难通过逆向工程得到他的原明文结果,比特币采用的是 Double SHA-256 也就是将明文通过 SHA-256 计算过一次之后,再拿 SHA-256 针对散列值再次进行计算,在这里我们只使用 SHA-256 来进行加密。

工作证明

比特币通过让参与者散列随机的字母与数字的组合,直到计算出来的散列包含前导 0

例如我们计算 886 的散列值可以得到如下结果:

000f21ac06aceb9cdd0575e82d0d85fc39bed0a7a1d71970ba1641666a44f530

它返回了 30 作为前缀的散列值,但是我们怎么知道 886 计算出来的散列结果产生了 30 呢?

答案是我并不需要知道。。。我需要知道矿工给我的散列值前导有几个零就好了,并不需要复杂的算法来验证整个散列值的有效性。

比特币则稍微复杂一点,它每隔 10 分钟生成一个新的区块,新区块的散列值的难度它可以动态调整,就类似于 CLR 的 GC 一样,它可以根据目前挖矿的人数来进行难度动态调整,如果挖矿的人多的话,则调高难度,少则调低。

动手开发

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; }
/// <summary>
/// 下一个区块生成难度
/// </summary>
public int Difficulty { get; set; }
/// <summary>
/// 随机值
/// </summary>
public string Nonce { get; set; }
}

Difficulty 是一个整形,他定义了我们希望得到哈希前导 0 的数量,前导 0 越多,生成正确的散列值就越困难,我们现在从 1 开始。

Nonce 则是每次计算块散列值所需要的随机值。

3. 工作证明

我们首先添加一个新的方法来验证生成的散列值是否包含指定数量的前导 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;
}

然后我们更改了之前区块 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}{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 随机值作为散列生成的依据。

那么我们生成新区块的时候就顺便来挖矿吧:

/// <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,
Difficulty = Difficulty
}; // 挖矿 ing...
for (int i = 0; ; i++)
{
newBlock.Nonce = i.ToString("x2");
if (!IsHashValid(CalculateHash(newBlock), Difficulty))
{
Console.WriteLine($"目前结果:{CalculateHash(newBlock)} ,正在计算中...");
Task.Delay(1);
continue;
}
else
{
Console.WriteLine($"目前结果:{CalculateHash(newBlock)} ,计算完毕...");
newBlock.Hash = CalculateHash(newBlock);
break;
}
} // 原有代码
// newBlock.Hash = CalculateHash(newBlock);
return newBlock;
}

效果

结语

其实代码并不复杂,但是这几十行代码表明了区块链挖矿的本质,后面你可以参考原文实现 P2P 与 股权权益证明方法与智能合约。

项目代码地址:http://git.myzony.com/Zony/BlockChain.git

PDF 文件地址:http://git.myzony.com/Zony/BlockChain/src/6ef2bdb7d9a086d8e214603c88670896de6b108c/PDF 文件/[C%23] 使用 C%23 编写自己区块链的挖矿算法.pdf

Code a simple P2P blockchain in Go.

[C#]使用 C# 编写自己的区块链挖矿算法的更多相关文章

  1. [转帖][区块链]共识算法(POW,POS,DPOS,PBFT)介绍和心得

    [区块链]共识算法(POW,POS,DPOS,PBFT)介绍和心得 置顶 2017-03-12 18:31:19 乐扣老师lekkoliu 阅读数 127953  收藏 更多 分类专栏: 技术管理 区 ...

  2. 【原】用Java编写第一个区块链(一)

    写这篇随笔主要是尝试帮助自己了解如何学习区块链技术开发. [本文禁止任何形式的全文粘贴式转载,本文来自 zacky31 的随笔] 目标: 创建一个最基本的"区块链" 实现一个简单的 ...

  3. 用Java编写第一个区块链

    原文地址:https://www.cnblogs.com/zacky31/p/9057193.html 目标: 创建一个最基本的“区块链” 实现一个简单的挖矿系统 前提: 对面向对象编程有一定的基础 ...

  4. 【原】用Java编写第一个区块链(二)

    这篇文章将去介绍如何使用区块链进行交易. [本文禁止任何形式的全文粘贴式转载,本文来自 zacky31 的随笔] 目标: 在上一篇文章中,我们已经创建了一个可信任的区块链.但是目前所创建的链中包含的有 ...

  5. [区块链] 共识算法之争(PBFT,Raft,PoW,PoS,DPoS,Ripple)

    近几天对区块链中几种常见的共识机制(PBFT,Raft,PoW,PoS,DPoS,Ripple)进行了总结.尽量使用简单易懂语言,篇幅较大,想了解的可以只读每个算法介绍中前边的原理.本篇文章主要参考& ...

  6. 区块链共识算法 PBFT(拜占庭容错)、PAXOS、RAFT简述

    共识算法 区块链中最重要的便是共识算法,比特币使用的是POS(Proof of Work,工作量证明),以太币使用的是POS(Proof of Stake,股权证明)使得算理便的不怎么重要了,而今PO ...

  7. 区块链共识算法|RAFT和PBFT的区别

    这里有个很形象的比喻: 一个团队一定会有一个老大和普通成员.对于 raft 算法,共识过程就是:只要老大还没挂,老大说什么,我们(团队普通成员)就做什么,坚决执行.那什么时候重新老大呢?只有当老大挂了 ...

  8. 未来-区块链-Micron:区块链永远不会忘记:内存对这项革命性技术的推动作用

    ylbtech-未来-区块链-Micron:区块链永远不会忘记:内存对这项革命性技术的推动作用 1.返回顶部 1. 俗话说,大象永远不会忘记.区块链亦是如此. 内存是区块链的核心,它是一种以关键方式构 ...

  9. 只用120行Java代码写一个自己的区块链-2网络

    已经看完第一章的内容了吗,欢迎回来. 上一章我们介绍了关于怎么去编写自己的区块链,完成哈希和新块的校验.但是它只是在一个终端(结点)上跑.我们怎么样来连接其他结点以及贡献新的块呢,怎么样广播到其他结点 ...

随机推荐

  1. Redefine:Change in the Changing World

    EMC World 2014的主题就是REDEFINE.的确,现在科技的发展在重新定义了技术,影响了生活,改变了你我. 对于一个有数万员工,甚至数十万员工的企业来说,Redefine无疑更加具有挑战, ...

  2. 【项目管理】 项目管理术语总结 (PMP培训笔记)

    1. 项目管理简介 (1) 项目管理定义 项目管理定义 : 将 知识, 技能, 工具 与 技术 应用与项目活动, 以满足项目的要求; (2) 现代项目管理 现代项目管理与传统项目管理区别 : -- 传 ...

  3. web安全认证机制知多少

    如今web服务随处可见,成千上万的web程序被部署到公网上供用户访问,有些系统只针对指定用户开放,属于安全级别较高的web应用,他们需要有一种认证机制以保护系统资源的安全,本文将探讨五种常用的认证机制 ...

  4. mixer: 一个用go实现的mysql proxy

    介绍 mixer是一个用go实现的mysql proxy,支持基本的mysql代理功能. mysql的中间件很多,对于市面上面现有的功能强大的proxy,我主要考察了如下几个: mysql-proxy ...

  5. [RDLC]一步一步教你使用RDLC(一)

    一:加数据集,并且命名为Quotation,如下图所示: 二: 添加一张报表,命名为Quotation,如下图所示: 向报表中添加"表"这一项,如下图所示: 这时就弹出一个选择数据 ...

  6. ECMAScript中所有的函数的参数都是按值传递的

    看下面一段代码 function setName(obj){ obj.name='Nicholas'; obj=new Object(); obj.name="Greg"; } v ...

  7. ORM对象关系映射之使用GreenDAO进行CRUD操作

    在Android中,我们都知道使用的数据库是SQLite,而使用这种原生的数据库非常繁琐,它对表的管理和进行CRUD操作都需要我们写sql语句,在进行多表关联的操作上,更是需要写一堆sql,而且维护起 ...

  8. 传输控制协议(TCP) -- TCP状态转换图

    TCP状态转换图 在<UNIX网络编程 卷1>一书中,作者给出了TCP状态转换图(如下).本文也将围绕此图进行阐释. 注:上图红框表示比较特殊的地方. TCP状态转换两条主线 图2-4中的 ...

  9. Otto事件总线框架的使用

    Otto是一个在Android中的事件总线框架,它是square的一个开源框架,具体介绍点击这里,项目下载点击这里 为什么要使用Otto事件总线: 通常来说在Android中: 1.Activity与 ...

  10. 【Android 应用开发】Android中的回调Callback

    回调就是外部设置一个方法给一个对象, 这个对象可以执行外部设置的方法, 通常这个方法是定义在接口中的抽象方法, 外部设置的时候直接设置这个接口对象即可. 例如给安卓添加按钮点击事件, 我们创建了OnC ...