主页 > 区块链 > 比特币和以太币这样的加密货币是如何工作的

比特币和以太币这样的加密货币是如何工作的

佚名 区块链 2021年11月29日

很多朋友都听说过比特币和以太坊等加密货币,但只有少数人了解它们背​​后的技术。接下来,我将通过本文向您介绍如何使用 JavaScript 创建一个简单的区块链来演示它们。内部是怎么操作的,有兴趣的朋友一起来看看吧

几乎每个人都听说过比特币和以太坊等加密货币区块链编程实现,但很少有人了解它们背​​后的技术。在本文中区块链编程实现,我将使用 JavaScript 创建一个简单的区块链来演示它们的内部工作原理。我会称它为SavjeeCoin!

全文分为三个部分:

第 1 部分:实现一个基本的区块链

第 2 部分:实施 POW

Part3:交易挖矿奖励

Part1:实现一个基本的区块链

区块链

区块链是由任何人都可以访问的块组成的公共数据库。看起来没什么特别的,但它们有一个有趣的特性:它们是不可变的。一旦一个区块被添加到区块链中,除非剩余的区块无效,否则它不会被更改。

这就是加密货币基于区块链的原因。你绝对不希望人们在交易完成后更改交易!

创建块

区块链由许多块链接(这听起来没什么错......)。链上的区块以某种方式让我们能够检测是否有人操纵了任何先前的区块。

那么我们如何保证数据的完整性呢?每个块都包含一个根据其内容计算的哈希值。它还包含前一个块的哈希值。

下面是一个用 JavaScript 编写的块类的粗略外观:

const SHA256 = require("crypto-js/sha256");
class Block {
 constructor(index, timestamp, data, previousHash = '') {
 this.index = index;
 this.previousHash = previousHash;
 this.timestamp = timestamp;
 this.data = data;
 this.hash = this.calculateHash();
 }
 calculateHash() {
 return SHA256(this.index + this.previousHash + this.timestamp + JSON.stringify(this.data)).toString();
 }
}

因为 JavaScript 不支持 sha256,所以我引入了 crypto-js 库。然后我定义了一个构造函数来初始化我的块的属性。每个块都有一个索引属性,告诉我们这个块在整个链中的位置。我们还生成了时间戳和一些需要存储在块中的数据。最后一个是前一个块的哈希值。

创建一个链

现在我们可以链接区块链类中的块了!下面是用 JavaScript 实现的代码:

class Blockchain{
 constructor() {
 this.chain = [this.createGenesisBlock()];
 }
 createGenesisBlock() {
 return new Block(0, "01/01/2017", "Genesis block", "0");
 }
 getLatestBlock() {
 return this.chain[this.chain.length - 1];
 }
 addBlock(newBlock) {
 newBlock.previousHash = this.getLatestBlock().hash;
 newBlock.hash = newBlock.calculateHash();
 this.chain.push(newBlock);
 }
 isChainValid() {
 for (let i = 1; i < this.chain.length; i++){
  const currentBlock = this.chain[i];
  const previousBlock = this.chain[i - 1];
  if (currentBlock.hash !== currentBlock.calculateHash()) {
  return false;
  }
  if (currentBlock.previousHash !== previousBlock.hash) {
  return false;
  }
 }
 return true;
 }
}

在构造函数中,我通过创建一个包含创世块的数组来初始化整个链。第一个块是特殊的,因为它不能指向前一个块。我还添加了以下两种方法:

最后,我创建了一个 isChainValid() 以确保没有人篡改区块链。它将遍历所有块以检查每个块的哈希是否正确。它将通过比较previousHash来检查每个块是否指向正确的前一个块。如果一切正常,它将返回真,否则将返回假。

使用区块链

我们的区块链类已经写好了,可以真正开始使用了!

let savjeeCoin = new Blockchain();
savjeeCoin.addBlock(new Block(1, "20/07/2017", { amount: 4 }));
savjeeCoin.addBlock(new Block(2, "20/07/2017", { amount: 8 }));

在这里,我刚刚创建了一个区块链实例并将其命名为 SavjeeCoin!然后我在链中添加了一些块。该块可以包含您想要的任何数据,但在上面的代码中,我选择添加一个具有数量属性的对象。

尝试一下!

在介绍中,我说过区块链是不可变的。一旦添加,块就不能更改。让我们试试吧!

// 检查是否有效(将会返回true)
console.log('Blockchain valid? ' + savjeeCoin.isChainValid());
// 现在尝试操作变更数据
savjeeCoin.chain[1].data = { amount: 100 };
// 再次检查是否有效 (将会返回false)
console.log("Blockchain valid? " + savjeeCoin.isChainValid());

我将在开始时通过运行 isChainValid() 来验证整个链的完整性。我们已经操作过任何块,所以它会返回 true。

之后,我更改了链上第一个区块的数据(索引为1)。之后,我再次检查了整个链的完整性,发现返回false。我们的整个链不再有效。

综上所述

这个小栗子还远未完成。它尚未实施 POW(工作量证明)或 P2P 网络与其他矿工进行通信。

