Node.js实现简易区块链(三):交易数据类和挖矿机制的引入

论坛 期权论坛 期权     
MortyZHAO来说   2020-4-11 02:11   1564   0




我们知道,区块包含的最重要的信息是交易数据,从发起者(sender)到接收者(receiver),总共发起的金额(amount),交易时间(timestamp)。我们可以将之前区块data进行细化,为此我们引入Transaction类。

  1. class Transaction {
  2.     constructor(sender, receiver, amount) {
  3.         this.sender = sender;
  4.         this.receiver = receiver;
  5.         this.amount = amount;
  6.         this.timestamp = Date.now();
  7.     }
  8. }
复制代码


在比特币构想中,比特币是通过个人挖矿的方式,系统奖励比特币的方式将区块添加到链上。因此,我们为区块添加一个时间戳(区块创建时间),哈希值应由交易数据、随机数、时间戳、前区哈希值几部分组成计算;此外,为链添加交易资源池,用于存储所有交易信息,矿工奖励金额两个属性。


我们用代码完成上述操作。

  1. class Block {
  2.     constructor(transactions, previousHash, Hash) {
  3.         this.transactions = transactions;
  4.         this.previousHash = previousHash;
  5.         this.hash = this.computeHash();
  6.         // 添加成员属性:随机数,参与区块哈希值的运算
  7.         // 初始值设置为1
  8.         this.nonce = 1;
  9.         // 添加属性:区块创建时间
  10.         this.timestamp = Date.now();
  11.     }
  12.     // 计算当前区块的哈希值
  13.     computeHash() {
  14.         return sha256(
  15.             // 将交易数据“们”字符串化
  16.             JSON.stringify(this.transactions) +
  17.             this.previousHash +
  18.             this.nonce +
  19.             this.timestamp
  20.         ).toString();
  21.     }
  22. class Chain {
  23.     constructor() {
  24.         this.chain = [this.createGenesisBlock()];
  25.         // 增加一个属性:工作量证明机制的难度
  26.         // 设置为3:检查区块哈希值起始3位为0
  27.         this.difficulty = 3;
  28.         // 交易数据资源池:将所有交易数据添加进池中
  29.         this.transactionsPool = [];
  30.         // 矿工奖励:2个币
  31.         this.minerReward = 2;
  32.     }
复制代码


我们想一下矿工“挖矿”操作,其实就是上篇文章《Node.js实现简易区块链(二):工作量证明机制的引入》中实现的生成满足工作量证明机制难度要求的区块哈希值,因此我们复用这块代码就OK了。

  1.     // 增加方法:用于生成满足工作量证明机制难度的区块哈希值
  2.     // 可视为“挖矿操作”
  3.     createHashForPoW(difficulty) {
  4.         // 如果区块哈希值前几位不满足工作量证明机制要求
  5.         // 重新计算区块哈希值
  6.         while (true) {
  7.             if (this.hash.substring(0, difficulty)
  8.                 !== this.getNumberOfZeros(difficulty)) {
  9.                 this.nonce++;
  10.                 this.hash = this.computeHash();
  11.             }
  12.             else {
  13.                 break;
  14.             }
  15.         }
  16.     }
复制代码


我们接下来需要实现链将交易数据添加到资源池,以及发放矿工奖励两个方法的实现。

  1.     // 将交易数据添加至交易资源池中
  2.     addTransactionToPool(transaction) {
  3.         this.transactionsPool.push(transaction);
  4.     }
  5.     // 将交易数据“们”们添加至交易资源池中
  6.     addTransactionsToPool(transactions) {
  7.         for (let transaction of transactions) {
  8.             this.addTransactionToPool(transaction);
  9.         }
  10.     }
  11.     // 发放矿工奖励
  12.     sendMinerReward(minerAddress) {
  13.         const minerRewardTransaction = new Transaction(
  14.             '',
  15.             minerAddress,
  16.             this.minerReward
  17.         );
  18.         this.transactionsPool.push(minerRewardTransaction);
  19.         // 创建一个新区块
  20.         const newBlock = new Block(
  21.             this.transactionsPool,
  22.             this.getPreviousBlock().hash
  23.         );
  24.         // 挖矿
  25.         newBlock.createHashForPoW(this.difficulty);
  26.         // 将区块添加到链上
  27.         this.chain.push(newBlock);
  28.         // 资源池清空:不需要所有区块重复记录交易数据
  29.         this.transactionsPool = [];
  30.     }
复制代码


到此,代码实现基本完成了,我们再写一段测试代码进行测试:我们创建两条交易数据,并将它们添加至链上,通过发放矿工奖励的方式吸引矿工们挖矿。



  1. // 创建一个新链
  2. const chain = new Chain();
  3. // 创建两条交易数据
  4. const transaction1 = new Transaction('addr1', 'addr2', 2);
  5. const transaction2 = new Transaction('addr2', 'addr1', 1);
  6. const transactions = [transaction1, transaction2];
  7. // 将交易数据“们”添加到链上
  8. chain.addTransactionsToPool(transactions);
  9. // 发放矿工奖励
  10. chain.sendMinerReward('addr3');
  11. // 查看链上信息
  12. console.log(chain);
  13. // 查看第二个区块的交易数据
  14. console.log(chain.chain[1].transactions);
复制代码


测试代码如下:

  1. // 打印结果
  2. Chain {
  3.   chain: [
  4.     Block {
  5.       transactions: 'genesisBlock',
  6.       previousHash: '',
  7.       hash: '83b54c90a4bf904ef7b15fa78d3a08cbe3122bc590ec2a7ce9f7e0915f2a4a41',
  8.       nonce: 1,
  9.       timestamp: 1585799587502
  10.     },
  11.     Block {
  12.       transactions: [Array],
  13.       previousHash: '83b54c90a4bf904ef7b15fa78d3a08cbe3122bc590ec2a7ce9f7e0915f2a4a41',
  14.       hash: '00004f9116557429477ab3d71f76b155dcc049cc4dec49f30726498a803c0178',
  15.       nonce: 2733,
  16.       timestamp: 1585799587502
  17.     }
  18.   ],
  19.   difficulty: 3,
  20.   transactionsPool: [],
  21.   minerReward: 2
  22. }
  23. [
  24.   Transaction {
  25.     sender: 'addr1',
  26.     receiver: 'addr2',
  27.     amount: 2,
  28.     timestamp: 1585799587502
  29.   },
  30.   Transaction {
  31.     sender: 'addr2',
  32.     receiver: 'addr1',
  33.     amount: 1,
  34.     timestamp: 1585799587502
  35.   },
  36.   Transaction {
  37.     sender: '',
  38.     receiver: 'addr3',
  39.     amount: 2,
  40.     timestamp: 1585799587502
  41.   }
  42. ]
复制代码


可以看到区块已经包含了三条交易数据,分别是我们创建的两条交易数据以及发放的矿工奖励数据,测试成功。


但是我们知道,交易数据并非完全是合法有效的,如果挖取非真实的交易数据带来的是CPU算力的浪费,我们需要一种方式去验证其有效性。在下篇文章中,遵循中本聪的构想,我们采用数字签名的方式解决这一问题,欢迎大家持续关注!


Ps:个人博客与公众号同步更新,点击阅读原文即可访问!



   
   
     
      
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:54
帖子:2
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP