Visual Bitcoin Engine

Rust로 만든 비트코인 엔진을 WebAssembly로 컴파일해 브라우저에서 직접 돌려보는 학습 도구

엔진 로딩 중…

비트코인은 결국 "해시로 연결된 거래 장부"예요

아래 6개 부품이 어떻게 맞물리는지 차례대로 직접 만져보면, "비트코인이 왜 위조가 안 되는가, 주인 없이도 왜 돌아가는가"가 손에 잡혀요.

부품 1
SHA-256 해시
어떤 데이터든 64자리 지문으로. 되돌릴 수 없음(단방향).
부품 2
블록 · 체인
거래 묶음 + 이전 블록의 해시 + nonce. 해시로 줄줄이 연결.
부품 3
채굴 (PoW)
해시가 0으로 시작하게 만드는 nonce 찾기 = 일(work).
부품 4
UTXO · 디지털 서명
동전은 주소에 잠기고, 개인키 서명(ECDSA)으로만 풀림.
부품 5
P2P 합의
수천 개 노드가 "가장 긴 체인" 규칙 하나로 장부를 맞춤.
부품 6
공격과 방어
이중지불 · 51% · 양자컴 — 왜 뚫기 어려운지까지 직접 실험.

여기서 진짜로 돌아가는 것

  • 화면의 모든 계산(SHA-256, 채굴, ECDSA 서명·검증, P2P 합의, 공격 시뮬레이션)은 src/Rust 엔진이 합니다.
  • 그 Rust 코드를 WebAssembly(.wasm) 로 컴파일해서 브라우저 안에서 실행해요. JavaScript는 그림만 그립니다.
  • 즉, CLI에서 cargo run 으로 돌던 그 엔진이 그대로 웹에서 돕니다.
왜 WASM인가? 브라우저는 Rust를 바로 못 돌리고 JS/WASM만 실행해요. Rust→WASM으로 컴파일하면 "진짜 엔진"을 웹에서 그대로 쓸 수 있습니다.
소스 구조: block.rs(해시·채굴) · transaction.rs(거래) · blockchain.rs(체인·잔액·검증) · utxo.rs(UTXO·입력별 서명) · wallet.rs(키·ECDSA) · merkle.rs(머클트리) · header.rs(80B 헤더) · network.rs(P2P 합의) · attack.rs(이중지불) · wasm_api.rs(브라우저 다리)

추천 학습 순서

  • 1 · SHA-256 — 글자 하나만 바꿔도 지문이 완전히 달라지는 걸 눈으로 보기 (눈사태 효과).
  • 2 · 채굴 실험실 — 난이도를 올리면 왜 채굴이 기하급수적으로 어려워지는지 체감.
  • 3 · 블록체인 시뮬레이터 — 거래 → 채굴 → 몰래 조작 → 검증으로 잡아내기까지 한 사이클.
  • 4 · UTXO 모델 — 동전(UTXO) · 주소 · 개인키 서명으로 "내 돈"이 증명되는 원리.
  • 5 · 블록 해부 — 80바이트 헤더 · 머클루트를 실제 hex 단위까지 뜯어보기.
  • 6 · 노드 합의 (P2P) — 여러 노드 · 포크 · 재구성(reorg)으로 장부가 하나로 수렴하는 과정.
  • 7 · 이중지불 공격 — 51% 공격을 직접 실행해 보고, 성공 확률까지 계산.
  • 8 · 양자컴퓨터 위협 — 쇼어 vs 그로버, 뭐가 진짜 위험하고 뭐가 과장인지 총정리.

SHA-256 — 모든 것의 출발점

아무 글자나 입력해 보세요. 입력이 1바이트든 1메가든, 결과는 항상 64자리 16진수(256비트)입니다.

SHA-256 해시 결과

길이: 자 (16진수) = 256 비트
단방향(one-way): 해시에서 원본을 역으로 계산하는 공식은 존재하지 않아요. 스크램블한 계란을 다시 못 되돌리는 것과 같습니다. 비트코인 보안의 토대죠.

눈사태 효과 (Avalanche Effect)

한 글자만 바꿔도 결과의 절반 가까운 비트가 뒤집힙니다. 두 입력을 비교해 보세요.

해시 A

해시 B (A와 다른 자리는 빨간색)

다른 16진수 자릿수
0 / 64
입력은 한 글자밖에 안 다른데 해시는 거의 무작위로 달라지죠. 그래서 블록 안의 거래를 살짝만 고쳐도 해시가 완전히 어긋나 즉시 들통납니다.

그래서 이걸로 뭘 하냐면 — 블록과 블록을 "해시로" 잇습니다

비트코인의 핵심 아이디어예요. 각 블록은 자기 데이터뿐 아니라 바로 앞 블록의 해시까지 함께 SHA-256에 넣습니다. 그래서 블록들이 사슬(chain)처럼 이어져요 — 이게 블록체인이라는 이름의 유래죠.

계산식: 이 블록 해시 = SHA-256( 이전 블록 해시 + 데이터 + nonce )
맨 앞(제네시스) 블록은 앞이 없으니 이전 해시를 0000… 으로 둡니다.
nonce는 채굴자가 바꾸는 숫자예요. ⛏ 채굴 버튼을 누르면 해시 앞이 0으로 시작할 때까지 nonce를 자동으로 찾습니다(= 탭 2에서 본 그 작업증명).
이렇게 찾은 nonce는 앞서 말한 대로 그 블록 해시를 확정하는 데 쓰여요. 그래서 데이터를 하나라도 조작하면 → 블록 해시가 바뀌고 → 그 블록을 기점으로 뒤의 모든 블록을 다시 채굴(nonce 다시 찾기)해야 합니다. 이게 조작이 어려운 이유예요. 아래에서 직접 확인해 보세요. 👇

👉 아래 블록의 데이터를 고치거나 ⛏ 채굴을 눌러보세요. 그 블록 해시가 바뀌면, 그걸 품고 있던 뒤 블록들의 해시가 줄줄이 다시 계산돼요(주황색 반짝임). 채굴해둔 뒤 블록이 있었다면 0으로 시작하던 게 깨지는 것도 보입니다.

그래서 위조가 안 됩니다: 지난 블록의 데이터를 하나만 몰래 바꿔도, 그 뒤 모든 블록의 해시가 어긋나 사슬이 끊긴 게 즉시 보여요. 공격자는 바꾼 블록부터 끝까지 전부 다시 채굴해야 하는데(탭 2에서 그게 얼마나 힘든지 체감했죠), 정직한 네트워크를 따라잡는 건 사실상 불가능합니다.
→ 실제로 거래를 넣고 채굴해 사슬을 키운 뒤, 블록을 몰래 조작해 검증으로 잡아내는 체험은 탭 3 · 블록체인 시뮬레이터에서.
🧪 곁다리 — "그럼 양자 컴퓨터가 나오면 비트코인 깨지는 거 아냐?"

자주 나오는 얘기예요. 근데 두 가지 위협을 나눠서 봐야 정확합니다.

  • ① 해시 · 채굴 (SHA-256) — 양자의 그로버(Grover) 알고리즘은 이 "0으로 시작하는 nonce 찾기" 같은 무차별 대입을 제곱근(√)만큼만 빨라지게 해요. 256비트가 체감 128비트로 줄 뿐 여전히 천문학적이고, 난이도가 자동 조정돼 흡수됩니다. → 위에서 말한 재채굴을 "가능"하게 만들진 못해요.
  • ② 디지털 서명 (secp256k1 · 탭 4) — 여기가 진짜 급소예요. 양자의 쇼어(Shor) 알고리즘공개키에서 개인키를 역산할 수 있어서, 충분히 큰 양자컴이 나오면 남의 서명을 위조해 코인을 훔칠 수 있게 됩니다.

그러니까 양자 컴퓨터가 노리는 건 "해시 연결"보다 "서명" 쪽이에요. 대비책으로 양자내성 서명(post-quantum)으로 갈아타자는 논의가 이미 진행 중이고, 무엇보다 그만한 규모의 양자 컴퓨터는 아직 존재하지 않습니다.

채굴 = "조건을 만족하는 nonce 찾기" 노가다

블록 데이터는 그대로 두고 nonce(숫자)만 0,1,2,… 바꿔가며 해시를 다시 계산해요. 해시가 0이 N개로 시작하면 성공. 정답을 찾는 빠른 방법은 없고 오직 무차별 대입뿐입니다.

난이도
3
목표: 해시가 000… 으로 시작해야 합니다.

채굴기

현재 해시 입력:
시도한 nonce
0
해시 계산 횟수
0
속도 (해시/초)
0
경과
0.0s

노가다 로그 nonce를 1씩 올리며 해시를 다시 계산

한 줄 = 한 번의 시도예요. 데이터 + nonce 를 SHA-256에 넣어 본 결과죠. 앞에 0이 모자라면 ❌, 목표만큼 0으로 시작하면 ✅. 정답을 미리 알 방법이 없어서 0번부터 하나씩 무작정 대입하는 게 전부입니다.

⛏ 채굴을 시작하면 시도 과정이 여기 한 줄씩 찍힙니다.
왜 이게 보안이 되나요? 난이도를 1 올리면 평균 시도 횟수가 약 16배로 늘어요(16진수라서). 블록을 위조하려면 그 블록부터 끝까지 전부 다시 채굴해야 하는데, 정직한 네트워크의 계산력을 따라잡지 못하면 불가능합니다. 반면 검증은 해시 한 번이면 끝 — 찾기는 어렵고 확인은 쉽다.
🔎 이 실험실은 쉽게 보여주려고 3가지를 단순화했어요 (실제 비트코인은?)

여긴 브라우저에서 즉시 체감하려고 난이도를 확 낮췄어요(1~6). 실제 비트코인은 이렇게 다릅니다:

  • ① "0 개수"가 진짜 기준이 아니에요 — 여기선 "해시 앞 0이 N개"로 판정하지만, 실제론 해시(를 숫자로 본 값)가 target이라는 256비트 숫자보다 작거나 같은가로 판정해요. 0이 많을수록 작은 수라 결과는 비슷하지만, 이 방식이라 난이도를 0 개수처럼 뚝뚝 끊지 않고 연속적으로 미세 조정할 수 있습니다.
  • ② SHA-256을 두 번 — 여기선 한 번만 하지만, 실제 헤더 채굴은 SHA-256( SHA-256(헤더) )double SHA-256이에요.
  • ③ 난이도는 기하급수적으로 폭증 — 요구하는 선행 0이 1비트 늘 때마다 평균 시도 횟수가 2배(16진수 0 한 자리 기준 약 16배)로 뛰어요. 실제 비트코인은 16진수로 약 19자리 이상의 0(약 2⁷⁶ 이상)이 필요해서, 평균 10²²~10²³번 해시해야 블록 하나가 나옵니다.

그래서 이 실험실 속도(초당 수만~수십만)로는 우주 나이로도 못 찾아요. 전 세계 채굴기를 합치면 특수 장비(ASIC)로 초당 약 10²⁰번(= 1억 × 1조) 규모의 해시를 돌려서, 그걸로 평균 10분마다 블록 하나를 캡니다.

→ target · double SHA-256 · 80바이트 헤더의 정밀한 버전은 탭 5 · 블록 해부에서 실제 hex까지 직접 볼 수 있어요.

⚡ 그럼 이 계산력의 절반 이상을 가지면? = 51% 공격
방금 본 그 어마어마한 계산력(전 세계 합산)을 혼자 절반 넘게 감당할 수 있다면, 정직한 네트워크보다 빠르게 블록을 쌓아 더 긴 체인을 만들어 과거 거래를 뒤집을 수 있어요. 이게 51% 공격입니다.
하지만 ⑴ 그 정도 장비면 정직하게 채굴하는 게 더 이득이고, ⑵ 블록이 깊이 묻힐수록(=컨펌↑) 성공 확률이 기하급수적으로 0에 수렴해서 사실상 불가능해요.
→ "가장 긴 체인이 이긴다" 규칙과 51% 공격을 그림으로 보는 설명은 탭 3 · 블록체인 시뮬레이터 맨 아래 ⑤에서.

① 엔진 설정

프리셋을 고르거나 값을 직접 바꾼 뒤 엔진을 시작하세요. (제네시스 블록이 채굴되며 시작됩니다)

블록 높이 ?
0
현재 난이도 ?
0
현재 블록 보상 ?
0 BTC
멤풀 대기 거래 ?
0
총 발행량 ?
0 BTC

② 거래 만들기

보내는 사람의 잔액이 부족하면 엔진이 거부해요(이중지불 방지).

멤풀 (다음 블록에 담길 거래)

아직 대기 중인 거래가 없습니다.

지갑 잔액

채굴 보상(코인베이스)과 거래로 잔액이 바뀝니다.

아직 잔액이 없습니다. 블록을 채굴해 보세요.

③ 블록 채굴

멤풀의 거래들을 모아 새 블록을 채굴합니다. 맨 앞에는 채굴 보상(코인베이스) 거래가 자동으로 들어가요.

④ 블록체인 & 검증

