如何在JavaScript中创建你自己的加密货币

432 阅读8分钟

如今,有很多方法可以以数字方式向他人汇款。大多数方法是通过银行或一些钱包,但最近,使用加密货币已经变得很流行。

加密货币是一种匿名向他人汇款的好方法。加密货币的另一个优点是其网络是去中心化的,这意味着没有人看管交易,也没有中间人。有些人认为这不是好事,因为大多数骗子都在加密货币上操作,但有些人认为这是向隐私迈出的又一步。

今天,我们将使用JavaScript创建一个加密货币。希望这篇文章能让你对如何创建自己的加密货币有一个基本的概念,你可以继续研究这些技能,以改善你财务方面的隐私。

要求

如果你想看一下代码,你可以随时参考GitHub仓库

开始工作

让我们从创建一个Node项目开始。导航到一个安全的目录,并输入以下命令来创建一个新项目。

npm init -y

这应该为你生成一个package.json 文件。如果该文件被创建,那么该项目就被创建了。

现在让我们创建一个新的文件,名为index.js 。首先,导入 crypto包,这样我们就可以在我们的项目中处理哈希值了。crypto 包帮助我们处理哈希值、签名和密钥。它允许我们在Node中进行加密转换。

这是一个与Node一起预装的软件包,所以你不需要单独安装它。

const crypto = require("crypto");

我们将在这些项目中处理四个类。它们是。

  • Transaction
  • Block
  • Chain
  • Wallet

首先让我们创建Transaction 类。

创建Transaction

一个事务的基本属性将是amountsenderPublicKey ,和recieverPublicKey 。因此,让我们为这些属性设置一个构造函数,以便我们以后可以使用这个类。

class Transaction {
  constructor(amount, senderPublicKey, recieverPublicKey) {
    this.amount = amount;
    this.senderPublicKey = senderPublicKey;
    this.recieverPublicKey = recieverPublicKey;
  }
}

我们还需要一个方法将该类的对象转换为字符串,以便将其转换为哈希值。因此,我们将创建一个函数,将对象转换为字符串,以便以后使用。

toString() {
  return JSON.stringify(this);
}

你的完整的Transaction 类应该如下所示。

class Transaction {
  constructor(amount, senderPublicKey, recieverPublicKey) {
    this.amount = amount;
    this.senderPublicKey = senderPublicKey;
    this.recieverPublicKey = recieverPublicKey;
  }
  // convert the data of the class to json so that
  // it can be converted into a hash
  toString() {
    return JSON.stringify(this);
  }
}

现在我们可以将这些事务存储在一个块内,接下来我们将创建这个块。

创建Block

术语 "区块链 "的意思和它听起来一样--一个区块链。区块链是区块(包含交易)的集合,它们彼此相连,这样我们就可以系统地访问它们。

为了开始工作,让我们来设置我们将在Block 类中使用的构造函数和属性。

class Block {
  constructor(previousHash, transaction, timestamp = Date.now()) {
    this.previousHash = previousHash;
    this.transaction = transaction;
    this.timestamp = timestamp;
  }
}

在一个区块中,我们将有previousHash (链上前一个区块的哈希值),transactionTransaction 类的对象),和timestamp (区块创建的时间)。

现在,让我们创建一个函数来生成区块的哈希值。

getHash() {
  const json = JSON.stringify(this);
  const hash = crypto.createHash("SHA256");
  hash.update(json).end();
  const hex = hash.digest("hex");
  return hex;
}

首先,我们将该对象转换为JSON格式。然后,我们创建一个SHA256 散列,这是一种不能被解密的散列方法。我们以后使用哈希值来验证区块;一旦哈希值被验证,它就为区块提供了合法性。

接下来,我们添加JSON作为数据,使其被转换为SHA256 散列。最后,我们为哈希值创建一个HEX digest,并将其返回。

现在,我们再次创建一个函数,将块对象转换成JSON。

toString() {
  JSON.stringify(this);
}

你的完整的Block 类现在应该看起来像这样。

class Block {
  constructor(previousHash, transaction, timestamp = Date.now()) {
    this.previousHash = previousHash;
    this.transaction = transaction;
    this.timestamp = timestamp;
  }
  getHash() {
    const json = JSON.stringify(this);
    const hash = crypto.createHash("SHA256");
    hash.update(json).end();
    const hex = hash.digest("hex");
    return hex;
  }
  toString() {
    return JSON.stringify(this);
  }
}

现在让我们来创建Chain 类。

创建Chain

现在我们已经准备好了我们的Block 类,我们可以在一个Chain 中填写这些块。一条链保存着区块链上发生的每一个区块,或每一笔交易。正如之前所讨论的,区块链包含了所有相互链接的区块,我们的项目需要一个Chain 类,以便将所有的区块都放在一个地方。

因为我们只需要初始化一次链,而不是多次,所以我们将在类本身中立即初始化它。

class Chain {
  static instance = new Chain();
}

让我们来设置我们的构造函数,以便在程序运行时,我们在链中准备好第一个块。这也将设置放置块的数组。

我们这样做是为了消除我们项目中的任何错误,因为我们在部分代码中依赖前一个块,所以我们需要一开始就初始化一个假块。

constructor() {
  this.chain = [new Block("", new Transaction(100, "temp", "temp"))];
}

