🔥
Nonce в каждый дом.
Практически каждый, кто когда-то писал смарт контракты, знаком с концепцией
nonce. Каждый пользователь TON хоть раз, но использовал
nonce, встроенный в контракт wallet w5/v4/v3.
Nonce — это (обычно) некоторая информация, которая делает уникальным каждое исполнение подписанного offchain ордера в контракте. Это нужно для того, чтобы контракт нельзя было переиспользовать — например, чтобы нельзя было взять ваш свап на
@bidask, отправить его снова, и заставить ваш кошелек произвести свап заново.
Обычно все представляют
nonce как одно число, которое увеличивается на 1 при исполнении ордера. Однако такая концепция обладает проблемой (вы, возможно, с ней сталкивались) — в таком случае ордера должны быть обязательно исполнены последовательно один за другим, в строго определённом порядке. На пользовательских кошельках в TON могут пропадать транзакции, если быстро исполнить два действия подряд — второе действие может попасть валидатору перед первым, или же у обоих действий будет одинаковый
nonce — тогда одно исполнится, а второе пропадёт, ведь
nonce в контракте и ордере не совпадут. Ходят слухи, что это хотят исправить.
Для борьбы с этой проблемой существует множество концепций nonce. Расскажем про некоторые:
⚫️В
@bidask в trade account-ах реализована система с 16 параллельными
nonce-ами. Кроме числа, пользователь также должен приложить к ордеру номер nonce от 0 до 15 — и именно этот
nonce будет увеличен на 1 после исполнения ордера. Это позволяет отправлять в любой последовательности
⚫️В TON существует
highload wallet. Он сохраняет query_id пришедшего ордера и дедлайн, когда этот ордер перестанет быть валиден. Как только этот дедлайн истекает, он чистит сохранённые query_id, разумно считая, что все ранее исполненные ордера истекли. Таким образом он поддерживает гигантское количество параллельных транзакций — им пользуются CEX и многие сервисы, централизованно взаимодействующие с блокчейном.
⚫️На EVM блокчейнах есть и более экзотические варианты
nonce. Совсем недавно
его предложили хранить как двойной map { address => {uint256 => uint256}}. Каждому адресу юзера здесь сопоставляется map {uint256 => uint256}. Когда на такой контракт приходит ордер с nonce, контракт берет map по адресу юзера, и извлекает из от
nonce два значения:
word = nonce / X;
bitIndex = nonce % X;
// X -- это некоторое число (256 или 64)
Переменная word является ключом, а bitIndex — индекс бита в числе, который, по задумке, является нулевым битом (после исполнения ордера станет равным 1). Таким образом,
nonce позволяет исполнять огромное количество параллельных ордеров, являясь bitmap-ом. Подробнее можно почитать
тут.
Вариантов
nonce очень много — нужно просто понять, для чего он нужен в конкретном случае.
🎄 С новым годом.
@TheOpenDevBlog