Workspace IndexKnowledge Notes › Your app doesn't read the chain — it reads a projection

#143PoC

Your app doesn't read the chain — it reads a projection

Every real product reads an indexer, not the chain — a derived read model that is always some blocks behind. The honest UI prints which block it is speaking for; the dishonest one just looks occasionally wrong.

Serve the same balance screen twice — one from direct RPC, one from an indexer with injected lag — then add an as-of-block label and a pending-transaction overlay, and watch which version stops looking broken.

Why

Reading the chain directly does not scale past one widget — real screens need joins, history and aggregates, so they read a projection built by an indexer. That is CQRS by necessity, and it imports CQRS's one cost: the read model lags the write model. The user who just paid sees an old balance; the list is missing the newest row.

The failure mode is not the lag — it is hiding it. A screen that says balance as of block 19,342,001, with your payment pending on top, is telling the truth and feels fine. A screen that silently shows stale data feels broken exactly when the user cares most, seconds after they acted. The staleness is unavoidable; the dishonesty is a choice.

How it works

Two data paths for one screen, lag you control, and the two UI elements that repair trust.

PoC

An anvil chain with a token, a tiny indexer (Ponder or a hand-rolled event loop) writing balances to SQLite, and one balance page with a data-source toggle. Add a configurable indexing delay. Make a transfer, watch the indexer-backed view lie for N seconds, then add (1) an as-of block label read from the projection's own cursor and (2) an optimistic pending row sourced from the app's submitted-transactions list. Assert the repaired view never contradicts what the user just did.

What it proves

The projection's lag cannot be engineered away, only labeled and bridged: the as-of label bounds what the screen claims, and the pending overlay covers the gap between the user's action and the indexer's cursor. Every serious dapp front end converges on these two elements — this PoC derives why in fifty lines.

Where it lands in Jayverse

  • Rabbit: label every balance or wallet screen with the indexer's as-of block, plus a pending-transaction overlay. The portal's balance view is a projection, not a live read; showing which block it speaks for and overlaying the user's just-submitted transaction is what stops "silently wrong" after every send.
  • Verex: apply the same as-of label to order-book and market-state reads. The CLOB UI reads an indexer or cache, not the chain directly, so a resolved market or a filled order needs the same cursor label and an optimistic row for the user's own just-placed order.
  • gitboard: show the as-of block or timestamp on any aggregated number. TVL, volume or the recycling-multiple figures gitboard reports are themselves projections; the dashboard should carry the same honesty device this page derives, not just the headline number.

Key expressions

Words and phrases from this page worth keeping, with the Korean meaning and the sentence they come from.

Expression뜻 · 쓰이는 자리
scale past(그 이상으로) 확장되지 않다 · 방법이 규모가 커지면 한계에 부딪힐 때. "does not scale past one widget"
import (a cost)(문제·비용을) 함께 들여오다 · 한 설계를 채택하면 그 단점도 같이 따라올 때. "imports CQRS's one cost"
lag (verb)뒤처지다, 시차를 두고 따라가다 · 읽기 모델이 쓰기 모델보다 늦을 때. "the read model lags the write model"
repair trust신뢰를 회복시키다 · UI 요소가 사용자 불신을 해소할 때. "the two UI elements that repair trust"
cover the gap간극을 메우다, 이어주다 · 대기 중 항목이 지연을 감춰줄 때. "the pending overlay covers the gap"
engineer away(기술로) 없애버리다, 제거하다 · 근본적으로 해결 불가능한 지연을 말할 때. "cannot be engineered away"
derive (verb)(논리적으로) 이끌어내다, 도출하다 · 짧은 코드로 원리를 증명할 때. "this PoC derives why in fifty lines"
CQRS명령과 조회 책임 분리(Command Query Responsibility Segregation) · 쓰기 모델과 읽기(프로젝션) 모델을 분리하는 아키텍처 패턴, 읽기 지연이 그 대가. "That is CQRS by necessity"
Ponder폰더 · 이더리움 이벤트를 색인하는 오픈소스 인덱서 프레임워크, PoC의 예시 도구. "a tiny indexer (Ponder or a hand-rolled event loop)"

← All Knowledge Notes · Workspace Index · Top ↑

앱은 체인을 읽지 않는다 — 프로젝션을 읽는다

모든 실제 제품은 체인이 아니라 인덱서 — 항상 몇 블록 뒤처진 파생 읽기 모델 — 를 읽습니다. 정직한 UI 는 자신이 어느 블록을 대변하는지 표기하고, 정직하지 않은 UI 는 그냥 가끔 틀려 보입니다.

같은 잔액 화면을 두 번 서빙합니다 — 하나는 직접 RPC, 하나는 지연을 주입한 인덱서에서. 그다음 기준-블록 라벨과 대기 중 트랜잭션 오버레이를 더하고, 어느 버전이 더는 고장나 보이지 않는지 관찰합니다.

