
이더리움 프로토콜의 사전 역사: 니르바나에서 천천히 깨어나다
본문은 2017년 9월 14일에 작성되었습니다.
편집자 주: 본 글은 비탈릭이 이더리움 프로토콜의 발전 과정을 회상한 글로, 이더리움 프로토콜이 구상 단계부터 최초 출시 및 반복 개선까지 이루어진 이야기를 담고 있습니다.
현재 이더리움 프로토콜의 핵심 개념은 지난 몇 년간 대체로 안정화되었지만, 오늘날의 이더리움이 갖는 전체적인 형태와 구상은 하루아침에 완성된 것이 아닙니다. 블록체인으로서의 이더리움이 등장한 이후에도, 그 프로토콜은 수많은 중대한 변화와 결정을 겪었습니다.
본문은 이더리움 프로토콜이 처음 시작되어 공개되기까지의 진화 과정을 되돌아보는 것을 목적으로 합니다. 여기에는 Geth, cppethereum, pyethereum, EthereumJ 등의 프로토콜 구현에서 수행된 막대한 작업이나, 이더리움 생태계 내 애플리케이션과 비즈니스 역사에 관한 내용은 다루지 않습니다.
또한 카스퍼(Casper)나 샤딩(sharding) 연구의 역사 또한 범위에서 제외됩니다. 분명히 말해, 우리는 프라드(Vlad), 가빈(Gavin), 저 자신 그리고 다른 사람들이 제안했다가 폐기한 다양한 아이디어들—예컨대 작업증명의 증명(proof of proof of work), 윤곽 보조 다중 체인(rim-chain multi-chain), 초입방체(hypercube), 섀도우 체인(플라즈마의 전신이라 할 수 있음), 체인 섬유(fibers), 카스퍼의 다양한 반복 버전, 또는 합의 프로토콜 참여자들에게 대한 인센티브 설계를 신속하게 발전시킨 프라드의 사고 방식—등에 대해 별도의 글을 쓸 수도 있을 것입니다. 이러한 아이디어들의 배경에 얽힌 이야기 자체가 너무나 복잡하여 별도의 논의가 필요하므로, 일단 이번에는 다루지 않겠습니다.
가장 초기 버전부터 시작하겠습니다. 이 버전은 결국 이더리움이 되었지만, 당시엔 '이더리움'이라는 이름조차 없었습니다. 저는 2013년 10월 이스라엘을 방문했을 때 마스터코인(Mastercoin) 팀과 오랜 시간 함께하며, 심지어 그들에게 일부 기능 추가를 제안하기도 했습니다. 그들이 추진하고 있는 일을 여러 번 고민한 후, 저는 해당 팀에게 프로토콜을 더욱 일반화하여 방대하고 복잡한 기능 세트를 추가하지 않고도 더 많은 유형의 계약을 지원할 수 있도록 하는 제안서를 보냈습니다:
https://web.archive.org/web/20150627031414/http://vbuterin.com/ultimatescripting.html
이 버전은 이후 이더리움이 가지게 된 광범위한 비전과는 크게 다르다는 점에 주목해야 합니다. 이는 당시 마스터코인이 시도하고 있던 기술, 즉 양자간 계약에만 집중했습니다. 예를 들어 A와 B 두 당사자가 자금을 공동으로 예치한 후, 특정 조건에 따라 자금을 인출하는 계약입니다. (예: "X가 발생하면 모든 자금을 A에게, 그렇지 않으면 B에게 준다"). 이 계약을 구현하는 스크립트 언어는 튜링 완전(Turing-complete)하지 않았습니다.
마스터코인 팀은 이 제안에 깊은 인상을 받았지만, 자신의 모든 노력을 포기하고 이 방향으로 나아갈 의향은 없었습니다. 그러나 저는 이 길이 올바른 선택임을 점점 더 확신하게 되었고, 결국 12월경 두 번째 버전이 등장합니다:
https://web.archive.org/web/20131219030753/http://vitalik.ca/ethereum.html
이 버전에서는 상당한 재구성이 이루어진 결과를 확인할 수 있습니다. 대부분의 재구성은 11월, 제가 샌프란시스코에서 장시간 산책하면서 떠올렸습니다. 이때 저는 스마트 계약이 완전히 일반화될 수 있다는 가능성을 깨달았습니다. 단순히 양자 간 관계를 묘사하는 스크립트 언어를 넘어서, 계약 자체가 자산을 소유하고 송수신하며 영구 저장소를 유지할 수 있는 완전한 계정(account)이 될 수 있다고 생각했습니다. (당시 영구 저장소는 "메모리"라고 불렸으며, 임시 "메모리"는 256개의 레지스터뿐이었습니다.) 언어는 스택 기반 가상머신에서 제가 선호하는 레지스터 기반 가상머신으로 바뀌었습니다. 다만 이것이 더 복잡해 보일 수 있다는 점 외에는 큰 문제는 없었습니다.
여기서 "이더(ether)"는 문자 그대로 에테르(즉 연료, 가스와 동일)를 의미합니다. 각 계산 단계가 완료되면 거래가 호출한 계약의 잔액이 일부 감소합니다. 계약의 자금이 바닥나면 실행은 중단됩니다. 이 수취자 지불 메커니즘은 계약 자체가 송신자로부터 수수료를 지불하도록 요구해야 한다는 것을 의미합니다. 수수료가 도착하지 않으면 바로 실행이 종료됩니다. 이 프로토콜 버전은 계약이 수수료 없는 거래를 거부할 수 있도록 16단계의 무료 실행 한도를 부여했습니다.
이 시점까지 이더리움 프로토콜은 사실상 제가 혼자 구축한 것이었습니다. 그러나 이제부터 새로운 참가자들이 등장하기 시작합니다. 현재까지 프로토콜 측면에서 가장 두드러진 기여자는 가빈(Gavin)으로, 그는 2013년 12월 about.me의 개인 메시지를 통해 저에게 연락을 시작했습니다.
제프리 윌크(Jeffrey Wilcke), Go 클라이언트(당시 "ethereal"이라 불림)의 주요 개발자도 거의 같은 시기에 저에게 연락해 개발을 시작했습니다. 다만 그의 기여는 클라이언트 개발 중심이었으며 프로토콜 연구보다는 거리가 있었습니다.
가빈의 초기 기여는 두 가지였습니다. 먼저 초기 설계에서 계약 호출 모델은 비동기식이었습니다. 계약 A가 계약 B에게 내부 거래(internal transaction)를 생성할 수 있었지만(내부 거래는 이더리움의 은어이며, 원래는 단순히 "거래", 이후 "메시지 호출" 또는 "호출"이라 불렸음), 첫 번째 거래의 실행이 완전히 종료되기 전까지 내부 거래의 실행은 시작되지 않았습니다. 이는 거래가 내부 거래를 통해 다른 계약의 정보를 가져올 수 없다는 것을 의미했습니다. 다른 계약의 정보를 얻으려면 EXTRO 오퍼코드(SLOAD처럼 다른 계약의 저장소를 읽는 데 사용되는 명령어)를 사용해야 했는데, 이 오퍼코드는 이후 가빈과 다른 사람들의 지지 아래 제거되었습니다.
저의 초기 명세를 구현하면서, 가빈은 자연스럽게 내부 거래를 동기식으로 구현했습니다. 그는 두 설계 사이의 의도적 차이를 인식하지 못했던 것으로 보입니다. 즉, 가빈의 구현에서는 한 계약이 다른 계약을 호출할 때 내부 거래가 즉시 실행되며, 그 실행이 끝나면 가상머신은 내부 거래를 생성한 계약으로 돌아와 다음 오퍼코드를 계속 실행합니다. 우리 둘 모두에게 이런 방식이 더 우수해 보였고, 따라서 이를 공식 명세의 일부로 채택하기로 결정했습니다.
두 번째 기여는 샌프란시스코의 산책 중 나눈 대화에서 비롯되었습니다. 정확한 세부 사항은 역사의 강물 속으로 사라졌지만(혹은 NSA의 깊은 기밀 파일 어딘가에 복사본이 남아있을지도 모릅니다), 이 대화가 거래 수수료 모델을 재설계하는 계기가 되었습니다. 즉, 계약이 지불하는 방식에서 발신자가 지불하는 방식으로 전환하고, 연료(fuel) 아키텍처로 전환한 것입니다. 개별 계산 단계마다 즉시 이더를 소비하는 대신, 이제 거래 발신자는 일정한 수수료를 지불하고 일정량의 연료를 할당받습니다. 연료는 계산 단계의 카운터 역할을 하며, 거래의 연료 한도에 따라 실행됩니다. 만약 거래가 모든 연료를 소진하면, 그 연료는 소모되지만 실행은 완전히 되돌려집니다. 이렇게 함으로써 계약이 부분 실행 공격에 노출되는 위험을 제거할 수 있으므로 가장 안전한 방법으로 여겨졌습니다. 거래가 성공적으로 완료되면, 사용하지 않은 연료에 대한 수수료는 환불됩니다.
가빈은 이더리움의 비전을 매우 미묘하게 변화시켰습니다. 즉, 블록체인 기반 계약이 디지털 자산을 보유하고 미리 설정된 규칙에 따라 이체할 수 있는 프로그래밍 가능한 화폐 플랫폼에서, 보다 일반적인 컴퓨팅 플랫폼으로의 전환입니다. 이러한 변화는 이더리움의 초점과 용어의 미세한 변화에서 시작되었으며, 웹3 통합(Web 3 integration)에 대한 관심이 커짐에 따라 더욱 강화되었습니다. 웹3는 이더리움을 탈중앙화 기술 패키지의 일부로 보며, 다른 구성 요소로는 위스퍼 프로토콜(whisper protocol)과 스웜 프로토콜(swarm protocol)이 있습니다(그림 1).

