/*
作 者: itdef
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
技术交流群 群号码:432336863
欢迎c c++ windows驱动爱好者 服务器程序员沟通交流
部分老代码存放地点
http://www.oschina.net/code/list_by_user?id=614253
*/
今天,我将开启一个使用c++模拟区块链的系列,记录自己学习区块链与实践的心得体会.
通过使用c++编写和讲解一个简单的区块链代码,来加深自己对区块链原理的理解。
区块链中大量使用哈希算法。
算法将参与需要计算的整体内容全部作为元素添加至哈希计算中,最后得出一个独一无二的计算结果。
他的好处在于,可以用来验证一个文件没有被任何人更改。如果同时拥有待验证内容和哈希计算的结果,那么你可以很快验证自己的待验证内容是否正确。同时,正确内容遭到刻意的修改而计算出正确的哈希结果这种事情几乎不存在。
在这个示例中 我们使用来自Zedwood的C++ sha256函数提供我们需要的哈希计算,该链接中有sha256.h,sha256.cpp和LICENSE.txt文件,我们将它们保存在项目文件夹中。
前言少叙,开始建立工程。使用工具为vs2017,环境为windows操作系统.
创建一个窗口程序,名字叫做MyBlockChainCppSample.如图
![]()
建成后,MyBlockChainCppSample.cpp就是main文件包含main入口函数,暂时不必管它.如图
![]()
我们接下来创建区块和区块链的结构说明和实现。
区块的结构放在Block.h,由Block.cpp实现。
区块链的结构放在Blockchain.h,由Blockchain.cpp实现.
还有刚才提到的sha256.h,sha256.cpp和LICENSE.txt也要添加进工程中.
![]()
![]()
1 #pragma once
2
3
4 #include
5 #include
6
7
8 using namespacestd;9
10 #define DifficultyNum 4
11
12 classBlock {13 public:14 string sPrevHash; //记录上个块的哈希值
15 Block(uint32_t nIndexIn, const string &sDataIn); //构造函数
16 string GetHash(); //获取哈希函数
17 void MineBlock(uint32_t nDifficulty); //挖矿函数
18 private:19 uint32_t _nIndex; //该区块的索引值
20 int64_t _nNonce; //区块随机数 用于哈希值的产生??
21 string _sData; //区块描述字符
22 string _sHash; //区块哈希值
23 time_t _tTime; //创建时间
24 string _CalculateHash() const; //哈希值计算函数
25 };
Block.h
![]()
![]()
1 #include "Block.h"
2 #include "sha256.h"
3 #include
4 #include
5
6 Block::Block(uint32_t nIndexIn, const string &sDataIn) : _nIndex(nIndexIn), _sData(sDataIn) {7 _nNonce = -1;8 _tTime =time(nullptr);9 }10
11 stringBlock::GetHash() {12 return_sHash;13 }14
15 voidBlock::MineBlock(uint32_t nDifficulty) {16 char cstr[DifficultyNum + 1];17 for (uint32_t i = 0; i < DifficultyNum; ++i) {18 cstr[i] = '0';19 }20 cstr[DifficultyNum] = '\0';21 stringstr(cstr);22 do{23 _nNonce++;24 _sHash =_CalculateHash();25 } while (_sHash.substr(0, nDifficulty) !=str);26 cout << "Block mined:" << _sHash <
29
30 inline string Block::_CalculateHash() const{31 stringstream ss;32 ss << _nIndex << _tTime << _sData << _nNonce <
Block.cpp
![]()
![]()
1 #pragma once
2
3 #include
4 #include
5 #include "Block.h"
6
7 using namespacestd;8
9 classBlockchain {10 public:11 Blockchain(); //区块链构造函数
12 void AddBlock(Block bNew); //区块链添加区块函数
13 private:14 uint32_t _nDifficulty; //难度值
15 vector _vChain; //记录区块链
16 Block _GetLastBlock() const; //获取最后一个区块
17 };
Blockchain.h
![]()
![]()
1 #include "Blockchain.h"
2
3
4 Blockchain::Blockchain() {5 _vChain.emplace_back(Block(0, "Genesis Block"));6 _nDifficulty =DifficultyNum;7 }8
9 voidBlockchain::AddBlock(Block bNew) {10 bNew.sPrevHash =_GetLastBlock().GetHash();11 bNew.MineBlock(_nDifficulty);12 _vChain.push_back(bNew);13 }14
15 Block Blockchain::_GetLastBlock() const{16 return_vChain.back();17 }
Blockchain.cpp
最后的工程结构如图
![]()
在MyBlockChainCppSample.cpp中添加以下代码
#include "Blockchain.h"
int main() {
Blockchain bChain = Blockchain();
cout << "Mining block 1..." << endl;
bChain.AddBlock(Block(1, "Block 1 Data"));
cout << "Mining block 2..." << endl;
bChain.AddBlock(Block(2, "Block 2 Data"));
cout << "Mining block 3..." << endl;
bChain.AddBlock(Block(3, "Block 3 Data"));
return 0;
}
到此代码添加结束 但是VC中编译代码可能会遇到以下问题
1 提示 stdafx.h未添加 这是VC默认要添加预编译头 我们可以设置不需要预编译头来解决这个问题(也可以在每个cpp文件中添加stdafx.h)
解决方式如图
![]()
2 会提示sprintf函数 不能使用。这是因为该函数时候早期使用的,在字符串处理上可能存在潜在处理错误。我们可以定义一个宏来告知编译器我们知道此类错误并愿意使用
定义如图
![]()
最后编译结果如图
这是设置 #define DifficultyNum 6 , 难度为6的计算结果
Mining block 1...
Block mined: 000000182cfdfadfd84a0578f64d68a1c38bbaf4cbcf18027b0be00ee9a37e18
Mining block 2...
Block mined: 0000002f57459a48244bbf39d089a2b6e7b9aac8dca7ef8b7e71ef6a24753522
Mining block 3...
Block mined: 000000a2eaf0c37a192b182e038e4b20146bfdadb5fffb3bb836d8a7af89c16d
请按任意键继续. . .
这是设置 #define DifficultyNum 4 , 难度为4的计算结果
Mining block 1...
Block mined: 0000dcdb20156ad2777f685bab10bde456b756c40ac7c1a70ab5015ccf207309
Mining block 2...
Block mined: 0000350fb47c51201df28dd8e5b0baf517bcf6175dad8df29feba87b5eaadfbe
Mining block 3...
Block mined: 0000aede11083363a82c9ec43346b1895d818ecde528a171e837e5577478cd78
请按任意键继续. . .
下篇进行代码解析