Cardano-db-sync: Исключение из-за юникода в тестовой сети

Созданный на 19 сент. 2020  ·  15Комментарии  ·  Источник: input-output-hk/cardano-db-sync

В сети testnet cardano-db-sync в tags/5.0.0 в режиме extended выдает исключения в блоке 1816809 из-за проблем с синтаксическим анализом / обработкой Unicode. Он не может выполнить синхронизацию после этого блока.

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

Самый полезный комментарий

Вот как это выглядит теперь с временным исправлением:

[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

Все 15 Комментарий

Это ОГРОМНАЯ боль в шее.

Вставляемые метаданные tx:

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

который кодируется как 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"

что, конечно, не является допустимым UTF8, и, следовательно, база данных отклоняет его.

Хуже того, приведенное выше кодируется как UTF8 библиотекой Haskell Text как показано, но PostgreSQL затем отклоняет его.

Позвольте мне повторить, какая это ОГРОМНАЯ боль в шее.

Рассматриваемая строка декодируется в UTF8 библиотекой Haskell Text а затем передается в Postgres, который генерирует исключение SqlError . Я попытался перехватить это исключение, но перехват исключения, похоже, не работает.

Я могу поймать и зарегистрировать исключение:

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

но есть еще одно исключение:

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

Это говорит о том, что мне нужно более полно проверить JSON перед вставкой.

Мы можем хранить недопустимый UTF8 в PostgreSQL, но только как bytea data, а не как jsonb и если мы перейдем к предыдущему запросу Postgres, поддержка запросов JSON будет недоступна.

Я пробовал ручное декодирование UTF8:

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

и это тоже имеет ту же проблему.

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

Нулевой байт недопустим в строке PostgreSQL. Также нет нулевой кодовой точки.

В настоящее время думают, что это связано с тем, как Haskell / Persistent сериализует это для отправки в postgres. В настоящее время пытаюсь подтвердить эту теорию.

Aeson.encode уже экранирует NUL char на \u0000 который затем отклоняет Persistent.

Придумать аккуратное решение для этого будет непросто.

Я изучал это, и, похоже, эти свойства сохраняются:

  • "\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" вполне допустима как UTF-8, поскольку UTF-8 позволяет напрямую представлять \u0000 .
  • \u0000 нельзя использовать для jsonb потому что он не может быть преобразован в text .

Единственное временное решение для кодирования его в JSON, а затем в Text а затем обнаружение неправильной последовательности символов и отклонение объекта JSON, если он содержит неправильную последовательность. Мне также интересно, является ли \u0000 единственной последовательностью, которую мне нужно отклонить,

Не могли бы вы сохранить две колонки? байта и JSON, если он не содержит нетекстового символа, так что любой может использовать все, что ему нужно.

@erikd \u0000 ограничение четко указано здесь , наряду со всеми другими правилами, Postgres следующим образом . Итог: происходят отказы и преобразования.

Чтобы избежать нечеткой абстракции, необходимо сохранять точные значения (указанные пользователем). Это примерно означает либо большой двоичный объект (= отсутствие структуры в БД), либо строковые значения JSON, которые каким-то образом сохраняют исходное значение: например, строковые значения в кодировке base64 в БД (таким образом, восстановление структуры за счет дополнительной обработки в приложении в чтобы перевести из base64 в фактическое значение).

Временное исправление (просто удаление объектов метаданных, которые нельзя вставить в Postgres) было объединено в master.

Вот как это выглядит теперь с временным исправлением:

[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

Отремонтирован ли докер и какая версия отремонтирована

Это не исправлено, но 5.0.x (но я бы рекомендовал 5.0.2 ) имеет обходной путь, который позволяет избежать этой проблемы, отбрасывая tx_metadata содержащий символ Unicode NUL .

Была ли эта страница полезной?
0 / 5 - 0 рейтинги