Cardano-db-sync: Exceção devido a unicode em testnet

Criado em 19 set. 2020  ·  15Comentários  ·  Fonte: input-output-hk/cardano-db-sync

Na rede testnet , cardano-db-sync em tags/5.0.0 no modo extended , está lançando exceções no bloco 1816809 devido a problemas de processamento / análise unicode. Não é possível sincronizar após este bloco.

[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\"}"]

Comentários muito úteis

É assim que fica agora com correção temporária:

[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

Todos 15 comentários

Esta é uma dor ENORME no pescoço.

Os metadados tx que estão sendo inseridos são

(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")

que está sendo codificado como 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"

que obviamente não é UTF8 válido e, portanto, o banco de dados o rejeita.

Pior ainda, o código acima é codificado como UTF8 pela biblioteca Haskell Text conforme mostrado, mas o PostgreSQL então o rejeita.

Deixe-me reiterar como isso é uma enorme dor no pescoço.

A string em questão é decodificada para UTF8 pela biblioteca Haskell Text e então passada para o Postgres que lança uma exceção SqlError . Eu tentei capturar essa exceção, mas ela não parece funcionar.

Posso capturar e registrar a exceção:

[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 = ""}

mas então há uma segunda exceção:

[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 = ""}

Isso sugere que preciso validar mais completamente o JSON antes da inserção.

Podemos armazenar UTF8 inválido no PostgreSQL, mas apenas como bytea dados não como jsonb e se formos para o antigo suporte de consulta JSON do Postgres não estará disponível.

Eu tentei uma decodificação UTF8 manual:

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

e isso também tem o mesmo problema.

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

Um byte nulo não é válido em uma string PostgreSQL. Nenhum deles é um ponto de código zero.

Atualmente acho que isso é devido à maneira como Haskell / Persistent serializa isso para enviar para o postgres. Atualmente tentando validar essa teoria.

Aeson.encode já escapa do NUL char para \u0000 que Persistente então rejeita.

Encontrar uma solução simples para isso não será fácil.

Eu estava investigando isso e parece que essas propriedades são válidas:

  • "\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" é bastante válido como UTF-8, uma vez que UTF-8 permite que \u0000 seja representado diretamente.
  • \u0000 não é permitido para jsonb porque não pode ser convertido em text .

A única solução temporária para codificá-lo para um JSON e, em seguida, para Text e, em seguida, detectar a sequência de caracteres inválida e rejeitar o objeto JSON se contiver a sequência inválida. Também me pergunto se \u0000 é a única sequência que preciso rejeitar,

Você não poderia armazenar duas colunas? o bytea e o JSON quando não contém o caractere não textual, para que qualquer pessoa seja livre para usar o que precisar.

@erikd A \u0000 é claramente declarada aqui , junto com todas as outras regras que o Postgres segue. Resumindo: há rejeições e transformações acontecendo.

Para evitar uma abstração com vazamento, os valores exatos (conforme fornecidos pelo usuário) devem ser armazenados. Isso significa aproximadamente um blob (= sem estrutura no banco de dados) ou valores de string JSON que de alguma forma preservam o significado original: por exemplo, valores de string codificados em base64 no banco de dados (recuperando assim a estrutura às custas de processamento extra no aplicativo em para converter de base64 para o valor real).

A correção temporária (simplesmente descartar objetos de metadados que não podem ser inseridos no Postgres) foi mesclada com o master.

É assim que fica agora com correção temporária:

[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

Se o docker foi reparado e qual é a versão reparada

Não foi corrigido, mas 5.0.x (mas eu recomendaria 5.0.2 ) tem uma solução alternativa que evita esse problema eliminando tx_metadata contendo o caractere Unicode NUL .

Esta página foi útil?
0 / 5 - 0 avaliações