소개
2024년, Solana는 극적으로 부상하며 연초 10억 달러였던 총 예치 자산(TVL)이 거의 50억 달러까지 치솟아 네 번째로 큰 퍼블릭 블록체인이 되었습니다.
이더리움과 비교했을 때, Solana는 더 빠른 속도와 낮은 비용으로 사용자에게 우수한 경험을 제공합니다. 역사 증명(Proof of History) 기반의 합의 메커니즘과 비동기 트랜잭션 처리 모델은 개발자에게 높은 트랜잭션 처리량과 낮은 지연 시간을 제공하여, 모든 종류의 탈중앙화 애플리케이션에 선호되는 플랫폼으로 자리잡게 했습니다.
BlockSec은 Solana의 기본 개념, Solana 트랜잭션 분석 실전 가이드, Solana 스마트 계약 작성 튜토리얼을 다루는 "Solana 간편 가이드" 시리즈를 특별히 기획했습니다.
이 시리즈의 첫 번째 글로서, 본문은 Solana 네트워크의 핵심 개념인 운영 메커니즘, 계정 모델, 트랜잭션을 깊이 있게 다루며, Solana에서 올바르고 효율적인 스마트 계약을 작성하기 위한 기반을 마련합니다.
eBPF: Solana 트랜잭션 실행의 핵심
스마트 계약을 작성하고 실행하기 위해, 블록체인은 일반적으로 프로그래밍 언어와 튜링 완전한 계산 환경을 필요로 합니다.
이더리움의 스마트 계약은 보통 Solidity라는 고급 언어로 작성됩니다. 컴파일러는 이를 바이트코드로 변환하고, 이 바이트코드는 이더리움 가상 머신(EVM)에서 실행됩니다. Solana는 완전히 새로운 가상 환경과 언어를 개발하는 대신, 기존의 고급 기술을 최대한 활용하는 방식을 선택했습니다. 원래 Linux 커널 기능 확장을 위해 설계된 eBPF(extended Berkeley Packet Filter) 가상 머신이 Solana의 기본 실행 환경으로 채택되었습니다.
그렇다면 eBPF는 EVM에 비해 어떤 장점을 제공할까요?
해석 실행에만 국한된 EVM과 달리, eBPF는 JIT(Just-In-Time) 컴파일을 지원하여 바이트코드를 프로세서가 직접 실행할 수 있는 기계어 명령어로 변환할 수 있습니다. 이러한 기능은 프로그램 효율성을 크게 향상시킵니다.
또한, eBPF는 효율적인 명령어 집합과 성숙한 인프라를 갖추고 있습니다. 개발자는 Rust 언어를 사용하여 스마트 계약을 작성할 수 있습니다. LLVM 컴파일러 프레임워크의 eBPF 백엔드를 활용하여 Rust 프로그램을 eBPF 바이트코드로 직접 컴파일할 수 있습니다.
Solana의 계정 모델
Solana 계정 구조
Solana에서 데이터는 계정 형태로 저장됩니다. 아래 그림에서 볼 수 있듯이, Solana 내의 모든 데이터는 거대한 키-값 데이터베이스로 개념화할 수 있습니다. 이 데이터베이스의 키는 계정 주소입니다. "지갑" 계정(즉, Solana 사용자가 공개-개인 키 쌍을 통해 직접 제어하는 계정)의 경우, 이 주소는 Ed25519 서명 시스템을 사용하여 생성된 공개 키입니다. 데이터베이스의 값은 잔액 및 기타 관련 정보를 포함한 각 계정의 구체적인 세부 정보로 구성됩니다.
Solana는 계정을 설명하기 위해 AccountInfo로 알려진 다음 구조를 사용합니다.
각 계정의 AccountInfo에는 네 가지 필드가 포함됩니다. 각 필드에 대한 설명은 다음과 같습니다:
-
Data필드: 이 필드는 계정과 관련된 데이터를 저장합니다. 계정이 프로그램(즉, 스마트 계약)인 경우 eBPF 바이트코드를 저장합니다. 그렇지 않은 경우, 데이터 형식은 일반적으로 계정 생성자에 의해 정의됩니다. -
Executable필드: 이 필드는 계정이 프로그램인지 여부를 나타내는 데 사용됩니다. 이더리움과 달리 Solana의 프로그램은 업데이트될 수 있다는 점을 주목해야 합니다. -
Lamports필드: 이 필드는 계정의 Solana 토큰 잔액을 기록합니다. Lamport는 실제로 SOL 토큰의 최소 단위입니다(1 SOL = 10억 Lamport). -
Owner필드: 이 필드는 계정의 소유자를 나타냅니다. Solana에서는 모든 계정에 "소유자"가 있습니다. 예를 들어, 모든 "지갑" 계정의 소유자는 System Program으로, 계정 생성 등의 기능을 담당하는 Solana 네트워크의 특수 계정입니다. 계정 소유자만이 계정 데이터를 수정하고 잔액에서 Lamport를 차감할 수 있습니다(단, 누구든지 계정에 자금을 전송하여 Lamport를 증가시킬 수 있습니다).
사전 정의된 Solana 계정
Solana에는 고정된 주소에 배포된 Native Programs라고 알려진 사전 정의된 실행 가능한 프로그램 집합이 있습니다. Solana 네트워크가 업그레이드됨에 따라 이러한 사전 정의된 프로그램도 업데이트될 수 있습니다. 이들은 API 및 라이브러리 함수로서, Solana 네트워크 내에서 특정 기능을 제공합니다.
Native Programs 중에서 개발자가 자주 상호작용하는 것은 System Program입니다. System Program은 개발자에게 각각 독립적인 작업을 수행하는 명령어 집합을 제공합니다. 예를 들어, 개발자는 CreateAccount 명령어를 사용하여 새 계정을 생성하거나, Transfer 명령어를 사용하여 다른 계정에 Lamport를 전송할 수 있습니다.
또 다른 일반적인 Native Programs는 BPF Loader 프로그램입니다. 이 프로그램은 다른 모든 프로그램 계정의 소유자이며, 커스텀 프로그램의 배포, 업데이트, 실행을 담당합니다. "지갑" 계정이 배포한 프로그램을 업데이트해야 할 때, 프로그램의 소유자만이 데이터를 직접 수정할 권한이 있으므로 실제로는 BPF Loader 프로그램에 위임하는 방식으로 이루어집니다.
Native Programs 외에도, Solana는 Sysvars라고 알려진 계정 집합을 제공합니다. 이 계정들은 Solana 네트워크의 프로그램에 현재 클록이나 가장 최근의 블록 해시와 같이 Solana 네트워크의 현재 상태와 관련된 정보 및 전역 변수를 제공합니다.
계정 렌트
Solana 블록체인에서 각 계정은 렌트로 알려진 최소 잔액으로 일정 수의 Lamport를 유지해야 합니다. 실제 생활의 임대료와 달리, Solana의 렌트는 회수 가능합니다. 계정의 데이터가 체인에서 사용 가능하도록 보장하려면, 계정은 적절한 양의 Lamport를 보유해야 합니다. 렌트의 양은 계정이 차지하는 데이터의 크기와 관련이 있습니다.
계정 잔액을 렌트 금액 미만으로 줄이려는 트랜잭션은 잔액을 정확히 0으로 줄이는 경우가 아니라면 실패합니다. 잔액을 0으로 낮추는 것은 계정의 렌트가 회수되었음을 나타내며, 트랜잭션이 끝날 때 Solana는 가비지 컬렉션 프로세스에서 해당 계정의 데이터를 지웁니다.
🧐 Solana Scans에서 Solana 계정 살펴보기
앞서 언급한 개념들을 더 잘 이해하기 위해, Solana의 "Hello World" 프로젝트를 사용하여 프로그램 계정을 배포했으며, Solana의 블록체인 탐색기인 Solscan을 사용하여 확인할 수 있습니다.

