Подсказки по безопасности - 9
Удаление struct в котором есть mapping, не удаляет сам mapping. Это может быть использовано против вас.
struct BalancesStruct{
address owner;
mapping(address => uint) balances;
}
mapping(address => BalancesStruct) public stackBalance;
function remove() internal{
delete stackBalance[msg.sender];
}
В этом случае лучше использовать закрытие struct(lock), а не его удаление.
#security #tip #st
Удаление struct в котором есть mapping, не удаляет сам mapping. Это может быть использовано против вас.
struct BalancesStruct{
address owner;
mapping(address => uint) balances;
}
mapping(address => BalancesStruct) public stackBalance;
function remove() internal{
delete stackBalance[msg.sender];
}
В этом случае лучше использовать закрытие struct(lock), а не его удаление.
#security #tip #st
Оптимизация газа - 1
Компилятор Solidity считывает и выполняет функции по их селектору. Селектор, как мы знаем, располагается в первых четырех байтах сигнатуры функции из хеша kessac256. Например:
function tryThis(uint256 _value, string[] memory _names) external {}
В этом случае:
Сигнатура функции - tryThis(uint256,string[]);
Селектор функции - keccak256(signature) = 0x7f6ca090;
Компилятор Solidity располагает все функции в контракте по их селектору (в порядке hexadecimal) и проходит по каждой из них в тот момент, когда вызвана какая-либо из них. Проход по всем функциям в контракте стоит 22 газа.
Приведем к примеру такие функции:
red() => 2930cf24
white() => a0811074
yellow() => be9faf13
blue() => ed18f0a7
purple() => ed44cd44
green() => f2f1e132
Вызов green() будет стоит на 110 газа больше, чем вызов red(), только потому что она ниже.
Если вы наперед знаете, что какая-либо функция в вашем контракте будет вызываться чаще остальных, то старайтесь располагать ее выше остальных в контракте.
#gas #optimization #hint
Компилятор Solidity считывает и выполняет функции по их селектору. Селектор, как мы знаем, располагается в первых четырех байтах сигнатуры функции из хеша kessac256. Например:
function tryThis(uint256 _value, string[] memory _names) external {}
В этом случае:
Сигнатура функции - tryThis(uint256,string[]);
Селектор функции - keccak256(signature) = 0x7f6ca090;
Компилятор Solidity располагает все функции в контракте по их селектору (в порядке hexadecimal) и проходит по каждой из них в тот момент, когда вызвана какая-либо из них. Проход по всем функциям в контракте стоит 22 газа.
Приведем к примеру такие функции:
red() => 2930cf24
white() => a0811074
yellow() => be9faf13
blue() => ed18f0a7
purple() => ed44cd44
green() => f2f1e132
Вызов green() будет стоит на 110 газа больше, чем вызов red(), только потому что она ниже.
Если вы наперед знаете, что какая-либо функция в вашем контракте будет вызываться чаще остальных, то старайтесь располагать ее выше остальных в контракте.
#gas #optimization #hint
🔥3
Оптимизация газа - 2
Если взглянуть на таблицу стоимости газа, то мы заметим, что вызов переменной в первый раз стоит нам 2100 газа, а во второй - уже 100 газа. Эта разница может стать проблемой, особенно, когда мы работаем с динамическими массивами в циклах. Посмотрите на второй пример на скрине.
Работая с данными внутри функции стоит намного меньше газа, даже с учетом того, что добавились новые строчки кода. В данном примере мы экономим почти 2000 газа!
#gas #optimization #hint
Если взглянуть на таблицу стоимости газа, то мы заметим, что вызов переменной в первый раз стоит нам 2100 газа, а во второй - уже 100 газа. Эта разница может стать проблемой, особенно, когда мы работаем с динамическими массивами в циклах. Посмотрите на второй пример на скрине.
Работая с данными внутри функции стоит намного меньше газа, даже с учетом того, что добавились новые строчки кода. В данном примере мы экономим почти 2000 газа!
#gas #optimization #hint
🔥2
Оптимизация газа - 3
Изменение значения с "0" до любого-другого в сети Эфира стоит 20 000 газа (Gsset), в то время как обнуление значения может возвращает часть газа на баланс (Rsclear). Тут важно отметить, что вернуть можно только 20% от стоимости транзакции, которая превышает 24 000 газа.
Пример 1
У Алисы 10 токенов, а у Боба 0 токенов. Алиса пересылает 5 токенов Бобу. Таким образом баланс Алисы меняется с 10 токенов до 5, а у Боба с 0 до 5. Итого:
У Алисы - 5000 газа + у Боба - 20 000 газа. Всего 25 000 газа за транзакцию.
Пример 2
У Алисы 10 токенов, у Боба - 0. Алиса пересылает все 10 токенов Бобу, и ее баланс обнуляется. Получается:
У Алисы - 5000 газа + у Боба 20 000 газа = 25 000 газа. При этом Алисе вернут 4 800 газа обратно. Итого транзакция у нас выйдет в 20 200 газа.
Очевидно, что второй пример позволяет нам сэкономить немного газа, который может быть потрачен на другие операции в контракте.
#gas #optimization #hint
Изменение значения с "0" до любого-другого в сети Эфира стоит 20 000 газа (Gsset), в то время как обнуление значения может возвращает часть газа на баланс (Rsclear). Тут важно отметить, что вернуть можно только 20% от стоимости транзакции, которая превышает 24 000 газа.
Пример 1
У Алисы 10 токенов, а у Боба 0 токенов. Алиса пересылает 5 токенов Бобу. Таким образом баланс Алисы меняется с 10 токенов до 5, а у Боба с 0 до 5. Итого:
У Алисы - 5000 газа + у Боба - 20 000 газа. Всего 25 000 газа за транзакцию.
Пример 2
У Алисы 10 токенов, у Боба - 0. Алиса пересылает все 10 токенов Бобу, и ее баланс обнуляется. Получается:
У Алисы - 5000 газа + у Боба 20 000 газа = 25 000 газа. При этом Алисе вернут 4 800 газа обратно. Итого транзакция у нас выйдет в 20 200 газа.
Очевидно, что второй пример позволяет нам сэкономить немного газа, который может быть потрачен на другие операции в контракте.
#gas #optimization #hint
Оптимизация газа - 4
Хранение данных в calldata всегда стоит меньше газа, чем хранение в memory. Это с учетом того, что вы будете просто считывать данные в calldata, а не изменять их. Во втором случае, memory более разумный выбор.
#gas #optimization #hint
Хранение данных в calldata всегда стоит меньше газа, чем хранение в memory. Это с учетом того, что вы будете просто считывать данные в calldata, а не изменять их. Во втором случае, memory более разумный выбор.
#gas #optimization #hint
Оптимизация газа - 5
В Solidity существует 4 способа инкремента / декремента числа на 1.
Для каждой задачи используется разный опкод, потому стоимость газа будет слегка отличаться.
#gas #optimization #hint
В Solidity существует 4 способа инкремента / декремента числа на 1.
Для каждой задачи используется разный опкод, потому стоимость газа будет слегка отличаться.
#gas #optimization #hint
👍1
Оптимизация газа - 6
Solidity Optimizer прорабатывает две вещи в смарт контрактах: стоимость деплоя и стоимость вызова функций. Чем меньше "runs" установлено в Оптимизатор, чем меньше будет стоимость деплоя. С другой стороны, чем больше "runs" - тем меньше стоимость вызова функций.
Вы можете сами настраивать количество "runs", чтобы оптимизиваровать стоимость газа конкретно для вашего контракта.
#gas #optimization #hint
Solidity Optimizer прорабатывает две вещи в смарт контрактах: стоимость деплоя и стоимость вызова функций. Чем меньше "runs" установлено в Оптимизатор, чем меньше будет стоимость деплоя. С другой стороны, чем больше "runs" - тем меньше стоимость вызова функций.
Вы можете сами настраивать количество "runs", чтобы оптимизиваровать стоимость газа конкретно для вашего контракта.
#gas #optimization #hint
Оптимизация газа - 7
Функции помеченные как payable потребляют меньше газа, так как для них требуется меньше опкода для проверки, может ли другой контракт пересылать Эфир.
#gas #optimization #hint
Функции помеченные как payable потребляют меньше газа, так как для них требуется меньше опкода для проверки, может ли другой контракт пересылать Эфир.
#gas #optimization #hint
Оптимизация газа - 8
Когда вызову в контракте требуется больше 32kb памяти в одной транзакции, стоимость газа в разы возрастает. Посмотрите на пример.
Стоимость добавление 10 000 uint256 в память больше примерно в 10 раз больше добавления 1000 значений.
При этом стоимость добавления 20 000 значений уже больше в 4 раза стоимости добавления 10 000 uint256.
Чтобы избежать этого, вам стоит разбивать большие данные на более мелкие части и работать прицельно с ними.
#gas #optimization #hint
Когда вызову в контракте требуется больше 32kb памяти в одной транзакции, стоимость газа в разы возрастает. Посмотрите на пример.
Стоимость добавление 10 000 uint256 в память больше примерно в 10 раз больше добавления 1000 значений.
При этом стоимость добавления 20 000 значений уже больше в 4 раза стоимости добавления 10 000 uint256.
Чтобы избежать этого, вам стоит разбивать большие данные на более мелкие части и работать прицельно с ними.
#gas #optimization #hint
Оптимизация газа - 9
В выражениях, где используются операторы сравнения (<,>,<=,>=), дешевле будет использовать простые операторы - < или >, так как в случае с <= и >= компилятор сначала использует опкод "больше / меньше", а после опкод "iszero", чтобы проверить результат работы предыдущего сравнения.
#gas #optimization #hint
В выражениях, где используются операторы сравнения (<,>,<=,>=), дешевле будет использовать простые операторы - < или >, так как в случае с <= и >= компилятор сначала использует опкод "больше / меньше", а после опкод "iszero", чтобы проверить результат работы предыдущего сравнения.
#gas #optimization #hint
😱1
Оптимизация газа - 10
Когда вы используете require с двумя и более проверками, то в начало ставьте операторы && или | | для уменьшения стоимости газа. Например:
- require(A | | B) - если true, то компилятор не будет проверять остальные значения;
- require (A && B) - если false, то компилятор также остановит проверку дальше;
#gas #optimization #hint
Когда вы используете require с двумя и более проверками, то в начало ставьте операторы && или | | для уменьшения стоимости газа. Например:
- require(A | | B) - если true, то компилятор не будет проверять остальные значения;
- require (A && B) - если false, то компилятор также остановит проверку дальше;
#gas #optimization #hint
Оптимизация газа - 11
Указание правильной видимости функций влияет не только на безопасность ее исполнения, но и на экономию газа.
Например, создав external функцию, вы установите место хранения ее параметров, как calldata. Это позволит экономить газ каждый раз при ее вызове.
#gas #optimization #hint
Указание правильной видимости функций влияет не только на безопасность ее исполнения, но и на экономию газа.
Например, создав external функцию, вы установите место хранения ее параметров, как calldata. Это позволит экономить газ каждый раз при ее вызове.
#gas #optimization #hint
👍1
Оптимизация газа - 12
В Solidity некоторые data types дороже остальных. Вот несколько рекомендаций к их использованию:
- Тип uint лучше использовать вместо string, если это возможно;
- uint256 стоит меньше, чем uint8;
- bytes лучше использовать вместо byte[];
- Если длина bytes может быть ограничена, то лучше использовать наименьшие числа от bytes1 до bytes32;
- bytes32 дешевле, чем string;
#gas #optimization #hint
В Solidity некоторые data types дороже остальных. Вот несколько рекомендаций к их использованию:
- Тип uint лучше использовать вместо string, если это возможно;
- uint256 стоит меньше, чем uint8;
- bytes лучше использовать вместо byte[];
- Если длина bytes может быть ограничена, то лучше использовать наименьшие числа от bytes1 до bytes32;
- bytes32 дешевле, чем string;
#gas #optimization #hint
👍1
Оптимизация газа - 13
Если вам нужно провести цикл по массиву, то, для экономии газа, следует зафиксировать его длину в переменную выше. Например так:
uint length = arr.length;
for (uint i = 0; i < length; i++) {
// do something that doesn't change arr.length
}
так как в случае i < arr.length компилятор будет считывать длину при каждой итерации, что потребует дополнительного газа.
#gas #optimization #hint
Если вам нужно провести цикл по массиву, то, для экономии газа, следует зафиксировать его длину в переменную выше. Например так:
uint length = arr.length;
for (uint i = 0; i < length; i++) {
// do something that doesn't change arr.length
}
так как в случае i < arr.length компилятор будет считывать длину при каждой итерации, что потребует дополнительного газа.
#gas #optimization #hint
👍1
Оптимизация газа - 14
В некоторых случаях, пометив переменные как immutable, можно сэкономить немного газа при их вызове позже. Например:
contract C {
/// The owner is set during construction time, and never changed afterwards.
address public owner = msg.sender;
}
В этом случае, при вызове owner будет задействован sload, и будет затрачено 2100 газа при первом вызове и 100 - при последующих. Однако в следующем примере:
contract C {
/// The owner is set during construction time, and never changed afterwards.
address public immutable owner = msg.sender;
}
sload не применяется и вызов owner будет стоить всего 3 газа.
#gas #optimization #hint
В некоторых случаях, пометив переменные как immutable, можно сэкономить немного газа при их вызове позже. Например:
contract C {
/// The owner is set during construction time, and never changed afterwards.
address public owner = msg.sender;
}
В этом случае, при вызове owner будет задействован sload, и будет затрачено 2100 газа при первом вызове и 100 - при последующих. Однако в следующем примере:
contract C {
/// The owner is set during construction time, and never changed afterwards.
address public immutable owner = msg.sender;
}
sload не применяется и вызов owner будет стоить всего 3 газа.
#gas #optimization #hint
👍1
Оптимизация газа - 15
Используйте смещения вместо деления. Более того в этом случае не произойдет overflow.
#gas #optimization #hint
Используйте смещения вместо деления. Более того в этом случае не произойдет overflow.
#gas #optimization #hint
Оптимизация газа - 16
Тип bool в Solidity занимает 1 байт в памяти, из которых используется только один байт. При необходимости нескольких булевых значений можно заменить bool на uint32 или uint256 и битовой арифметики. Таким образом, uint256 может хранить до 256 булевых значений.
#gas #optimization #hint
Тип bool в Solidity занимает 1 байт в памяти, из которых используется только один байт. При необходимости нескольких булевых значений можно заменить bool на uint32 или uint256 и битовой арифметики. Таким образом, uint256 может хранить до 256 булевых значений.
#gas #optimization #hint
👍1
Оптимизация газа - 17
Ключевое слово event позволяет объявить события которая потом можно пробрасывать во время выполнения контракта, и эти события будут доступны извне. Помечание аргументов ключевым словом indexed позволяет искать по ним с помощью фильтров, но не только - они начинают стоит меньше памяти. Секрет кроется в том, что indexed аргументы кладутся на стек, а обычные - в память. Стоимость новой памяти растет квадратично, и использование indexed параметров почти всегда сохранит газ.
#gas #optimization #hint
Ключевое слово event позволяет объявить события которая потом можно пробрасывать во время выполнения контракта, и эти события будут доступны извне. Помечание аргументов ключевым словом indexed позволяет искать по ним с помощью фильтров, но не только - они начинают стоит меньше памяти. Секрет кроется в том, что indexed аргументы кладутся на стек, а обычные - в память. Стоимость новой памяти растет квадратично, и использование indexed параметров почти всегда сохранит газ.
#gas #optimization #hint
👍1
Оптимизация газа - 18
Ну, и в завершении, несколько дополнительных общих рекомендаций:
1. Используйте последние версии Solidity, так как они более безопасные и оптимизированные по газу;
2. Не используйте длинные string в revert(condition, string).
3. Лучше использовать кастомные Error, так как они дешевле по газу и стоимости деплоя. Более того, им можно дать подробное описание для других разработчиков в natspec;
Следите за циклами:
4) Чтобы не было dead функций:
if(x < 1) {
if(x > 2) {
return x;
}
}
5) Чтобы не было не нужны частей:
if(x > 1) {
if(x > 0) {
return x;
}
}
6) Чтобы не было не нужных циклов:
function constantOutcome() public pure returns(uint) {
uint num = 0;
for(uint i = 0; i < 100; i++) {
num += 1;
}
return num;
}
7) Чтобы не было overflow:
for (uint256 i = 0; i < length; ) {
// do something that doesn't change the value of i
unchecked {
i++;
}
}
Другие способы оптимизации газа ранее были на канале и будут еще. Следите за хештегами и присылайте свои заметки.
#gas #optimization #hint
Ну, и в завершении, несколько дополнительных общих рекомендаций:
1. Используйте последние версии Solidity, так как они более безопасные и оптимизированные по газу;
2. Не используйте длинные string в revert(condition, string).
3. Лучше использовать кастомные Error, так как они дешевле по газу и стоимости деплоя. Более того, им можно дать подробное описание для других разработчиков в natspec;
Следите за циклами:
4) Чтобы не было dead функций:
if(x < 1) {
if(x > 2) {
return x;
}
}
5) Чтобы не было не нужны частей:
if(x > 1) {
if(x > 0) {
return x;
}
}
6) Чтобы не было не нужных циклов:
function constantOutcome() public pure returns(uint) {
uint num = 0;
for(uint i = 0; i < 100; i++) {
num += 1;
}
return num;
}
7) Чтобы не было overflow:
for (uint256 i = 0; i < length; ) {
// do something that doesn't change the value of i
unchecked {
i++;
}
}
Другие способы оптимизации газа ранее были на канале и будут еще. Следите за хештегами и присылайте свои заметки.
#gas #optimization #hint
Гайд_по_проверке_контракта_и_его_кода.pdf
440.4 KB
Гайд по проверке контракта
За эту неделю я прочитал огромное количество информации по безопасности, включая все материалы из roadmap, который публиковал в начале этой недели.
Из всего я понял два основных момента:
1. Контракты строятся на максимальном zero-trust. Ни кому не доверять и проверять каждый шаг пользователя.
2. В контракте должны быть роли доступа. Самый простой пример это owner и другие пользователи. Если функцию, которую должен вызывать только owner, не защитить, то злоумышленник найдет способы, как пройти проверки и вызвать ее.
Из всех материалов в roadmap, меня привлек этот прекрасный гайд для проверки своего смарт контракта. Если пройтись по всем вопросам внимательно, то безопасность вашего контракта возрастет в несколько раз.
Предлагаю его перевод для всех.
#гайд #проверка
За эту неделю я прочитал огромное количество информации по безопасности, включая все материалы из roadmap, который публиковал в начале этой недели.
Из всего я понял два основных момента:
1. Контракты строятся на максимальном zero-trust. Ни кому не доверять и проверять каждый шаг пользователя.
2. В контракте должны быть роли доступа. Самый простой пример это owner и другие пользователи. Если функцию, которую должен вызывать только owner, не защитить, то злоумышленник найдет способы, как пройти проверки и вызвать ее.
Из всех материалов в roadmap, меня привлек этот прекрасный гайд для проверки своего смарт контракта. Если пройтись по всем вопросам внимательно, то безопасность вашего контракта возрастет в несколько раз.
Предлагаю его перевод для всех.
#гайд #проверка
👍4🔥1