5개월, 110,000줄의 Rust, 그리고 스마트 컨트랙트 0개: NOVAI 기술 투어
요약
NOVAI 프로젝트의 기술적 아키텍처와 Rust 기반의 L1 블록체인 구현 과정을 상세히 설명합니다. 11만 줄 이상의 Rust 코드로 구축된 이 시스템은 범용 VM 대신 최적화된 트랜잭션 및 메모리 객체 구조를 채택하며, 엄격한 보안 감사와 테스트를 거쳤음을 강조합니다.
핵심 포인트
- 11만 줄 이상의 Rust 코드로 구현된 AI-native L1 아키텍처
- HotStuff 스타일의 BFT 합의 알고리즘 및 3-chain 커밋 규칙 적용
- unsafe 코드 0개 및 퍼징 테스트를 통한 높은 보안성 확보
- 범용 VM을 배제한 최적화된 트랜잭션 및 메모리 객체 설계
저는 왜 AI-native L1(Layer 1)이 존재해야 하는지를 주장하는 다섯 개의 포스트를 게시해 왔습니다. 이 글은 그중 하나가 아닙니다. 이것은 기술적인 워크스루 (walkthrough)입니다.
아래는 NOVAI가 실제로 L1에 보유하고 있는 것, 의도적으로 제외된 것, 그리고 아키텍처 측품을 뒷받침하는 코드 경로입니다. 모든 아키텍처 주장은 오픈 소스 (open-source) 코드에서 검증 가능합니다. 이 글을 쓰는 시점의 리포지토리 (repo)는 github.com/0x-devc/NOVAI-node, HEAD 2a69c2a입니다.
저는 18세이며, 혼자서 5개월 동안 이것을 구축해 왔습니다. 코드는 MIT/Apache-2.0 라이선스 하에 오픈 소스입니다.
수치 (클론 (clone)을 통해 5분 내에 검증 가능):
175개 파일에 걸친 111,055줄의 Rust 코드. 16개의 프로토콜 크레이트 (protocol crates)와 3개의 도구, 그리고 3개의 SDK 언어 (Rust, Python, TypeScript). 5개월 동안 364개의 커밋 (commits). 통과된 1,892개의 Rust 테스트 (실패 0, 무시 0). 로컬 데브넷 (devnet)에 대한 200개의 Python 유닛 테스트 (unit tests) 및 8개의 통합 테스트 (integration tests). Clippy 에러 0개. 워크스페이스 린트 (Workspace lint)는 컴파일 타임에 unsafe를 금지합니다. 라이선스는 cargo-deny를 통과합니다 (GPL/AGPL 없음, 클린룸 불변성 (clean-room invariant) 유지).
처음부터 작성된 3-chain 커밋 규칙을 가진 HotStuff 스타일의 BFT 합의 (consensus).
RE 저는 코드베이스에 대해 Tier 1 감사 (audit) 스위트를 실행했습니다: cargo-audit, cargo-geiger, clippy --pedantic --nursery, semgrep (p/rust + p/r2c-security-audit, Trail of Bits의 Rust 규칙 세트 포함), 그리고 세 개의 와이어 포맷 (wire-format) 디코더에 대한 cargo-fuzz를 총 18시간의 컴퓨팅 자원으로 실행했습니다. 전체 결과는 docs/SECURITY_AUDIT_2026-05-29.md에 있습니다. 주요 수치: 워크스페이스 어디에서도 unsafe 코드 0개 (린트 레벨에서 금지됨), Trail of Bits 및 r2c semgrep 규칙에 따른 프로토콜 코드의 보안 취약점 발견 0개, 합의 (consensus) 및 코덱 (codec) 내의 모든 정수 캐스트 (integer casts)가 수동으로 경계 검증됨, 세 개의 타겟에 대해 411.8억 번의 적대적 퍼징 (adversarial fuzz) 반복 수행 중 패닉 (panic) 0회, 그리고 발견 후 24시간 이내에 패치된 두 개의 전이적 의존성 (transitive dependency) CVE (quinn-proto DoS, rustls-webpki panic).
이것은 전문 감사인들이 1차 검토로 실행하는 작업의 오픈 소스 버전입니다. 유료 제3자 계약이 아닙니다. 저는 문서에서 그 점을 명확히 밝히고 있습니다.
그것은 엔지니어링 측면입니다. 프로토콜 측면은 더 흥미롭습니다.
NOVAI에는 11가지 트랜잭션 (transaction) 유형, 23가지 시그널 (signal) 유형, 16가지 온체인 메모리 객체 (on-chain memory object) 유형이 있습니다. 7개의 권한 비트 (capability bits)와 하나의 예약된 슬롯이 있습니다. 그게 전부입니다. 범용 가상 머신 (general-purpose virtual machine)은 없습니다. 사용자가 임의의 코드를 합의 (consensus) 과정에 배포할 수 있는 방법도 없습니다.
전체 프로토콜 표면 (protocol surface)은 하나의 표에 들어갑니다. 핵심 와이어 포맷 (wire formats)은 바이트 레벨의 골든 벡터 테스트 (golden vector tests)로 고정되어 있으며, 모든 새로운 프리미티브 (primitive)는 코덱 라운드트립 테스트 (codec round-trip tests)와 함께 출시됩니다. 체인은 모든 연산이 무엇을 하는지 알고 있는데, 이는 모든 연산이 체인 자체가 직접 구현하는 것이기 때문입니다.
이것이 바로 경계가 지정된 L1 (bounded L1) 설계입니다. 이에 대한 논거는, 고정된 프리미티브 (fixed primitives)를 잘 선택하면 범용 체인 (general-purpose chains)이 할 수 없는 것들을 체인이 강제할 수 있다는 점입니다.
다른 곳에서는 스마트 컨트랙트였을 네 가지 프리미티브
이것들은 일반적인 L1에서는 컨트랙트를 배포해야만 가능한 NOVAI의 네 가지 연산입니다. NOVAI에서 이것들은 프로토콜 레벨 (protocol-level)입니다.
권한 검사가 이루어지는 에이전트 등록 (Capability-checked agent registration)
NOVAI에 AI 엔티티 (entity)를 등록할 때, 등록 시점에 권한 비트 (capability bits)를 설정합니다. 현재 7개가 활성화되어 있으며, 체인 상태 읽기, 제안 (proposals) 발행, 실행 요청, 평판 (reputation) 업데이트 제출, 오라클 앵커 (oracle anchors) 게시 등의 기능을 담당합니다. 여덟 번째 슬롯은 향후 사용을 위해 예약되어 있습니다.
result = client.register_entity(
keypair=kp,
code_hash=code_hash,
capabilities=Capabilities.oracle(),
autonomy_mode=AutonomyMode.GATED,
initial_balance=1_000_000,
)
체인은 컨트랙트 호출 (contract-call) 시점이 아니라 시그널 핸들러 (signal-handler) 시점에 권한을 확인합니다. 엔티티가 오라클 앵커를 게시하려고 하면, 핸들러는 requires_capability(db, issuer, current_height, |c| c.post_oracle_anchors)를 실행합니다. 이 확인 작업은 매번 현재 상태 (current state)로부터 다시 읽힙니다. 취소된 권한은 재사용(replay)될 수 없습니다.
Ethereum에서는 이와 가장 유사한 기능이 OpenZeppelin의 AccessControl입니다. 역할 관리 (role management) 기능을 갖춘 약 600줄 규모의 감사 완료된 (audited) 컨트랙트 하나가 존재합니다. 각 권한 (capability)은 bytes32 역할 해시 (role hash)가 됩니다. 배포자 (deployer)가 역할을 발행 (mint)합니다. 업그레이드 가능성 (upgradability)을 원한다면 이를 프록시 (proxy)로 감싸야 합니다. 이는 또 다른 컨트랙트이자 또 다른 감사 범위 (audit surface)를 의미합니다.
NOVAI가 Ethereum 버전과 달리 보장하는 점은 다음과 같습니다: 권한 비트 (capability bits)는 엔티티의 프로토콜 수준의 신원 (protocol-level identity)의 일부이며, 엔티티의 코드 해시 (code hash)에 결합되어 있습니다. 컨트랙트 자체가 존재하지 않기 때문에 컨트랙트 업그레이드로 인해 권한이 삭제될 수 없습니다. 권한 확인 (capability check)은 해당 권한이 제어하는 동작과 동일한 원자적 배치 (atomic batch) 내에서 발생합니다. 따라서 역할을 확인하는 시점과 동작을 수행하는 시점 사이에 레이스 윈도우 (race window)가 존재하지 않습니다.
자동 슬래싱 (auto-slashing) 기능이 포함된 SLA
NOVAI에서의 SLA는 두 엔티티가 서명하는 메모리 객체 (memory object, type 14)입니다. 구매자가 이를 생성하면, 판매자가 SlaAccept 신호 (type 18)로 이를 수락합니다. 수락되면 구매자가 발행하는 모든 서비스 증명 (ServiceAttestation, type 17)은 위반 임계값 (violation threshold)에 합산됩니다.
구매자가 SLA 기간 내에 증명 실패를 보고하면, ServiceAttestation 핸들러는 하나의 원자적 배치 (atomic batch) 내에서 다음 네 가지 작업을 수행합니다:
- 판매자의 스테이크 잔액 (stake balance)에서 포화 차감 (Saturating-debit) 방식으로 slash_amount를 차감
- 슬래싱 재고 (slash treasury)에 입금
- SLA 위반에 따른 평판 변화량 (reputation delta) 적용
- SLA 상태를 VIOLATED 상태로 전환
StakeWithdraw 신호는 활성화된 SLA 담보 확인 (open-SLA collateral check)에 의해 제어됩니다. 판매자는 SLA가 활성화된 동안 스테이크를 인출할 수 없습니다. 이는 기계적으로 방지됩니다.
Ethereum에서는 최소 세 개의 컨트랙트가 필요합니다: 담보를 보유하는 에스크로 (Escrow), 증명을 제공하는 오라클 (Oracle), 그리고 오라클을 감시하며 에스크로를 호출하는 슬래셔 (Slasher)입니다. 구성 위험 (composition risks)에는 오라클의 최신성 (freshness), 슬래싱 시의 재진입 (reentrancy), 증명 이벤트와 슬래싱 트랜잭션 사이의 레이스 (race), 그리고 컨트랙트 간의 비대칭적 일시 중단 (asymmetric pause) 동작 등이 포함됩니다.
NOVAI에서는 슬래싱 (slash), 재무 (treasury) 크레딧, 평판 델타 (reputation delta), 그리고 상태 전이 (state transition)가 모두 하나의 apply_batch 내에서 발생합니다. 모든 효과가 적용되거나, 아니면 아무것도 적용되지 않습니다. "오라클 (oracle)"은 구매자 자신의 신호입니다. 업그레이드해야 할 제3의 컨트랙트도 없고, 감사 (audit)를 위한 신선도 윈도우 (freshness window)도 존재하지 않습니다.
Oracle anchors
OracleAnchor는 신호 타입 22입니다. post_oracle_anchors 권한을 가진 엔티티는 오프체인 (off-chain) 데이터의 32바이트 해시와 "price/ETH-USD"와 같은 태그 (tag)를 커밋합니다. 체인은 이를 ai/oracle_anchors/by_hash/ 하위의 KV 보조 레코드 (aux record)로 저장하며, 엔티티별 및 태그별 조회를 위한 보조 인덱스 (secondary indices)를 제공합니다.
result = client.post_oracle_anchor(
keypair=kp,
issuer_entity_id=entity_id,
data_hash=data_hash,
external_timestamp=int(time.time()),
data_tag="price/ETH-USD",
)
세 가지 RPC가 앵커 (anchors)를 쿼리합니다: novai_getOracleAnchor, novai_getOracleAnchorsByEntity, novai_getOracleAnchorsByTag. 태그 조회는 일급 시민 (first-class)입니다. 심볼 (symbol)로 쿼리하기 위해 별도의 인덱서 (indexer)를 구축할 필요가 없습니다.
Ethereum에서는 직접 오라클 컨트랙트를 작성하거나 Chainlink를 통합해야 합니다. 임의의 태그를 가진 사용자 정의 피드 (user-defined feeds)를 원한다면 권한 부여 레이어 (permissioning layer)를 직접 작성해야 합니다. 태그별로 과거의 앵커를 쿼리하고 싶다면 TheGraph 서브그래프 (subgraph)를 구축해야 합니다.
NOVAI가 보장하는 것: 앵커는 게시되면 불변 (immutable)입니다. UPDATE_ORACLE_ANCHOR 신호는 존재하지 않습니다. 해시 뒤의 데이터는 오프체인에서 부패할 수 있지만, 온체인 (on-chain)에서의 약속 (commitment)은 수정될 수 없습니다. 또한 앵커는 발행자 (issuer)의 비활성화 이후에도 유지됩니다. 프로토콜 수준의 강제 집행 (enforcement)은 오직 이 불변의 레코드만을 읽습니다.
Conditional payments
PaymentRequest 신호는 조건에 따른 해제를 제어하는 트레일러 마커 (trailer marker) 0xC1을 포함합니다.
result = client.pay(
keypair=payer_kp,
issuer_entity_id=payer_entity_id,
payee=payee_entity_id,
amount=1_000,
signal_hash=secrets.token_bytes(32),
service_descriptor_hash=service_descriptor_hash,
request_hash=secrets.token_bytes(32),
max_block_height=current_height + 100,
condition=PaymentCondition.anchor_data_hash_equals(
anchor_signal_hash=anchor_signal_hash,
expected_data_hash=expected_data_hash,
),
)
네 가지 조건 종류가 있습니다: anchor 존재 여부, anchor의 데이터 해시가 예상 값과 일치하는지 여부, anchor의 태그가 예상 태그와 일치하는지 여부, anchor가 만료되지 않았는지 여부. 체인은 불변의 OracleAnchorRecord를 읽어 이 조건을 검증합니다.
성공: 결제가 실행되고, 수수료가 공제되며, 기록이 작성됩니다. 실패: 전체 트랜잭션은 단일 end-of-handler apply_batch를 통해 롤백됩니다. 수수료는 청구되지 않습니다. Nonce도 소모되지 않습니다. 상태(state)도 변경되지 않습니다.
Ethereum에서는 최소 두 개의 컨트랙트가 필요합니다. 가격 해시를 보유하는 오라클과, 오라클을 읽어 지급할지 환불할지 결정하는 release() 함수를 가진 에스크로입니다. 구성 위험 요소로는 오라클의 신선도(freshness), 오라클의 목록 제외(delisting), release에서의 재진입 공격(reentrancy) 등이 있습니다. 또한, require()가 실패하더라도 원래 송신자가 지불한 가스(gas)는 소모된다는 사실도 위험 요소입니다.
이 컴팩트한 프레이밍은 두 개의 컨트랙트 대신 하나의 신호 유형을 사용합니다. 에스크로와 오라클의 조합 대신 단일 원자적 배치(atomic batch)를 사용합니다. 조건 실패에 따른 롤백은 무료입니다. EVM의 require() 실패는 그렇지 않습니다.
Bounded가 고정되었다는 의미는 아닙니다.
사람들이 제기하는 반론: 만약 기본 요소 집합(primitive set)이 고정된다면, 그것이 체인을 오늘날 표면처럼 보이는 것에 가두지 않겠습니까?
여기에 데이터가 있습니다. 2026년 5월에 출시된 여섯 가지 새로운 프로토콜 기본 요소입니다.
원시 요소(Primitive) | 기능
SLAs with auto-slash | 인증 실패 시 원자적 스테이크 슬래싱(atomic stake slashing)이 트리거되는 양자 간 서비스 계약
Payment channels | 협력적 종료(cooperative close) 및 더 높은 논스에 의한 분쟁 해결(dispute-by-higher-nonce settlement) 기능을 갖춘 오프체인(Off-chain) 결제 수단
Payment splits | 단일 결제를 최대 8명의 수취인에게 단일 배치로 원자적 분배
Agent code-hash upgrade | 최소 간격 강제 및 기능 보존을 통한 제한적 코드 해시(code-hash) 로테이션
Oracle anchors | 엔티티 또는 태그별로 쿼리 가능한 오프체인 데이터에 대한 불변의 온체인(on-chain) 약속
Conditional payments | 오라클 앵커(oracle anchor) 상태에 따라 제어되는 결제, 실패 시 수수료 없이 롤백(fail-revert)
각 요소는 정형 와이어 포맷(canonical wire format)을 변경했습니다. 각 요소는 바이트 수준의 코덱(codec) 테스트를 포함하여 배포됩니다. 이 목록에 있는 모든 원시 요소는 사용자가 배포하는 계약이 아니라 프로토콜의 결정 사항입니다.
이것이 모델입니다. 체인은 제한적이지만, 표면은 계약 배포가 아닌 프로토콜 업그레이드를 통해 확장됩니다. Bitcoin은 제한적이고 정적입니다. Ethereum은 설계상 무제한입니다. NOVAI는 제한적이지만 성장하고 있습니다.
일반적인 프로그래밍 가능성(general programmability)은 어떻게 되나요?
NOVAI에 스마트 컨트랙트가 없다면, 일반적인 프로그래밍 가능성은 어디에 존재합니까?
정답은 L2입니다.
NOVAI는 결제(settled)를 받도록 구축되었습니다. L2가 NOVAI에 결제하는 데 필요한 원시 요소들이 갖춰져 있습니다. 협력적 결제 및 더 높은 논스에 의한 분쟁 해결 메커니즘을 갖춘 L1-to-L2 입금을 위한 결제 채널(Payment channels). 태그로 쿼리 가능한 L2-to-L1 상태 인증을 위한 오라클 앵커(Oracle anchors). 교차 L2 원자적 결제를 위한 조건부 결제(Conditional payments). 각 증명이 전체 검증 키(VK)를 인라인으로 포함하는 대신 32바이트 핸들을 참조할 수 있도록 온체인 검증 키 등록 기능을 갖춘 ZK 증명 제출. L2 시퀀서(sequencer) 평판을 위한 자동 슬래싱 기능이 포함된 SLA.
경제 모델은 현재 Ethereum이 수익을 창출하는 방식과 동일합니다. L1(Layer 1)은 결제 기질(settlement substrate)로서 수수료를 확보합니다. L2(Layer 2)들은 실행(execution) 작업을 수행합니다. EIP-4844는 롤업의 데이터 가용성(data-availability) 비용을 대략 10배에서 100배 정도 낮추었지만, 롤업들은 여전히 결제를 위해 Ethereum에 비용을 지불합니다. Base 하나만으로도 2025년 5월에 580만 달러를 생성했으며, 연간 환산 수익률(annualized run rate) 7,000만 달러 이상을 달성할 궤도에 올라 있습니다. (출처: Dune research)
만약 NOVAI 상단에 범용 스마트 컨트랙트(smart contracts)를 구축하고 싶다면, EVM L2를 구축하면 됩니다. 프라이버시를 원한다면, 프라이버시 L2를 구축하면 됩니다. 특정 워크로드에 최적화된 도메인 특화 VM(domain-specific VM)을 원한다면, 해당 L2를 구축하면 됩니다. L1은 이 중 그 어떤 것도 차단하지 않습니다. L1은 이를 지원합니다.
이것이 바로 플러스 섬(positive-sum) 프레임워크입니다. "아무도 필요로 하지 않는 또 다른 L1"이라는 비판은 L1이 L2와 경쟁한다고 가정합니다. 하지만 그렇지 않습니다. L1은 L2로부터 이익을 얻습니다.
제가 주장하지 않는 것들
현재 NOVAI가 갖추지 못한 것들에 대한 솔직한 목록입니다.
유료 제3자 보안 감사(security audit) 없음. 자체적으로 수행한 Tier 1 통과는 실제이며 결과도 공개되어 있지만, 이는 Trail of Bits나 Halborn과 같은 곳을 고용하는 것이 아니라 린터(linter)와 퍼저(fuzzer)를 실행하는 것과 대등한 수준입니다. 더 엄격한 보안 작업은 우선순위와 리소스가 뒷받침되는 NOVAI의 여정 중 나중에 다시 검토할 예정입니다.
공식적인 비잔틴 증명(formal byzantine proof) 없음. 합의(Consensus)는 3-체인 커밋 규칙을 가진 HotStuff 스타일이며, 클린룸(clean-room) 방식으로 구현되었습니다. 안전성 추론(Safety reasoning)은 비공식적입니다. TLA+ 모델도 없고 기계 검증된 증명(machine-checked proof)도 없습니다. 체인은 96개 이상의 카오스 테스팅(chaos-testing) 시나리오를 통과하며 출시되었습니다. 이것은 형식 검증(formal verification)과는 다른 것입니다.
아직 공개 데브넷(public devnet) 없음. 체인은 현재 프라이빗 테스트넷(private testnet)에서 실행됩니다. 공개 데브넷은 계획 단계에 있으며 아직 출시되지 않았습니다.
단일 노드 구현. 모든 검증자(validator)는 동일한 크레이트(crates)/노드 바이너리(node binary)를 실행합니다. 와이어 포맷(wire format)은 정형화되어 있고 골든 벡터(golden-vector)로 잠겨 있어 두 번째 구현이 가능하지만, 구현체가 존재하기 전까지는 노드 바이너리 수준의 버그가 모든 검증자에게 영향을 미칠 것입니다.
이것들은 실제적인 한계점들입니다. 그럼에도 불구하고 저는 이 포스트를 게시합니다. 왜냐하면 아키텍처에 대한 논거는 이러한 문제들이 오늘 당장 해결되는지에 의존하지 않으며, 무엇이 부족한지에 대해 솔직하게 밝히는 것 또한 논거의 일부이기 때문입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기