使用 C# 编写自己的区块链挖矿算法

[复制链接]
8463 |0
发表于 2019-8-8 23:00:16 | 显示全部楼层 |阅读模式
来自:博客园,作者:MyZony链接:https://www.cnblogs.com/myzony/p/9003628.html什么是加密货币挖掘?一个加密货币的价值体现在它的稀缺性上,如果任何人都可以任意构造一个BTC,那么BTC就毫无价值,所以BTC的区块链会让参与者完成一项“工作”,根据这个工作的最终结果还分发BTC,这个过程就被叫做“挖矿”。这就类似于一个黄金矿工花一些时间来工作,然后获得一点黄金。挖矿的原理如果你百度/谷歌搜索 BTC挖矿的原理 的话,都会给你说是计算一个复杂的数学问题而已,但是这么说的话太笼统而且也太简单。采矿引擎如何工作这是一个重要的知识点,所以我们需要了解一些密码学知识和哈希算法相关的知识,才能知道挖矿的基本原理。哈希/散列介绍单向加密人类能够理解的输入,例如 HelloWorld ,并将其扔到某个加密函数(即所谓的复杂的数学问题),加密函数的算法越复杂,逆向工程就越困难。例如一个SHA-256的例子,这个网站(链接:http://tool.oschina.net/encrypt?type=2)可以很快的计算散列值,让我们来散列“HelloWorld”看看会得到什么结果:



不管你试验几次都会得到一样的散列值,在编程中这种被称之为幂等性。加密算法的一个基本特性就是,它们很难通过逆向工程来得到明文结果,但是十分容易验证他们的加密结果,例如这里的“HelloWorld”很难通过逆向工程得到他的原明文结果,BTC采用的是 DoubleSHA-256 也就是将明文通过SHA-256计算过一次之后,再拿SHA-256针对散列值再次进行计算,在这里我们只使用SHA-256来进行加密。工作证明BTC通过让参与者散列随机的字母与数字的组合,直到计算出来的散列包含前导 0。例如我们计算886的散列值可以得到如下结果:
000f21ac06aceb9cdd0575e82d0d85fc39bed0a7a1d71970ba1641666a44f530

它返回了3个 0 作为前缀的散列值,但是我们怎么知道886计算出来的散列结果产生了3个 0呢?答案是我并不需要知道。我需要知道矿工给我的散列值前导有几个零就好了,并不需要复杂的算法来验证整个散列值的有效性。
BTC则稍微复杂一点,它每隔10分钟生成一个新的区块,新区块的散列值的难度它可以动态调整,就类似于CLR的GC一样,它可以根据目前挖矿的人数来进行难度动态调整,如果挖矿的人多的话,则调高难度,少则调低。动手开发1.项目配置首先新建一个Asp.NetCore项目,然后选择EmptyProject(空项目)类型,建立完成后无需进行任何配置。2.数据模型这里我们来创建一个具体的区块数据模型,使用的是Struct结构体。public struct Block
{
    ///
    /// 区块位置
    ///
    public int Index { get; set; }
    ///
    /// 区块生成时间戳
    ///
    public string TimeStamp { get; set; }
    ///
    /// 心率数值
    ///
    public int BPM { get; set; }
    ///
    /// 区块 SHA-256 散列值
    ///
    public string Hash { get; set; }
    ///
    /// 前一个区块 SHA-256 散列值
    ///
    public string PrevHash { get; set; }
    ///
    /// 下一个区块生成难度
    ///
    public int Difficulty { get; set; }
    ///
    /// 随机值
    ///
    public string Nonce { get; set; }
}

Difficulty是一个整形,他定义了我们希望得到哈希前导0的数量,前导0越多,生成正确的散列值就越困难,我们现在从1开始。Nonce则是每次计算块散列值所需要的随机值。3.工作证明我们首先添加一个新的方法来验证生成的散列值是否包含指定数量的前导0:
///
/// 校验 Hash 是否有效
///
/// Hash 值
/// 难度
///
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
然后我们更改了之前区块Hash的生成方法:

///
/// 计算区块 HASH 值
///
/// 区块实例
/// 计算完成的区块散列值
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随机值作为散列生成的依据。那么我们生成新区块的时候就顺便来挖矿吧:///
/// 生成新的区块
///
/// 旧的区块数据
/// 心率
/// 新的区块
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
●编号267,输入编号直达本文
●输入m获取文章目录

使用 C# 编写自己的区块链挖矿算法.jpg

使用 C# 编写自己的区块链挖矿算法.jpg
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

热门版块
快速回复 返回顶部 返回列表