Когда результат математической операции выходит за пределы диапазона, который может представлять целочисленный тип, это приводит к неправильному переносу значения, что может быть использовано злоумышленником для получения дополнительных токенов или ресурсов.
Предположим, у нас есть смарт-контракт,Он получает депозиты пользователей и сохраняет их в переменной. Если сумма, которую пользователь пытается внести, плюс существующий баланс превышает максимальное значение целого числа (в Solidity,uint256
Максимальное значение типа2^256-1),Произойдёт переполнение.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract OverflowExample {
uint256 public balance;
function deposit(uint256 amount) public {
balance += amount;
}
function getBalance() public view returns (uint256) {
return balance;
}
}
Для тестового переполнение,Мы предполагаем
balance
Ужеuint256
Максимальное значение типа,Попробуйте еще раз сохранить любое положительное число.,вызовет переполнение,То есть результат будет меняться от максимального значения до 0.
// Предположим, что баланс уже равен максимальному значению uint256.
uint256 maxUint256 = type(uint256).max;
balance = maxUint256;
// Попытка сохранить любое положительное число приведет к переполнению.
deposit(1);
// В это время баланс станет 0
Недополнение обычно происходит при операциях вычитания. Если вы вычитаете большее число из меньшего числа, результат будет меньше минимального целочисленного значения (для беззнаковых целых чисел минимальное значение равно 0), что приводит к переполнению.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract UnderflowExample {
uint256 public balance;
function withdraw(uint256 amount) public {
balance -= amount;
}
function getBalance() public view returns (uint256) {
return balance;
}
}
В целых числах без знака отсутствие переполнения фактически приводит к переходу значения от 0 до максимального значения, но обычно это не ожидаемое поведение и по-прежнему считается ошибкой.
// Предположим, баланс равен 0
balance = 0;
// Попытка вынуть любое положительное число приведет к переполнению
withdraw(1);
// В это время баланс станет максимальным значением uint256.
Чтобы избежать целочисленного переполнения и опустошения,Solidityобеспечивает безопасностьматематика БиблиотекаSafeMath
,Он содержит функции целочисленной арифметики для проверки переполнения и опустошения. Начиная с Solidity 0.8.0,Безопасностьматематика ОператорcheckedAdd
, checkedSub
, checkedMu
l, и checkedDiv
быть представленным,Может автоматически обнаруживать и выбрасывать аномальные объекты.
using SafeMath for uint256;
function deposit(uint256 amount) public {
balance = balance.checkedAdd(amount);
}
function withdraw(uint256 amount) public {
balance = balance.checkedSub(amount);
}
Таким образом, если обнаружено переполнение или опустошение, Solidity автоматически выдаст исключение, предотвращая выполнение транзакции и тем самым защищая контракт от таких ошибок.