Как создать свою криптовалюту с помощью JavaScript

Как создать свою криптовалюту с помощью JavaScript

@WebMentor

Оригинал статьи на английском


В настоящее время существует множество способов отправить деньги кому-то в цифровом виде. Большинство способов — через банк или какие-то кошельки, но в последнее время стало популярным использовать криптовалюту.

Криптовалюта — отличный способ анонимно отправить деньги другим. Еще одним преимуществом криптовалют является то, что их сеть децентрализована, что означает, что никто не просматривает транзакцию и не имеет посредников. Кто-то считает это нехорошим, потому что большинство мошенников оперируют криптовалютами, а кто-то считает, что это еще один шаг к конфиденциальности.

Сегодня мы собираемся создать криптовалюту с помощью JavaScript. Надеюсь, эта статья даст вам общее представление о том, как создать собственную криптовалюту, и вы сможете продолжить работу над этими навыками для повышения конфиденциальности своих финансов.

Требования

  • Node.js  установлен на вашем компьютере
  • Редактор кода (я предпочитаю Visual Studio Code )
  • Знание Node.js

Вы всегда можете обратиться к репозиторию GitHub , если хотите взглянуть на код.

Начало

Давайте начнем с создания проекта Node. Перейдите в безопасный каталог и введите следующую команду, чтобы создать новый проект:

npm init -y

Это должно сгенерировать файл для вас. Если файл создан, то создается проект.package.json

Теперь давайте создадим новый файл с именем . Во-первых, импортируйте  пакет, чтобы мы могли работать с хэшами в нашем проекте. Пакет помогает нам работать с хэшами, подписями и ключами. Это позволяет нам выполнять криптографическое преобразование в Node.index.jscryptocrypto

Это предустановленный пакет с 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(хэш предыдущего блока в цепочке), transaction(объект класса Transaction) и 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дайджест для хеша и возвращаем его.

Теперь снова создадим функцию для преобразования блочного объекта в 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);
  }
}

Здесь мы сначала используем createVerifyфункцию из cryptoпакета для проверки хэшей с открытыми ключами. Затем мы используем данные из 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формат для ключей. Это хорошо известный формат, который можно сохранить на компьютере пользователя. Алгоритм 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);
}

В приведенном выше коде мы берем amountи recieverPublicKeyв качестве параметров и создаем новый объект из 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 , чтобы посмотреть код.

Если вы хотите поэкспериментировать еще больше, я бы порекомендовал включить в этот проект систему баланса кошелька и систему майнинга.

LogRocket : более простая отладка ошибок JavaScript благодаря пониманию контекста.

Отладка кода всегда утомительная задача. Но чем больше вы понимаете свои ошибки, тем легче их исправить.

LogRocket позволяет вам понять эти ошибки новыми и уникальными способами. Наше решение для мониторинга внешнего интерфейса отслеживает взаимодействие пользователей с вашим внешним интерфейсом JavaScript, чтобы дать вам возможность узнать, что именно пользователь сделал, что привело к ошибке.

Баннер бесплатной пробной версии LogRocket Dashboard

LogRocket записывает журналы консоли, время загрузки страниц, трассировки стека, медленные сетевые запросы/ответы с заголовками и телами, метаданными браузера и пользовательскими журналами. Понимание влияния вашего кода JavaScript никогда не будет таким простым!

Попробуйте бесплатно .


Перевод статьи LogRocket


Report Page