Trois hashes pour un seul message
Un message TON circule sous forme de bag of cells — un BoC — et trois hashes différents sont appelés « le hash du message » selon qui parle. Le flux mempool de TONNode livre les trois pour chaque message en attente, sous ces noms :
cell_hash— le hash de représentation de la cellule racine. C'est ce que les explorateurs appellent le hash du message et, une fois le message inclus dans un bloc, il est égal au hashin_msgde cette transaction. Il ne dépend que des cellules, pas de la façon dont elles ont été sérialisées en octets.norm_hash— le hash normalisé TEP-467 : le hash du même message externe entrant réécrit sous une forme fixe —ext_in_msg_info$10 src:addr_none dest:<unchanged> import_fee:0 init:nothing body:right$1 ^body. Il reste stable quand le message est resérialisé ou quand ses champssrc,import_feeouinitchangent. Si le message a déjà cette forme,norm_hashest égal àcell_hash.sha256— le SHA-256 des octets du BoC exactement tels qu'ils ont été livrés. Les mêmes cellules peuvent être sérialisées de plusieurs façons valides (avec ou sans index, avec ou sans CRC32C), et chaque sérialisation a un SHA-256 différent alors que les deux hashes de cellule ne bougent pas.
L'outil affiche chacun en hex et en base64, parce que les API ne sont pas d'accord entre elles : les explorateurs et le protocole liteserver utilisent l'hex, plusieurs API HTTP renvoient du base64.
Pourquoi le hash normalisé existe
Un message externe est signé par un portefeuille et remis au réseau par celui qui le relaie. En chemin, il peut être réencodé, et un relayeur peut ajouter ou retirer l'adresse src, l'import_fee ou un init joint — rien de tout cela n'ayant été signé par le portefeuille. Chaque modification donne une nouvelle cellule racine et un nouveau cell_hash, de sorte qu'un nœud qui dédupliquerait par hash de cellule accepterait plusieurs fois la même charge signée. TEP-467 fixe la forme qui est hachée pour que toutes ces variantes se réduisent à une seule identité, et la fonction du nœud get_ext_in_msg_hash_norm (dans validator/impl/external-message.cpp) le calcule ainsi.
La construction est petite : prendre les bits de la destination tels quels, mettre la source à zéro, mettre les frais à zéro, supprimer l'init, et placer le corps dans une référence qu'il y ait été ou non. Seul un message externe entrant a un hash normalisé ; pour un message interne ou externe sortant, l'outil affiche les deux autres et le dit.
Ce que transporte le flux mempool
Chaque trame msg du flux mempool de TONNode transporte le boc lui-même, sa size, et cell_hash, norm_hash et sha256 tels que définis ci-dessus. Dédupliquez votre propre traitement par cell_hash : le même message peut arriver deux fois, d'abord en early (non vérifié) puis en checked, et de nouveau après une reconnexion. sha256 est la clé que le nœud utilise pour dédupliquer les octets qu'il a reçus, c'est pourquoi il est calculé sur les octets livrés et non sur un réencodage.
Testé contre des messages réels
L'implémentation présentée ici construit la cellule normalisée exactement comme le fait le propre parseur du flux, et la suite de tests du dépôt lui soumet 72 messages externes réels du mainnet — le jeu de fixtures du flux, chacun avec le cell_hash, le norm_hash et le sha256 que le flux a livrés — et vérifie que les trois correspondent. Le message d'exemple de la documentation du mempool en fait partie ; collez-le pour voir les trois valeurs côte à côte.