🔍 체인 검증은 뭘 하나요? 먼저 오해 하나 풀고 갈게요 — 검증은 노드끼리 투표하거나 서로 블록을 비교·승인하는 게 아니에요. 각 노드가 혼자서 "이 블록이 수학·규칙적으로 앞뒤가 맞나"를 다시 계산해 채점하는 거예요(맞으면 인정, 틀리면 남이 뭐라든 그냥 버림). 제네시스(#0)는 기준점이라 건너뛰고, #1부터 모든 블록에 대해 딱 두 가지를 확인해요:
  • ① 해시 재계산 일치? — 그 블록의 현재 내용으로 SHA-256(이전해시 + nonce + 거래데이터 …)다시 계산해 저장된 해시와 비교(= 정합성 확인). 다르면 → 데이터 조작. (실제 비트코인은 80바이트 헤더를 double SHA-256, 즉 두 번 해시해요.)
  • ② 연결 일치? — 그 블록의 이전 해시 가 진짜 앞 블록의 해시와 같은지 확인. 다르면 → 사슬 끊김.
하나라도 어긋나면 어느 블록이 왜 깨졌는지 딱 짚어줘요. 검증은 해시 계산 몇 번이면 끝 — 찾기는 어려워도 확인은 순식간. 이렇게 모두가 같은 규칙으로 각자 채점하니, 굳이 서로 물어보거나 투표하지 않아도 결과가 똑같이 나와요.
위변조 실험: 아래 채굴된 블록의 거래 옆에 버튼이 두 개 있어요. 둘 다 체인 검증을 누르면 잡히지만, 걸리는 지점이 달라요:
  • 조작 — 데이터만 바꾸고 해시는 그대로. → 검증 ①(해시 불일치)에서 걸림.
  • 조작+재해시 — 바꾼 뒤 해시도 다시 계산(채굴은 생략). 해시는 내용과 맞지만 0으로 시작 안 함. → 검증 ③(작업증명)에서 걸림. "재해시만으론 부족, 진짜 채굴이 필요"를 보여줘요.
(복구하려면 엔진을 새로 시작)

⑤ 왜 못 되돌리나 — "가장 긴 체인이 이긴다" & 51% 공격

위에서 블록을 조작하면 검증에 걸리죠. 그럼 공격자가 조작한 블록부터 다시 채굴하면 되지 않을까요? 문제는 그러는 동안에도 정직한 네트워크는 계속 블록을 쌓는다는 거예요. 그래서 공격자는 따라잡는 게 아니라 추월해야 합니다.

#5 공격자가 여기(#5)를
조작 → 여기서 갈라짐
├─ 6789 ✅ 정직한 체인 — 더 길다 → 노드들이 자동으로 이걸 채택
└─ 6′7′ ❌ 공격자 체인 — 짧다 → 버려짐(고아 블록)
노드의 규칙은 딱 하나: 유효한 체인 중 "가장 긴(누적 작업량이 가장 큰)" 것을 따른다.
누구에게 허락·투표를 받는 게 아니라, 더 긴 체인이 나타나면 노드들이 알아서 그걸로 갈아탑니다.
  • 추월하려면 = 해시파워 51%+ — 정직한 네트워크 전체보다 빠르게 블록을 쌓아야 더 긴 체인을 만들 수 있어요. 그건 전 세계 채굴 계산력의 절반 이상을 혼자 가져야 한다는 뜻(수십조 원어치 장비·전기).
  • 그럴 능력이면 정직하게 채굴이 이득 — 공격에 성공해도 신뢰가 무너져 코인 가치가 폭락하니, 차라리 정직하게 보상 받는 게 이득이라 공격 유인 자체가 없어요.
  • 깊이 묻힐수록 안전(컨펌) — 목표 블록 위에 블록이 쌓일수록(=컨펌 수↑) 추월 확률이 기하급수적으로 0에 수렴. 그래서 거래소는 보통 6 컨펌(블록 6개)을 기다립니다.
한 줄 요약: 위조 = 바꾼 블록부터 끝까지 재채굴 + 정직한 네트워크를 추월할 만큼 더 길게 만들기. 노드는 "가장 긴 체인" 규칙으로 판단하므로, 추월하려면 계산력 51% 이상이 필요 → 사실상 불가능합니다.

엔진 로그 Rust가 출력하는 메시지

CLI에서 println! 으로 찍히던 그 메시지를 브라우저로 그대로 가져온 거예요.

비트코인엔 "잔액"이 없어요 — 동전(UTXO)만 있습니다

3번 탭은 계좌식(Alice=20, Bob=10처럼 잔액을 기억)이었어요. 하지만 진짜 비트코인은 잔액을 저장하지 않고, "아직 안 쓴 거래 출력(UTXO)" 조각들만 둡니다. 지갑이 그걸 다 더해 잔액을 계산할 뿐이죠.

지폐 비유: 지갑에 5만원권 한 장이 있을 때 1.2만원을 내려면? 5만원을 통째로 내고 → 상대는 1.2만원, 나는 거스름돈 3.8만원을 새로 받죠. "잔액에서 빼기"가 아니라 헌 동전 소비 + 새 동전 발행입니다. 이 "새 동전"이 바로 UTXO예요.
  • 입력(input) = 소비할 기존 UTXO들 (반드시 통째로)
  • 출력(output) = 새로 생기는 UTXO (받는 사람 몫 + 거스름돈)
  • 수수료(fee) = 입력 합계 − 출력 합계 → 채굴자 몫
🔑 그런데 — 그 동전이 "내 것"인 건 어떻게 증명하죠? 각 UTXO는 받는 사람의 주소(= 공개키를 해시한 값)에 잠겨 있어요. 그 동전을 쓰려면 짝이 되는 개인키로 거래에 서명해서 "내가 주인이다"를 증명해야 합니다. 누구나 공개키로 서명을 검증할 수 있지만, 개인키 없이는 유효한 서명을 만들 수 없어요. 이게 바로 비트코인이 실제로 쓰는 secp256k1 ECDSA 디지털 서명입니다. (이 데모는 진짜 secp256k1로 동작해요.)

지갑 (키쌍) secp256k1

발행/송금에 처음 등장하는 이름마다 개인키·공개키 한 쌍이 자동 생성돼요. 주소는 공개키를 해시해 만든 값이고, 동전은 이 주소에 잠깁니다. 개인키는 비밀(엔진 내부에만 존재).

아직 지갑이 없습니다. 아래 ①에서 코인을 발행하면 키쌍이 생겨요.

🎨 그림으로 이해하기 — 개인키·공개키가 대체 뭔데? (수식 없이)

공개키·개인키는 타원곡선 위에서 하는 "점 점프 놀이"예요. 시작점 G에서 정해진 규칙(선 긋고 → 만나는 점 → 위아래 뒤집기)으로 점프하는데 — 몇 번 점프했는지 = 개인키(비밀), 최종 착지점 = 공개키(공개). 버튼을 눌러 한 번씩 더해보세요.

G (시작점) 중간 착지점 지금 착지점 = 공개키 Q 선 긋기(덧셈) 위아래 뒤집기
🔑 여기가 핵심: G에서 d번 점프해 Q에 도착하는 건 쉬워요(그냥 버튼 d번). 하지만 착지점 Q만 보고 "몇 번 점프했게?"(= d)를 알아내는 건 불가능합니다 — 점프가 곡선 위를 마구 튀어다녀서 거꾸로 되짚을 방법이 없거든요.
  • 개인키 d = 점프 횟수 (비밀)
  • 공개키 Q = 착지점 (공개 · = d개의 G를 더한 점)
  • 주소 = 공개키 Q를 해시한 값
실제 비트코인 개인키는 이 점프를 2256(우주의 원자 수보다 많음) 근처 횟수만큼 한 착지점이라, 슈퍼컴을 다 끌어와도 못 되짚어요. 그래서 공개키는 맘껏 공개해도 안전해요.
그럼 "서명"은? "나는 이 착지점 Q를 만든 점프 횟수 d를 안다"를, d를 한 번도 말하지 않고 증명하는 수학 트릭이 바로 서명이에요. 남들은 공개키 Q로 그 증명이 맞는지 확인(검증)만 하죠. → 개인키 없인 서명을 못 만들고, 만들어진 서명은 공개키로 누구나 검증돼요. (송금할 때 아래 서명 블록에서 이게 실제로 돌아가요.)

지갑 만들기 한눈에 — 그리고 이더리움과 뭐가 같고 다른가

위 "점프" 그림이 바로 ②단계(개인키→공개키)예요. 전체를 이으면 난수(개인키) → 타원곡선 곱 → 공개키 → 해시 → 주소. 이더리움도 같은 secp256k1 곡선을 써서 ①②는 완전히 같고, 주소 만들 때 해시 함수만 달라요.

단계 비트코인 이더리움
① 개인키256비트 난수256비트 난수 동일
② 공개키개인키 × G (secp256k1)개인키 × G 같은 곡선
③ 주소RIPEMD160(SHA256(pub)) → Base58Keccak256(pub) 끝 20B → 0x… 해시만 다름
서명ECDSA (secp256k1)ECDSA 동일
시드 문구BIP-39 (12/24단어)BIP-39 동일
계정 경로m/44'/0'/…m/44'/60'/… 숫자만 다름
저장 위치wallet.dat · 하드웨어 칩브라우저 확장(암호화) · 하드웨어 칩
🔑 핵심: 지갑의 근본(키·서명·시드)은 두 체인이 거의 같아요. 그래서 하드웨어 지갑 하나로 BTC·ETH를 같이 관리할 수 있죠. 눈에 보이는 차이는 사실상 주소 표기(해시)뿐입니다.
개인키는 어디에 저장되나? · 시드 문구 · 서명은 어디서?

개인키는 블록체인에 없어요. 체인엔 UTXO·주소·트랜잭션·서명만 올라갑니다. 개인키는 내 지갑 안에만 있어요 — 노드도 내 개인키를 모릅니다(알면 누구나 내 돈을 훔치니까).

  • Bitcoin Corewallet.dat 파일에 보관(암호화 가능).
  • 하드웨어 지갑(Ledger·Trezor) — 기기 안 보안 칩에 갇혀 밖으로 안 나옴. 서명도 기기 안에서.
  • 시드 문구(12단어) — 개인키들의 씨앗. 이거 하나로 모든 계정 복구 가능 → 유출되면 전부 털림.

서명은 "내 기기 안에서" 일어나요. 지갑이 로컬에서 개인키로 거래에 서명 → 체인엔 서명 + 거래만 전송 → 노드는 공개키로 검증만. "서명은 나만, 검증은 누구나"의 비대칭이죠. (이더리움도 완전히 동일한 방식이에요.)

① 코인 발행 (코인베이스)

UTXO가 있어야 보낼 수 있어요. 먼저 누군가에게 새 코인을 만들어 줍니다.

예시로 한 주소에 여러 번 발행하면, 그 사람 지갑에 동전이 여러 개 쌓입니다(각각이 UTXO).

② 송금

큰 동전부터 골라 목표+수수료 이상이 될 때까지 소비하고, 거스름돈을 돌려받아요.

③ 위조 시도 — 남의 동전 훔치기 🦹

공격자가 피해자의 UTXO를 자기 앞으로 보내는 거래를 만들어 봅니다. 하지만 공격자는 피해자의 개인키가 없어요. 자기 키로 서명할 수밖에 없고, 그 키의 주소는 피해자 주소와 다르므로 검증에서 거부됩니다.

UTXO 풀 (현재 안 쓴 모든 동전)

주소별로 묶었어요. 각 칩 = UTXO 한 개. 파란 테두리는 거스름돈으로 생긴 UTXO예요. 잔액은 칩들의 합으로 계산됩니다(저장 아님).

아직 UTXO가 없습니다. ①에서 코인을 발행해 보세요.

엔진 로그 UTXO 엔진(Rust)

채굴할 때 실제로 해시하는 건 거래가 아니라 "80바이트 헤더"예요

2·3번 탭에선 설명을 위해 블록 전체를 문자열로 이어붙여 해시했어요. 하지만 진짜 비트코인은 다릅니다. 거래 수천 건은 머클트리로 32바이트 머클루트 하나로 요약하고, 채굴자는 딱 80바이트 헤더double SHA-256으로 반복 해시하죠. 그리고 난이도는 "0의 개수"가 아니라 target이라는 256비트 숫자보다 작은가로 판정해요.

이 탭은 이 4가지(머클트리 · 헤더 · double SHA-256 · target)를 한 흐름으로 직접 만들어 봅니다. 모든 계산은 동일한 Rust 엔진이 합니다.

① 거래들 → 머클트리 → 머클루트

거래를 한 줄에 하나씩 적어요(내용은 자유). 각 거래를 double SHA-256해 잎(leaf)을 만들고, 둘씩 이어붙여 해시하길 반복해 꼭대기의 루트 하나로 압축합니다. 노드 수가 홀수면 마지막 노드를 복제해 짝을 맞춰요.

② 블록 헤더(80바이트) 조립 + 목표(target)

머클루트와 직전 블록 해시, 난이도를 넣어 헤더를 만듭니다. 헤더는 정확히 6필드 · 80바이트예요.

노드는 여러 대예요. "누구 체인이 진짜냐"는 규칙으로 정해집니다

지금까지의 탭은 전부 노드 1대의 내부 동작이었어요. 하지만 진짜 비트코인은 수만 대의 노드가 각자 자기 체인을 들고, 서로 블록을 주고받아요. 여기서 '합의'는 노드끼리 투표하거나 서로 승인해 주는 게 아니에요 — 각 노드가 받은 블록을 혼자서 규칙대로 검증하고(위반이면 그냥 버림), 통과한 체인들 중 가장 긴(누적 작업량이 큰) 걸 스스로 채택할 뿐이죠. 중앙 서버도, 심판도, 투표도 없어요. 딱 하나의 규칙으로 정리됩니다 — 가장 길고 유효한 체인이 이긴다.

노드끼리의 규칙 (합의 프로토콜)
  1. 같은 뿌리 — 모든 노드는 동일한 제네시스 블록에서 출발해요. 그래야 서로의 체인을 비교할 수 있어요.
  2. 채굴 = 자기만의 블록 — 노드가 블록을 캐면 일단 자기만 알아요. 방송하기 전엔 남들은 몰라요.
  3. 방송(P2P gossip) — 캔 블록/체인을 이웃에게 퍼뜨려요. 이웃은 또 자기 이웃에게 전달하며 네트워크 전체로 번져요.
  4. 가장 긴 체인 채택 — 더 길고 유효한(해시·연결·PoW가 맞는) 체인을 받으면 자기 걸 버리고 갈아탑니다(재구성 / reorg).
  5. 포크 & orphan — 두 노드가 동시에 같은 높이 블록을 캐면 포크가 생겨 잠깐 공존해요. 다음 블록이 한쪽에 붙는 순간 그쪽이 이기고, 진 블록은 버려집니다(orphan/stale).

🧠 그런데 왜 하필 "채굴(PoW)"이었을까? — 비트코인의 진짜 발명

방금 봤듯 합의는 '투표'가 아니에요. 그런데 왜 투표로 하면 안 되고, 굳이 전기까지 태우는 채굴이어야 했을까요? 여기에 비트코인의 진짜 발명이 숨어 있어요.

진짜 풀어야 했던 문제: 중앙은행도 심판도 없이, 서로 못 믿는 낯선 사람들끼리 "누가 언제 무엇을 보냈나(장부)"에 하나로 합의하기 (= 비잔틴 장군 문제).
  • ❌ 그냥 투표로 정하면? 인터넷에서 신원은 공짜로 무한 생성돼요. 가짜 계정 100만 개를 만들어 표를 쓸어담으면 끝이에요(시빌 공격). "1인 1표"를 셀 방법이 없죠.
  • 💡 비트코인의 발상: 발언권을 돈 주고도 위조 못 하는 자원 — 계산(전기·시간)에 묶자. 블록을 만들려면 실제로 어마어마한 해시 노가다=에너지를 태워야 하니, 가짜 신원 100만 개로는 아무것도 못 해요. 힘(해시파워)을 쓴 만큼만 발언권(≈ "1 CPU 1표").
  • ⚖️ 결정적 비대칭성: 블록 만들기는 미친 듯이 어렵지만 확인(검증)은 해시 한 번이면 끝. 만약 검증하는 데도 블록을 만드는 것만큼의 엄청난 컴퓨팅 자원이 든다면, 모든 노드가 매 블록마다 그 노가다를 통째로 다시 해야 해서 → 확장 불가 + 공격자를 값싸게 걸러낼 이점도 사라지는 치명적인 문제가 발생합니다. "생성은 비싸게, 검증은 싸게" — 이 비대칭이 시스템을 성립시킨 핵심이에요.
  • 🎯 마지막 한 방, 인센티브: 그 힘든 일을 왜 하냐면 보상(새 코인 + 수수료) 때문이에요. 그래서 계산력을 가진 사람은 공격보다 정직한 채굴이 더 이득이라, 스스로 네트워크를 지키는 쪽으로 움직여요. 신뢰를 '믿음'이 아니라 '경제적 이득'으로 바꿔버린 거죠.
한 줄 요약: 채굴은 단순한 낭비가 아니라 — 중앙 심판 없이 위조 불가능한 투표권정직할 동기를 동시에 만들어낸 장치예요.

각 노드에서 채굴해 블록을 붙이고, 방송으로 이웃에게 퍼뜨려 보세요. 두 노드에서 각각 캐면 포크가 생기고, 한쪽을 더 길게 만든 뒤 방송하면 재구성(reorg)이 일어납니다.

네트워크 로그

"가장 긴 체인이 이긴다"를 악용하면 — 이중지불 공격

한마디로 "돈 내고 물건 받은 뒤, 그 결제 기록을 몰래 지워버리는" 사기예요. 같은 코인을 두 번 쓰는 거죠.

🛒 쉽게: 중고로 노트북 사기
  1. 공격자판매자(상점)에게서 노트북을 사며 비트코인 10개를 보냄 → 이 결제가 블록에 담김
  2. 판매자는 "입금 확인!" 하고 노트북을 택배로 발송 📦 (현실에선 되돌릴 수 없음)
  3. 그 사이 공격자는 몰래 다른 버전의 역사를 캐고 있었음 — 그 역사엔 노트북 결제가 아예 없고, 코인을 자기 지갑으로 돌려놓음
  4. 이 비밀 체인이 더 길어지면 공개 → 네트워크가 더 긴 체인으로 갈아탐(재구성/reorg)
  5. 결과: 노트북 결제는 없던 일이 됨. 공격자는 노트북 + 코인 둘 다 챙기고, 판매자는 둘 다 잃음 😱

아래 시뮬레이터에서 공개 체인(모두가 아는 진짜 기록)과 공격자의 비밀 체인을 직접 경쟁시켜, 결제가 어떻게 증발하는지 볼 수 있어요.

공격이 성공하려면 공격자가 정직한 네트워크보다 블록을 더 빨리 캐야 해요(= 51% 해시파워). 그리고 판매자가 입금 확인(컨펌)을 오래 기다릴수록 공격자가 그만큼 더 앞서야 해서 성공이 어려워집니다. "왜 입금 6번 확인하고 물건 주라는가"가 바로 이거예요.

왜 "입금 확인(컨펌)을 기다리면" 안전해질까?

컨펌 = 내 결제가 담긴 블록 위에 쌓인 블록 수. 판매자가 물건을 보내기 전에 이걸 더 기다릴수록, 공격자가 결제를 뒤집으려고 따라잡아야 할 거리가 멀어져요. 공격자의 비밀 체인이 정직한 체인보다 더 길어져야 뒤집을 수 있는데, 기다리는 동안 정직한 체인이 계속 앞서 나가기 때문이죠.

😮 1컨펌에 바로 발송 (성급)
결제
정직한 체인이 1블록만 앞섬 → 공격자는 2블록만 몰래 만들면 추월. 해볼 만함 😈
🛡️ 6컨펌 기다렸다 발송 (신중)
결제
정직한 체인이 6블록이나 앞섬 → 공격자는 이 격차를 다 따라잡고 + 한 발 더 앞서야 함. 훨씬 어려움 🛡️
한마디로: 판매자가 오래 기다릴수록 정직한 체인의 리드가 커지고, 공격자가 뒤집어야 할 격차도 그만큼 벌어져요. 그래서 컨펌이 하나 늘 때마다 성공 확률이 (공격자가 과반 미만이면) 지수적으로 뚝뚝 떨어집니다. → 소액은 1컨펌, 큰 금액(거래소 입금 등)은 6컨펌 이상을 기다리는 이유예요.

그래서 51% 공격, 어디까지 가능할까? — 성공 확률 계산기

51% 공격에도 한계가 있어요. 결론부터: 갓 결제된 최근 몇 블록은 노려볼 수 있어도, 깊은 과거(제네시스 근처)는 사실상 절대 불가능합니다. 아래에서 공격자 해시파워와 컨펌 수를 바꿔보면 왜 그런지 숫자로 보여요. (모든 계산은 Rust 엔진이 합니다.)

공격자 < 50%
컨펌이 쌓일수록 성공 확률이 지수적으로 급락. 6컨펌이면 사실상 0. → 깊은 과거는 불가능.
공격자 ≥ 50%
이론상 언젠가는 성공(확률 100%). 하지만 깊을수록 필요한 시간·전기가 폭발.
제네시스/오래된 블록
누적된 일(PoW)이 방패 + 제네시스는 하드코딩. → 물리적으로 불가능.

컨펌 깊이에 따른 성공 확률 (이 해시파워 기준)

🟢 정직한 공개 체인네트워크가 인정하는 체인
😈 공격자 비밀 체인공개 전까지 아무도 모름

공격 로그

양자컴퓨터가 비트코인을 망하게 한다? — 케이스 총정리

결론부터: "하루아침에 붕괴"는 아니지만, 특정 조건의 코인엔 실질 위협이에요. 핵심은 딱 두 알고리즘이에요 — 쇼어(Shor)는 서명을 깨고(치명적), 그로버(Grover)는 해시를 조금 빠르게 할 뿐(제한적). 이 사이트에서 본 secp256k1 서명(탭 4)이 쇼어의 표적, SHA-256(탭 1·2·5)이 그로버의 표적입니다.

양자컴퓨터의 위협은 "채굴을 빠르게 해서 51%"가 아니라, 대부분 "공개키에서 개인키를 알아내 남의 코인을 훔치는" 쪽이에요. 왜 그런지 아래에서 케이스별로 봅니다.

① 두 개의 무기: 쇼어 vs 그로버

쇼어 (Shor) 치명적
  • 표적: ECDSA / secp256k1 (디지털 서명)
  • 효과: 공개키 Q에서 개인키 d를 직접 역산 (Q = d·G를 되돌림). 사실상 불가능하던 걸 몇 시간 안에.
  • 의미: 공개키가 드러난 코인은 서명을 위조해 훔칠 수 있음.
그로버 (Grover) 제한적
  • 표적: SHA-256 (해시 · 채굴 · 주소)
  • 효과: 무차별 대입을 제곱근만큼 단축 (2²⁵⁶ → 2¹²⁸). "보안 비트 절반" 수준.
  • 의미: 해시는 여전히 안전권. 채굴이 조금 유리해질 뿐, 붕괴 아님.
💡 왜 쇼어가 무섭냐면 — 탭 4의 "시계 비유"처럼 d·G는 정방향(개인키→공개키)은 쉽지만 역방향(공개키→개인키)은 불가능한데, 쇼어는 바로 그 역방향을 가능하게 만들어요. 그로버는 그냥 "빨리 찍기"라 급이 다릅니다.

② 공격 케이스 총정리

1 노출된 공개키 털기 핵심 위협
무엇을 이미 블록체인에 공개키가 드러난 코인의 개인키를 쇼어로 복원 → 몰래 이동
대상 P2PK(초기 채굴 코인·사토시 추정 ~110만 BTC), 재사용 주소, Taproot(P2TR)
현실성 대형 양자컴 필요(아직 없음). 하지만 느긋하게 공격 가능 → 방어 못 하는 분실 코인이 특히 위험
방어 안 쓰던 새 주소로 이동 · 주소 재사용 금지 · 포스트양자 서명 전환
2 전송 중 거래 가로채기 치명적
무엇을 거래를 방송하면 공개키+서명이 드러남 → 확정(컨펌) 전 짧은 틈에 개인키를 복원해, 더 높은 수수료로 가로채는 거래를 끼워넣어 훔침
대상 사용하는 모든 코인 (돈을 쓰는 그 순간)
현실성 수 분 안에 secp256k1을 깨야 함 → 케이스 1보다 훨씬 빠른 양자컴 필요(더 먼 미래)
방어 결국 서명 알고리즘 교체(PQ)가 유일한 근본 해법
3 채굴 지배 (그로버) 낮음
무엇을 그로버로 해시 탐색을 가속해 채굴 우위 확보(→ 51% 시도, 탭 7)
현실성 제곱근 속도라 전용 ASIC 대비 압도적이지 않음. 위협 낮음
방어 난이도 자동조정이 대부분 흡수
4 해시·주소 자체 붕괴 사실상 없음
무엇을 SHA-256을 깨서 안 쓴 주소의 공개키 해시를 역산
현실성 그로버로도 2¹²⁸ → 현실적으로 불가능. 안 쓴 P2PKH/P2WPKH는 안전

③ 어떤 코인이 위험하고, 어떤 게 안전한가

가르는 기준은 딱 하나 — 공개키가 체인에 드러나 있느냐. 일반 주소는 공개키를 해시 뒤에 숨겨 두기 때문에, "한 번도 출금 안 한" 주소는 (현재로선) 안전해요.

🛡️ 안전 (현재로선)
  • 한 번도 출금 안 한 P2PKH / P2WPKH 주소
  • 이유: 공개키가 SHA-256+RIPEMD-160 해시 뒤에 숨음 → 쇼어의 표적(공개키)이 안 보임
  • 뚫으려면 해시를 깨야 하는데 그건 그로버로도 불가
⚠️ 위험
  • P2PK — 초기 채굴 코인·사토시 코인(공개키가 그대로 노출)
  • 재사용 주소 — 한 번 출금하는 순간 공개키 공개
  • Taproot(P2TR) — 구조상 공개키 노출
  • 쓰는 순간의 모든 코인 — mempool에 공개키가 뜨는 그 틈
가장 골치 아픈 건 주인이 방어할 수 없는 코인이에요. 사토시 코인처럼 개인키를 잃어버려 이동이 불가능한 노출 공개키 코인들은, 누군가 양자컴을 갖는 순간 그대로 털릴 수 있어요.

④ 현실적으로 가능한가? — "지금 당장은 아니다"

필요한 규모
오류정정된 논리 큐비트 수천 개
= 노이즈 물리 큐비트 수백만~수천만 개, 수 시간 연속 연산
현재(2026) 수준
물리 큐비트 ~1,000개대, 노이즈 큼
오류정정 논리 큐비트는 이제 막 한 자릿수 → 격차가 큼
예상 시점
대체로 2030년대 중반~2040년대+
암호 위협 수준(CRQC), 불확실성 큼
세상은 이미 대비 중
NIST가 2024년 포스트양자 표준 확정
ML-KEM · ML-DSA · SLH-DSA

⑤ 그래서 비트코인은 끝나나? — 대응책

  • 포스트양자 서명으로 하드포크 — 격자 기반 / 해시 기반(SPHINCS⁺, Lamport 등)으로 서명 알고리즘 교체
  • 취약 코인을 새(양자내성) 주소로 이동 — 노출된 공개키 코인을 미리 옮기기
  • 주소 재사용 금지 — 지금도 유효한 최선의 습관 (공개키를 계속 숨김)
  • 점진적 전환 — 양자 위협은 갑자기 오지 않고 충분히 예고되므로, 커뮤니티가 미리 갈아끼울 시간이 있음
결론: "양자컴 = 비트코인 즉사"는 과장이에요. 대부분은 서명을 갈아끼우면 막을 수 있는 문제입니다. 다만 사토시 코인처럼 이동 불가능한 노출 공개키 코인에는 진짜 위협이고, 그 시점엔 "누가 그 오래된 코인을 먼저 털지" 같은 초유의 사건이 벌어질 수 있어요.

이더리움은 "코드를 실행하는 장부"예요

비트코인이 돈의 장부라면, 이더리움은 거기에 프로그램(스마트 컨트랙트)을 올려 두는 장부입니다. 한번 배포된 코드는 아무도 못 바꾸고, 조건이 맞으면 자동으로 실행돼요. 합의는 The Merge 이후 Proof of Stake — validator가 32 ETH를 걸고 블록을 제안·검증합니다.

Bitcoin
PoW · UTXO · 돈의 장부
"누가 얼마를 가졌나"를 기록. 스크립트는 최소한. 보안·단순함에 올인.
Ethereum
PoS · 계정 · 코드 실행 장부
잔액 + 컨트랙트 코드·storage까지 기록. 토큰·거래소·보험이 전부 "체인 위 프로그램".
핵심 한 줄: 스마트 컨트랙트 = "미리 써둔 규칙대로만 움직이는 금고". 은행 약관은 은행이 바꿀 수 있지만, 배포된 컨트랙트는 만든 사람도 못 바꿉니다. 이 사이트에서 직접 배포하고 호출해 보세요.
← 검증 원리는 Bitcoin 탭과 같아요: 각 노드가 혼자서 규칙을 채점합니다. 다른 건 시빌 방어 — PoW는 전기, PoS는 담보(32 ETH + slashing)로 막습니다.

추천 학습 순서

  • 1 · Keccak · 주소 — 해시에서 주소가 만들어지는 과정 (SHA-256과 대비)
  • 2 · 계정 · Gas — 잔액·nonce·EIP-1559 수수료 (UTXO와 대비)
  • 3 · 스마트 컨트랙트 — 배포 → 호출 → storage · 이벤트 · gas (메인)
  • 4 · 토큰 (ERC-20) — 토큰 = 컨트랙트의 잔액 표 (SAND 예시)
  • 5 · 오라클 — 체인은 바깥세상을 모른다 · Chainlink식 price feed · 보험
  • 6 · PoS 합의 — slot → attest → justified/finalized · slashing
  • 7 · 부동산 거래 — 배운 걸 전부 묶는 에스크로 실전 (총정리)
  • 8 · EVM 실행기 — 바이트코드가 실제로 실행되는 과정을 한 스텝씩
  • 9 · 머클 증명 — 라이트 클라이언트가 state 전체 없이 값 하나만 검증하는 원리 (애니메이션)
  • 10 · 마무리 — 릴레이·검산·Web2 비유로 이더리움 전체를 한 장에 총정리

Keccak-256 — 이더리움이 "id"를 만드는 해시

이더리움에서 만나는 거의 모든 id — 주소·함수 셀렉터·이벤트 topic·컨트랙트 주소 — 는 이 해시 하나에서 나옵니다. 비트코인의 SHA-256과 같은 자리인데, 이더는 Keccak-256을 써요. 먼저 직접 해시해 보세요.

Keccak-256 (임의 길이 입력 → 항상 32바이트 = 64 hex)
눈사태 효과: 한 글자만 바꿔도 결과의 절반쯤 비트가 뒤집힙니다. 되돌리기(해시→입력)는 불가능하고, 입력이 같으면 결과는 항상 같아요 — SHA-256과 같은 성질입니다.
함정: Keccak-256 ≠ NIST SHA3-256

이더리움이 쓰는 건 표준 확정 이전의 원조 Keccak이라, NIST가 확정한 SHA3-256과 패딩 바이트 하나가 다릅니다. 같은 입력인데 결과가 완전히 달라요.

Keccak-256("")  = c5d2460186f7233c…5d85a470   (패딩 0x01)
SHA3-256("")    = a7ffc6f8bf1ed766…c5f8dd9a   (패딩 0x06)

라이브러리에서 sha3_256을 부르면 이더리움 주소가 안 나오는 이유예요. 반드시 keccak256을 써야 합니다.

주소 = keccak(공개키)의 "끝 20바이트"

지갑 주소는 공개키를 Keccak한 뒤 끝 20바이트만 잘라 만듭니다. (이 데모는 공개키 대신 이름을 해시 — 규칙은 동일)

① Keccak-256 전체 (32바이트) — 앞 12바이트는 회색, 끝 20바이트만 씀
② 주소 = 끝 20바이트 + 0x
왜 앞 12바이트를 버리나? 해시는 32바이트인데 주소는 20바이트(160비트)면 충분해요 — 짧게 줄여 저장 공간은 아끼되, 서로 다른 두 사람이 우연히 같은 주소를 갖게 될 확률은 사실상 0입니다(이런 우연을 "해시 충돌"이라고 불러요 — 20바이트면 경우의 수가 2¹⁶⁰개라 사실상 안 생깁니다). 실제 공개키는 secp256k1의 X·Y 좌표 64바이트(압축 접두사 0x04는 떼고)를 해시합니다.

그럼 공개키는 어디서 오나 — 지갑 생성 3단계

지갑 만들기는 난수(개인키) → 타원곡선 곱 → 공개키 → 해시 → 주소가 전부예요. 앞 두 단계(개인키→공개키)는 비트코인과 완전히 동일하고(같은 secp256k1 곡선), 주소 만들 때 해시 함수만 달라요. 이 "타원곡선 곱(점프)"을 그림으로 보고 싶으면 Bitcoin 탭 4를 보세요.

단계 비트코인 이더리움
① 개인키256비트 난수256비트 난수 동일
② 공개키개인키 × G (secp256k1)개인키 × G 같은 곡선
③ 주소RIPEMD160(SHA256(pub)) → Base58Keccak256(pub) 끝 20B → 0x… 해시만 다름
서명ECDSA (secp256k1)ECDSA 동일
시드 문구BIP-39 (12/24단어)BIP-39 동일
계정 경로m/44'/0'/…m/44'/60'/… 숫자만 다름
저장 위치wallet.dat · 하드웨어 칩브라우저 확장(암호화) · 하드웨어 칩
🔑 핵심: 지갑의 근본(키·서명·시드)은 두 체인이 거의 같아요. 실제로 하드웨어 지갑 하나로 BTC·ETH를 같이 관리할 수 있는 이유죠. 눈에 보이는 차이는 사실상 주소 표기(해시)뿐입니다.
개인키는 어디에 저장되나? · 시드 문구 · 서명은 어디서?

개인키는 블록체인에 없어요. 체인엔 주소·잔액·트랜잭션·서명만 올라갑니다. 개인키는 내 지갑 안에만 있어요 — 노드도 내 개인키를 모릅니다(알면 누구나 내 돈을 훔치니까).

  • 메타마스크 — 브라우저 확장 저장소에 비밀번호로 암호화돼 보관, 쓸 때만 복호화.
  • 하드웨어 지갑(Ledger·Trezor) — 기기 안 보안 칩에 갇혀 밖으로 안 나옴. 서명도 기기 안에서.
  • 시드 문구(12단어) — 개인키들의 씨앗. 이거 하나로 모든 계정 복구 가능 → 유출되면 전부 털림.

서명은 "내 기기 안에서" 일어나요. 지갑이 로컬에서 개인키로 tx에 서명 → 체인엔 서명 + tx만 전송 → 노드는 공개키로 검증만. "서명은 나만, 검증은 누구나"의 비대칭이죠.

이더리움 곳곳에서 쓰는 Keccak — 미리 둘러보기

이더리움은 여러 곳에서 Keccak을 씁니다. 쓰임새마다 입력이 다르고, 해시한 결과에서 필요한 부분만 잘라 써요. 지금은 아래를 눌러 보며 "아, 여기저기서 Keccak을 쓰는구나" 정도만 느끼면 충분합니다.

① 함수 셀렉터 — 시그니처 해시의 앞 4바이트

컨트랙트 호출 때 "어떤 함수?"를 가리키는 id. 탭 3에서 buy()·transfer()를 부를 때 앞에 붙는 값이에요.

② 이벤트 topic0 — 시그니처 해시 전체 32바이트

로그에서 "이건 Transfer 이벤트"라고 구분하는 값. 탭 3·4 이벤트 로그의 topic0가 바로 이거예요.

③ 컨트랙트 주소 — keccak(배포자 주소 + nonce)의 끝 20바이트

배포할 때마다 nonce가 올라가서 주소가 매번 달라집니다. 탭 3에서 자판기를 배포하면 이 규칙으로 주소가 정해져요.

정리 — 같은 해시 함수를 여러 곳에서
  • 주소공개키를 해시 → 끝 20바이트
  • 컨트랙트 주소배포자+nonce를 해시 → 끝 20바이트
  • 함수 셀렉터시그니처를 해시 → 앞 4바이트
  • 이벤트 topic0시그니처를 해시 → 전체 32바이트
더 깊이: mapping 저장 위치 · CREATE2 · 체크섬 주소

mapping 저장 위치: balanceOf[Alice]가 storage 어디에 놓이는지도 keccak(key ‖ slot번호)로 정해집니다 — 탭 4 "토큰 storage 표"의 실제 주소 계산 방식이에요.

CREATE2: nonce 대신 keccak(0xff ‖ 배포자 ‖ salt ‖ keccak(코드))로 주소를 미리 계산 — 배포 전에 주소를 알 수 있어 L2·지갑에서 많이 씁니다.

체크섬 주소(EIP-55): 주소의 대소문자는 주소 자체를 keccak한 값으로 정해져요. 오타를 잡는 체크섬이라, 0xAbC… 처럼 섞인 대소문자에 의미가 있습니다.

계정 = 잔액을 "숫자로 직접" 저장 (UTXO와 다른 선택)

비트코인은 동전 조각(UTXO)을 모아 잔액을 계산했죠. 이더리움은 계좌처럼 잔액 숫자를 직접 저장해요. 보내면 내 숫자가 줄고 상대 숫자가 늘 뿐 — 거스름돈도, UTXO 조각도 없습니다. 직접 보내 보세요.

한 줄: value → 받는 사람, tip → 블록 제안자, base fee → 소각. 잔액이 그대로 증감하고, 오른쪽 n= 값(nonce)이 1씩 오르는 걸 보세요.

비트코인 UTXO ↔ 이더리움 계정

항목 비트코인 (UTXO) 이더리움 (계정)
잔액동전(UTXO) 조각들의 합 — 직접 저장 안 함숫자로 직접 저장
보낼 때UTXO 통째 소비 + 거스름돈 새로 생성내 잔액 , 상대 잔액 + (거스름돈 없음)
재사용 방지UTXO가 한 번 쓰면 소멸 (자동)nonce 번호로 방지 (아래 카드)
병렬성서로 다른 UTXO는 동시 처리 쉬움한 계정은 nonce 순서라 직렬
컨트랙트 상태표현이 까다로움잔액+storage로 자연스러움
왜 이렇게 갈렸나? 비트코인은 "돈"에 집중해 단순·병렬·프라이버시에 유리한 UTXO를 골랐고, 이더리움은 프로그램(컨트랙트) 상태를 다뤄야 해서 "이 주소가 지금 얼마·무슨 값을 갖는가"를 바로 읽는 계정 모델이 편했어요. 좋고 나쁨이 아니라 목적이 다른 설계입니다.
그런데 이 잔액은 정확히 어디에 저장돼요?

"직접 저장"이라 했지만 블록 안에 잔액이 적히는 건 아니에요. 각 노드가 관리하는 월드 스테이트(world state)주소 → 계정 객체 라는 거대한 맵 — 안에 있습니다. 계정 하나는 딱 4개 필드예요.

필드
nonce그 계정이 보낸 tx 수 (아래 카드의 그 번호)
balance잔액 (wei 단위) ← 여기
storageRoot컨트랙트 storage의 요약 해시 (지갑 EOA는 빈 값)
codeHash컨트랙트 코드의 해시 (지갑 EOA는 빈 값)

지갑(EOA)이든 컨트랙트든 구조는 똑같고, 지갑은 뒤 두 필드가 비어 있을 뿐이에요.

블록에는 뭐가 들어가나: 이 맵 전체를 해시 트리로 묶은 꼭대기 해시 하나 = state root블록 헤더에 박힙니다. 잔액 숫자 자체는 노드가 트랜잭션을 실행하며 자기 DB를 갱신해 유지해요. 즉 블록 = "이 시점 상태의 지문(state root)" + "그 블록의 tx들".

↔ 비트코인: 비트코인은 잔액을 저장하는 곳이 아예 없고, 노드가 UTXO 집합을 들고 있다가 "내 주소로 쓸 수 있는 UTXO 합"으로 그때그때 계산. 이더리움은 주소별 balance 숫자를 직접 들고 있어 조회 한 번이면 끝.

nonce — 계정 모델의 "재사용 방지 번호"

nonce는 계정마다 따로 매기는 트랜잭션 순번(0, 1, 2, …)이에요. 왜 이게 꼭 필요한지 먼저 보죠.

문제: 이더 잔액은 그냥 숫자예요. 내가 서명한 "Bob에게 1 ETH" tx를 누가 10번 복붙해 방송하면? 비트코인이면 그 UTXO가 이미 소멸돼 자동으로 막히지만, 계정은 잔액만 있어서 막을 게 없습니다.
해결 — nonce가 두 가지를 동시에:
  • ① 재사용(replay) 방지 — 각 번호는 딱 한 번만. 이미 쓴 nonce의 tx는 거부돼요. 그래서 복붙 방송이 안 통함.
  • ② 순서 보장 — 반드시 0 → 1 → 2 순으로. 중간을 건너뛴 tx는 앞 번호가 처리될 때까지 대기(pending).
🔑 탭 1 서명과 연결: nonce는 서명 대상(sighash)에 포함돼요. 그래서 내용이 똑같은 송금이라도 nonce가 다르면 서명이 완전히 달라집니다 → 옛 서명을 복붙해도 그 nonce는 이미 소비돼 거부. "서명이 내용을 잠근다"가 여기서 재사용 방지로 이어져요.
더 깊이: pending·stuck tx · nonce gap · 컨트랙트 주소

stuck tx: nonce 5를 낮은 수수료로 보내 안 처리되면, nonce 6·7은 아무리 급해도 대기해요(순서 때문). 해결은 같은 nonce 5를 더 높은 수수료로 다시 보내 덮어쓰기.

nonce gap: 5 다음에 실수로 7을 보내면, 6이 올 때까지 7은 영원히 대기. mempool에서 6을 기다려요.

컨트랙트 주소와의 관계: 탭 1에서 봤듯 컨트랙트 주소 = keccak(배포자 주소 + nonce). 그래서 같은 사람이 배포해도 nonce가 올라가 매번 다른 주소가 나와요.

Gas · EIP-1559 — 수수료는 어떻게 나뉘나

보낼 때 tip 값을 바꾸면 위 미리보기(소각·tip·차감)가 실시간으로 바뀌어요. 그 숫자가 어디서 오는지 정리합니다.

gas가 뭔가요? 모든 연산·저장은 노드의 자원을 씁니다. 그 작업량을 재는 단위가 gas예요. 단순 ETH 전송은 프로토콜이 21,000 gas로 고정(토큰·컨트랙트는 더 큼). 수수료 = gas × gas당 단가 — 스팸을 막고 검증자에게 보상하는 장치죠.
EIP-1559 — 단가가 두 조각:
  • base fee — 네트워크가 혼잡도에 따라 자동으로 정함. 이 사이트는 10 Gwei/gas 고정. → 아무에게도 안 가고 소각(burn).
  • priority tip — 내가 정하는 웃돈(위 입력칸). → 블록 proposer(검증자)에게.
수수료 계산식 펼치기 (EIP-1559)

gas used = 21,000 · base fee = 10 Gwei/gas · tip = 입력 T Gwei/gas

소각 = 21,000 × 10 × 10⁻⁹ ETH
tip  = 21,000 × T × 10⁻⁹ ETH → 제안자
차감 = value + 소각 + tip
🔥 소각(burn)의 의미: base fee로 낸 ETH는 영원히 사라져요. 네트워크가 붐빌수록 소각이 늘어 ETH 총량이 줄어드는 디플레 압력이 생깁니다. 비트코인이 "새 코인 발행을 반감기로 줄이는" 것과 방향은 비슷하지만, 이더는 이미 있는 코인을 태우는 방식이에요.
엔진 로그

스마트 컨트랙트 — 자판기를 배포해 보세요

아래는 진짜 Solidity로 쓴 자판기(SnackMachine)입니다. 배포하면 코드가 체인에 박제되고, 누구든 buy()를 호출할 수 있어요. owner도 규칙을 못 바꿉니다.

먼저 — 이더리움 계정은 두 종류

지갑 계정 (EOA)
Alice · Bob · 당신의 MetaMask
주소 = keccak(공개키)의 끝 20바이트. 개인키가 있어서 서명으로 트랜잭션을 시작할 수 있음.
컨트랙트 계정
SnackMachine · SAND · Uniswap
주소 = keccak(배포자 주소 + nonce)의 끝 20바이트. 개인키가 없고 코드·storage가 붙어 있음 — 호출당할 때만 움직임.
전송·배포·호출은 전부 "같은 tx" — 하나같이 nonce를 +1 합니다. EOA가 밖으로 보내는 건 결국 다 트랜잭션이고, to·data가 뭐냐로 이름만 갈려요. 그래서 배포도 전송처럼 nonce를 먹고, 그 nonce가 위 컨트랙트 주소의 재료가 됩니다.
하는 일tx 생김새nonce
단순 전송to=받는 사람 · value · data 없음+1
컨트랙트 배포to=비어있음(null) · data=바이트코드+1
컨트랙트 호출to=컨트랙트 주소 · data=함수+인자+1

Solidity 코드 (호출한 함수가 빛나요)


          
한 줄: 컨트랙트도 주소·잔액·nonce를 가진 계정입니다. 다른 점은 코드와 storage가 붙어 있고, 그 코드대로만 돈이 움직인다는 것. withdraw()를 Bob으로 호출해 보세요 — revert되지만 gas는 나갑니다.
왜 "코드가 곧 규칙"이 큰일인가

은행 예치: 약관·직원·법원이 개입 가능. 컨트랙트 예치: 배포된 코드 조건 말고는 그 무엇도 돈을 못 움직입니다.

주소가 keccak(배포자, nonce)로 결정되는 것, 이벤트의 topic0 = keccak(시그니처)인 것 전부 1번 탭에서 본 해시 규칙 그대로예요.

단점도 같은 원리에서 나옵니다 — 코드에 버그가 있어도 못 고칩니다 (The DAO 해킹이 그 사례).

그런데 이게 다 어디에 저장되나요? — 블록 vs 노드 DB

방금 만든 코드·storage·잔액이 블록 안에 적힐 것 같지만, 블록에는 "주문서"만 적힙니다. 결과물은 각 노드가 직접 계산해서 자기 DB에 보관해요.

블록 (체인에 영원히)
모두가 공유하는 기록
트랜잭션 목록 — "Bob이 buy()를 0.5 ETH와 호출" 같은 주문서들 + stateRoot — 실행 후 상태 전체를 요약한 해시 32바이트. 상태 자체는 없음.
상태 DB (각 노드 로컬)
주문서를 재생해서 만든 결과물
계정마다 { nonce, balance, storageRoot, codeHash }. 지갑 계정은 코드가 비어 있고, 컨트랙트 계정엔 바이트코드 + storage가 붙어 있어요.
왜 이래도 되나? 상태 전이가 순수함수(새 상태 = f(이전 상태, tx))라서, 블록에 입력(tx)만 적어두면 누구든 처음부터 재생해 같은 상태에 도달합니다. 노드끼리는 stateRoot 32바이트 비교 한 번으로 "우리 계산 같네"를 검증해요 — 비트코인 5번 탭의 머클루트와 같은 원리.

지금 이 시뮬의 상태 DB (실시간)

이 시뮬 세계의 모든 계정이 나옵니다 — 다른 탭에서 쓰는 컨트랙트(SAND는 4번 토큰 탭, ETH/USD Feed는 5번 오라클 탭)는 시작할 때 미리 배포돼 있어요. 실제 이더리움 상태 DB에 USDT·Uniswap이 이미 들어 있는 것과 같습니다.

Solidity 소스는 체인에 없습니다. 체인에 올라가는 건 컴파일된 바이트코드뿐이에요. Etherscan에서 소스가 보이는 건 개발자가 소스를 제출하면 다시 컴파일해 바이트코드와 대조해 주는 체인 밖 서비스 덕분입니다. 이 페이지가 Solidity를 보여주는 것도 같은 취지예요.
엔진 로그

ERC-20 — ETH 잔액과 토큰 잔액은 저장 위치가 다름

ETH는 1번 탭처럼 프로토콜이 계정 객체의 balance로 직접 관리합니다 (비트코인 UTXO가 아니라 계좌 숫자). The Sandbox의 SAND나 USDT는 그 필드가 아니라, 이더리움 위 그 토큰 컨트랙트 storage의 표(주소→수량)예요. ERC-20은 그 표의 표준이고, 아래 SAND는 그 구조를 만져 보는 교육용 미니 토큰입니다.

같은 world state, 다른 칸. 이더리움이 관리하는 건 계정 balance(ETH). SAND·USDT 같은 앱 토큰은 자기 storage 표. (실제 SAND는 gas 때문에 Polygon에서도 많이 거래되지만, 토큰 자체는 이더리움 ERC-20 계열입니다.)

storage (컨트랙트의 상태)

The Sandbox의 SAND 장부가 이렇게 생겼다고 보면 됩니다. 오른쪽 mapping(address → uint256) balanceOf — 지갑이 보여주는 "토큰 잔액"의 정체예요. ETH 계정 balance와는 다른 칸입니다. (교육용 미니 버전 · 메인넷 SAND 컨트랙트 아님)

이벤트 로그

Solidity 코드 (호출한 함수가 빛나요)


          
확인 포인트: ① Transfer의 value=50 SAND는 Bob에게 ETH를 준 게 아님 — storage 표만 바뀜 ② 그래도 tx를 실행하려면 gas는 ETH로 냄 (그래서 Alice ETH는 아주 조금 줄 수 있음) ③ 이벤트의 topic0은 실제 메인넷 ERC-20 Transfer와 동일한 keccak 값.
엔진 로그

오라클 — 체인은 바깥세상을 모른다

컨트랙트는 인터넷도 API도 못 씁니다. 모든 노드가 같은 계산을 재현해야 하니까요 — 예를 들어 날씨 API를 직접 치면, 어떤 노드는 성공·어떤 노드는 실패하거나, 어떤 노드는 A·어떤 노드는 B를 받을 수 있어 결과가 갈라집니다. 그래서 바깥 데이터(가격·날씨·경기 결과)는 oracle 노드들이 트랜잭션으로 넣어줘야 합니다. Chainlink가 이 방식이에요.

① oracle 노드가 가격 보고

각 노드가 거래소 API에서 본 가격을 tx로 올린다고 생각하세요. (실제 Chainlink 노드는 거래소 자체가 아니라, 여러 거래소·집계 API를 조회하는 독립 운영자입니다 — 여기선 출처 이름으로 표시)

이벤트 로그

Solidity 코드 (호출한 함수가 빛나요)


          
왜 median? 노드 하나가 가격을 조작해도 중앙값은 안 움직입니다. Coinbase에 터무니없는 값을 넣어보세요 — latestAnswer가 버팁니다. 단일 oracle이면 그대로 뚫려요 (실제 DeFi 해킹 단골 원인).

② oracle을 쓰는 컨트랙트 — 가격 보험

“ETH가 3,000달러 아래로 떨어지면 1 ETH를 지급한다”는 보험을 배포해 보세요. 지급 여부는 사람이 아니라 feed의 median이 결정합니다. 아래 Bob 잔액이 settle 후 늘어나는지 보세요.

계정 잔액 (지급 추적)

가입·정산할 때마다 Bob ETH가 어떻게 바뀌는지 처음부터 보여 줍니다.

오라클 문제: 컨트랙트 코드가 아무리 완벽해도, 먹이는 데이터가 오염되면 끝입니다. 그래서 다중 노드·median·스테이크 기반 페널티로 데이터 자체를 탈중앙화하는 게 Chainlink 같은 oracle 네트워크의 일입니다.
더 깊이: 오라클 문제 · 써드파티 vs 퍼스트파티 · 보상과 슬래싱

오라클 문제가 뭐였나: 온체인 데이터는 구성원들이 서로 검증하며 신뢰를 유지하지만, 외부(오프체인) 데이터는 인체인 방식으로 참·거짓을 검증할 방법이 없습니다. 외국 여행객이 입국 심사를 거치듯, 바깥 데이터도 심사자가 필요한데 — 그 심사를 한 업체에 맡기면 다시 중앙화가 되죠. 이 딜레마가 오라클 문제입니다.

써드파티 오라클 (Chainlink·Band): 여러 검증 노드가 각자 데이터를 가져와 비교·합의합니다(위 median이 그 축소판). 정확히 보고한 노드는 보상(LINK)을 받고, 틀리게 보고한 노드는 스테이킹한 코인을 잃고 평판이 깎여 다음 검증 기회가 줄어요. 탈중앙적이지만 노드가 많아 느리고 보상이 분산됩니다.

퍼스트파티 오라클 (PYTH 등): 거래소·데이터 제공자가 직접 서명해 올립니다. 스테이킹으로 거짓 보고를 억제해요. 빠르고 효율적이지만 제공자를 믿어야 해서 중앙화 쪽으로 기웁니다.

왜 중요한가: 오라클이 신뢰를 확보해줘야 부동산·주식 같은 실물 자산(RWA)도 스마트 컨트랙트로 다룰 수 있게 됩니다. LINK 코인 자체가 기술이 아니라, 검증 노드에게 주는 보상 수단이라는 점도 포인트.

엔진 로그

Proof of Stake — 누가 블록을 만들고, 언제 확정되나

The Merge(2022) 이후 이더리움엔 비트코인 같은 채굴이 없습니다. 시간이 slot(실제 12초짜리 칸)으로 잘게 나뉘고, 매 slot마다 지분 비례 무작위 추첨(실제는 RANDAO)으로 validator 한 명이 뽑혀 블록을 제안합니다. 나머지 validator들은 그 블록이 맞는지 확인하고 attest(찬성 투표)를 던져요. slot 여러 개(여기선 8개, 실제 32개)를 묶은 게 epoch이고, epoch 단위로 투표를 집계해 확정을 진행합니다.

0%

읽는 법: Slot = 지금 몇 번째 시간 칸인지 · Epoch = slot 묶음 번호 · Justified/Finalized = 아래 "2단계 확정"이 어느 epoch까지 진행됐는지 ( = 아직 확정된 epoch 없음).

체인 (justified → finalized)

블록마다 stateRoot(그 시점 world state의 지문)가 실립니다. 다른 탭에서 송금·컨트랙트 호출을 한 뒤 slot을 진행해 보세요 — 지문이 바뀝니다. 검증자가 attest 전에 재실행으로 대조하는 값이 바로 이거예요. 블록의 attest 줄은 이 블록에 찬성 투표한 validator 명단입니다 (✓ 투표 · ✗ 오프라인).

왜 확정이 2단계인가? 계약서에 비유하면 — epoch의 투표가 2/3 지분을 모으면 그 epoch은 justified(가서명). 다음 epoch도 2/3를 모으면 직전 justified가 finalized(공증 완료)로 승격됩니다(Casper FFG). finalized를 뒤집으려면 validator들이 서로 모순된 투표에 서명해야 하는데, 그 순간 전체 지분의 1/3+가 slashing으로 소각돼요. 그래서 "경제적으로" 최종입니다.
확정의 단위와 리듬: 확정은 블록 낱개가 아니라 epoch 단위로 진행됩니다. 평상시엔 컨베이어 벨트처럼 — epoch 5가 2/3를 모으면 epoch 5 justified + 직전의 epoch 4가 finalized — 항상 justified가 한 칸 앞서 나란히 전진해요 (실제로는 블록 생성 후 약 2 epoch ≈ 13분 뒤 확정). 단, finalized는 조상까지 소급되기 때문에, 오프라인 사태로 확정이 몇 epoch 멈췄다가 투표율이 회복되면 멈춰 있던 구간이 한꺼번에 따라잡힙니다 — 아래 실험에서 슬라이더를 내려보면 Finalized 숫자가 훌쩍 뛰는 걸 볼 수 있어요.
실험: 오프라인 슬라이더를 34% 이상으로 올리고 epoch을 진행해 보세요 — 투표가 2/3에 못 미쳐 justified/finalized가 멈춥니다. 블록은 계속 쌓이는데 확정만 안 되는 상태. 실제 이더리움은 이 상태가 길어지면 오프라인 validator의 지분을 서서히 깎아(inactivity leak) 다시 2/3를 회복해요.
Bitcoin 대비: PoW의 확정은 확률적("컨펌이 쌓일수록 안전")이지만, PoS Gasper는 2/3 지분이 서명한 checkpoint를 뒤집으려면 지분 1/3+가 slashing으로 불타는 경제적 파이널리티입니다.
제안자가 tx를 조작할 수 있나? 멤풀에서 어떤 tx를 넣을지·순서는 고를 수 있지만, 남이 서명한 tx의 금액·수신자를 고치면 서명이 깨져서 거절됩니다(탭 1·2). 본인 tx는 새로 서명해 넣을 수 있지만 자기 돈 범위뿐. 검증자는 블록 안 tx를 다시 실행해 stateRoot가 일치하는지 보고(탭 8), 맞으면 attest · 틀리면 거부합니다.

validator 라이프사이클 — staking · slashing

블록을 제안·투표하려면 32 ETH를 staking하고 활성화해야 합니다. 이중서명 같은 위반은 slashing으로 담보가 깎여요 — PoW의 전기 대신 담보로 시빌을 막는 구조입니다.

validator 목록

왜 전액 몰수가 아니라 일부만 깎이나? 실제 이더리움의 즉시 벌금은 의외로 작아요 (32 ETH 중 약 1 ETH). 대신 자격이 영구 박탈되고(여기서도 Slashed는 재활성화 불가), 결정적으로 같은 기간에 slashing된 지분이 많을수록 벌금이 커지는 상관관계 페널티가 있어서 — 지분 1/3+가 공모해 finalized를 뒤집으려는 순간 전액 소각됩니다. 혼자 한 실수(키 관리 사고)는 가볍게, 조직적 공격은 파멸적으로 벌하는 설계예요.

공격해 보기 — 포크 · 이중 제안

제안자 당번이 된 validator가 같은 slot에 서로 다른 블록 2개를 서명해 절반씩 다른 버전을 보여주는 공격입니다(이중지불 시도 — BTC 탭 7의 "비밀 체인"의 PoS 버전). 결과: ① 체인이 두 갈래로 갈라지지만 ② 정직한 다수의 투표 가중치가 원래 체인을 헤드로 지키고 ③ 같은 slot에 대한 서명 2개 = 수학적 증거라 변명 불가 — 자동으로 slashing됩니다. BTC와 달리 실패한 공격은 담보를 잃어 재시도가 불가능해요.

여기서 "서명"은 tx 서명이 아니에요 — 서명은 세 층이 있습니다.tx 서명 = "이 돈을 보내는 게 나다" (보낸 사람의 지갑 키, 탭 1·2) ② 블록 서명 = "이 블록을 만든 게 나다" (제안자가 완성된 블록 헤더에 validator 키로 서명) ③ attest 서명 = "이 블록에 찬성한 게 나다" (투표자의 서명). 이중 제안의 증거는 ②가 같은 slot에 2개 존재하는 것. 참고로 validator 키는 지갑 키(ECDSA)와 다른 BLS 서명을 쓰는데, 수천 개 서명을 하나로 합칠 수 있어서(집계) 100만 validator가 epoch마다 전원 투표해도 블록에 담을 수 있어요.
51%와의 차이: BTC의 이중지불은 "더 긴 비밀 체인" 경쟁이라 전기만 있으면 재시도 가능. PoS에서 finalized checkpoint를 공격하면 담보가 소각되어 같은 공격을 반복할 수 없습니다.
엔진 로그

부동산 거래를 이더리움으로 — 에스크로 컨트랙트

지금까지 배운 걸 하나의 실제 거래로 꿰어 봅니다. 전통 부동산은 에스크로 회사·등기소·중개인이 신뢰를 맡죠. 여기선 코드(컨트랙트)가 그 역할을 대신해요 — 대금을 잠그고, 조건이 확인돼야만 매도자에게 넘깁니다. 단계마다 tx·nonce·gas·storage·블록·stateRoot가 어떻게 움직이는지 보세요.

시작: 매도자(Bob)가 ① 매물 등록을 누르면 Escrow 컨트랙트가 배포됩니다. 이게 곧 "이 거래 전용 계좌 + 규칙"이에요.

지금 컨트랙트 · 계정 상태

왼쪽은 실제 잔액·컨트랙트 storage·이벤트, 오른쪽은 그 규칙을 정한 Solidity 코드예요. 방금 호출한 함수가 코드에서 빛납니다.

계정 잔액 (거래 당사자)

storage (컨트랙트의 상태)

이벤트 로그

Solidity 코드 (호출한 함수가 빛나요)


          

블록에 쌓이는 과정 — tx + stateRoot

각 단계는 트랜잭션이고, 블록에 담기면 전체 상태의 지문 stateRoot가 바뀝니다. git 커밋처럼 이전 걸 고치는 게 아니라 새 블록이 앞으로 쌓여요. (stateRoot는 이 시뮬의 계정+컨트랙트 스냅샷을 keccak-256 한 값입니다.)

읽는 법: 블록마다 담긴 tx(누가·무슨 함수)와 그 직후의 stateRoot가 보여요. tx가 상태를 바꾸면 stateRoot가 완전히 달라지고, revert된 tx는 상태를 안 바꾸니 stateRoot도 그대로입니다.

전통 부동산 ↔ 이더리움 에스크로

역할 전통 부동산 거래 이더리움 에스크로
대금 보관에스크로 회사·은행 계좌컨트랙트가 잠금 (아무도 못 빼감)
조건 확인등기소·법무사·중개인확인자 tx (confirm)
지급 실행사람이 송금 처리 (지연·실수)코드가 자동 (조건 충족 시만)
파기·환불분쟁·소송 가능refund로 원자적 환불
신뢰 주체여러 기관·사람배포된 코드 (변경 불가)
기록기관별 장부 (분산·불투명)블록·stateRoot (공개·검증가능)
핵심: 바뀐 건 "누구를 믿느냐"예요. 여러 기관·사람에게 흩어졌던 신뢰가 배포 후 못 바꾸는 코드 한 조각으로 모입니다. 대신 코드에 버그가 있으면 그것도 규칙이 되므로(탭 3), 실제 서비스는 감사(audit)를 거칩니다.
엔진 로그

EVM — 이더리움을 돌리는 CPU

스마트 컨트랙트는 결국 바이트코드고, 그걸 한 명령(opcode)씩 실행하는 가상 CPU가 EVM이에요. world state(데이터)에 tx(명령)를 넣으면, EVM이 gas를 태우며 실행해 새 상태를 만듭니다. JVM처럼 스택 기반 가상머신이고, JS 이벤트 루프처럼 단일 스레드로 끝까지 실행돼요.

컴퓨터 이더리움 뭐냐
디스크 / DB (전체)world state모든 계정 잔액 + 모든 컨트랙트 storage
그중 한 파일·테이블storage컨트랙트 하나분의 영구 칸 (world state의 일부)
RAM (휘발)stack · memorytx 끝나면 사라짐
실행할 프로그램tx누가·어떤 함수·인자 (동작)
CPUEVM바이트코드를 opcode씩 실행
전기요금·클럭gas실행 비용·상한
전체 DB 체크섬stateRootworld state 전체의 지문
JVM 닮은 점: 둘 다 스택 머신 — 레지스터가 아니라 스택에 값을 쌓아 계산해요. PUSH 3, PUSH 4, ADD → 스택에 7. JS 이벤트 루프 닮은 점: 단일 스레드로 끝까지 실행(중간에 안 끊김), 끝나거나 통째로 revert.
결정적으로 다른 점: EVM은 완전 결정적이어야 해요 — random·현재시각·네트워크 I/O가 없음. 전 세계 노드가 같은 tx를 각자 실행해 똑같은 스택·스토리지·gas가 나와야 합의가 되니까요. gas도 이래서 존재해요(무한루프·DoS 방지).

한 스텝씩 실행해 보기

프로그램을 고르고 다음 스텝을 누르면, opcode 하나가 실행될 때마다 스택·스토리지·gas가 어떻게 변하는지 보여줘요. 이벤트 루프 시각화처럼요.

바이트코드 · PC

Stack (top ↑ · 휘발성)

Memory (휘발성)

Storage (이 컨트랙트 칸 · world state의 일부)

Gas

World state ↔ stateRoot — git처럼 보기

왼쪽이 지금 storage 내용(working tree), 오른쪽이 그걸 해시한 stateRoot(커밋 해시)예요. SSTORE로 값이 바뀌면 새 커밋이 쌓이고, 프로그램을 바꿔도 히스토리는 남습니다.

storage (world state의 일부)
keccak-256
stateRoot · commit hash
커밋 히스토리

이게 왜 이더리움의 본체인가

ERC-20·오라클·DeFi는 전부 이 위에서 도는 앱이에요. 컨트랙트 코드=class, 배포된 주소=인스턴스 하나, storage=그 인스턴스의 필드, 함수 호출=메서드 호출. EVM은 그 메서드를 실제로 굴리는 엔진이고요.
SSTORE가 왜 비싼가: 스택·메모리는 tx 끝나면 사라지지만 storage는 영구(world state)라, 모든 노드가 영원히 들고 있어야 해요. 그래서 스토리지 쓰기(20000 gas)가 산술(3 gas)보다 압도적으로 비쌉니다.
핵심: new_state = EVM.execute(state, tx) 하고 stateRoot = hash(new_state). 이 상태 전이 기계를 이해하면, 나머지는 전부 "이 기계 위의 인스턴스들"로 보입니다.

먼저 — 노드는 world state를 다 들고 있나?

"모두가 재실행한다"는 건 state를 들고 있어야 가능해요. 근데 노드 종류마다 얼마나 들고 있느냐가 달라요. 특히 라이트 클라이언트는 state를 안 들고 있어서, 아래에서 볼 머클 증명으로 값을 확인해요.

노드 종류 world state 보유 설명
풀 노드 (가장 흔함) ✅ 현재(최근) state 최신 world state + 모든 블록 보관. 아주 오래된 중간 state는 잘라냄(prune). 필요하면 제네시스부터 재실행해 복원.
아카이브 노드 ✅ 모든 과거 state 전부 블록 1번부터 지금까지 모든 시점의 state 스냅샷을 다 보관. 용량 수 TB(탐색기·인프라용).
라이트 클라이언트 ❌ 안 들고 있음 블록 헤더만 보관. 잔액 등이 필요하면 풀 노드에 요청하고, 헤더의 stateRoot로 머클 증명만 검증.
머지(2022) 이후: 이더리움 풀 노드는 프로그램이 둘이 한 세트예요. 실행 클라이언트(Geth·Nethermind 등)가 world state를 들고 EVM을 실행하고, 합의 클라이언트(Prysm·Lighthouse 등)가 PoS·투표·slot/epoch를 담당해요. "world state를 들고 있다"는 건 정확히는 실행 클라이언트 쪽이에요.

머클 증명 — state 전체 없이 값 하나만 검증하기

라이트 클라이언트는 블록 헤더의 stateRoot 하나만 신뢰해요. "이 계정 잔액이 진짜야?"를 확인하려고, state를 가진 풀 노드가 경로의 형제 해시 몇 개만 보내주면, 그걸로 잎에서 꼭대기까지 해시를 직접 재계산해 stateRoot와 대조해요. 아래에서 계정을 고르고 증명을 재생해 보세요 — 경로가 깜빡이며 stateRoot까지 타고 올라가요.

누가 하나? 제안자와 무관해요. "state를 가진 쪽(풀 노드)이 증명 생성 / 안 가진 쪽(라이트)이 검증"하는 노드 간 on-demand 상호작용이에요.

머클 트리 시뮬레이터

풀 노드가 보내는 증명 (형제 해시들 + 값)

라이트 클라이언트의 재계산

왜 못 속이나

해시는 값 하나만 바뀌어도 꼭대기 해시가 완전히 달라져요. 그래서 풀 노드가 잔액을 부풀려 보내면, 라이트가 재계산한 stateRoot가 헤더의 stateRoot와 안 맞아요. 위 😈 거짓말 토글을 켜고 재생하면 직접 확인할 수 있어요 — 풀 노드를 믿지 않고도 몇 개 해시만으로 진위를 가려내는 게 핵심이에요.
git 비유: 파일(계정) → 디렉토리 해시(중간 노드) → 최종 트리 해시(stateRoot)로 올라가는 구조와 똑같아요. 커밋 해시 하나만 믿으면, 특정 파일이 그 커밋에 진짜 들어있는지 부분 검증할 수 있는 것과 같은 원리예요.

마무리 — 이더리움은 "멈추지 않는 서버"를 릴레이로 합성한다

Web2.0에는 24시간 혼자 도는 중앙 서버 한 대가 있어요. 이더리움엔 그런 서버가 없어요. 대신 slot마다 다른 노드가 바통(블록)을 이어받아 상태를 한 칸 전진시키고, 나머지 노드들이 각자 재검산해서 맞는지 확인해요. "쉬지 않는 서버"라는 겉모습은, 번갈아 이어달리는 수천 개의 노드가 합성해내는 착시예요.

중앙 서버 1대 (24h 상시) → 대체 → 유인을 가진 수천 노드 · slot마다 바통 릴레이 + 상호 검산

릴레이 도식 — 바통은 블록 + stateRoot

각 slot(12초)마다 랜덤 추첨된 제안자 노드 한 명이 tx를 실행해 새 world state와 stateRoot를 만들고(바통 생성), 그걸 다음 slot으로 넘겨요. 나머지 검증자들은 그 바통을 받아 각자 재실행해서 stateRoot가 같은지 채점하고 투표해요. 32 slot(=1 epoch)마다 충분히 표가 쌓이면 finalized — 되돌릴 수 없게 굳어요.

slot 10012초
🏃 제안자 #7RANDAO 추첨
📦 블록
stateRoot: a1c3…
✔ 검증자 재실행 2/3 이상 동의
state
이어받기
slot 10112초
🏃 제안자 #42다른 노드로 교대
📦 블록
stateRoot: 9f0b…
✔ 검증자 재실행 2/3 이상 동의
state
이어받기
slot 10212초
🏃 제안자 #13stateRoot 조작 시도
📦 블록
stateRoot: ☠ 위조
✘ 재실행 → 불일치 거부 · 바통 탈락
slot 0 justified ✔ finalized 🔒 (되돌릴 수 없음) 1 epoch = 32 slot
포인트 1 · 상시 실행이 아님: 어느 노드도 "서버처럼 24시간 돌지" 않아요. 바통이 올 때(=블록이 올 때)만 깨어나 검산하고 다시 쉬어요. 컨트랙트 코드가 tx가 없으면 자는 것과 똑같은 이치예요(수동적 실행).
포인트 2 · 조작은 처벌이 아니라 탈락: stateRoot를 위조한 블록(slot 102)은 재검산에서 걸려 그냥 거부·무시돼요. 몰수(slashing)는 이중 서명·모순 투표처럼 합의 자체를 공격할 때만 일어나요.
포인트 3 · 연속성은 합성물: slot·epoch·투표·페널티라는 톱니가 맞물려 "끊기지 않는 한 대의 서버" 같은 겉모습을 만들어내요. 실체는 번갈아 이어달리며 서로 검산하는 릴레이예요.

Web2.0 서버 vs 이더리움 릴레이

Web2.0 — 중앙 서버
  • 한 대가 24시간 상시 실행(프로세스 상주)
  • 그 서버가 계산하면 믿어줌
  • 신뢰의 근거 = 운영 회사
  • 회사가 마음먹으면 값·로직을 바꿀 수 있음
  • 멈추면 서비스도 멈춤 (단일 실패점)
Web3.0 — 이더리움
  • 상시 서버 없음. slot마다 다른 노드가 바통 이어받음
  • 수천 노드가 전부 재실행해 대조(믿지 않고 검산)
  • 신뢰의 근거 = 경제적 유인 + 게임이론(stake·보상·slashing)
  • 코드는 불변. 아무도 결과를 못 바꿈
  • 노드 일부가 죽어도 나머지가 릴레이 계속
한 줄로: Web2가 "신뢰할 수 있는 회사"로 중앙화를 정당화했다면, 이더리움은 그걸 "신뢰할 필요 없는 인센티브 설계(인간 심리)"로 대체했어요. 중앙화 문제를 기술이 아니라 경제·게임이론으로 푼 게 핵심이에요.

우리가 짚은 것 총정리

1
코드는 잔다
컨트랙트는 state에 저장된 데이터일 뿐. tx가 호출할 때만 실행(수동적).
2
자동 실행은 없음
"3000 넘으면 execute"는 체인 밖 keeper·봇이 감시하다 tx로 호출. 가격은 오라클이 넣어줌.
3
모두가 재실행
각 노드가 자기 복사본에서 계산. 그래서 v+1을 N번 해도 v+N이 아니라 전부 v+1(같은 문제 N명이 풀기).
4
결정론이 조건
난수·외부 API·현재시각 금지. 안 그러면 노드마다 답이 달라져 검산 불가.
5
틀리면 탈락 / 공격은 몰수
stateRoot 오류 → 거부. 이중 서명·모순 투표 → slashing. offline → 소액 감소.
6
justified → finalized
2/3 투표로 굳어지면 되돌릴 수 없음. 그때 world state에 블록 확정.
결론: 스마트 컨트랙트는 "스스로 사는 프로그램"이 아니라 호출되면 약속대로만 움직이는 불변 규칙 엔진이고, 그 호출을 누가·언제 할지는 여전히 인간 세계(Web2)에 남아 있어요. 이더리움이 Web2에 기대 보이는 건 순수하지 못해서가 아니라, 하려는 일이 더 많아서예요.