在testnet
网络上, extended
模式下tags/5.0.0
cardano-db-sync 由于 unicode 解析/处理问题在块 1816809 处引发异常。 它无法同步超过此块。
[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\"}"]
这是颈部的巨大疼痛。
正在插入的 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,因此数据库拒绝它。
更糟糕的是,上面的代码被 Haskell Text
库编码为 UTF8,如图所示,但是 PostgreSQL 拒绝了它。
让我重申一下这是多么巨大的颈部疼痛。
有问题的字符串由 Haskell Text
库解码为 UTF8,然后传递给 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。
我们可以在 PostgreSQL 中存储无效的 UTF8,但只能作为bytea
数据而不是jsonb
并且如果我们使用以前的 Postgres 的 JSON 查询支持将不可用。
我尝试过手动 UTF8 解码:
decodeUtf8IO :: ByteString -> IO (Either Text.UnicodeException Text)
decodeUtf8IO = try . evaluate . Text.decodeUtf8With Text.strictDecode
这也有同样的问题。
来自: https :
PostgreSQL 字符串中的空字节是不合法的。 也不是零代码点。
目前认为这是由于 Haskell/Persistent 将其序列化以发送到 postgres 的方式。 目前正在尝试验证这一理论。
Aeson.encode
已经将NUL
字符转义为\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
是否是我需要拒绝的唯一序列,
你不能存储两列吗? bytea 以及不包含非文本字符时的 JSON,以便任何人都可以自由使用他们需要的任何内容。
@erikd \u0000
限制在此处明确说明,以及 Postgres 遵循的所有其他规则。 底线:拒绝和转变正在进行。
为了避免泄漏抽象,必须存储准确的值(由用户给出)。 这大致意味着以某种方式保留原始含义的 blob(= DB 中没有结构)或 JSON 字符串值:例如 DB 中的 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
docker是否修复,修复的版本是什么
它不是固定的,但5.0.x
(但我建议5.0.2
)有一个解决方法,可以通过删除包含 Unicode NUL
字符的tx_metadata
来避免这个问题。
最有用的评论
这是现在使用临时修复的样子: