프로그램
Solana에서 "스마트 컨트랙트"는 프로그램이라고 불립니다. 프로그램은 컴파일된 실행 가능한 바이너리가 포함된 계정에 온체인으로 배포됩니다. 사용자는 프로그램에게 무엇을 할지 알려주는 명령어가 포함된 트랜잭션을 보내 프로그램과 상호작용합니다.
주요 포인트
- 프로그램은 실행 가능한 코드를 포함하는 계정으로, 명령어라고 불리는 함수로 구성됩니다.
- 프로그램은 상태가 없지만, 데이터를 저장하기 위해 다른 계정을 생성하고 업데이트하는 명령어를 포함할 수 있습니다.
- 업그레이드 권한을 가진 계정이 프로그램을 업데이트할 수 있습니다. 이 권한이 제거되면 프로그램은 불변이 됩니다.
- 사용자는 검증 가능한 빌드를 통해 온체인 프로그램 계정의 데이터가 공개 소스 코드와 일치하는지 확인할 수 있습니다.
Solana 프로그램 작성하기
Solana 프로그램은 주로 Rust 프로그래밍 언어로 작성되며, 개발에는 두 가지 일반적인 접근 방식이 있습니다:
-
Anchor: Solana 프로그램 개발을 위해 설계된 프레임워크입니다. Rust 매크로를 사용하여 상용구 코드를 줄이고, 더 빠르고 간단한 방식으로 프로그램을 작성할 수 있습니다. 초보자의 경우 Anchor 프레임워크로 시작하는 것이 권장됩니다.
-
네이티브 Rust: 이 접근 방식은 프레임워크를 활용하지 않고 Rust로 Solana 프로그램을 작성하는 것입니다. 더 많은 유연성을 제공하지만 복잡성이 증가합니다.
Solana 프로그램 업데이트하기
프로그램 배포 및 업그레이드에 대해 자세히 알아보려면 프로그램 배포 페이지를 참조하세요.
프로그램은 "업그레이드 권한"으로 지정된 계정에 의해
직접 수정될
수 있으며, 이는 일반적으로 프로그램을 처음 배포한 계정입니다.
업그레이드 권한이
취소되고 None
으로 설정되면, 프로그램은 불변이 되어 더 이상 업데이트할 수 없게
됩니다.
검증 가능한 프로그램
검증 가능한 빌드를 통해 누구나 프로그램의 온체인 코드가 공개 소스 코드와 일치하는지 확인할 수 있어, 소스와 배포된 버전 간의 불일치를 감지할 수 있습니다.
Solana 개발자 커뮤니티는 검증 가능한 빌드를 지원하는 도구를 도입하여 개발자와 사용자 모두가 온체인 프로그램이 공개적으로 공유된 소스 코드를 정확하게 반영하는지 확인할 수 있게 했습니다.
-
검증된 프로그램 검색: 검증된 프로그램을 빠르게 확인하려면 사용자가 Solana Explorer에서 프로그램 주소를 검색할 수 있습니다. 검증된 프로그램의 예시는 여기에서 볼 수 있습니다.
-
검증 도구: Ellipsis Labs의 Solana Verifiable Build CLI를 통해 사용자는 온체인 프로그램을 공개된 소스 코드와 독립적으로 검증할 수 있습니다.
-
Anchor에서의 검증 가능한 빌드 지원: Anchor는 검증 가능한 빌드를 기본적으로 지원합니다. 자세한 내용은 Anchor 문서에서 확인할 수 있습니다.
Berkeley Packet Filter (BPF)
Solana는 LLVM(Low Level Virtual Machine)을 사용하여 프로그램을 ELF(Executable and Linkable Format) 파일로 컴파일합니다. 이 파일들은 "Solana Bytecode Format"(sBPF)이라 불리는 Solana의 커스텀 버전의 eBPF 바이트코드를 포함합니다. ELF 파일은 프로그램의 바이너리를 포함하며 프로그램이 배포될 때 실행 가능한 계정에 온체인으로 저장됩니다.
내장 프로그램
로더 프로그램
모든 프로그램은 그 자체가 다른 프로그램에 의해 소유되며, 이를 로더라고 합니다. 현재 다섯 가지 로더 프로그램이 존재합니다:
로더 | 프로그램 ID | 참고 | 명령어 링크 |
---|---|---|---|
native | NativeLoader1111111111111111111111111111111 | 다른 네 개의 로더를 소유함 | — |
v1 | BPFLoader1111111111111111111111111111111111 | 관리 명령어는 비활성화되었지만 프로그램은 여전히 실행됨 | — |
v2 | BPFLoader2111111111111111111111111111111111 | 관리 명령어는 비활성화되었지만 프로그램은 여전히 실행됨 | 명령어 |
v3 | BPFLoaderUpgradeab1e11111111111111111111111 | 단계적으로 폐지 중 | 명령어 |
v4 | LoaderV411111111111111111111111111111111111 | v4는 표준 로더가 될 것으로 예상됨 | 명령어 |
이러한 로더는 커스텀 프로그램을 생성하고 관리하는 데 필요합니다:
- 새 프로그램 또는 버퍼 배포
- 프로그램 또는 버퍼 닫기
- 기존 프로그램 재배포/업그레이드
- 프로그램에 대한 권한 이전
- 프로그램 완료
Loader-v3와 loader-v4는 초기 배포 이후 프로그램 수정을 지원합니다. 각 프로그램의 계정 소유권이 로더에 있기 때문에 이러한 수정 권한은 프로그램의 권한에 의해 규제됩니다.
사전 컴파일된 프로그램
Ed25519 프로그램
프로그램 | 프로그램 ID | 설명 | 명령어 |
---|---|---|---|
Ed25519 프로그램 | Ed25519SigVerify111111111111111111111111111 | ed25519 서명을 검증합니다. 서명이 실패하면 오류가 반환됩니다. | 명령어 |
ed25519 프로그램은 명령어를 처리합니다. 첫 번째 u8은 확인할 서명 수를 나타내며, 그 뒤에 단일 바이트 패딩이 있습니다. 그 후, 확인할 각 서명에 대해 다음 구조체가 직렬화됩니다.
struct Ed25519SignatureOffsets {signature_offset: u16, // 명령어 데이터 내 서명의 오프셋signature_instruction_index: u16, // 트랜잭션 내 명령어 인덱스public_key_offset: u16, // 명령어 데이터 내 공개 키의 오프셋public_key_instruction_index: u16, // 트랜잭션 내 명령어 인덱스message_offset: u16, // 명령어 데이터 내 메시지의 오프셋message_instruction_index: u16, // 트랜잭션 내 명령어 인덱스message_data_size: u16, // 메시지 데이터의 크기}
서명 검증의 의사 코드:
for i in 0..num_signatures {let offset = ed25519_signature_offsets[i];// 서명 가져오기let signature = get_signature_from(transaction,offset.signature_instruction_index,offset.signature_offset);// 공개 키 가져오기let public_key = get_public_key_from(transaction,offset.public_key_instruction_index,offset.public_key_offset);// 메시지 가져오기let message = get_message_from(transaction,offset.message_instruction_index,offset.message_offset,offset.message_data_size);// 서명 검증if !ed25519::verify(message, public_key, signature) {return Error;}}
Secp256k1 프로그램
프로그램 | 프로그램 ID | 설명 | 명령어 |
---|---|---|---|
Secp256k1 프로그램 | KeccakSecp256k11111111111111111111111111111 | secp256k1 공개 키 복구 작업(ecrecover)을 검증합니다. | 명령어 |
secp256k1 프로그램은 명령어를 처리하며, 첫 번째 바이트로 명령어 데이터에 직렬화된 다음 구조체의 수를 받습니다:
struct Secp256k1SignatureOffsets {signature_offset: u16, // 명령어 데이터 내 서명의 오프셋signature_instruction_index: u16, // 트랜잭션 내 명령어 인덱스eth_address_offset: u16, // 명령어 데이터 내 이더리움 주소의 오프셋eth_address_instruction_index: u16,// 트랜잭션 내 명령어 인덱스message_offset: u16, // 명령어 데이터 내 메시지의 오프셋message_instruction_index: u16, // 트랜잭션 내 명령어 인덱스message_data_size: u16, // 메시지 데이터의 크기}
복구 검증의 의사 코드:
for i in 0..num_signatures {let offset = secp256k1_signature_offsets[i];// 서명 가져오기let signature = get_signature_from(transaction,offset.signature_instruction_index,offset.signature_offset);// 이더리움 주소 가져오기let eth_address = get_eth_address_from(transaction,offset.eth_address_instruction_index,offset.eth_address_offset);// 메시지 가져오기let message = get_message_from(transaction,offset.message_instruction_index,offset.message_offset,offset.message_data_size);// 서명에서 공개 키 복구let recovered_key = secp256k1::recover(message, signature);// 복구된 키에서 이더리움 주소 계산let calculated_address = keccak256(recovered_key)[12..32];// 주소 검증if eth_address != calculated_address {return Error;}}
이를 통해 사용자는 서명 및 메시지 데이터에 대해 트랜잭션에서 원하는 명령어 데이터를 지정할 수 있습니다. 특별한 instructions sysvar를 지정하면 트랜잭션 자체에서 데이터를 받을 수도 있습니다.
트랜잭션 비용은 검증할 서명 수에 서명 검증 비용 승수를 곱한 값으로 계산됩니다.
Secp256r1 프로그램
프로그램 | 프로그램 ID | 설명 | 명령어 |
---|---|---|---|
Secp256r1 프로그램 | Secp256r1SigVerify1111111111111111111111111 | 최대 8개의 secp256r1 서명을 검증합니다. 서명, 공개 키, 메시지를 입력받고 실패 시 오류를 반환합니다. | Instructions |
secp256r1 프로그램은 명령어를 처리합니다. 첫 번째 u8
는 확인할 서명 수를
나타내며, 그 뒤에 단일 바이트 패딩이 있습니다. 그 후에는 다음 구조체가 각 확인할
서명마다 직렬화됩니다:
struct Secp256r1SignatureOffsets {signature_offset: u16, // offset to compact secp256r1 signature of 64 bytessignature_instruction_index: u16, // instruction index to find signaturepublic_key_offset: u16, // offset to compressed public key of 33 bytespublic_key_instruction_index: u16, // instruction index to find public keymessage_data_offset: u16, // offset to start of message datamessage_data_size: u16, // size of message datamessage_instruction_index: u16, // index of instruction data to get message data}
서명 검증의 의사 코드:
process_instruction() {if data.len() < SIGNATURE_OFFSETS_START {return Error}num_signatures = data[0] as usizeif num_signatures == 0 || num_signatures > 8 {return Error}expected_data_size = num_signatures * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_STARTif data.len() < expected_data_size {return Error}for i in 0..num_signatures {offsets = parse_signature_offsets(data, i)signature = get_data_slice(data, instruction_datas, offsets.signature_instruction_index, offsets.signature_offset, SIGNATURE_SERIALIZED_SIZE)if s > half_curve_order {return Error}pubkey = get_data_slice(data, instruction_datas, offsets.public_key_instruction_index, offsets.public_key_offset, COMPRESSED_PUBKEY_SERIALIZED_SIZE)message = get_data_slice(data, instruction_datas, offsets.message_instruction_index, offsets.message_data_offset, offsets.message_data_size)if !verify_signature(signature, pubkey, message) {return Error}}return Success}
참고: 모든 서명에 대해 낮은 S 값이 적용되어 우발적인 서명 가변성을 방지합니다.
코어 프로그램
Solana 클러스터 제네시스에는 네트워크의 핵심 기능을 제공하는 특별 프로그램 목록이 포함되어 있습니다. 역사적으로 이들은 "네이티브" 프로그램으로 불렸으며 validator 코드와 함께 배포되었습니다.
프로그램 | 프로그램 ID | 설명 | 명령어 |
---|---|---|---|
System Program | 11111111111111111111111111111111 | 새 계정 생성, 계정 데이터 할당, 계정을 소유 프로그램에 할당, System Program이 소유한 계정에서 lamport 전송, 트랜잭션 수수료 지불. | SystemInstruction |
Vote Program | Vote111111111111111111111111111111111111111 | validator 투표 상태와 보상을 추적하는 계정을 생성하고 관리합니다. | VoteInstruction |
Stake Program | Stake11111111111111111111111111111111111111 | validator에 위임된 스테이크와 보상을 나타내는 계정을 생성하고 관리합니다. | StakeInstruction |
Config Program | Config1111111111111111111111111111111111111 | 체인에 구성 데이터를 추가하고, 그 뒤에 수정할 수 있는 공개 키 목록을 추가합니다. 다른 프로그램과 달리 Config 프로그램은 개별 명령어를 정의하지 않습니다. 단 하나의 암시적 명령어 "store"만 있습니다. 명령어 데이터는 계정 접근을 제어하는 키 세트와 그 안에 저장할 데이터입니다. | ConfigInstruction |
Compute Budget Program | ComputeBudget111111111111111111111111111111 | 트랜잭션의 컴퓨팅 유닛 한도와 가격을 설정하여 사용자가 컴퓨팅 리소스와 우선순위 수수료를 제어할 수 있게 합니다. | ComputeBudgetInstruction |
Address Lookup Table Program | AddressLookupTab1e1111111111111111111111111 | 주소 조회 테이블을 관리하여 트랜잭션이 계정 목록에 맞는 것보다 더 많은 계정을 참조할 수 있게 합니다. | ProgramInstruction |
ZK ElGamal Proof Program | ZkE1Gama1Proof11111111111111111111111111111 | ElGamal 암호화 데이터에 대한 영지식 증명 검증을 제공합니다. | — |
Is this page helpful?