Cardano-db-sync: Exception due à l'unicode sur testnet

Créé le 19 sept. 2020  ·  15Commentaires  ·  Source: input-output-hk/cardano-db-sync

Sur le réseau testnet , cardano-db-sync à tags/5.0.0 en mode extended , lève des exceptions au bloc 1816809 en raison de problèmes d'analyse/gestion Unicode. Il ne peut pas se synchroniser après ce bloc.

[db-sync-node:Info:234667] [2020-09-19 14:23:20.41 UTC] Starting chainSyncClient
[db-sync-node:Info:234667] [2020-09-19 14:23:20.48 UTC] Cardano.Db tip is at slot 6061839, block 1816809
[db-sync-node:Info:234672] [2020-09-19 14:23:20.48 UTC] Running DB thread
[db-sync-node:Info:234672] [2020-09-19 14:23:20.65 UTC] Rolling back to slot 6061839, hash 98414d12d1d1f05210dea6ce4082e1bcbbcfdf56343fd1cb44a8778c4c9ea57a
[db-sync-node:Info:234672] [2020-09-19 14:23:20.66 UTC] Deleting blocks numbered: []
[db-sync-node:Error:234672] [2020-09-19 14:23:21.03 UTC] runDBThread: DbInsertException "TxMetadata" (SqlError {sqlState = "22P05", sqlExecStatus = FatalError, sqlErrorMsg = "unsupported Unicode escape sequence", sqlErrorDetail = "\\u0000 cannot be converted to text.", sqlErrorHint = ""})
[db-sync-node:Error:234667] [2020-09-19 14:23:21.05 UTC] ChainSyncWithBlocksPtcl: DbInsertException "TxMetadata" (SqlError {sqlState = "22P05", sqlExecStatus = FatalError, sqlErrorMsg = "unsupported Unicode escape sequence", sqlErrorDetail = "\\u0000 cannot be converted to text.", sqlErrorHint = ""})
[db-sync-node.Subscription:Error:234663] [2020-09-19 14:23:21.05 UTC] [String "Application Exception: LocalAddress {getFilePath = \"/run/cardano-node/node.socket\"} DbInsertException \"TxMetadata\" (SqlError {sqlState = \"22P05\", sqlExecStatus = FatalError, sqlErrorMsg = \"unsupported Unicode escape sequence\", sqlErrorDetail = \"\\\\u0000 cannot be converted to text.\", sqlErrorHint = \"\"})",String "SubscriptionTrace"]
[db-sync-node.ErrorPolicy:Error:4] [2020-09-19 14:23:21.05 UTC] [String "ErrorPolicyUnhandledApplicationException (DbInsertException \"TxMetadata\" (SqlError {sqlState = \"22P05\", sqlExecStatus = FatalError, sqlErrorMsg = \"unsupported Unicode escape sequence\", sqlErrorDetail = \"\\\\u0000 cannot be converted to text.\", sqlErrorHint = \"\"}))",String "ErrorPolicyTrace",String "LocalAddress {getFilePath = \"/run/cardano-node/node.socket\"}"]

Commentaire le plus utile

Voici à quoi cela ressemble maintenant avec le correctif temporaire :

[db-sync-node:Info:37] [2020-09-22 10:19:09.66 UTC] insertShelleyBlock: epoch 84, slot 6060000, block 1816721, hash 3ec15354c53deae4eb26a206cc3185f799e80bd09393f279bce7e53a7d633144
[db-sync-node:Warning:37] [2020-09-22 10:19:24.08 UTC] insertTxMetadata: dropped due to a Unicode NUL character.
[db-sync-node:Warning:37] [2020-09-22 10:19:24.08 UTC] insertTxMetadata: dropped due to a Unicode NUL character.
[db-sync-node:Warning:37] [2020-09-22 10:19:24.10 UTC] insertTxMetadata: dropped due to a Unicode NUL character.
[db-sync-node:Warning:37] [2020-09-22 10:19:24.10 UTC] insertTxMetadata: dropped due to a Unicode NUL character.
[db-sync-node:Info:37] [2020-09-22 10:19:24.93 UTC] insertShelleyBlock: epoch 84, slot 6065000, block 1816973, hash 0ab0dd5c36c6eb480b8bbd05508be952c5ed8597a4e422af25bd80a905a9368d

Tous les 15 commentaires

C'est une douleur ÉNORME dans le cou.

Les métadonnées tx qui sont insérées sont

(1,S "\NUL\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX\ETX")

qui est encodé en JSON :

"\u0000\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003"

qui bien sûr n'est pas valide UTF8 et donc la base de données le rejette.

Pire encore, ce qui précède est encodé en UTF8 par la bibliothèque Haskell Text comme indiqué, mais PostgreSQL le rejette ensuite.

Permettez-moi de répéter à quel point c'est une douleur ÉNORME dans le cou.

La chaîne en question est décodée en UTF8 par la bibliothèque Haskell Text puis transmise à Postgres qui lève une exception SqlError . J'ai essayé d'attraper cette exception mais attraper l'exception ne semble pas fonctionner.