위 이미지에서 볼 수 있듯이, 먼저 계정이 "Program"으로 표시된 것을 확인할 수 있습니다. 이 계정의 렌트로 발신자의 잔액에서 일부 Lamport가 차감되었으므로, SOL Balance 필드가 비어 있지 않습니다. 또한, 생성한 계정이 프로그램이므로 Executable 필드가 Yes로 설정되어 있습니다.
Executable Data 필드에 eBPF 프로그램 대신 주소가 저장되어 있는 것이 혼란스러울 수 있습니다. 앞서 언급했듯이 Solana는 프로그램 업데이트를 허용하며, 이는 실제로 "프록시" 패턴을 통해 구현됩니다. 처음에는 프로그램 계정에 대한 직접 수정이 허용되지 않으므로, Solana는 eBPF 프로그램을 저장하기 위한 별도의 데이터 계정을 생성하고, 프로그램 계정의 Data 필드에는 이 데이터 계정의 주소만 저장합니다.
프로그램을 업데이트해야 할 때마다, 데이터 계정의 Data 필드만 수정하면 됩니다. Solscan을 사용하여 데이터 계정을 확인하면, "Program Executable Data Account"로 표시되어 있으며 해당 Data 필드에 실제 프로그램이 저장되어 있음을 알 수 있습니다.

"More Info" 섹션의 Owner 필드는 앞서 언급한 내용과 일치하는 BPF Loader입니다.
일부 독자들은 "Overview"의 마지막 필드인 Upgrade Authority가 AccountInfo에 없다는 것을 알아챌 수 있습니다. 이것은 무엇을 의미할까요?
앞서 언급했듯이, "지갑" 계정은 BPF Loader에 프로그램 업데이트를 위임합니다. 업데이트 전에 BPF Loader는 위임자가 원래 프로그램을 배포한 계정인지 확인합니다. 프로그램 계정의 Owner가 이미 BPF Loader로 설정되어 있으므로, 이 정보를 저장할 공간이 없습니다. 따라서 Solana는 이를 데이터 계정의 Data 필드에 저장합니다. 그렇기 때문에 "Overview"에 Upgrade Authority 필드가 있으며, 이것은 실제로 프로그램을 배포한 지갑 주소입니다.
아래 이미지는 프로그램 계정과 데이터 계정 간의 관계를 보여줍니다. 데이터 계정의 Data 필드에는 지갑 주소와 eBPF 코드가 모두 포함되어 있음에 유의하세요.

