Три хеші одного повідомлення

TON-повідомлення передається як bag of cells — BoC, і «хешем повідомлення» називають три різні хеші залежно від того, хто говорить. Мемпул-стрім TONNode доставляє всі три для кожного очікуваного повідомлення під такими іменами:

  • cell_hash — representation hash кореневої комірки. Саме його оглядачі називають хешем повідомлення, а після включення повідомлення в блок він дорівнює хешу in_msg тієї транзакції. Він залежить лише від комірок, а не від того, як їх серіалізовано в байти.
  • norm_hash — нормалізований хеш за TEP-467: хеш того самого зовнішнього вхідного повідомлення, переписаного у фіксовану форму — ext_in_msg_info$10 src:addr_none dest:<unchanged> import_fee:0 init:nothing body:right$1 ^body. Він не змінюється при пересеріалізації повідомлення та при зміні полів src, import_fee або init. Якщо повідомлення вже в цій формі, norm_hash дорівнює cell_hash.
  • sha256 — SHA-256 байтів BoC рівно в тому вигляді, в якому їх доставлено. Ті самі комірки можна серіалізувати кількома припустимими способами (з індексом або без, з CRC32C або без), і в кожної серіалізації свій SHA-256, тоді як два хеші комірок не змінюються.

Інструмент виводить кожен із них у hex і в base64, бо API розходяться: оглядачі та протокол liteserver використовують hex, низка HTTP API повертає base64.

Навіщо існує нормалізований хеш

Зовнішнє повідомлення підписує гаманець, а в мережу його передає той, хто ретранслює. Дорогою його можуть перекодувати, а ретранслятор — додати або прибрати адресу src, import_fee чи прикріплений init, нічого з цього гаманець не підписував. Кожна зміна дає нову кореневу комірку і новий cell_hash, тож нода, що відсіює дублікати за хешем комірки, прийняла б той самий підписаний payload кілька разів. TEP-467 фіксує форму, за якою обчислюється хеш, щоб усі ці варіанти зводилися до однієї сутності, і власна функція ноди get_ext_in_msg_hash_norm (у validator/impl/external-message.cpp) обчислює його саме так.

Конструкція проста: взяти біти отримувача як є, обнулити джерело, обнулити комісію, відкинути init і покласти тіло в посилання незалежно від того, чи було воно там. Нормалізований хеш має лише зовнішнє вхідне повідомлення; для внутрішнього або зовнішнього вихідного інструмент показує два інші хеші й прямо про це каже.

Що несе мемпул-стрім

Кожен кадр msg мемпул-стріму TONNode несе сам boc, його size, а також cell_hash, norm_hash і sha256 у визначеному вище сенсі. Відсіюйте дублікати у своїй обробці за cell_hash: те саме повідомлення може прийти двічі — спочатку як early (неперевірене), потім як checked, — і ще раз після перепідключення. sha256 — ключ, за яким нода відсіює дублікати отриманих байтів, тому він обчислюється за доставленими байтами, а не за перекодуванням.

Перевірено на реальних повідомленнях

Реалізація тут будує нормалізовану комірку точно так, як це робить власний парсер стріму, а набір тестів репозиторію пропускає через неї 72 реальні зовнішні повідомлення mainnet — набір фікстур стріму, для кожного з яких відомі cell_hash, norm_hash і sha256, доставлені стрімом, — і перевіряє збіг усіх трьох. Приклад повідомлення з документації мемпулу — одне з них; вставте його, щоб побачити три значення поруч.