Je peux intercepter et enregistrer l'exception :

[db-sync-node:Warning:37] [2020-09-21 00:26:18.77 UTC] insertTxMetadata: Failed to insert (1,S "\NUL...\ETX")
SqlError {sqlState = "22P05", sqlExecStatus = FatalError, sqlErrorMsg
 = "unsupported Unicode escape sequence", sqlErrorDetail = "\\u0000 cannot be converted to text.", sqlErrorHint = ""}

mais alors il y a une deuxième exception:

[db-sync-node:Error:37] [2020-09-21 00:26:18.77 UTC] runDBThread: SqlError {sqlState = "25P02", sqlExecStatus = FatalError, sqlErrorMsg = "current transaction is aborted, commands ignored until end of transaction
 block", sqlErrorDetail = "", sqlErrorHint = ""}

Cela suggère que je dois valider plus complètement le JSON avant l'insertion.

Nous pouvons stocker UTF8 non valide dans PostgreSQL, mais uniquement sous forme de données bytea et non sous forme de jsonb et si nous optons pour l'ancien support de requête JSON de Postgres ne sera pas disponible.

J'ai essayé un décodage UTF8 manuel :

decodeUtf8IO :: ByteString -> IO (Either Text.UnicodeException Text)
decodeUtf8IO = try . evaluate . Text.decodeUtf8With Text.strictDecode

et cela aussi a le même problème.

De : https://stackoverflow.com/questions/31671634/handling-unicode-sequences-in-postgresql

Un octet nul n'est pas légal dans une chaîne PostgreSQL. Ni est un point de code zéro.

Je pense actuellement que cela est dû à la façon dont Haskell/Persistent sérialise cela pour l'envoyer à postgres. J'essaye actuellement de valider cette théorie.

Aeson.encode échappe déjà au caractère NUL à \u0000 que Persistent rejette ensuite.

Trouver une solution soignée pour cela ne va pas être facile.

Je cherchais cela et il semble que ces propriétés soient valables :

  • "\u0000\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003" est assez valide comme UTF-8, puisque UTF-8 permet à \u0000 d'être représenté directement.
  • \u0000 n'est pas autorisé pour jsonb car il ne peut pas être converti en text .

La seule solution temporaire pour l'encoder en JSON, puis en Text , puis détecter la mauvaise séquence de caractères et rejeter l'objet JSON s'il contient la mauvaise séquence. Je me demande aussi si \u0000 est la seule séquence que je dois rejeter,

Ne pourriez-vous pas stocker deux colonnes ? l'octet et le JSON lorsqu'il ne contient pas le caractère non textuel, afin que chacun soit libre d'utiliser ce dont il a besoin.

@erikd La \u0000 est clairement énoncée ici , ainsi que toutes les autres règles suivies par Postgres. Conclusion : il y a des rejets et des transformations en cours.

Pour éviter une abstraction qui fuit, les valeurs exactes (telles que données par l'utilisateur) doivent être stockées. Cela signifie à peu près soit un blob (= aucune structure dans la base de données) soit des valeurs de chaîne JSON qui préservent en quelque sorte la signification d'origine : par exemple des valeurs de chaîne codées en base64 dans la base de données (récupérant ainsi la structure au détriment d'un traitement supplémentaire dans l'application dans afin de traduire de la base64 à la valeur réelle).

Le correctif de contournement temporaire (simplement la suppression des objets de métadonnées qui ne peuvent pas être insérés dans Postgres) a été fusionné avec master.

Voici à quoi cela ressemble maintenant avec le correctif temporaire :

[db-sync-node:Info:37] [2020-09-22 10:19:09.66 UTC] insertShelleyBlock: epoch 84, slot 6060000, block 1816721, hash 3ec15354c53deae4eb26a206cc3185f799e80bd09393f279bce7e53a7d633144
[db-sync-node:Warning:37] [2020-09-22 10:19:24.08 UTC] insertTxMetadata: dropped due to a Unicode NUL character.
[db-sync-node:Warning:37] [2020-09-22 10:19:24.08 UTC] insertTxMetadata: dropped due to a Unicode NUL character.
[db-sync-node:Warning:37] [2020-09-22 10:19:24.10 UTC] insertTxMetadata: dropped due to a Unicode NUL character.
[db-sync-node:Warning:37] [2020-09-22 10:19:24.10 UTC] insertTxMetadata: dropped due to a Unicode NUL character.
[db-sync-node:Info:37] [2020-09-22 10:19:24.93 UTC] insertShelleyBlock: epoch 84, slot 6065000, block 1816973, hash 0ab0dd5c36c6eb480b8bbd05508be952c5ed8597a4e422af25bd80a905a9368d

Si docker est réparé, et quelle est la version réparée

Ce n'est pas corrigé, mais 5.0.x (mais je recommanderais 5.0.2 ) a une solution de contournement qui évite ce problème en supprimant tx_metadata contenant le caractère Unicode NUL .

Cette page vous a été utile?
0 / 5 - 0 notes