kona-engine crate는 OP Stack rollup node를 위한 모듈식 실행 엔진 구현을 제공합니다. 이 crate는 rollup 프로토콜과 실행 계층(EL) 사이의 다리 역할을 하며, 정교한 작업 큐(task queue) 시스템을 통해 Engine API 상호작용을 관리합니다.
아키텍처 개요
실행 엔진은 다음과 같은 주요 구성 요소를 중심으로 구축됩니다.- Engine Task Queue: Engine API 작업을 관리하는 우선순위 정렬 큐
- Trait 추상화: 작업, 오류, 상태 관리를 위한 확장 가능한 인터페이스
- Engine Client: 실행 계층과 통신하는 HTTP 클라이언트
- Actor 통합:
EngineActor를 통한 서비스 계층 통합
핵심 Trait 추상화
ExecutableEngineTask
ExecutableEngineTask trait은 모든 엔진 작업의 인터페이스를 정의합니다.
EngineState에 대한 원자적 작업- 사용자 지정 작업을 위한 확장 가능한 작업 구현
- 적절한 오류 처리를 갖춘 비동기 실행
EngineTaskError
EngineTaskError trait은 심각도 수준을 갖춘 정교한 오류 처리를 제공합니다.
작업 큐 시스템
엔진은 우선순위 기반 작업 큐(EngineTask의 Ord 구현으로 정렬되는 이진 힙)를 사용하며, 작업은 OP Stack 동기화 요구 사항에 따라 정렬됩니다. 작업은 구체 타입인 EngineClient를 사용하며, 이 클라이언트의 Alloy provider들은 RPC 연결을 공유합니다. 테스트에서는 같은 클라이언트에 mock transport를 제공합니다.
작업 우선순위(높은 순서부터)
- Canonicalize - conductor 커밋 이후 봉인된(sealed) 블록을 가져옵니다(sequencer 모드)
- Seal - 빌드가 끝난 블록을 봉인합니다(sequencer 모드)
- Build - 새 블록을 빌드합니다(sequencer 모드)
- Insert - gossip에서 받은 unsafe 블록을 삽입합니다
- Consolidate - derivation을 통해 safe 체인을 진행시킵니다
- Finalize - L2 블록을 최종 확정합니다
engine_forkchoiceUpdated를 보내고 실행 계층의 동기화 완료 여부를 추적합니다. 이 단계의 실패는 SynchronizeTaskError로 보고됩니다.
작업 유형
BuildTask
sequencer 모드에서 새 블록 빌드를 시작하고 payload ID를 생성합니다.engine_forkchoiceUpdated를 호출하기 전에, 부모가 더 이상 unsafe head와 일치하지 않는 sequencer 빌드를 거부합니다. 빌드 실패는 sequencer에 전달되어 새 attributes로 재시도할 수 있게 합니다. 유효하지 않은 forkchoice 오류는 엔진 복구도 트리거합니다. Derivation은 공유 빌드 헬퍼를 직접 호출하며, reorg 중에는 다른 부모 위에 빌드할 수 있습니다.
SealTask
sequencer 모드에서BuildTask가 시작한 블록을 봉인합니다. 빌드의 부모가 여전히 unsafe head인지 확인하고, 버전별 engine_getPayload 호출로 payload를 가져옵니다. forkchoice는 변경하지 않습니다. CanonicalizeTask가 payload를 가져오기 전에 sequencer가 payload를 conductor에 커밋합니다.
CanonicalizeTask
sequencer 모드에서 sequencer가 봉인된 블록을 conductor에 커밋하면 해당 블록을 가져와 새 unsafe head로 만듭니다. conductor 커밋은 엔진 큐 밖에서 이루어지므로, 작업은 먼저 블록의 부모가 여전히 unsafe head인지 확인합니다. 거부된 블록은 deposit 전용 블록으로 대체되지 않습니다. 대체 블록에는 별도의 conductor 커밋이 필요하기 때문입니다. 새 unsafe head는 결과가 sequencer에 반환되기 전에 게시되며, 그 후 sequencer가 블록을 gossip으로 전파합니다.InsertTask
payload(예: gossip에서 받은 unsafe 블록)를 실행 엔진에 삽입합니다.ConsolidateTask
derivation을 통해 safe 체인을 진행시킵니다.FinalizeTask
L2 블록을 최종 확정합니다.엔진 상태 관리
EngineState는 실행 엔진의 현재 상태를 추적합니다.
EngineSyncState에 저장됩니다. 상태 업데이트는 watch 채널을 통해 전달되므로 시스템 전반에서 반응형 프로그래밍 패턴을 사용할 수 있습니다.
kona-node와의 통합
kona-node 서비스 계층은 EngineActor를 통해 엔진을 통합합니다.
Actor 패턴
EngineActor는 NodeActor trait을 구현합니다.
통신 채널
EngineActor는 상태를 변경하는 모든 입력을 EngineActorRequest 메시지의 단일 인바운드 요청 채널을 통해 받습니다. 여기에는 derivation에서 오는 payload attributes, gossip에서 오는 unsafe 블록, 리셋 요청, 최종 확정 요청, 블록 빌드 요청(sequencer 모드 전용)이 포함됩니다. RollupRpc 모듈은 읽기 전용 RPC 요청을 직접 처리합니다. 이 모듈은 output_at_block만 노출하는 EngineQueryClient를 통해 엔진의 L2 연결을 공유하며, watch 채널을 통해 엔진 상태를 읽습니다.
Rollup RPC 읽기
RollupRpc는 optimism_rollupConfig를 위해 rollup 구성을 복제하고, optimism_syncStatus를 위해 엔진 상태 스냅샷과 L1 watcher 상태를 결합하며, optimism_outputAtBlock을 위해 EngineQueryClient::output_at_block을 호출합니다. 이러한 읽기는 jsonrpsee 요청 핸들러에서 실행되므로, 느린 output root 조회가 다른 엔진 상태 읽기를 차단하지 않습니다.
사용 패턴
기본 엔진 설정
작업 추가
큐 비우기
오류 처리 및 복구
엔진은 다음을 통해 견고한 오류 처리를 제공합니다.심각도 기반 복구
- 일시적 오류: 자동으로 재시도됩니다
- 치명적 오류: actor로 전파됩니다
- 리셋 오류: derivation 파이프라인 리셋을 트리거합니다
- Flush 오류: derivation 파이프라인 flush를 트리거합니다
engine_forkchoiceUpdated에서 INVALID payload 상태가 반환되면 요청한 head가 거부된 것이므로, Kona는 같은 forkchoice를 재시도하는 대신 엔진과 derivation을 리셋합니다. 이는 Holocene의 deposit 전용 대체 경로를 유지하는 -38003 invalid-payload-attributes 오류와는 다릅니다. Derivation은 리셋을 처리하는 동안 복구된 safe head를 채택하고 재개합니다. head가 변경되지 않은 경우에도 마찬가지이며, 다른 L1 업데이트나 별도의 확인을 기다리지 않습니다.
상태 일관성
작업은EngineState에서 원자적으로 동작하므로, 오류 상황에서도 일관성이 보장됩니다.
버전 지원
엔진은 하드포크 활성화에 따라 적절한 Engine API 버전을 자동으로 선택합니다.- Ecotone 이전(Bedrock, Canyon, Delta):
engine_newPayloadV2와engine_getPayloadV2를 사용합니다 - Ecotone 이후:
engine_newPayloadV3와engine_getPayloadV3를 사용합니다 - Isthmus 이후:
engine_newPayloadV4와engine_getPayloadV4를 사용합니다 - Karst(Osaka) 이후:
engine_getPayloadV5를 사용합니다(engine_newPayload와engine_forkchoiceUpdated는 각각 V4/V3 버전을 유지합니다)
메트릭 및 관측 가능성
엔진에는 항상 다음에 대한 메트릭 계측이 포함됩니다.- 작업 실행 성공 및 실패 횟수
- 작업 유형별 오류율
- 엔진 상태 전이
- API 호출 지연 시간
확장성
trait 기반 아키텍처는 다음을 가능하게 합니다.ExecutableEngineTask를 통한 사용자 지정 작업 구현EngineTaskError를 통한 사용자 지정 오류 처리- 사용자 지정 상태 관리 확장
- 테스트 및 mocking 지원