
OP Stack 롤업 프로세스 및 해당 코드에 대한 상세 설명
글: Rayer
Optimism Bedrock는 OP Stack의 현재 버전입니다. Bedrock 버전은 프로덕션 수준의 Optimistic Rollup 블록체인을 구동할 수 있는 도구를 제공합니다. 이 시점에서 OP Stack의 각 계층별 API는 여전히 스택의 Rollup 설정과 밀접하게 결합되어 있습니다.
Op-stack의 주요 rollup은 두 가지 서비스가 담당합니다.
-
op-batcher: 일정 시간마다 sequencer 상의 트랜잭션 내용을 읽어와서 이를 체인상의 DA(Data Availability)에 롤업하는 역할을 합니다.
-
op-proposer: 트랜잭션 상태를 컨트랙트에 롤업하는 역할을 합니다.
Rollup 아키텍처
op-batcher
op-batcher 실행 흐름도

loadBlocksInfoState 실행 로직
loadBlocksInfoState는 마지막으로 읽었던 블록 이후 아직 읽지 않은 모든 블록을 읽어오는 작업을 수행합니다.
전체적인 흐름은 다음과 같습니다.

코드는 다음과 같습니다:



loadBlocksIntoState가 수행하는 작업
1. sequencer 내의 동기화 상태를 가져옵니다.
2. 153행, calculateL2BlockRangeToStore 함수를 호출합니다.
-
calculateL2BlockRangeToStore는 제출해야 할 최신 L2 블록의 시작과 끝 번호를 가져오며, 판단합니다. 시작 블록은 L2의 현재 안전한 최고 블록이며, 종료 블록은 L2의 현재 가장 높은 비안전 블록입니다.
3. 164행, 제출할 시작 및 종료 블록을 확보한 후, 시작 블록부터 블록 정보를 가져오며, loadBlockIntoState 함수를 호출하여 블록을 가져옵니다.
-
loadBlockIntoState는 블록 정보와 geth 정보를 점검한 후 문제가 없으면, 200행에서
AddL2Block함수를 호출하여 해당 블록을 channelManager의 blocks []*types.Block 배열에 추가합니다.
4. 165~168행, 블록 재제출이 필요한지 검사하고, 필요하다면 l.lastStoredBlock을 eth.BlockID{}로 설정합니다. 173행에서는 그렇지 않을 경우 l.lastStoredBlock을 eth.ToBlockID(block)로, latestBlock을 block으로 설정합니다.
5. 177행, L2BlockToBlockRef는 L2 블록 참조 소스로부터 기본적인 L2BlockRef 정보를 추출하며, 블록 번호에 따라 필요시 제네시스 정보로 되돌립니다.
publishStateToL1 실행 로직
publishStateToL1은 큐에 있는 모든 트랜잭션을 L1에 제출하며, 큐에 트랜잭션이 없거나 오류가 발생할 때까지 반복합니다.
코드는 다음과 같습니다:

1. publishStateToL1은 큐에 있는 트랜잭션을 반복적으로 Layer1 네트워크에 전송합니다.
2. 377행에서 publishTxToL1을 호출합니다.