체인을 직접 읽는 방식은 위젯 하나를 넘어서면 확장되지 않습니다 — 실제 화면에는 조인, 이력, 집계가 필요하므로 인덱서가 만든 프로젝션을 읽습니다. 필요에 의한 CQRS 이고, CQRS 의 비용 하나를 그대로 수입합니다: 읽기 모델은 쓰기 모델보다 늦습니다. 방금 결제한 사용자는 옛 잔액을 보고, 목록에는 최신 행이 빠져 있습니다.

실패 모드는 지연이 아니라 지연을 숨기는 것입니다. “블록 19,342,001 기준 잔액” 위에 대기 중인 결제를 얹어 보여주는 화면은 진실을 말하고 있고, 괜찮게 느껴집니다. 낡은 데이터를 말없이 보여주는 화면은 사용자가 가장 신경 쓰는 순간 — 행동한 직후 몇 초 — 에 정확히 고장나 보입니다. 뒤처짐은 불가피하고, 부정직은 선택입니다.

동작 방식

한 화면에 두 데이터 경로, 직접 제어하는 지연, 그리고 신뢰를 복구하는 두 UI 요소.

PoC

토큰이 있는 anvil 체인, 잔액을 SQLite 에 쓰는 작은 인덱서(Ponder 또는 직접 만든 이벤트 루프), 데이터 소스 토글이 있는 잔액 페이지 하나. 설정 가능한 인덱싱 지연을 추가합니다. 전송을 실행해 인덱서 기반 뷰가 N 초간 거짓말하는 것을 본 뒤, (1) 프로젝션 자신의 커서에서 읽은 기준-블록 라벨과 (2) 앱의 제출-트랜잭션 목록에서 가져온 낙관적 대기 행을 더합니다. 복구된 뷰가 사용자의 직전 행동과 절대 모순되지 않음을 확인합니다.

무엇을 증명하나

프로젝션의 지연은 공학으로 없앨 수 없고, 라벨을 붙이고 다리를 놓을 수만 있습니다: 기준 라벨은 화면의 주장 범위를 한정하고, 대기 오버레이는 사용자 행동과 인덱서 커서 사이의 틈을 덮습니다. 진지한 dapp 프런트엔드는 전부 이 두 요소로 수렴합니다 — 이 PoC 는 그 이유를 50줄로 유도합니다.

Jayverse에서의 위치

  • Rabbit: 모든 잔액/월렛 화면에 인덱서의 as-of 블록과 대기중 트랜잭션 오버레이를 표시한다. 포털의 잔액 화면은 실시간 읽기가 아니라 프로젝션이다. 어느 블록을 대변하는지 보여주고 사용자가 방금 제출한 트랜잭션을 오버레이하는 것이, 전송 직후 '조용히 틀린' 상태를 막는다.
  • Verex: 오더북·마켓 상태 읽기에도 같은 as-of 라벨을 적용한다. CLOB UI는 체인을 직접 읽지 않고 인덱서나 캐시를 읽는다. 정산된 마켓이나 체결된 주문에도 같은 커서 라벨과 사용자가 방금 낸 주문에 대한 낙관적 행이 필요하다.
  • gitboard: 집계된 숫자마다 as-of 블록이나 타임스탬프를 보여준다. gitboard가 보고하는 TVL, 거래량, 재순환 배수 수치도 그 자체가 프로젝션이다. 헤드라인 숫자만이 아니라 이 페이지가 도출한 것과 같은 정직성 장치를 대시보드에 넣는다.

핵심 표현

이 페이지의 영어 본문에서 배울 만한 단어와 표현, 뜻과 나온 자리.

Expression뜻 · 쓰이는 자리
scale past(그 이상으로) 확장되지 않다 · 방법이 규모가 커지면 한계에 부딪힐 때. "does not scale past one widget"
import (a cost)(문제·비용을) 함께 들여오다 · 한 설계를 채택하면 그 단점도 같이 따라올 때. "imports CQRS's one cost"
lag (verb)뒤처지다, 시차를 두고 따라가다 · 읽기 모델이 쓰기 모델보다 늦을 때. "the read model lags the write model"
repair trust신뢰를 회복시키다 · UI 요소가 사용자 불신을 해소할 때. "the two UI elements that repair trust"
cover the gap간극을 메우다, 이어주다 · 대기 중 항목이 지연을 감춰줄 때. "the pending overlay covers the gap"
engineer away(기술로) 없애버리다, 제거하다 · 근본적으로 해결 불가능한 지연을 말할 때. "cannot be engineered away"
derive (verb)(논리적으로) 이끌어내다, 도출하다 · 짧은 코드로 원리를 증명할 때. "this PoC derives why in fifty lines"
CQRS명령과 조회 책임 분리(Command Query Responsibility Segregation) · 쓰기 모델과 읽기(프로젝션) 모델을 분리하는 아키텍처 패턴, 읽기 지연이 그 대가. "That is CQRS by necessity"
Ponder폰더 · 이더리움 이벤트를 색인하는 오픈소스 인덱서 프레임워크, PoC의 예시 도구. "a tiny indexer (Ponder or a hand-rolled event loop)"

← 전체 기술 노트 · 워크스페이스 인덱스 · 맨 위 ↑