Введение
Разработка смарт-контрактов и экономика Web3 все еще находятся в зачаточном состоянии, и во всем мире существует высокий спрос на разработчиков блокчейна.
Согласно недавнему отчету LinkedIn, в 2021 году в США количество вакансий, содержащих такие термины, как биткоин, блокчейн и другие связанные с цифровыми активами роли, увеличилось на 395 процентов по сравнению с предыдущим годом. С 98-процентным ростом эта отрасль стала самой быстрорастущей в истории, опередив всю промышленность в четыре раза.
Разработка блокчейна имеет больше шансов получить работу вашей мечты с шестизначной зарплатой. И самое приятное, что большинство рабочих мест в сфере блокчейна являются удаленными, так что вам не нужно беспокоиться о местонахождении.
Но как влиться в это пространство и извлечь из него выгоду? Это научиться создавать вещи с помощью этой технологии.
Если вы ищете личного репетитора, который ускорит вас в разработке web3, пожалуйста, запишитесь ко мне.
С учетом сказанного, давайте приступим к этому уроку…
Загляните на мой канал YouTube, чтобы получить БЕСПЛАТНЫЕ уроки по web3 прямо сейчас.
Почему вы должны освоить CRUD-функции в Solidity
Умение создавать, читать, обновлять и удалять записи из блокчейна — это навык, который вы должны понимать. Да, вы можете удалять данные из блокчейна (в определенной степени), используя технику, которую вы сейчас изучите.
Навыки CRUD необходимы для эффективного построения системы, управляемой контентом, а поскольку блокчейн служит базой данных для неизменного хранения записей, мудрость требует, чтобы вы понимали, как работать с этой технологией.
Опять же, если вы собираетесь работать над проектом блокчейна для компании или клиента, может возникнуть необходимость удалить некоторые ненужные записи, поэтому вам следует уже сейчас совершенствовать свои навыки работы с Solidity CRUD.
Что если вы работаете над проектом web3-блога и знаете, что там должна быть кнопка удаления очень плохих комментариев. В этом случае вам понадобится функциональность удаления.
Вы видите, что хорошее знание CRUD станет неизбежным, когда вы погрузитесь в разработку блокчейна.
Кстати, удаление записи из сети блокчейн отличается от удаления из обычной базы данных. Запись все еще будет существовать в сети, но будет удалена из вашего приложения web3.
Полный пример ниже покажет вам шаг за шагом, как этого добиться.
Пример CRUD-функций
Это смарт-контракт, который я создал и протестировал; чтобы увидеть, как он работает, вы можете открыть его в редакторе remix и запустить самостоятельно. Но сначала дочитайте учебник до конца; ниже есть важная информация, которая объясняет каждую функцию в отдельности.
Итак, давайте разберем этот смарт-контракт шаг за шагом; если вы новичок, не волнуйтесь; я написал этот пример смарт-контракта, чтобы продемонстрировать простоту.
Шаг 1: Структура смарт-контракта
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract Blog {
// code goes here...
}
Это типичная структура смарт-контракта; считайте ее классом в объектно-ориентированном программировании, потому что в реальности она таковой является.
SPDX используется для указания типа лицензии смарт-контракта. Pragma указывает на версию компилятора solidity, которая будет использоваться для смарт-контракта. Наконец, имя смарт-контракта — Blog.
Важно отметить, что имя файла всегда должно соответствовать имени класса; это обеспечит последовательность и предотвратит ненужные ошибки в вашем коде.
Шаг 2: Определение переменных контракта
address public owner;
uint256 public activePostCounter = 0;
uint256 public inactivePostCounter = 0;
uint256 private postCounter = 0;
Здесь у нас есть два типа переменных: адрес и uint256. Адрес представляет учетную запись пользователя, а uint256 — целое число без знака в диапазоне от 0 до 2256-1.
Владелец будет держать аккаунт развертывателя, а activePostCounter хранит количество доступных постов. inactivePostCounter хранит удаленный пост, на случай, если его нужно будет восстановить. postCounter хранит общее количество постов в смарт-контракте, но он является приватным.
Шаг 3: Определение связок
mapping(uint256 => address) public delPostOf;
mapping(uint256 => address) public authorOf;
mapping(address => uint256) public postsOf;
authorOf() — это сопоставленная переменная, которая принимает идентификатор поста и возвращает адрес автора поста. В то время как postsOf() отслеживает сообщения автора, а delPostOf() служит корзиной для каждого автора.
Шаг 4: Определение перечислимого
enum Deactivated { NO, YES }
Используется для указания того, был ли пост удален или нет. Enum преобразует алфавитное значение в беззнаковые целые числа, начинающиеся с нуля. Например, значения NO и YES станут 0 и 1 соответственно.
Шаг 5: Определение структуры
struct PostStruct {
uint256 postId;
string title;
string description;
address author;
Deactivated deleted; // We are using the enum here
uint256 created;
uint256 updated;
}
PostStruct[] activePosts;
PostStruct[] inactivePosts;
Структуры используются для определения сложных структур данных, которые состоят из двух или более типов данных.
В приведенном выше PostStruct мы указали, что пост должен иметь Id, заголовок, описание, автора, ключ удаления, время создания и время обновления.
Далее мы создали два массива: один для активных сообщений и один для неактивных, или удаленных, сообщений. Этот метод предотвращает потерю данных, но вы также можете использовать один массив и включать и выключать только ключ для удаленных. Однако в этом случае возникает другая проблема: перед тем как показать активные сообщения, вам придется прочитать их все в вашем фронтенд-приложении. Я бы хотел избавить вас от этого.
Шаг 6: Определение события
event Action (
uint256 postId,
string actionType,
Deactivated deleted,
address indexed executor,
uint256 created
);
Мы определили динамическое событие для передачи некоторой важной информации о созданных, обновленных, удаленных и восстановленных функциях соответственно.
Шаг 7: Определение модификатора
modifier ownerOnly(){
require(msg.sender == owner, "Owner reserved only");
_;
}
Модификатор — это функция, которая изменяет поведение другой функции во время компиляции. Можно сказать, что он является необходимым условием для выполнения функции.
В приведенном выше модификаторе мы указали, что вызывающая функция, к которой будет присоединен этот модификатор, должна быть владельцем или разработчиком смарт-контракта.
Шаг 8: Определение конструктора
constructor() {
owner = msg.sender;
}
Из ваших знаний ООП следует, что конструктор — это первая функция, которая запускается при инстанцировании класса. ООП-конструктор является взаимным для смарт-контрактов.
Первой функцией, запускаемой при развертывании смарт-контракта, является конструктор, и мы указали, что он должен сделать владельца тем, кто развернул смарт-контракт.
Шаг 9: Функция createPost()
function createPost(
string memory title,
string memory description
) external returns (bool) {
// Checks for empty string
require(bytes(title).length > 0, "Title cannot be empty");
require(bytes(description).length > 0, "Description cannot be empty");
// Performs computations
postCounter++;
authorOf[postCounter] = msg.sender;
postsOf[msg.sender]++;
activePostCounter++;
// Adds post to array
activePosts.push(
PostStruct(
postCounter,
title,
description,
msg.sender,
Deactivated.NO,
block.timestamp,
block.timestamp
)
);
// Emits a created event
emit Action (
postCounter,
"POST CREATED",
Deactivated.NO,
msg.sender,
block.timestamp
);
// Returns success
return true;
}
Эта функция выполняет создание поста в пять шагов.
Во-первых, она проверяет, что вы отправляете смарт-контракту реальную информацию, а не просто пустую строку.
Во-вторых, она выполняет некоторые вычисления, например, увеличивает количество постов для блога и для автора, в том числе делает автора владельцем поста.
В-третьих, он добавляет пост в список activePosts, используя PostStruct, определенный ранее.
В-четвертых, он выдает событие «POST CREATED», которое регистрируется на EVM, это необходимо для обогащения информации, полученной в транзакции.
Наконец, мы вернули булев ключ true, указывающий на то, что вся функция была выполнена успешно.
Шаг 10: Функция updatePost().
function updatePost(
uint256 postId,
string memory title,
string memory description
) external returns (bool) {
// Checks for empty string
require(authorOf[postId] == msg.sender, "Unauthorized entity");
require(bytes(title).length > 0, "Title cannot be empty");
require(bytes(description).length > 0, "Description cannot be empty");
// Changes post record
for(uint i = 0; i < activePosts.length; i++) {
if(activePosts[i].postId == postId) {
activePosts[i].title = title;
activePosts[i].description = description;
activePosts[i].updated = block.timestamp;
}
}
// Emits a updated event
emit Action (
postId,
"POST UPDATED",
Deactivated.NO,
msg.sender,
block.timestamp
);
// Returns success
return true;
}
Эта функция работает аналогично функции createPost(). Разница в том, что при проверке пустой строки функция updatePost() гарантирует, что человек, обновляющий ее, является владельцем (автором) поста.
Затем она нацеливается на конкретный пост по Id и обновляет запись.
Шаг 11: Функция showPost()
function showPost(
uint256 postId
) external view returns (PostStruct memory) {
PostStruct memory post;
for(uint i = 0; i < activePosts.length; i++) {
if(activePosts[i].postId == postId) {
post = activePosts[i];
}
}
return post;
}
Эта функция просто возвращает наш пост путем рекурсивного поиска совпадения в массиве activePost.
Шаг 12: Функция getPosts().
function getPosts() external view returns (PostStruct[] memory) {
return activePosts;
}
Возвращает все доступные активные посты блога.
Шаг 13: Функция getDeletedPost().
function getDeletedPost()
ownerOnly external view returns (PostStruct[] memory) {
return inactivePosts;
}
Эта функция просто возвращает все удаленные посты, и доступ к ней может получить только владелец блога.
Шаг 14: Функция deletePost()
function deletePost(uint256 postId) external returns (bool) {
// check if post belong to user
require(authorOf[postId] == msg.sender, "Unauthorized entity");
// find and delete post
for(uint i = 0; i < activePosts.length; i++) {
if(activePosts[i].postId == postId) {
activePosts[i].deleted = Deactivated.YES;
activePosts[i].updated = block.timestamp;
inactivePosts.push(activePosts[i]);
delPostOf[postId] = authorOf[postId];
delete activePosts[i];
delete authorOf[postId];
}
}
// Recallibrate counters
postsOf[msg.sender]--;
inactivePostCounter++;
activePostCounter--;
// Emits event
emit Action (
postId,
"POST DELETED",
Deactivated.YES,
msg.sender,
block.timestamp
);
// Returns success
return true;
}
Приведенная выше функция была реализована в четыре шага.
Сначала мы проверили, что удалением занимается владелец поста, затем выполнили поиск поста, удалили его и выдали событие «POST DELETED», а также вернули булево значение true.
Обратите внимание, что удаление происходит не так, как в обычной базе данных, мы задали два массива: activePosts и inactivePosts. Когда мы удаляем пост, он перемещается в массив inactivePosts, и только владелец блога может восстановить его по просьбе автора поста.
Шаг 15: Функция восстановления постов
function restorDeletedPost(
uint256 postId,
address author
) ownerOnly external returns (bool) {
// checks if post exists in users recycle bin
require(delPostOf[postId] == author, "Unmatched Author");
// Finds and restore the post to the author
for(uint i = 0; i < inactivePosts.length; i++) {
if(inactivePosts[i].postId == postId) {
inactivePosts[i].deleted = Deactivated.NO;
inactivePosts[i].updated = block.timestamp;
activePosts.push(inactivePosts[i]);
delete inactivePosts[i];
authorOf[postId] = delPostOf[postId];
delete delPostOf[postId];
}
}
// Recallibrates counter to reflect restored post
postsOf[author]++;
inactivePostCounter--;
activePostCounter++;
// Emits a restoration event
emit Action (
postId,
"POST RESTORED",
Deactivated.NO,
msg.sender,
block.timestamp
);
// resturns success
return true;
}
Когда пост восстанавливается, он перемещается из массива inactivePosts в массив activePosts.
Стоит отметить, что вы можете спроектировать свой шаблон удаления немного иначе, чем я. Вы можете использовать структуру enum Deactivated, которую мы создали выше, и удалять только при переключении состояния удаления на YES или NO.
Мужики и братья, вот как вы сокрушаете CRUD-функции Solidity…
Смотрите мои БЕСПЛАТНЫЕ учебники по web3 на YouTube прямо сейчас.
Заключение
Было очень приятно пройти с вами этот курс, надеюсь, вы получили ценные знания о том, как писать CRUD-функции для смарт-контрактов Solidity.
Я хочу сообщить вам о моих частных уроках для тех, кто хочет освоить web3. Если вы заинтересованы, пожалуйста, запишитесь на моем сайте.
Это все для этого урока, пожалуйста, ставьте лайк и делитесь…
Жду вас в следующем уроке, а пока наслаждайтесь!
Об авторе
Госпел Дарлингтон начал свой путь в качестве инженера-программиста в 2016 году. За эти годы он приобрел полноценные навыки работы с такими стеками JavaScript, как React, ReactNative, NextJs, а теперь и блокчейн.
В настоящее время он работает фрилансером, создает приложения для клиентов и пишет технические руководства, обучая других тому, как делать то, что делает он.
Евангелие Дарлингтон открыто и готово выслушать вас. Вы можете связаться с ним на LinkedIn, Facebook, Github или на его сайте.