服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - 使用C#编写自己的区块链挖矿算法

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

2022-08-01 11:13MyZony C#

这篇文章主要介绍了使用C#编写自己的区块链挖矿算法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

什么是加密货币挖掘?

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

挖矿的原理

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

哈希/散列介绍

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

例如一个 sha - 256 的例子,这个网站(链接: )可以很快的计算散列值,让我们来散列 “hello world” 看看会得到什么结果:

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

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

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

工作证明

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

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

000f21ac06aceb9cdd0575e82d0d85fc39bed0a7a1d71970ba1641666a44f530

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

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

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

动手开发

1.项目配置

首先新建一个 asp.net core 项目,然后选择 empty project(空项目) 类型,建立完成后无需进行任何配置。

2.数据模型

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 :

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/// <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 的生成方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/// <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 随机值作为散列生成的依据。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/// <summary>
/// 生成新的区块
/// </summary>
/// <param name="oldblock">旧的区块数据</param>
/// <param name="bpm">心率</param>
/// <returns>新的区块</returns>
public static block generateblock(block oldblock, int bpm)
{
  block newnewblock = new block()
  {
    index = oldblock.index + 1,
    timestamp = calculatecurrenttimeutc(),
    bpmbpm = bpm,
    prevhash = oldblock.hash,
    difficultydifficulty = 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;
}

效果

 

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

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

 

结语

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

总结

以上所述是小编给大家介绍的使用c#编写自己的区块链挖矿算法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

原文链接:http://blockchain.51cto.com/art/201908/600970.htm

延伸 · 阅读

精彩推荐
  • C#C#中自定义高精度Timer定时器的实例教程

    C#中自定义高精度Timer定时器的实例教程

    这篇文章主要介绍了C#中自定义高精度Timer定时器的实例教程,多线程的Timer编写需要注意线程安全的问题,需要的朋友可以参考下...

    winnow5892021-11-19
  • C#C#实现Nginx平滑加权轮询算法

    C#实现Nginx平滑加权轮询算法

    这篇文章主要为大家详细介绍了C#实现Nginx平滑加权轮询算法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Gangle3592022-02-27
  • C#C#中ToString数据类型格式大全(千分符)

    C#中ToString数据类型格式大全(千分符)

    这篇文章主要介绍了C#中ToString数据类型格式大全 千分符,需要的朋友可以参考下...

    C#教程网8732021-12-24
  • C#C#导入导出Excel数据的两种方法

    C#导入导出Excel数据的两种方法

    这篇文章主要为大家详细介绍了C#导入导出Excel数据的两种方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    路博林9862021-12-29
  • C#C#下listview如何插入图片

    C#下listview如何插入图片

    这篇文章主要为大家详细介绍了C#下listview如何插入图片,如何在listview中插入图片的每一个步骤为大家分享,感兴趣的朋友可以参考一下...

    C#教程网5252021-11-21
  • C#C#中foreach实现原理详解

    C#中foreach实现原理详解

    这篇文章主要为大家详细介绍了C#中foreach实现原理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    阿珑5502022-01-22
  • C#C#实现Excel表数据导入Sql Server数据库中的方法

    C#实现Excel表数据导入Sql Server数据库中的方法

    这篇文章主要介绍了C#实现Excel表数据导入Sql Server数据库中的方法,结合实例形式详细分析了C#读取Excel表数据及导入Sql Server数据库的具体操作步骤与相关操...

    aparche12132022-01-05
  • C#利用lambda表达式树优化反射详解

    利用lambda表达式树优化反射详解

    这篇文章主要给大家介绍了关于如何利用lambda表达式树优化反射的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学...

    Fode7472022-03-06