Публікація Створення блокчейн-додатку за допомогою C++ вперше з’явилася на Coinpedia Fintech News
вступ
Технологія блокчейн докорінно змінила управління фінансами та ланцюгом поставок, запропонувавши децентралізовані, прозорі та безпечні механізми, які усувають потребу в посередниках.
Чому потрібно створювати блокчейн-додаток?
Програми Blockchain забезпечують покращену цілісність і безпеку даних, а також забезпечують надійне середовище для обміну інформацією. За допомогою блокчейну можна впроваджувати смарт-контракти та створювати цифрові токени, які відкривають двері для нових економічних моделей, таких як децентралізовані фінанси (DeFi) і токенізовані активи тощо.
Ця стаття є коротким 10-хвилинним туром у світ розробки Blockchain за допомогою C++.
Основи Blockchain
Блокчейн — це цифровий ланцюжок, що складається з окремих захищених і захищених від втручання блоків. Кожен блок містить свої метадані та визначену інформацію про транзакцію. Поки що ми створили лише окремі блоки, чи не так?! Як би ви спробували встановити значущий зв’язок між кожним блоком? Відповідь полягає в тому, щоб зв’язати кожен блок з його попереднім блоком за допомогою унікальних випадкових криптографічних функцій, відомих як хеш. Кожен блок має власний хеш, який є первинним ключем, і ви можете зв’язати всі блоки через хешування в хронологічному порядку, утворюючи ланцюжок, який представляє всю історію транзакцій у мережі.
C++ в блокчейні
C++ є однією з найпотужніших мов, що використовуються в блокчейні, завдяки своїй швидкості, гнучкості та контролю. Він творить чудеса під час обробки складних систем, розробки ігор і фінансових програм. Без сумніву, це найуніверсальніша мова!
C++ блищить у блокчейні з кількох причин. Він дозволяє розробникам створювати ефективні блокчейн-системи завдяки низькорівневому управлінню пам’яттю, яке забезпечує точний контроль. Ми всі знаємо, наскільки величезною та безпечною є мережа Bitcoin. Уявіть собі, наскільки складним має бути його ядро, оскільки воно має обробляти незліченну кількість транзакцій. Тому для вирішення цього складного завдання було обрано C++. Є деякі важливі програми, розроблені з використанням C++, як-от Bitcoin, Lifecoin, Ripple, Monero та EOS.
Чому C++ є ідеальною мовою для розробки блокчейнів?
Швидші обчислення
Високопродуктивний
Ефективне управління пам'яттю
Об'єктно-орієнтовані функції
Підтримує багатопотоковість
Контроль системних ресурсів
Незалежно від того, чи ви новачок у блокчейні, чи прагнете розширити межі можливого, C++ є надійним вибором для створення довготривалих програм.
Розуміння концепцій блокчейну за допомогою C++
Транзакції: у блокчейні транзакції є суттю, яка керує всією системою. Окремі блоки схожі на захищені сховища, які зберігають престижну інформацію про обмін і вартість транзакцій разом з учасниками. Ці транзакції є фундаментальними записами, які розповідають про те, хто чим обмінювався, з ким і коли.
Стовпи блокчейна, які ви повинні знати
Децентралізація: децентралізація є причиною того, чому блокчейн виділяється в усій технологічній сфері. Що таке децентралізація? Це властивість блокчейну, завдяки якій жодна сутність не контролює всю базу даних. Це робить систему стійкою до збоїв і перешкоджає будь-яким упередженням. Кожен пристрій-учасник (вузол) підтримує копію блокчейну, забезпечуючи прозорість і запобігаючи централізованим збоям або маніпуляціям.
Незмінність: як тільки ви записуєте будь-які дані в блокчейн, ви не можете змінити їх без зміни наступних блоків. Це робиться за допомогою криптографічного хешування. Отже, усі зміни, зроблені один раз, не можна скасувати, що робить їх незмінними.
Механізми консенсусу: набір протоколів, що регулюють усі потреби блокчейну. Усі вузли в мережі повинні узгодити методи. Механізми консенсусу використовуються для оптимізації вузлів і забезпечення того, що всі вузли в мережі знаходяться на одній сторінці.
Досі ви, напевно, зрозуміли всі основи блокчейну, чи не так? Досить теорії! Тепер перейдемо до практичної частини. Готові забруднити руки?
У цьому розділі ми проведемо вас через весь процес розробки простого блокчейн-додатку. Від налаштування середовища до тестування та розгортання.
1. Налаштування середовища розробки C++
Перш ніж почати розробку, необхідно мати всі передумови. У цьому розділі ми розглянемо, як створити відповідне середовище розробки.
Встановлення компілятора C++
Почнемо з розуміння того, що таке компілятор.
Компілятор — це важливий інструмент у розробці програмного забезпечення, який діє як міст між написаним вами кодом, який читається людиною, і машинним кодом, який може зрозуміти та виконати процесор вашого комп’ютера. У контексті розробки блокчейн-додатків на C++ ваш перший крок — це оснастити себе надійним компілятором C++. Цей інструмент перетворить ваш код C++ у виконуваний машинний код, забезпечуючи ефективну роботу вашої блокчейн-програми на різних системах.
Отже, щоб почати розробку, спочатку встановіть компілятор C++, сумісний із вашою системою. Нижче наведено популярні компілятори C++, з яких ви можете вибрати:
GCC (Колекція компілятора GNU):
Linux/MacOS:
Відкрийте термінал і введіть наведені нижче команди відповідно
a)Ubuntu/Debian:sudo apt updatesudo apt install build-essentialb)Fedora sudo dnf install gcc gcc-c++c)MacOS (інструменти командного рядка)xcode-select –install
Windows: для користувачів Windows проект MinGW-w64 є чудовим вибором, оскільки він надає Windows-порт GCC (GNU Compiler Collection), пропонуючи можливості GCC у середовищі Windows.
Кроки для встановлення:
Завантажте інсталятор, відвідавши офіційний сайт MinGW-w64.
Запустіть інсталятор після завантаження
Виберіть відповідну архітектуру відповідно до ваших потреб
Виконайте кроки майстра для завершення
Оновіть систему (це необов’язковий крок, але рекомендований).
Кланг:
Linux/MacOS: sudo apt install clang (також clang уже встановлено в MacOS)Fedora: sudo dnf install clangWindows: Clang можна встановити за допомогою MinGW або за допомогою інсталятора проекту LLVM
MSVC (Microsoft Visual C++):
MSVC (Microsoft Visual C++) є невід’ємним компонентом Visual Studio, надійного інтегрованого середовища розробки (IDE), розробленого Microsoft. Visual Studio надає повний набір інструментів для розробки, тестування та розгортання додатків, і його встановлення автоматично налаштує MSVC у вашій системі.
Перевірте встановлення за допомогою таких команд у терміналі або командному рядку:
g++ –version # Для GCCclang –version # Для Clangcl # Для MSVC
Вибір IDE
Інтегроване середовище розробки (IDE) підвищує продуктивність, пропонуючи такі інструменти, як завершення коду, налагодження та керування проектами в рамках єдиного інтерфейсу. Нижче наведено деякі широко використовувані IDE для розробки C++:
Visual Studio: завантажте Visual Studio з офіційного веб-сайту.
Виконайте наступні кроки, як зазначено в таблиці нижче:
CLion: Встановлення та налаштування:
CLion є популярним IDE і працює на базі JetBrains, але вимагає підписки, але надає безкоштовні пробні версії.
надає безкоштовні пробні версії.
Код Visual Studio: установіть і налаштуйте розширення для розробки C++.
Встановлення необхідних бібліотек
Використовуйте менеджери пакунків, щоб інсталювати такі основні бібліотеки, як OpenSSL для криптографічних функцій. Нижче наведено кроки та різні бібліотеки для різних операційних систем та їхніх команд.
Так, ви успішно налаштували своє середовище розробки, ви можете безпосередньо почати виконувати код у вибраній вами IDE.
2. Створення простого блокчейну за допомогою C++
Перш ніж розпочати шлях до написання коду, давайте розберемося з компонентами класу блоку.
Компоненти Blockclass
Індекс — це ціле число, яке зберігає та підтримує відсортований порядок блоків у хронологічному порядку.
Мітка часу: мітка часу зберігає екземпляр, коли блок було створено у вигляді рядка.
Транзакції: Транзакції зберігають інформацію про обмін між учасниками та стан блокчейну на той момент.
Попередній хеш і хеш: попередній хеш зберігає криптографічний хеш попереднього блоку, тоді як хеш — це рядок криптографічної інформації, змішаної або хешованої.
Nonce: ціле число, яке використовується в алгоритмі консенсусу Proof of Work (PoW). Діє як лічильник, який збільшується, щоб знайти дійсний хеш, який відповідає цільовій складності. Одноразовий номер має вирішальне значення для процесу видобутку в PoW, де майнери змагаються, щоб знайти одноразовий номер, який генерує хеш із певною кількістю початкових нулів.
Давайте зараз реалізуємо всі функції в коді:
class Block {public: int index; std::string timestamp; std::vector<Transaction> транзакції; std::string previousHash; std::рядок хеш; int nonce; // Для PoW // Конструктор Block(int idx, std::string time, std::vector<Transaction> txs, std::string prevHash) { index = idx; timestamp = час; транзакції = txs; попередній хеш = попередній хеш; nonce = 0; хеш =calculateHash(); // Хеш поточного блоку } // Метод обчислення хешу блоку std::string calculateHash() { std::stringstream ss; ss << index << timestamp << previousHash << nonce; // Додайте дані транзакції та будь-які додаткові деталі до обчислення хешу повернення sha256(ss.str()); // Заповнювач для фактичної хеш-функції } // Метод видобутку блоку void mineBlock(int затруднення) { std::string target(difficulty, ‘0’); // Створення рядка цільового хешу while (hash.substr(0, затруднення) != ціль) { nonce++; хеш =calculateHash(); } }};
Після того, як ви закінчите з визначенням блок-класу та його атрибутів, ви можете перейти до створення блоку генезису. Блок Genesis — це перший блок у блокчейні, який потрібно ініціалізувати та має нульовий індекс. Після визначення блоку генезису ви можете продовжувати додавати нові блоки до свого блокчейну за допомогою методу addblock(). Нижче ви можете знайти код:
клас Blockchain {public: std::vector<Block> chain; Blockchain() { chain.push_back(createGenesisBlock()); } Block createGenesisBlock() { return Block(0, “01/01/2024”, “Genesis Block”, “0”); } Блок getLatestBlock() { повернути chain.back(); } void addBlock(Заблокувати новийБлок) { новийБлок.previousHash = getLatestBlock().hash; newBlock.hash = newBlock.calculateHash(); chain.push_back(новий блок); }};
Створіть і перевірте транзакцію. Кожна транзакція має власний ідентифікатор, попередньо визначений конструктор, інформацію про відправника та одержувача разом із сумою. Після створення транзакції її потрібно перевірити за допомогою методу validateTransaction().
class Transaction {public: std::string sender; std::string одержувач; подвійна сума; std::string ідентифікатор транзакції; // Конструктор Transaction(std::string snd, std::string rcp, double amt, std::string txID) { sender = snd; одержувач = rcp; сума = сума; ідентифікатор транзакції = txID; } // Метод перевірки транзакції bool validateTransaction() { // Реалізація логіки перевірки повернути істину; // Заповнювач }};
3. Реалізація механізмів консенсусу в C++
На даний момент ви виконали 25% процесу будівництва. Тепер ви рухаєтеся вперед і реалізуєте механізми консенсусу для свого блоку, який є основою всієї програми.
Підтвердження роботи
Доказ роботи (PoW) — це механізм консенсусу, за допомогою якого учасники мережі блокчейнів/майнери повинні знайти рішення складної обчислювальної математичної задачі, перш ніж вони зможуть додати новий блок до ланцюжка. По суті, це процес пошуку конкретного числа , який називається nonce, який поєднується з даними блоку, його хешем та іншими деталями, щоб створити хеш-значення, яке починається з певної кількості початкових нулів. Це робить процес ефективним і захищає мережу від зловмисних атак.
У C++ ви можете реалізувати Proof of Work, додавши атрибут proof і метод proof of work до класу Block. Ось як ви можете це зробити:
#include <iostream>#include <sstream>#include <ctime>#include <string>#include <vector>#include <openssl/sha.h>using namespace std;string sha256(const string str) { unsigned char hash[ SHA256_DIGEST_LENGTH]; SHA256_CTX sha256; SHA256_Init(&sha256); SHA256_Update(&sha256, str.c_str(), str.length()); SHA256_Final(хеш, &sha256); рядковий потік ss; for(int i = 0; i < SHA256_DIGEST_LENGTH; i++) { ss << hex << setw(2) << setfill(‘0’) << (int)hash[i]; } return ss.str();}class Block {public: int index; рядкові дані; рядок previousHash; хеш рядка; довгий доказ; мітка часу time_t; Block(int idx, string d, string prevHash) { index = idx; дані = d; попередній хеш = попередній хеш; timestamp = time(nullptr); доказ = 0; хеш =calculateHash(); } string calculateHash() const { stringstream ss; ss << index << timestamp << data << previousHash << proof; повернути sha256(ss.str()); } void proofOfWork(int трудність) { рядок target(складність, ‘0’); зробити { доказ++; хеш =calculateHash(); } while (hash.substr(0, затруднення) != ціль); }};клас Blockchain {public: vector<Block> chain; int труднощі; Blockchain(int diff) { складність = diff; chain.emplace_back(Блок(0, “Блок Genesis”, “0”)); } void addBlock(string data) { Блокувати newBlock(chain.size(), data, chain.back().hash); newBlock.proofOfWork(складність); if (isValidProof(newBlock)) { chain.push_back(newBlock); } } bool isValidProof(const Block& block) const { return block.hash.substr(0, трудність) == рядок(складність, ‘0’); }};
У наведеному вище фрагменті коду ми бачимо, що спочатку нам потрібно додати доказ і хеш до блоку. Потім визначте складність доказу та дослідіть його. Після цього ви можете підтвердити доказ.
4. Створення простого API блокчейну за допомогою C++
API – інтерфейс програмування додатків – це інструмент, який дозволяє різним програмам програмного забезпечення взаємодіяти один з одним. У блокчейні API-інтерфейси спрощують взаємодію з попередньо визначеними даними блокчейну, тому розробники можуть швидко створювати програми без необхідності знати всю базову структуру мережі. . API допомагають інтегрувати блокчейн з іншими платформами, такими як веб-програми або мобільні програми. Отже, API необхідні для забезпечення ефективної розробки та інтеграції.
Налаштування середовища API
Встановіть і налаштуйте інструменти, необхідні для створення API за допомогою C++, як зазначено в таблиці нижче:
Створення API
#include <cpprest/http_listener.h>#include <cpprest/json.h>#include “blockchain.h”використання простору імен web;використання простору імен http;використання утиліти простору імен;використання простору імен http::experimental::listener;Blockchain blockchain( 4); // рівень складності 4void handleGet(http_request request) { json::value response = json::value::array(); int i = 0; for (auto& block : blockchain.chain) { json::value block_json; block_json[U(“індекс”)] = json::value::number(block.index); block_json[U(“дані”)] = json::value::string(block.data); block_json[U(“previousHash”)] = json::value::string(block.previousHash); block_json[U(“хеш”)] = json::value::string(block.hash); block_json[U(“доказ”)] = json::value::number(block.proof); block_json[U(“timestamp”)] = json::value::number(block.timestamp); відповідь[i++] = block_json; } request.reply(status_codes::OK, response);}void handlePost(http_request request) { request.extract_json().then([&](json::value requestData) { auto data = requestData[U(“data” )].as_string();blockchain.addBlock(data);request.reply(status_codes::OK, U(“Блок додано успішно”));}).wait();}int main() {http_listener listener(U) (“http://localhost:8080”));listener.support(methods::GET, handleGet);listener.support(methods::POST, handlePost);спробуйте {listener.open().wait();cout << “Прослуховування на http://localhost:8080” << endl;while (true);} catch (exception const& e) {cerr << e.what() << endl; }повернути 0;}
handleGet отримує весь блокчейн у форматі JSON.
handlePost додає новий блок до блокчейну, використовуючи дані із запиту POST.
Запуск і тестування програми
Запуск програми
Після того, як ви завершите роботу з основними функціями коду відповідно до циклу розробки програмного забезпечення, вам потрібно перейти до найважливішого та неминучого кроку компіляції та тестування всієї програми. Це найважливіше, щоб підтвердити, що компоненти програми працюють належним чином.
Скомпілюйте код: g++ -o blockchain_api blockchain_api.cpp -lboost_system -lcrypto -lssl -lcpprest Запустіть виконуваний файл:./blockchain_api
Наведений вище код запускає сервер API на http://localhost:8080.
Тестування з листоношею
Перевірте кінцеві точки API за допомогою Postman або curl:
Додати блок:
Метод: POST
URL: http://localhost:8080
Тіло: формат JSON
{ “data”: “Це новий блок”}
Переглянути Blockchain:
Спосіб: GET
URL: http://localhost:8080
Приклад додавання блоку та перегляду блокчейна за допомогою API, створеного за допомогою C++.
void handleGet(http_request request) { json::value response = json::value::array(); int i = 0; for (auto& block : blockchain.chain) { json::value block_json; block_json[U(“індекс”)] = json::value::number(block.index); block_json[U(“дані”)] = json::value::string(block.data); block_json[U(“previousHash”)] = json::value::string(block.previousHash); block_json[U(“хеш”)] = json::value::string(block.hash); block_json[U(“доказ”)] = json::value::number(block.proof); block_json[U(“timestamp”)] = json::value::number(block.timestamp); відповідь[i++] = block_json; } request.reply(status_codes::OK, відповідь); }void handlePost(http_request request) { request.extract_json().then([&](json::value requestData) { auto data = requestData[U(“data”)].as_string();blockchain.addBlock(data) ;request.reply(status_codes::OK, U(“Блокування успішно додано”)) }).wait();}
Функція handlePost обробляє додавання блоку, витягуючи дані з тіла JSON і додаючи новий блок до блокчейну.
Функція handleGet отримує весь блокчейн і надсилає його назад як відповідь JSON.
6. Живий приклад створення програми Blockchain за допомогою C++
Поетапне виконання
Крок 1: Створіть клас Block з необхідними атрибутами за допомогою синтаксису C++.
#include <iostream>#include <ctime>#include <string>#include <sstream>#include <vector>#include <openssl/sha.h>using namespace std;class Block {public: int index; рядкові дані; рядок previousHash; хеш рядка; довгий доказ; мітка часу time_t; Block(int idx, const string& data, const string& prevHash) : index(idx), data(data), previousHash(prevHash), proof(0), timestamp(time(nullptr)) { hash = calculateHash(); } string calculateHash() const { stringstream ss; ss << index << timestamp << data << previousHash << proof; повернути sha256(ss.str()); } void proofOfWork(int трудність) { рядок target(складність, ‘0’); зробити { доказ++; хеш =calculateHash(); } while (hash.substr(0, затруднення) != ціль); }private: string sha256(const string& input) const { unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256_CTX sha256; SHA256_Init(&sha256); SHA256_Update(&sha256, input.c_str(), input.size()); SHA256_Final(хеш, &sha256); рядковий потік ss; for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) { ss << hex << setw(2) << setfill(‘0’) << (int)hash[i]; } повернути ss.str(); }};
Крок 2: Реалізуйте метод CalculateHash.
#include <iostream>#include <sstream>#include <iomanip>#include <openssl/sha.h>class Block {public: int index; std::рядкові дані; std::string previousHash; std::рядок хеш; довгий доказ; мітка часу time_t; Block(int idx, const std::string& data, const std::string& prevHash) : index(idx), data(data), previousHash(prevHash), proof(0), timestamp(time(nullptr)) { хеш = обчислитиХеш(); } std::string calculateHash() const { std::stringstream ss; ss << index << timestamp << data << previousHash << proof; повернути sha256(ss.str()); }private: std::string sha256(const std::string& input) const { unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256_CTX sha256; SHA256_Init(&sha256); SHA256_Update(&sha256, input.c_str(), input.size()); SHA256_Final(хеш, &sha256); std::stringstream ss; for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) { ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i] ; } повернути ss.str(); }};
Крок 3: Визначте клас Blockchain та ініціалізуйте його блоком genesis.
class Blockchain {public: Blockchain(int трудність) : трудність(складність) { chain.emplace_back(Block(0, “Genesis Block”, “0”)); } void addBlock(const string& data) { Блокувати newBlock(chain.size(), data, chain.back().hash); newBlock.proofOfWork(складність); chain.push_back(новий блок); } const Block& latestBlock() const { повернути chain.back(); } vector<Block> chain;private: int трудність;};
Крок 4: Реалізуйте метод CalculateHash.
#include <iostream>#include <sstream>#include <iomanip>#include <openssl/sha.h>class Block {public: int index; std::рядкові дані; std::string previousHash; std::рядок хеш; довгий доказ; мітка часу time_t; Block(int idx, const std::string& data, const std::string& prevHash) : index(idx), data(data), previousHash(prevHash), proof(0), timestamp(time(nullptr)) { хеш = обчислитиХеш(); } std::string calculateHash() const { std::stringstream ss; ss << index << timestamp << data << previousHash << proof; повернути sha256(ss.str()); }private: std::string sha256(const std::string& input) const { unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256_CTX sha256; SHA256_Init(&sha256); SHA256_Update(&sha256, input.c_str(), input.size()); SHA256_Final(хеш, &sha256); std::stringstream ss; for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) { ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i] ; } повернути ss.str(); }};
Крок 5: Визначте клас Blockchain та ініціалізуйте його блоком genesis.
class Blockchain {public: Blockchain(int трудність) : трудність(складність) { chain.emplace_back(Block(0, “Genesis Block”, “0”)); } void addBlock(const string& data) { Блокувати newBlock(chain.size(), data, chain.back().hash); newBlock.proofOfWork(складність); chain.push_back(новий блок); } const Block& latestBlock() const { повернути chain.back(); } vector<Block> chain;private: int трудність;};
Крок 6. Налаштуйте середовище API для обробки запитів за допомогою відповідної бібліотеки C++.
#include <cpprest/http_listener.h>#include <cpprest/json.h>using namespace web;using namespace web::http;using namespace web::http::experimental::listener;class BlockchainAPI {public: BlockchainAPI(const string& address, Blockchain& blockchain) : listener(http_listener(U(address))), blockchain(blockchain) { listener.support(methods::GET, std::bind(&BlockchainAPI::handleGet, this, std::placeholders:: _1));listener.support(methods::POST, std::bind(&BlockchainAPI::handlePost, this, std::placeholders::_1));void start() {listener.open().wait(); cout << «Blockchain API працює…» << endl; }Приватний:http_listener слухач; Blockchain& blockchain;void handleGet(http_request request) {json::value response = json::value::array();int i = 0;for (const auto& block : blockchain.chain) {json::value block_json;block_json[ U(“індекс”)] = json::value::number(block.index);block_json[U(“data”)] = json::value::string(block.data);block_json[U(“previousHash” ”)] = json::value::string(block.previousHash);block_json[U(“hash”)] = json::value::string(block.hash);block_json[U(“proof”)] = json::value::number(block.proof);block_json[U(“timestamp”)] = json::value::number(block.timestamp);response[i++] = block_json; } request.reply(status_codes::OK, відповідь); }void handlePost(http_request request) {request.extract_json().then([&](json::value requestData) {string data = requestData[U(“data”)].as_string();blockchain.addBlock(data) ;request.reply(status_codes::OK, U(“Блокування успішно додано”));}) . чекати (); }} ;
Крок 7. Протестуйте програму, видобувши новий блок і перевіривши блокчейн за допомогою Postman або curl.
Main:int main() { Блокчейн blockchain(4); // Рівень складності BlockchainAPI api(“http://localhost:8080”, blockchain); api.start(); return 0;}Testing:curl -X POST http://localhost:8080 -H “Content-Type: application/json” -d ‘{“data”:”Це новий блок”}’
Розробка блокчейну за допомогою C++ — це більше, ніж просто кодування; мова йде про створення основоположних елементів децентралізованих систем, які можуть революціонізувати різні галузі.
Підводячи підсумок, ми охопили все: від основ програмування C++ для блокчейну до розгортання та тестування програми.
Пройшовши цей модуль, ви зможете глибше вивчати такі концепції оптимізації, як масштабованість, методи безпеки, розширені механізми консенсусу та розумні контракти.
Залишайтеся цікавими, постійно навчайтеся та продовжуйте кодувати. Нехай ваш внесок стане рушійною силою розвитку технологій!