Solidity — это язык программирования смарт-контрактов для платформы Ethereum с синтаксической структурой, аналогичной JavaScript и C++. Он специально разработан для написания самоисполняющихся контрактов на блокчейне, поддержки разработки сложной бизнес-логики и децентрализованных приложений (dApps). С быстрым развитием технологии блокчейна Solidity стал предпочтительным языком для построения децентрализованных финансов (DeFi), рынков NFT и других приложений блокчейна (на самом деле, это в основном связано с большим количеством пользователей Ethereum).
При разработке блокчейнов эффективность обработки данных имеет решающее значение, особенно в смарт-контрактах, где эффективная работа массивов часто определяет производительность и стоимость газа контракта. Поскольку каждая транзакция в сети Ethereum взимает комиссию, сокращение ненужных операций вычислений и хранения становится особенно важным. Дедупликация массивов является одним из таких распространенных требований к манипулированию данными: нам может потребоваться удалить повторяющиеся адреса из списка пользователей или извлечь уникальные идентификаторы транзакций из списка транзакций. Эти операции не только предполагают корректность данных, но и напрямую влияют на стоимость исполнения контракта.
Итак, как эффективно дедуплицировать массивы в Solidity? Эту тему стоит изучить глубже. В этой статье будут представлены несколько распространенных методов дедупликации и проанализированы их преимущества и недостатки, чтобы помочь вам выбрать наиболее подходящую стратегию в реальной разработке.
существовать Solidity В России массивы являются одной из наиболее часто используемых структур данных, позволяющих разработчикам хранить и манипулировать рядом элементов одного типа. В зависимости от того, фиксирована ли длина массива, Solidity вмножествоможно разделить настатический массивидинамический массив。
существовать Solidity , метод определения и использования массивов очень интуитивно понятен. Типы массивов состоят из типа элемента и квадратных скобок, например. uint256[]
Экспресс одининдивидуальныйдинамический массив,uint256[5]
представляет собой содержащий 5 индивидуальный uint256
Статический массив элементов.
Вот несколько основных примеров манипуляций с массивами:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ArrayExample {
// динамический массив
uint256[] public dynamicArray;
// статический массив
uint256[5] public staticArray;
// Добавьте элементы в мотивацию массив
function addElement(uint256 element) public {
dynamicArray.push(element);
}
// Исправлятьстатический массиввэлемент function setElement(uint256 index, uint256 element) public {
require(index < staticArray.length, "Index out of bounds");
staticArray[index] = element;
}
// получатьдинамический массивиз длины
function getDynamicArrayLength() public view returns (uint256) {
return dynamicArray.length;
}
}
статический массив:статический массивиз длинысуществовать Определяется во время компиляции,исуществовать Не может быть изменено в течение жизненного цикла контракта.。использоватьстатический Использование массивов в качестве преимуществ заключается в том, что затраты на их эксплуатацию из хранилищ относительно невелики, поскольку они не требуют динамического изменение размера。статический Массив часто используется в контрактах, которым необходимо обрабатывать фиксированное количество транзакций, например фиксированное количество участников или предопределенное постоянное значение.
// Определение 1 «Индивидуальное лицо» содержит 3 индивидуальныйэлементизстатический массив
uint256[3] public staticArray = [1, 2, 3];
динамический массив:динамический массивиз длинасуществовать контракта является переменной в течение его жизненного цикла,Разработчики могутиспользовать push
Метод добавляет элементы в массив. Хотя динамические массивы обеспечивают гибкость, они также обладают более высокими gas расходы, особенно когда существование добавляет и удаляет элементы. динамичный Массив подходит для сценариев, в которых необходимо обрабатывать переменное количество данных, таких как списки адресов пользователей или записи транзакций.
// Определение 1индивидуальныйдинамический массив
uint256[] public dynamicArray;
// Кдинамический Добавляем элементы в массив
dynamicArray.push(4);
существовать смарт-контракт,Каждая множество операций будет потреблять определенное количество газа., поскольку операция включает в себя чтение и запись в виртуальную машину Ethereum (EVM). Газ, особенно в сети Ethereum Стоимость напрямую влияет на комиссию за транзакцию, поэтому эффективность операций с массивом особенно важна.
push
Эта операция не только требует написания новых элементов, но также может включать в себя множество операций изменения размера, которые добавят дополнительные элементы. gas расходы。Оптимизированные операции с массивами Solidity Разработайте индивидуальные ключевые моменты. Чтобы уменьшить ненужное gas Потребление: разработчики обычно тщательно учитывают множество методов использования и работы в логике контракта. Например, старайтесь избегать многократного выполнения цикла существования операции. записи или существование. Используйте медленную, когда в этом нет необходимости. массив。
Короче говоря, понимание основных операций массивов и их стоимости газа может помочь разработчикам писать более эффективные смарт-контракты, избегать ненужной траты ресурсов и улучшать общую производительность контракта.
существуют смарт-контракты в разработке, Solidity Ограничения часто влияют на то, как разработчики реализуют определенные функции. Одним из существенных ограничений является то, что Solidity Не поддерживается напрямую, как JavaScript в Set
Такая из динамической структуры данных. Это делает существование Solidity Обработка операций сбора данных (например, дедупликации) становится более сложной и дорогостоящей.
потому что Solidity Из-за ограничений среды блокчейна разработчики должны обеспечить дедупликацию, в то же время максимально сокращая вычислительные операции хранилища, чтобы сэкономить gas иуменьшатьхранилищерасходы。Это требует тщательного проектированиядоговорлогика,Выберите наиболее подходящие изданные структуру и алгоритм для оптимизации производительности ирасходов. существующие смарт-контракты находятся в разработке,Этот компромисс и оптимизация неизбежны,Это также ключевой момент, который разработчикам необходимо постоянно учиться и совершенствоваться.
Set
type, что означает, что нет прямого способа хранения уникальных значений.Set
из add
метод автоматического удаления дубликатов или используйте has
Способы быстрого поиска элементов с такими существующими Solidity Все нужно реализовывать вручную. в целом,Это требует написания дополнительной логики и циклов.,Дальнейшее увеличение сложности контракта и затрат на его исполнение.существовать Solidity Основная сложность дедупликации заключается в том, как обеспечить одновременно уникальность и контроль. gas расходы. Вот некоторые проблемы при реализации дедупликации:
Ниже приведен индивидуальный вариант использования openzepplin из EnumerableSet
KuLai быстро дедуплицирует адрес раздачи из примера смарт-контракта:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// version >= v3.3.0
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
contract AirdropUniqueAddresses {
// Using the EnumerableSet library for AddressSet
using EnumerableSet for EnumerableSet.AddressSet;
// Declare a state variable of type EnumerableSet.AddressSet to store unique addresses
EnumerableSet.AddressSet private seen;
// Function to add an address to the set if it is not already present
function addAirdropAddress(address _address) public returns (bool) {
// Add the address to the set
// Returns true if the address was not already in the set, false otherwise
return seen.add(_address);
}
// Function to check if an address is already in the set
function isAirdropAddressSeen(address _address) public view returns (bool) {
// Check if the address is in the set
return seen.contains(_address);
}
// Function to get the total number of unique addresses in the set
function getTotalUniqueAddresses() public view returns (uint256) {
// Return the number of unique addresses in the set
return seen.length();
}
// Function to retrieve an address by index in the set
function getAirdropAddressAtIndex(uint256 index) public view returns (address) {
// Ensure the index is within the bounds of the set
require(index < seen.length(), "Index out of bounds");
// Retrieve the address at the specified index
return seen.at(index);
}
// Function to remove an address from the set
function removeAirdropAddress(address _address) public returns (bool) {
// Remove the address from the set
// Returns true if the address was in the set and removed, false otherwise
return seen.remove(_address);
}
}
Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable.
mapping(uint256 => bool) memory seen;
uint256[] memory input = [1, 2, 2, 3, 4, 4];
for (uint256 i = 0; i < input.length; i++) {
if (!seen[input[i]]) {
seen[input[i]] = true;
}
}
Ниже приведен пример смарт-контракта, который использует двойной цикл для дедупликации адресов раздачи:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract AirdropUniqueAddresses {
// Function to get the unique addresses after removing duplicates
function getUniqueAirdropAddresses(address[] airdropAddresses;) public view returns (address[] memory) {
// Calculate the length of the airdropAddresses array
uint256 length = airdropAddresses.length;
// Create a dynamic array to store unique addresses
address[] memory uniqueAddresses = new address[](length);
uint256 uniqueCount = 0;
// Outer loop to iterate through each address in the airdropAddresses array
for (uint256 i = 0; i < length; i++) {
bool isDuplicate = false;
// Inner loop to check if the address is already in the uniqueAddresses array
for (uint256 j = 0; j < uniqueCount; j++) {
if (airdropAddresses[i] == uniqueAddresses[j]) {
isDuplicate = true;
break;
}
}
// If the address is not a duplicate, add it to the uniqueAddresses array
if (!isDuplicate) {
uniqueAddresses[uniqueCount] = airdropAddresses[i];
uniqueCount++;
}
}
// Create a new array with the size of uniqueCount to store the final unique addresses
address[] memory finalUniqueAddresses = new address[](uniqueCount);
// Copy the unique addresses to the final array
for (uint256 k = 0; k < uniqueCount; k++) {
finalUniqueAddresses[k] = uniqueAddresses[k];
}
return finalUniqueAddresses;
}
}