但他确实证明了区块链是如何运作的。很多人认为原理会很复杂,但是这篇文章证明了区块链的基本概念非常容易理解和实现。

Part2:实施POW(Proof-of-Work:Proof of Work)

在 part1 中,我们用 JavaScript 创建了一个简单的区块链来演示区块链的工作原理。然而,这个实现并不完整,很多人发现系统仍然可以被篡改。这是正确的!我们的区块链需要另一种机制来防御攻击。那么让我们看看我们如何做到这一点!

问题

现在我们可以非常快速地创建块并将它们添加到我们的区块链中。但这会导致三个问题:

显然我们需要一个方案来解决这些问题:POW。

什么是战俘

POW 是在创建第一个区块链之前就存在的机制。这是一种简单的技术,它使用一定量的计算来防止滥用。工作量是防止垃圾填充和篡改的关键。如果它需要大量的计算能力,那么填充垃圾就不再值得了。

比特币通过要求哈希为特定数量的零来实现 POW。这也叫难度

但是等一下!如何更改块的哈希值?在比特币场景中,一个区块包含各种金融交易信息。我们当然不想为了获得正确的哈希而混淆这些数据。

为了解决这个问题,区块链增加了一个 nonce 值。Nonce 是找到有效哈希的次数。而且,由于hash函数的输出无法预测,只能尝试大量组合,才能得到满足难度条件的hash。找到一个有效的哈希值(创建一个新区块)在圈内被称为挖矿。

在比特币场景中,POW 保证每 10 分钟只能添加一个区块。您可以想象垃圾邮件发送者创建新区块需要多少计算能力。他们很难欺骗网络,更别说篡改整个链条了。

实现 POW

我们怎样才能实现它?让我们首先修改我们的块类并在其构造函数中添加 Nonce 变量。我将初始化它并将其值设置为 0。

constructor(index, timestamp, data, previousHash = '') {
 this.index = index;
 this.previousHash = previousHash;
 this.timestamp = timestamp;
 this.data = data;
 this.hash = this.calculateHash();
 this.nonce = 0;
}

我们还需要一个新的方法来增加 Nonce 直到我们得到一个有效的哈希值。强调一下,这是由难度决定的。所以我们将接收难度作为参数。

mineBlock(difficulty) {
 while (this.hash.substring(0, difficulty) !== Array(difficulty + 1).join("0")) {
  this.nonce++;
  this.hash = this.calculateHash();
 }
 console.log("BLOCK MINED: " + this.hash);
}

最后,我们还需要更改 calculateHash() 函数。因为他还没有使用Nonce来计算hash。

calculateHash() {
 return SHA256(this.index +
 this.previousHash +
 this.timestamp +
 JSON.stringify(this.data) +
 this.nonce
 ).toString();
}

将它们组合起来,您将获得如下所示的块类:

class Block {
 constructor(index, timestamp, data, previousHash = '') {
 this.index = index;
 this.previousHash = previousHash;
 this.timestamp = timestamp;
 this.data = data;
 this.hash = this.calculateHash();
 this.nonce = 0;
 }
 calculateHash() {
 return SHA256(this.index + this.previousHash + this.timestamp + JSON.stringify(this.data) + this.nonce).toString();
 }
 mineBlock(difficulty) {
 while (this.hash.substring(0, difficulty) !== Array(difficulty + 1).join("0")) {
  this.nonce++;
  this.hash = this.calculateHash();
 }
 console.log("BLOCK MINED: " + this.hash);
 }
}

修改区块链

现在我们的区块有 Nonce 并且可以被挖掘,我们还需要确保我们的区块链支持这种新行为。我们先给区块链添加一个新的属性来追踪整条链的难度。我将其设置为 2(这意味着块的哈希值必须以 2 个零开头)。

constructor() {
 this.chain = [this.createGenesisBlock()];
 this.difficulty = 2;
}

现在剩下要做的就是更改 addBlock() 方法以确保在将块添加到链之前实际开采该块。下面我们将难度传递给块。

addBlock(newBlock) {
 newBlock.previousHash = this.getLatestBlock().hash;
 newBlock.mineBlock(this.difficulty);
 this.chain.push(newBlock);
}

就是这样!我们的区块链现在有 POW 来抵抗攻击。

测试

现在让我们测试一下我们的区块链,看看会在 POW 下添加一个新块会产生什么效果。我将使用以前的代码。我们将创建一个新的区块链实例并向其添加 2 个区块。

let savjeeCoin = new Blockchain();
console.log('Mining block 1');
savjeeCoin.addBlock(new Block(1, "20/07/2017", { amount: 4 }));
console.log('Mining block 2');
savjeeCoin.addBlock(new Block(2, "20/07/2017", { amount: 8 }));

如果你运行上面的代码,你会发现添加新块还是很快的。这是因为当前难度只有2(或者你的电脑性能很好)。

如果你创建一个难度为5的区块链实例,你会发现你的电脑大约需要十秒钟才能挖矿。随着难度的增加,你的防御攻击的保护程度就越高。

广告位
标签: 比特币区块   比特币   区块链