프로그램

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참고명령어 링크
nativeNativeLoader1111111111111111111111111111111다른 네 개의 로더를 소유함
v1BPFLoader1111111111111111111111111111111111관리 명령어는 비활성화되었지만 프로그램은 여전히 실행됨
v2BPFLoader2111111111111111111111111111111111관리 명령어는 비활성화되었지만 프로그램은 여전히 실행됨명령어
v3BPFLoaderUpgradeab1e11111111111111111111111단계적으로 폐지 중명령어
v4LoaderV411111111111111111111111111111111111v4는 표준 로더가 될 것으로 예상됨명령어

이러한 로더는 커스텀 프로그램을 생성하고 관리하는 데 필요합니다:

  • 새 프로그램 또는 버퍼 배포
  • 프로그램 또는 버퍼 닫기
  • 기존 프로그램 재배포/업그레이드
  • 프로그램에 대한 권한 이전
  • 프로그램 완료

Loader-v3와 loader-v4는 초기 배포 이후 프로그램 수정을 지원합니다. 각 프로그램의 계정 소유권이 로더에 있기 때문에 이러한 수정 권한은 프로그램의 권한에 의해 규제됩니다.

사전 컴파일된 프로그램

Ed25519 프로그램

프로그램프로그램 ID설명명령어
Ed25519 프로그램Ed25519SigVerify111111111111111111111111111ed25519 서명을 검증합니다. 서명이 실패하면 오류가 반환됩니다.명령어

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 프로그램KeccakSecp256k11111111111111111111111111111secp256k1 공개 키 복구 작업(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는 확인할 서명 수를 나타내며, 그 뒤에 단일 바이트 패딩이 있습니다. 그 후에는 다음 구조체가 각 확인할 서명마다 직렬화됩니다:

Secp256r1SignatureOffsets
struct Secp256r1SignatureOffsets {
signature_offset: u16, // offset to compact secp256r1 signature of 64 bytes
signature_instruction_index: u16, // instruction index to find signature
public_key_offset: u16, // offset to compressed public key of 33 bytes
public_key_instruction_index: u16, // instruction index to find public key
message_data_offset: u16, // offset to start of message data
message_data_size: u16, // size of message data
message_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 usize
if num_signatures == 0 || num_signatures > 8 {
return Error
}
expected_data_size = num_signatures * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_START
if 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 Program11111111111111111111111111111111새 계정 생성, 계정 데이터 할당, 계정을 소유 프로그램에 할당, System Program이 소유한 계정에서 lamport 전송, 트랜잭션 수수료 지불.SystemInstruction
Vote ProgramVote111111111111111111111111111111111111111validator 투표 상태와 보상을 추적하는 계정을 생성하고 관리합니다.VoteInstruction
Stake ProgramStake11111111111111111111111111111111111111validator에 위임된 스테이크와 보상을 나타내는 계정을 생성하고 관리합니다.StakeInstruction
Config ProgramConfig1111111111111111111111111111111111111체인에 구성 데이터를 추가하고, 그 뒤에 수정할 수 있는 공개 키 목록을 추가합니다. 다른 프로그램과 달리 Config 프로그램은 개별 명령어를 정의하지 않습니다. 단 하나의 암시적 명령어 "store"만 있습니다. 명령어 데이터는 계정 접근을 제어하는 키 세트와 그 안에 저장할 데이터입니다.ConfigInstruction
Compute Budget ProgramComputeBudget111111111111111111111111111111트랜잭션의 컴퓨팅 유닛 한도와 가격을 설정하여 사용자가 컴퓨팅 리소스와 우선순위 수수료를 제어할 수 있게 합니다.ComputeBudgetInstruction
Address Lookup Table ProgramAddressLookupTab1e1111111111111111111111111주소 조회 테이블을 관리하여 트랜잭션이 계정 목록에 맞는 것보다 더 많은 계정을 참조할 수 있게 합니다.ProgramInstruction
ZK ElGamal Proof ProgramZkE1Gama1Proof11111111111111111111111111111ElGamal 암호화 데이터에 대한 영지식 증명 검증을 제공합니다.

Is this page helpful?