От автора: в настоящее время существует множество способов отправить деньги кому-то в цифровом виде. Большинство способов — через банк или через онлайн кошельки, но в последнее время стало популярным использование криптовалюты.
Криптовалюта — отличный способ анонимно отправлять деньги другим людям. Еще одним преимуществом криптовалют является то, что их сеть децентрализована, а это означает, что никто не контролирует транзакцию и нет посредников. Одни люди думают, что это плохо, потому что большинство мошенников работают с криптовалютами, но для других — это очередной шаг к конфиденциальности.
Сегодня мы собираемся создать криптовалюту с помощью JavaScript. Надеюсь, эта статья даст вам общее представление о том, как создать собственную криптовалюту, и вы сможете продолжить работу над этими навыками для улучшения конфиденциальности своих финансов.
Требования:
Node.js установлен на вашем компьютере
Редактор кода (я предпочитаю Visual Studio Code)
Практическое знание Node
Вы всегда можете обратиться к репозиторию GitHub, если хотите взглянуть на код.
Давайте начнем с создания проекта Node. Перейдите в безопасный каталог и введите следующую команду, чтобы создать новый проект:
npm init -y
Это должно сгенерировать файл package.json. Если файл создан, значит, создался и проект.
Теперь давайте создадим новый файл с именем index.js. Сначала импортируйте crypto пакет, чтобы мы могли иметь дело с хешами в проекте. Пакет crypto помогает нам работать с хешами, подписями и ключами. Он позволяет выполнять криптографическое преобразование в Node.
Это предустановленный пакет с Node, поэтому вам не нужно устанавливать его отдельно:
const crypto = require("crypto");
Мы будем иметь дело с четырьмя классами. Их названия:
Transaction
Block
Chain
Wallet
Сначала давайте создадим класс Transaction.
Создание класса Transaction
Основными свойствами транзакции будут amount, senderPublicKey и 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. Наконец, мы создаем hash.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); } }
Здесь мы сначала используем функцию 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, чтобы взглянуть на код. Если вы хотите поэкспериментировать еще больше, я бы порекомендовал включить в этот проект систему баланса кошелька и систему майнинга.
Автор: Atharva Deosthale
Источник: blog.logrocket.com
Редакция: Команда webformyself.
Читайте нас в Telegram, VK, Яндекс.Дзен