publishTxToL1은 단일 트랜잭션을 L1에 제출하는 로직으로, publishTxToL1 메서드는 제출할 데이터를 수집해 트랜잭션을 생성하고 Layer1 네트워크에 전송한 후, 전송된 트랜잭션을 receiptCh chan TxReceipt[T] 채널에 기록합니다.
-
429행,
l1Tip: 현재 L1 팁(tip)을 L1BlockRef로 가져옵니다. 전달된 컨텍스트가 수명주기 컨텍스트라고 가정하므로, 내부적으로 네트워크 타임아웃이 적용됩니다. -
434행,
recordL1Tip: 이전 L1BlockRef를 l1Tip에서 가져온 최신 L1BlockRef로 교체합니다. -
437행,
TxData: 롤업할 트랜잭션 데이터를 수집합니다. TxData는 L1에 제출되어야 할 다음 트랜잭션 데이터를 반환합니다. 현재 각 트랜잭션은 한 프레임만 사용합니다. 보류 중인 채널이 꽉 찼다면, 성공적으로 L1에 완전히 전송될 때까지 해당 채널의 남은 프레임만 반환합니다. 대기 중인 프레임이 없으면 io.EOF를 반환합니다. -
447행,
sendTransaction: 트랜잭션을 1단계(Layer1)에 전송하고, 그 상태를 receiptCh chan TxReceipt[T] 채널에 업데이트합니다. sendTransaction은 주어진 '데이터'로 트랜잭션을 생성하고 배치 수신 주소(inbox address)에 제출합니다. 현재 저수준 'txmgr'를 사용하여 트랜잭션 전송 및 가격 관리를 처리합니다. 이는 블로킹 방식의 메서드이며, 동시에 호출해서는 안 됩니다.
handleReceipt
handleReceipt는 채널로부터 트랜잭션 처리 상태를 받아 성공적으로 처리된 트랜잭션을 채널에서 제거합니다.
코드는 다음과 같습니다:
op-proposer
실행 흐름도
상세 실행 흐름

FetchNextOutputInfo
FetchNextOutputInfo: 후속 제출을 위한 조합 작업을 위해 L2 블록의 output을 가져옵니다. 반환되는 output 구조는 다음과 같습니다:
type OutputResponse struct {Version Bytes32 json:"version"OutputRoot Bytes32 json:"outputRoot"BlockRef L2BlockRef json:"blockRef"WithdrawalStorageRoot common.Hash json:"withdrawalStorageRoot"StateRoot common.Hash json:"stateRoot"Status *SyncStatus json:"syncStatus"}
코드는 다음과 같습니다:

-
224행, NextBlockNumber: 다음 배치 제출을 위한 블록 범위를 가져옵니다. 범위 계산은 latestBlockNumber() + SUBMISSION_INTERVAL이며, SUBMISSION_INTERVAL 값은 L2OutputOracle 컨트랙트 배포 시 지정할 수 있습니다.
-
230행,
FetchCurrentBlockNumber호출하여 현재 블록 번호를 가져옵니다. -
236~241행, 위에서 nextCheckpointBlock이 규칙을 만족하는지 확인한 후,
FetchOutput을 호출하여 L2에서 제출할 stateRoot를 가져옵니다.
FetchCurrentBlockNumber 코드는 다음과 같습니다:

1. 254행, SyncStatus: L2 블록의 SafeL2와 FinalizedL2 상태 및 블록 정보를 가져옵니다.
FetchOutput 코드는 다음과 같습니다:

2. 279행, OutputAtBlock: 블록 높이에 따라 output을 가져옵니다. 여기에는 stateRoot가 포함되며, 결국 eth_getProof를 호출하여 stateRoot를 계산하고 가져옵니다. 코드 호출 흐름은 위 이미지를 참고하세요. 참고: 매번 하나의 블록마다 stateRoot를 제출하는 것이 아니라, SUBMISSION_INTERVAL 설정값에 따라 여러 개의 블록에 대한 stateRoot를 계산한 후, 이를 L2OutputOracle 컨트랙트에 제출합니다.
send Transaction
-
sendTransaction: output을 사용해 stateRoot 제출용 트랜잭션을 구성하고, 이를 1단계 체인에 제출합니다. 아래는 트랜잭션 패키징 데이터 세부 사항입니다.
return abi.Pack( "proposeL2Output", output.OutputRoot, new(big.Int).SetUint64(output.BlockRef.Number), output.Status.CurrentL1.Hash, new(big.Int).SetUint64(output.Status.CurrentL1.Number))
코드는 다음과 같습니다:

TechFlow 공식 커뮤니티에 오신 것을 환영합니다
Telegram 구독 그룹:https://t.me/TechFlowDaily
트위터 공식 계정:https://x.com/TechFlowPost
트위터 영어 계정:https://x.com/BlockFlow_News