2014년 초 무렵, 다른 사람들의 제안을 받아 몇 가지 수정도 진행되었습니다. 앤드류 밀러(Andrew Miller) 등을 포함한 일부가 스택 기반 아키텍처로 되돌아가는 것을 제안한 후, 결국 우리는 다시 스택 기반으로 돌아갔습니다(그림 2).

찰스 호스킨슨(Charles Hoskinson)은 비트코인의 SHA256에서 더 최근의 SHA3(더 정확히는 keccak256)로 전환할 것을 제안했습니다. 논란의 시기도 있었지만, 가빈, 앤드류 및 기타 사람들과의 논의를 통해 스택 내 값의 크기는 32바이트로 제한하기로 결정했습니다. 무제한 정수(unbounded integers)라는 대안도 여전히 고려되었지만, 덧셈, 곱셈 및 기타 연산에 소요되는 연료를 얼마나 정확히 산정할 수 있을지 어려운 문제가 남아 있었습니다.
2014년 1월 무렵, 우리가 처음 고안한 채굴 알고리즘은 '다거(Dagger)'였습니다:
https://github.com/ethereum/wiki/blob/master/Dagger.md
다거는 방향성 비순환 그래프(Directed Acyclic Graph, DAG)에서 이름을 따왔습니다. DAG는 알고리즘에서 사용되는 수학적 구조로, N개의 블록마다 시드(seed)로부터 의사 난수로 생성되는 새로운 DAG를 만든다는 아이디어입니다. DAG의 기본층은 수십억 바이트의 저장 공간을 필요로 하는 노드 집합으로 구성됩니다. 그러나 DAG 내에서 개별 값을 생성하는 것은 수천 개 항목만 계산하면 됩니다. 다거 계산은 이 하위 데이터셋의 임의 위치에서 여러 값을 추출한 후 해시하는 과정을 포함합니다. 즉, 빠른 방법(데이터를 이미 메모리에 저장한 상태)과 느리지만 메모리 부담이 적은 방법(DAG에서 매번 필요한 값을 새로 생성)이 존재합니다.
이 알고리즘의 목적은 Scrypt와 같이 당시 유행하던 메모리 제한 특성을 가지면서도 경량 클라이언트(light client)에게 친화적이도록 하는 것이었습니다. 채굴자는 빠른 방법을 사용하여 메모리 대역폭(memory bandwidth)에 의해 제한되도록 할 수 있었습니다(소비자용 메모리는 이미 충분히 최적화되어 있어 ASIC으로 추가 최적화하기 어렵다는 이론). 반면 경량 클라이언트는 느리지만 메모리를 덜 사용하는 방식으로 검증할 수 있었습니다. 빠른 방법은 수 마이크로초, 느린 방법은 수 밀리초 정도 걸릴 수 있으므로 경량 클라이언트에서도 실현 가능했습니다.
여기서부터 이 알고리즘은 이더리움의 발전 과정을 따라 여러 차례 변화했습니다. 다음 아이디어는 '적응형 작업증명(adaptive proof of work)'이었습니다. 이 방식에서는 작업증명이 임의로 선택된 이더리움 계약을 실행하는 것으로 구성되며, ASIC 저항을 위한 교묘한 메커니즘을 포함했습니다. ASIC이 개발된다면, 경쟁 채굴자들은 ASIC이 잘 처리하지 못하는 계약을 만들고 배포함으로써 대응할 동기를 갖게 됩니다. 어떤 ASIC도 범용 컴퓨팅에 최적화될 수 없으며, 궁극적으로 CPU와 같아질 수밖에 없습니다. 따라서 이러한 대립적 인센티브를 활용해 본질적으로 범용 컴퓨팅을 수행하는 작업증명을 구현할 수 있다고 생각했습니다.
하지만 하나의 간단한 이유로 이 아이디어는 무너졌습니다. 바로 장기 공격(long-range attack) 때문입니다. 공격자는 블록 1부터 체인을 새로 만들고, 단순한 계약들로만 체인을 채울 수 있습니다. 이때 공격자는 그런 단순 계약을 위해 특화된 하드웨어를 설계할 수 있으며, 이를 통해 공격 체인이 메인 체인을 금세 추월할 수 있습니다. 결국 우리는 원점으로 돌아가야 했습니다.
다음 알고리즘은 "무작위 회로(random circuit)"로, 구체적인 설명은 Google 문서에서 확인할 수 있습니다. 이 알고리즘은 저와 프라드 즘피르(Vlad Zamfir)가 제안했으며, 매튜 웜플러-도티(Matthew Wampler-Doty)와 다른 이들이 분석했습니다. 이 아이디어는 의사 난수로 생성된 회로를 실행함으로써 채굴 알고리즘 내 범용 컴퓨팅을 시뮬레이션하는 것입니다. 이번에도 이 원칙 기반의 시스템이 작동하지 않는다는 결정적 증거는 없었습니다. 그러나 2014년에 접촉한 컴퓨터 하드웨어 전문가들은 모두 매우 회의적이었습니다. 매튜 웜플러-도티는 SAT 해결 기반의 작업증명을 제안했지만, 결국 거부되었습니다.
결국 우리는 '다거 해시imoto(Dagger Hashimoto)' 알고리즘을 다시 제안하게 되었고, 때때로 Dashimoto라고 줄여 부릅니다. 이 알고리즘은 Hashimoto의 많은 아이디어를 차용했습니다. Hashimoto는 사디어스 드레야(Thaddeus Dryja)가 제안한 작업증명 메커니즘으로, "I/O 제약 작업증명" 개념을 처음 도입했습니다. 이 메커니즘에서는 채굴 속도의 주요 제한 요소가 초당 해시 연산 수가 아니라 초당 RAM이 접근할 수 있는 메가바이트 수입니다. 그러나 다거 해시imoto는 이 작업증명 메커니즘을, 경량 클라이언트 친화적인 DAG 데이터셋(다거 알고리즘에서 유래)과 결합했습니다. 저와 매튜, 팀 등 여러 사람의 반복적인 조정을 거쳐, 이러한 아이디어들은 결국 우리가 지금 'Ethash'라 부르는 알고리즘으로 정착했습니다.
2014년 여름이 되면, 작업증명이 Ethash 단계에 도달하는 것은 2015년 초로 예정되어 있었지만, 프로토콜 자체는 이미 상당히 안정화되었으며, 반공식적인 명세는 가빈의 '황백서(yellow paper)' 형태로 발표되었습니다.
2014년 8월, 저는 이더리움이 더 짧은 블록 생성 시간과 더 높은 처리 능력을 가지면서도 중앙화 위험을 줄일 수 있도록 하는 이른바 '삼촌 블록(uncle block)' 메커니즘을 개발하고 도입했습니다. 이 메커니즘에 대한 소개는 PoC6에서 확인할 수 있습니다.
비트쉐어(BitShares) 팀과의 논의 후, 힙(heap)을 일급 데이터 구조로 사용하는 방안을 고려했습니다. 하지만 시간 부족으로 실행하지 못했고, 이후의 보안 감사와 DoS 공격 경험을 통해 당시 이 기능을 안전하게 구현하는 것이 훨씬 더 어렵다는 것을 알게 되었습니다.
9월, 저는 가빈과 함께 프로토콜 설계에서 두 가지 중대한 변경을 계획했습니다. 첫째, 상태 트리(state tree)와 거래 트리(transaction tree) 외에도 각 블록이 수취 트리(receipt tree)를 포함하도록 하는 것입니다. 수취 트리는 각 거래가 생성한 로그의 해시와 중간 상태 루트(intermediate state root)를 포함합니다. 로그는 거래가 블록체인에 저장 가능한 출력을 생성할 수 있게 하며, 경량 클라이언트도 접근할 수 있습니다. 그러나 미래의 상태 계산은 이 로그에 접근할 수 없습니다. 이 방식을 통해 탈중앙화 애플리케이션은 토큰 이체, 구매, 생성 및 체결된 거래 주문, 진행 중인 경매 등의 이벤트를 쉽게 조회할 수 있게 됩니다.
또 다른 아이디어로는 거래의 전체 실행 경로에서 머클 트리를 추출해 임의의 내용을 증명할 수 있도록 하는 방안도 고려했습니다. 단순성과 완전성 사이의 타협 끝에 우리는 로그를 채택했습니다.
둘째는 '사전 컴파일(precompiled contract)' 개념입니다. 사전 컴파일은 EVM 내에서 복잡한 암호 계산을 가능하게 하면서도 EVM 오버헤드를 피할 수 있는 문제를 해결합니다. 우리는 또한 로컬 계약에 대한 더 야심 찬 아이디어들을 제안했습니다. 예를 들어, 채굴자가 특정 계약을 더 효율적으로 실행할 수 있는 방법을 가지고 있다면, 그 계약의 연료 비용을 낮추는 데 투표할 수 있도록 하는 것입니다. 그러면 대부분의 채굴자가 빠르게 실행할 수 있는 계약은 자연스럽게 더 낮은 연료 비용을 가지게 됩니다. 그러나 우리는 이를 암호경제학적으로 충분히 안전하게 구현할 방법을 찾지 못했기 때문에 모든 아이디어를 거부했습니다. 공격자는 활성화 백도어(backdoor)가 있는 암호 연산을 수행하는 계약을 만들고, 백도어를 자신과 친구들에게 배포하여 해당 계약을 더 빠르게 실행할 수 있습니다. 이후 공격자는 연료 비용을 낮추는 투표를 하고, 이를 통해 네트워크에 DoS 공격을 가할 수 있기 때문입니다. 대신 우리는 덜 야심 찬 접근법을 선택했습니다. 즉, 해시 및 서명 방식과 같은 일반적인 작업을 위해 프로토콜 내에 소수의 사전 컴파일된 계약을 간단히 지정하는 것입니다.
가빈은 또한 프로토콜 추상화(protocol abstraction) 개념의 초기 지지자였습니다. 이는 이더리움 잔고, 거래 서명 알고리즘, 논스(nonce) 등 프로토콜의 여러 부분을 프로토콜 자체 내에서 계약으로 이전하는 것을 의미합니다. 궁극적인 이론적 목표는 전체 이더리움 프로토콜이 특정 초기 상태를 가진 가상머신에 함수 호출을 추가하는 것으로 기술될 수 있도록 하는 것입니다. 우리는 이러한 아이디어들을 초기 프론티어(frontier) 버전에 모두 포함시킬 시간이 없었지만, 향후 '콘스탄티노플(Constantinople)'의 일부 변경사항, 카스퍼 계약, 샤딩 명세 등을 통해 점차 통합될 것으로 기대했습니다.
이 모든 내용은 PoC 7에서 구현되었습니다. PoC 7 이후 프로토콜은 실제로 큰 변화 없이 유지되었으며, 일부 사소하지만 중요한 조정만 있었습니다. 이러한 세부 사항은 보안 감사를 거친 후 공개될 예정입니다.
2015년 초, 유타 슈타이너(Jutta Steiner)와 다른 팀원들이 출시 전 보안 감사를 조직했습니다. 이는 소프트웨어 코드 감사와 학술 감사로 나뉘었습니다. 코드 감사는 주로 가빈과 제프리(Jeffrey)가 주도한 C++ 및 Go 구현에 집중되었으며, 제 Pyethereum 구현도 간단한 감사를 받았습니다. 학술 감사 중 하나는 '이기적 채굴(selfish mining)'로 유명한 이타이 에얄(Ittay Eyal)이 담당했고, 다른 하나는 앤드류 밀러와 Least Authority 팀이 수행했습니다. 에얄의 감사는 사소한 프로토콜 변경을 초래했는데, 즉 체인의 총 난이도 계산에 삼촌 블록을 포함하지 않는 것으로 변경한 것입니다. Least Authority의 감사는 스마트 계약, 연료 경제학, 패트리샤 트리(Patricia tree)에 초점을 맞췄으며, 이것 역시 몇 가지 프로토콜 변경을 유도했습니다. 그 중 작은 변경 사항 중 하나는 트리의 키로 주소와 키 값을 직접 사용하는 대신 sha3(addr)와 sha3(key)를 사용하는 것이었습니다. 이를 통해 공격자가 트리에 최악의 경우 공격을 가하기 어렵게 만들 수 있습니다.
우리가 논의한 또 다른 중요한 주제는 연료 한도 투표 메커니즘입니다. 당시 우리는 비트코인의 블록 크기 논쟁이 진전이 없었던 점에 우려를 갖고 있었고, 이더리움에서는 필요에 따라 시간이 지남에 따라 조정 가능한 유연한 설계를 갖기를 원했습니다. 그러나 문제는 최적의 한도가 무엇인지였습니다. 제가 처음 제안한 것은 실제 연료 사용량의 장기 지수이동평균(EMA)의 1.5배가 동적 한도가 되도록 하는 것이었습니다. 즉 장기적으로 평균 블록은 2/3 정도 사용되도록 하는 것입니다. 그러나 앤드류는 이 한도가 악용될 수 있음을 증명했습니다. 즉, 한도를 높이고 싶은 채굴자는 연료는 많이 소비하지만 처리 시간은 적게 드는 거래를 자신의 블록에 포함시키기만 하면 되며, 비용을 들이지 않고도 꽉 찬 블록을 만들 수 있다는 것입니다. 따라서 최종 결과 면에서 이 메커니즘의 보안 모델은 단순히 채굴자가 연료 한도에 투표하는 것과 동일하다는 결론이었습니다.
우리는 더 나은 연료 한도 전략을 제안하지 못했고, 앤드류는 채굴자가 명시적으로 연료 한도에 투표하도록 하고, 기본 투표 전략을 EMA의 1.5배로 설정할 것을 권장했습니다. 이는 우리가 최대 연료 한도를 설정하는 올바른 방법을 아직 모르며, 구체적인 방법이 실패할 위험이 채굴자의 투표권 남용 위험보다 훨씬 더 크다고 판단했기 때문입니다. 따라서 연료 한도를 투표로 결정하는 간단한 방식을 선택하고, 연료 한도가 너무 높거나 낮을 수 있는 위험을 감수하더라도 유연성과 필요 시 채굴자들이 연료 한도를 빠르게 조정할 수 있는 장점을 취하기로 한 것입니다.
저와 가빈, 제프(Jeff)가 미니 해커톤을 진행한 후, 3월에 PoC 9가 출시되었습니다. 이는 개념 증명의 최종 버전을 목표로 했습니다. 우리는 '올림픽(Olympic)'이라는 이름의 테스트넷을 4개월간 운영했습니다. 이 테스트넷은 메인넷에 적용될 예정인 프로토콜을 사용했습니다. 동시에 우리는 이더리움의 장기 로드맵도 수립했습니다. 비나이 구프타(Vinay Gupta)는 '이더리움의 출시 과정'이라는 글을 써서, 메인넷 개발의 4단계를 설명하고, 오늘날 널리 알려진 이름인 "프론티어(Frontier)", "홈스테드(Homestead)", "메트로폴리스(Metropolis)", "실런스(Serenity)"를 부여했습니다.
'올림픽' 테스트넷은 4개월간 운영되었습니다. 처음 2개월 동안 우리는 다양한 구현에서 많은 버그를 발견했고, 합의 실패 등의 문제가 있었습니다. 그러나 6월경 네트워크는 현저히 안정화되었습니다. 7월에는 코드를 동결하기로 결정했으며, 7월 30일 이더리움 메인넷이 공식 출시되었습니다.
TechFlow 공식 커뮤니티에 오신 것을 환영합니다
Telegram 구독 그룹:https://t.me/TechFlowDaily
트위터 공식 계정:https://x.com/TechFlowPost
트위터 영어 계정:https://x.com/BlockFlow_News