现在,我们需要一个函数来获取链的最后一个哈希值,以便在新的块中使用这些信息。

getPreviousBlockHash() {
    // sending the entire block itself
    return this.chain[this.chain.length - 1].getHash();
  }

接下来,让我们创建一个函数,实际创建一个区块并将其插入我们的链数组中。

insertBlock(transaction, senderPublicKey, sig) {
  // create verifier
  const verify = crypto.createVerify("SHA256");
  // add the transaction JSON
  verify.update(transaction.toString());
  // Verify it with the sender's public key
  const isValid = verify.verify(senderPublicKey, sig);
  if (isValid) {
    const block = new Block(this.getPreviousBlockHash(), transaction);
    console.log("Block added", block.toString());
    this.chain.push(block);
  }
}

在这里,我们首先使用crypto 包中的createVerify 函数来验证与公钥的哈希值。然后我们使用特定交易的JSON数据,最后通过提供发送者的公钥和签名来验证。

这将返回一个布尔值,我们可以用它来检查验证是否成功或失败。如果验证成功,我们只需用这些信息创建一个新的区块并将其添加到链数组中。

现在你的Chain 类应该看起来像这样。

class Chain {
  static instance = new Chain();
  // initializing our chain with no records
  constructor() {
    this.chain = [new Block("", new Transaction(100, "temp", "temp"))];
  }
  getPreviousBlockHash() {
    // sending the entire block itself
    return this.chain[this.chain.length - 1].getHash();
  }
  insertBlock(transaction, senderPublicKey, sig) {
    // create verifier
    const verify = crypto.createVerify("SHA256");
    // add the transaction JSON
    verify.update(transaction.toString());
    // Verify it with the sender's public key
    const isValid = verify.verify(senderPublicKey, sig);
    if (isValid) {
      const block = new Block(this.getPreviousBlockHash(), transaction);
      console.log("Block added", block.toString());
      this.chain.push(block);
    }
  }
}

创建Wallet

现在让我们来创建钱包,用户可以用它来发送加密货币给其他人。每个加密货币钱包都有一对密钥:一个公钥和一个私钥。私钥用于创建新的交易(例如,发送加密货币),公钥用于验证交易和接收加密货币。

让我们首先设置构造函数,这样我们就可以在钱包启动后立即生成一对密钥。

constructor() {
  const keys = crypto.generateKeyPairSync("rsa", {
    modulusLength: 2048,
    publicKeyEncoding: { type: "spki", format: "pem" },
    privateKeyEncoding: { type: "pkcs8", format: "pem" },
  });
  this.privateKey = keys.privateKey;
  this.publicKey = keys.publicKey;
}

在这里,我们使用PEM 格式的钥匙。这是一种众所周知的格式,可以保存在用户的PC上。RSA 算法允许我们创建公钥和私钥。

现在让我们创建一个函数,它将帮助我们将加密货币发送到网络上的其他钱包。

send(amount, recieverPublicKey) {
  const transaction = new Transaction(
    amount,
    this.publicKey,
    recieverPublicKey
  );
  const shaSign = crypto.createSign("SHA256");
  // add the transaction json
  shaSign.update(transaction.toString()).end();
  // sign the SHA with the private key
  const signature = shaSign.sign(this.privateKey);
  Chain.instance.insertBlock(transaction, this.publicKey, signature);
}

在上面的代码中,我们把amountrecieverPublicKey 作为参数,并使用这些信息从Transaction 类中创建一个新对象。然后我们创建交易的哈希值,并用私钥签名。最后,我们使用insertBlock 函数将其添加到链中。

测试东西

现在一切都准备好了,你可以通过创建钱包和使用它们创建交易来进行测试。

const itachi = new Wallet();
const madara = new Wallet();
const orochimaru = new Wallet();

itachi.send(50, madara.publicKey);
madara.send(23, orochimaru.publicKey);
orochimaru.send(5, madara.publicKey);

console.log(Chain.instance);

在上面的代码中,我创建了名字随机的钱包(不完全是随机的,它们是火影忍者中的反派),然后从一个钱包向另一个钱包汇款,最后记录下链的情况。

对我来说,我的链看起来是这样的(你的可能会因为不同的哈希值而有所不同)。

Chain {
  chain: [
    Block {
      previousHash: '',
      transaction: [Transaction],
      timestamp: 1634561976555
    },
    Block {
      previousHash: 'c22300510c923a8ebf4d804f6edb4370731fcfd58f938d255852b4ea2744f20e',
      transaction: [Transaction],
      timestamp: 1634561976623
    },
    Block {
      previousHash: '1799ab15685e086cdb539e1851a759c713b3f71205664286cd4024c9f74d2a69',
      transaction: [Transaction],
      timestamp: 1634561976628
    },
    Block {
      previousHash: '1eb1f51c1b94a18f1c35e0cd81245ea6c69bac0100573cb76f3dac8026132597',
      transaction: [Transaction],
      timestamp: 1634561976629
    }
  ]
}

接下来是什么?

这只是使用JavaScript创建加密货币的基础知识。你不应该在生产中使用这个,因为加密货币涉及很多不同的东西,比如挖矿,而且涉及很多安全问题。

如果你在什么地方卡住了,你可以随时访问我的GitHub仓库,看看代码。

如果你想做更多的实验,我建议在这个项目中加入一个钱包余额系统和挖矿系统。