Solana의 트랜잭션과 명령어
Solana에서 사용자는 트랜잭션을 발행하여 프로그램을 실행합니다. Solana의 독특한 측면은 이러한 트랜잭션을 병렬로 실행할 수 있다는 것으로, 이것이 빠른 트랜잭션 속도의 핵심 이유입니다. 이제 Solana에서 트랜잭션이 어떻게 설계되었는지 자세히 살펴보겠습니다.
Solana 트랜잭션은 서명과 메시지로 구성됩니다. 트랜잭션에는 여러 서명이 포함될 수 있습니다. 트랜잭션의 메시지는 아래 그림에서 볼 수 있듯이 네 부분으로 구성됩니다.

Header와 Compact Array of Account Addresses는 트랜잭션에 관련된 모든 계정과 트랜잭션 중 해당 계정의 특성을 지정합니다. 여기에는 계정이 서명자인지, 실행 중에 쓰기 가능한지 여부가 포함됩니다. 이 정보를 통해 Solana는 서명자 계정이 제공한 서명을 검증하고, 동일한 상태에 쓰는 계정이 포함되지 않는 한 트랜잭션을 병렬로 처리할 수 있습니다.
Recent Blockhash는 트랜잭션의 타임스탬프 역할을 합니다. 트랜잭션의 블록해시가 최신 블록해시보다 150블록 이상 오래된 경우, 만료된 것으로 간주되어 실행되지 않습니다.
Compact Array of Instructions는 트랜잭션에서 가장 중요한 부분으로, 하나 이상의 명령어를 포함합니다. 명령어는 본질적으로 프로그램 계정이 제공하는 루틴의 실행을 트리거합니다. 각 명령어는 아래 그림에서 볼 수 있듯이 세 가지 필드로 구성됩니다.

첫 번째 필드인 Program ID Index는 명령어의 수신자, 즉 명령어를 처리해야 하는 온체인 프로그램을 지정합니다. 32바이트 주소를 직접 저장하는 대신, 이 주소는 트랜잭션 메시지의 Compact Array of Account Addresses에 배치되며, 해당 필드에는 배열 내 주소를 가리키는 u8 인덱스만 저장됩니다.
첫 번째 필드와 유사하게, 두 번째 필드는 Compact Array of Account Address Indexes로 알려진 계정 주소 인덱스를 저장합니다. 이 배열은 이 명령어에 관련된 모든 계정을 지정합니다.
마지막 필드는 함수 인수와 같이 프로그램이 명령어를 처리하는 데 필요한 추가 데이터를 포함하는 바이트 배열입니다.
중요한 점은 Solana가 트랜잭션 내의 모든 명령어를 순서대로 처리하고 트랜잭션의 원자적 실행을 보장한다는 것입니다. 이는 모든 명령어가 성공적으로 처리되어 완전히 완료되거나, 전체가 실패한다는 것을 의미합니다. 일부 명령어는 처리되고 나머지는 처리되지 않는 상황은 발생하지 않습니다.
🧐 Solana Scans에서 Solana 트랜잭션 살펴보기
다른 Solana 탐색기를 사용하여 앞서 프로그램 계정을 생성한 트랜잭션을 확인합니다. Overview 섹션에서 Solana 트랜잭션 서명, 최근 블록해시 및 기타 정보를 확인할 수 있습니다:

Account Input 섹션에는 현재 트랜잭션에 관련된 모든 계정과 트랜잭션에서의 특성이 나열됩니다. 발신자와 프로그램 계정 주소 외에도 두 개의 Native Programs와 Sysvar 계정이 포함되어 있음을 확인할 수 있습니다.

단순한 프로그램 생성 트랜잭션이므로 두 개의 명령어만 포함됩니다. 첫 번째 명령어의 수신자는 프로그램 계정 생성을 담당하는 System Program입니다. 두 번째 명령어의 수신자는 BPF Loader로, 배포된 eBPF 코드를 저장하기 위한 데이터 계정을 생성하고 해당 주소를 프로그램 계정의 Data 필드에 씁니다.

결론
Solana의 스마트 계약은 Rust로 개발되어 eBPF 가상 머신에서 실행됩니다. Solana는 계정 모델을 따르며, 온체인 계정은 데이터가 제거되지 않도록 충분한 렌트를 유지해야 합니다. 트랜잭션은 필요한 모든 계정을 정의하는 하나 이상의 명령어로 구성되어 병렬 처리를 가능하게 하고, 처리량을 향상시키면서 응답 지연 시간을 줄입니다. 이러한 특징들이 함께 Solana의 급속한 발전에 기여하여 선호되는 블록체인 중 하나로 만들었습니다.



