Cardano-db-sync: ν…ŒμŠ€νŠΈλ„·μ˜ μœ λ‹ˆμ½”λ“œλ‘œ μΈν•œ μ˜ˆμ™Έ

에 λ§Œλ“  2020λ…„ 09μ›” 19일  Β·  15μ½”λ©˜νŠΈ  Β·  좜처: input-output-hk/cardano-db-sync

testnet λ„€νŠΈμ›Œν¬μ—μ„œ extended λͺ¨λ“œμ˜ tags/5.0.0 μžˆλŠ” cardano-db-syncλŠ” μœ λ‹ˆμ½”λ“œ ꡬ문 뢄석/처리 문제둜 인해 블둝 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\"}"]

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

μž„μ‹œ μˆ˜μ •μ΄ 적용된 λͺ¨μŠ΅μž…λ‹ˆλ‹€.

[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이 μ•„λ‹ˆλ―€λ‘œ λ°μ΄ν„°λ² μ΄μŠ€κ°€ 이λ₯Ό κ±°λΆ€ν•©λ‹ˆλ‹€.

μ„€μƒκ°€μƒμœΌλ‘œ μœ„μ™€ 같이 Haskell Text λΌμ΄λΈŒλŸ¬λ¦¬μ— μ˜ν•΄ μœ„μ˜ λ‚΄μš©μ΄ UTF8둜 μΈμ½”λ”©λ˜μ§€λ§Œ PostgreSQL은 이λ₯Ό κ±°λΆ€ν•©λ‹ˆλ‹€.

이것이 λͺ©μ— μ–Όλ§ˆλ‚˜ 큰 고톡인지 λ‹€μ‹œ ν•œ 번 λ§μ”€λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€.

문제의 λ¬Έμžμ—΄μ€ Haskell Text λΌμ΄λΈŒλŸ¬λ¦¬μ— μ˜ν•΄ UTF8둜 λ””μ½”λ”©λœ λ‹€μŒ SqlError μ˜ˆμ™Έκ°€ λ°œμƒν•˜λŠ” Postgres둜 μ „λ‹¬λ©λ‹ˆλ‹€. 이 μ˜ˆμ™Έλ₯Ό 작으렀고 μ‹œλ„ν–ˆμ§€λ§Œ μ˜ˆμ™Έλ₯Ό μž‘λŠ” 것이 μž‘λ™ν•˜μ§€ μ•ŠλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

μ˜ˆμ™Έλ₯Ό ν¬μ°©ν•˜κ³  기둝할 수 μžˆμŠ΅λ‹ˆλ‹€.

[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 μš°λ¦¬λŠ” avaiableμ΄λ‹€κ°€λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€ 이전 포슀트 그레슀의 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

null λ°”μ΄νŠΈλŠ” 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에 μ‚½μž…ν•  수 μ—†λŠ” 메타데이터 개체 μ‚­μ œ)이 λ§ˆμŠ€ν„°μ— λ³‘ν•©λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

μž„μ‹œ μˆ˜μ •μ΄ 적용된 λͺ¨μŠ΅μž…λ‹ˆλ‹€.

[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 ꢌμž₯)μ—λŠ” μœ λ‹ˆμ½”λ“œ NUL λ¬Έμžκ°€ ν¬ν•¨λœ tx_metadata λ₯Ό μ‚­μ œν•˜μ—¬ 이 문제λ₯Ό λ°©μ§€ν•˜λŠ” ν•΄κ²° 방법이 μžˆμŠ΅λ‹ˆλ‹€.

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