
Solana에서 블록해시 오류를 처리하는 방법
블록해시란 무엇인가요?
블록해시를 이해하려면 먼저 슬롯과 블록을 알아야 합니다.
- 슬롯은 검증인이 블록을 생성할 수 있는 시간 단위입니다.
- 블록은 검증인이 처리하는 트랜잭션과 메타데이터의 모음입니다. 각 블록의 메타데이터는 이전 블록과 연결되어 체인을 형성합니다.
슬롯은 400~600ms 동안 지속되며, 각 슬롯에서 검증인은 새 블록을 제안할 수 있습니다. 블록이 생성되지 않으면 슬롯 번호가 증가하고 다른 검증인이 새 블록 생성을 시도합니다. 따라서 모든 슬롯에 블록이 연결되는 것은 아니지만, 모든 블록은 제안된 슬롯과 연결됩니다.
그렇다면 블록해시란 무엇일까요? 블록해시는 한 슬롯 동안 생성된 블록체인의 모든 원장 항목을 나타내는 고유한 해시 값입니다. 블록의 마지막 항목 ID를 기준으로 계산됩니다. 블록이 생성될 때마다 고유한 블록해시가 만들어집니다. 이 블록해시는 타임스탬프로 사용됩니다.
Solana의 커밋먼트 레벨이란 무엇인가요?
이해해야 할 또 다른 중요한 개념은 커밋먼트 레벨입니다. 커밋먼트 레벨은 특정 블록에 대한 네트워크의 확인 수준을 나타냅니다. 세 가지 옵션은 처리됨(processed), 확인됨(confirmed), 최종 확정됨(finalized)입니다.
검증인이 체인에 블록을 제출하면 해당 블록은 처리됨 상태가 됩니다. 필요한 수의 검증인(검증인의 66%)이 블록 포함에 투표하면 블록이 체인에 추가되고 커밋먼트 레벨이 확인됨으로 변경됩니다. 이 블록 위에 31개 블록이 추가로 구축되면 커밋먼트 레벨이 최종 확정됨으로 변경됩니다.
블록해시 오류는 왜 발생하나요?
모든 트랜잭션에는 타임스탬프 역할을 하는 최근 블록해시가 포함됩니다. 해당 블록해시가 더 이상 충분히 최근의 것으로 간주되지 않으면 트랜잭션이 만료됩니다. 트랜잭션을 처리하는 검증인은 “BlockhashQueue”(최근 300개 블록해시 목록)를 확인해 트랜잭션의 블록해시가 충분히 최근의 것인지 판단합니다. 블록해시가 목록에 없으면 트랜잭션은 거부됩니다. 슬롯은 일반적으로 400~600ms 동안 지속되므로 블록해시는 60~90초 동안 유효합니다.
블록해시를 찾을 수 없음(Transaction simulation failed: Blockhash not found)
“블록해시를 찾을 수 없음” 오류는 검증인이 트랜잭션을 처리할 때 포함된 블록해시가 유효하지 않다고 판단하면 발생합니다. 블록해시가 너무 오래되었거나, 경우에 따라 너무 최신이기 때문일 수 있습니다.
이 오류의 가장 일반적인 원인은 트랜잭션에 포함된 블록해시가 검증인이 비교하는 최근 300개 블록해시 큐에 없는 경우입니다. 이때 블록해시를 찾을 수 없음 오류가 발생합니다. 트랜잭션이 필요한 시간 내에 생성되었지만 처리되지 않으면 만료될 수 있습니다. 사용자가 트랜잭션 서명에 너무 오랜 시간을 들이는 경우가 대표적입니다. 유효한 트랜잭션이 제출되었지만 현재 블록에 포함되지 않고, 이후 블록에 포함될 수 있게 되었을 때는 트랜잭션의 블록해시가 너무 오래된 상태일 수도 있습니다.
이처럼 트랜잭션이 사실상 만료된 경우에는 블록 높이 초과 오류(TransactionExpiredBlock heightExceededError)가 흔히 발생합니다. 이 오류를 제대로 이해하려면 블록 높이의 의미를 알아야 합니다. 블록 높이는 현재 블록 아래에 있는 블록의 수를 의미합니다. 현재 블록이 1000번 블록이라면 블록 높이는 1000입니다. 트랜잭션을 생성할 때 해당 트랜잭션이 유효한 최대 블록 높이가 기록됩니다. 트랜잭션 처리 중 현재 블록 높이가 트랜잭션의 최대 유효 블록 높이보다 높은 것으로 확인되면 오류가 발생합니다.
“블록해시를 찾을 수 없음 오류”가 발생할 수 있는 또 다른 상황은 트랜잭션의 블록해시가 해당 트랜잭션의 만료 여부를 확인하는 데 사용된 블록해시보다 최신인 경우입니다. 다소 복잡하므로 예를 들어 보겠습니다. 특정 블록의 블록해시를 포함한 트랜잭션을 생성한다고 가정해 보겠습니다. 이 블록을 1000번 블록이라고 하고 트랜잭션을 즉시 RPC로 전송합니다. 그러면 RPC는 이전 블록의 블록해시를 가져올 수 있습니다. 이 경우 999번 블록일 수 있습니다. RPC가 더 높은 커밋먼트 레벨을 사용하거나 RPC 노드가 네트워크보다 뒤처졌기 때문입니다. 결과적으로 트랜잭션의 블록해시를 찾지 못합니다. 드문 상황이지만 다음 두 가지 시나리오에서 발생할 수 있습니다.
1. 커밋먼트 레벨 불일치
트랜잭션을 생성할 때는 확인됨 커밋먼트 레벨을 사용하지만, RPC가 유효성을 계산할 때는 기본적으로 최종 확정됨 커밋먼트 레벨을 사용하는 경우입니다.
최종 확정된 블록은 최신 블록보다 31개 블록 “뒤에” 있으므로, 유효성 검사에 사용되는 블록해시가 트랜잭션의 블록해시보다 오래될 수 있습니다.
최종적으로 폐기되는 소수 포크에서 처리됨 커밋먼트 레벨을 사용해 트랜잭션의 블록해시를 가져오면, 해당 블록해시는 무효가 되어 처리 중에 찾을 수 없습니다.
2. RPC 불일치
블록해시를 가져올 때와 트랜잭션을 전송할 때 서로 다른 RPC를 사용하면, 트랜잭션을 전송하는 RPC의 지연으로 인해 유효성 검사에 사용하는 블록이 트랜잭션 생성 시 사용한 블록보다 오래될 수 있습니다.
블록해시 오류를 해결하는 방법
앞서 설명한 각 상황에 대응하려면 몇 가지 조치를 취해야 합니다.
1. 너무 오래되지 않은 블록해시로 트랜잭션을 제출하세요.
트랜잭션의 블록해시를 가져올 때 confirmed 커밋먼트 레벨을 사용하세요. 그러면 finalized 커밋먼트 레벨보다 최신 블록해시를 포함할 수 있습니다.
조금 더 최신인 블록해시가 필요하다면 processed 커밋먼트 레벨을 사용할 수도 있습니다. 하지만 처리된 블록 중 약 5%는 클러스터에서 최종 확정되지 않습니다. 이 경우 트랜잭션의 블록해시가 폐기된 포크에 속하게 되어 더 이상 유효하지 않습니다.
2. 트랜잭션의 블록해시가 유효성 검사에 사용되는 블록해시보다 최신이지 않도록 하세요.
preflightCommitment는 항상 트랜잭션의 블록해시를 가져올 때 사용한 것과 동일한 커밋먼트 레벨로 설정하세요. skipPreflight을 사용하는 경우에도 마찬가지입니다. 그러면 트랜잭션의 블록해시가 유효성 검사에 사용되는 블록해시보다 최신이 되는 상황을 방지할 수 있습니다.
트랜잭션 전송 시 RPC 노드의 지연에 대응하려면 RPC로 트랜잭션을 계속 다시 전송해야 합니다. 일정한 간격으로 재전송하면 RPC가 지연되더라도 결국 네트워크를 따라잡아 트랜잭션의 만료를 감지할 수 있습니다.
simulateTransaction 요청을 사용한다면 replaceRecentBlockhash 매개변수를 설정해야 합니다. 이 플래그는 시뮬레이션된 트랜잭션의 블록해시를 시뮬레이션에 항상 유효한 블록해시로 교체하도록 RPC에 지시합니다.
3. 블록해시가 유효한 동안 트랜잭션을 계속 재시도하세요.
트랜잭션을 생성하고 최신 블록해시를 가져올 때 해당 블록해시의 lastValidBlockHeight을 기록해야 합니다. 이후 현재 블록 높이가 트랜잭션의 유효 블록 높이를 초과할 때까지 해당 블록해시로 트랜잭션을 계속 재시도할 수 있습니다. getBlockHeight RPC 호출을 사용하면 트랜잭션이 여전히 유효한지 지속적으로 확인할 수 있습니다. 현재 블록 높이가 트랜잭션의 lastValidBlock 높이보다 높아지면 새 블록해시를 가져와 사용해야 합니다.
이 글이 블록해시 오류를 더 잘 이해하고 오류 발생 횟수를 줄이는 데 도움이 되기를 바랍니다. 추가 질문이 있다면 언제든 Discord 커뮤니티에 참여하거나 X에서 다이렉트 메시지를 보내 주세요.
추가 자료:
관련 아티클
Helius 구독하기
최신 Solana 개발 소식을 확인하고 새 게시물 알림을 받아보세요


