명령어

명령어는 솔라나 블록체인과 상호작용하기 위한 기본 구성 요소입니다. 명령어는 본질적으로 솔라나 네트워크를 사용하는 모든 사람이 호출할 수 있는 공개 함수입니다. 각 명령어는 특정 작업을 수행하는 데 사용됩니다. 명령어의 실행 로직은 프로그램에 저장되며, 각 프로그램은 자체적인 명령어 세트를 정의합니다. 솔라나 네트워크와 상호작용하려면 하나 이상의 명령어를 트랜잭션에 추가하여 처리를 위해 네트워크로 전송합니다.

SOL 전송 예제

아래 다이어그램은 트랜잭션과 명령어가 함께 작동하여 사용자가 네트워크와 상호작용할 수 있게 하는 방법을 보여줍니다. 이 예제에서는 SOL이 한 계정에서 다른 계정으로 전송됩니다.

송신자 계정의 메타데이터는 트랜잭션에 서명해야 함을 나타냅니다. (이를 통해 시스템 프로그램이 lamport를 차감할 수 있습니다.) 송신자와 수신자 계정 모두 lamport 잔액을 변경하기 위해 쓰기 가능해야 합니다. 이 명령어를 실행하기 위해 송신자의 지갑은 서명과 SOL 전송 명령어가 포함된 메시지가 담긴 트랜잭션을 전송합니다.

SOL 전송 다이어그램SOL 전송 다이어그램

트랜잭션이 전송된 후, 시스템 프로그램은 전송 명령어를 처리하고 두 계정의 lamport 잔액을 업데이트합니다.

SOL 전송 처리 다이어그램SOL 전송 처리 다이어그램

아래 예제는 위 다이어그램과 관련된 코드를 보여줍니다. (시스템 프로그램의 전송 명령어를 참조하세요.)

import {
airdropFactory,
appendTransactionMessageInstructions,
createSolanaRpc,
createSolanaRpcSubscriptions,
createTransactionMessage,
generateKeyPairSigner,
getSignatureFromTransaction,
lamports,
pipe,
sendAndConfirmTransactionFactory,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
signTransactionMessageWithSigners
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
// Create a connection to cluster
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate sender and recipient keypairs
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
const LAMPORTS_PER_SOL = 1_000_000_000n;
const transferAmount = lamports(LAMPORTS_PER_SOL / 100n); // 0.01 SOL
// Fund sender with airdrop
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: sender.address,
lamports: lamports(LAMPORTS_PER_SOL), // 1 SOL
commitment: "confirmed"
});
// Check balance before transfer
const { value: preBalance1 } = await rpc.getBalance(sender.address).send();
const { value: preBalance2 } = await rpc.getBalance(recipient.address).send();
// Create a transfer instruction for transferring SOL from sender to recipient
const transferInstruction = getTransferSolInstruction({
source: sender,
destination: recipient.address,
amount: transferAmount // 0.01 SOL in lamports
});
// Add the transfer instruction to a new transaction
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(sender, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstructions([transferInstruction], tx)
);
// Send the transaction to the network
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransaction,
{ commitment: "confirmed" }
);
const transactionSignature = getSignatureFromTransaction(signedTransaction);
// Check balance after transfer
const { value: postBalance1 } = await rpc.getBalance(sender.address).send();
const { value: postBalance2 } = await rpc.getBalance(recipient.address).send();
console.log(
"Sender prebalance:",
Number(preBalance1) / Number(LAMPORTS_PER_SOL)
);
console.log(
"Recipient prebalance:",
Number(preBalance2) / Number(LAMPORTS_PER_SOL)
);
console.log(
"Sender postbalance:",
Number(postBalance1) / Number(LAMPORTS_PER_SOL)
);
console.log(
"Recipient postbalance:",
Number(postBalance2) / Number(LAMPORTS_PER_SOL)
);
console.log("Transaction Signature:", transactionSignature);
Console
Click to execute the code.

명령어

3개 구성 요소로 나뉜 명령어가 포함된 트랜잭션을 보여주는 다이어그램3개 구성 요소로 나뉜 명령어가 포함된 트랜잭션을 보여주는 다이어그램

Instruction는 다음 정보로 구성됩니다:

  • program_id: 호출되는 프로그램의 ID입니다.
  • accounts: 계정 메타데이터의 배열입니다.
  • data: 명령어에서 사용할 추가 [데이터]가 포함된 바이트 배열입니다.
Instruction struct
pub struct Instruction {
/// Pubkey of the program that executes this instruction.
pub program_id: Pubkey,
/// Metadata describing accounts that should be passed to the program.
pub accounts: Vec<AccountMeta>,
/// Opaque data passed to the program for its own interpretation.
pub data: Vec<u8>,
}

프로그램 ID

명령어의 program_id는 명령어의 비즈니스 로직을 포함하는 프로그램의 공개 키 주소입니다.

계정 메타데이터

명령어의 accounts 배열은 AccountMeta 구조체의 배열입니다. 명령어가 상호작용하는 각 계정에 대한 메타데이터를 제공해야 합니다. (이를 통해 트랜잭션은 동일한 계정을 수정하지 않는 한 명령어를 병렬로 실행할 수 있습니다.)

아래 다이어그램은 단일 명령어를 포함하는 트랜잭션을 보여줍니다. 명령어의 accounts 배열에는 두 계정에 대한 메타데이터가 포함되어 있습니다.

하나의 명령어가 있는 트랜잭션. 명령어는 accounts 배열에 두 개의 AccountMeta 구조체를 포함합니다.하나의 명령어가 있는 트랜잭션. 명령어는 accounts 배열에 두 개의 AccountMeta 구조체를 포함합니다.

계정 메타데이터에는 다음 정보가 포함됩니다:

  • pubkey: 계정의 공개 키 주소
  • is_signer: 계정이 트랜잭션에 서명해야 하는 경우 true로 설정
  • is_writable: 명령어가 계정의 데이터를 수정하는 경우 true로 설정

명령어가 어떤 계정을 필요로 하는지, 그리고 어떤 계정이 쓰기 가능, 읽기 전용이어야 하는지, 또는 트랜잭션에 서명해야 하는지 알기 위해서는 프로그램에 정의된 명령어의 구현을 참조해야 합니다.

AccountMeta
pub struct AccountMeta {
/// An account's public key.
pub pubkey: Pubkey,
/// True if an `Instruction` requires a `Transaction` signature matching `pubkey`.
pub is_signer: bool,
/// True if the account data or metadata may be mutated during program execution.
pub is_writable: bool,
}

데이터

명령어의 data는 프로그램의 어떤 명령어를 호출할지 지정하는 바이트 배열입니다. 또한 명령어에 필요한 인수도 포함합니다.

명령어 생성 예제

아래 예제는 SOL 전송 명령어의 구조를 보여줍니다.

import { generateKeyPairSigner, lamports } from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
// Generate sender and recipient keypairs
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
// Define the amount to transfer
const LAMPORTS_PER_SOL = 1_000_000_000n;
const transferAmount = lamports(LAMPORTS_PER_SOL / 100n); // 0.01 SOL
// Create a transfer instruction for transferring SOL from sender to recipient
const transferInstruction = getTransferSolInstruction({
source: sender,
destination: recipient.address,
amount: transferAmount
});
console.log(JSON.stringify(transferInstruction, null, 2));
Console
Click to execute the code.

아래 코드는 이전 코드 스니펫의 출력을 보여줍니다. SDK에 따라 형식이 다를 수 있지만, 각 명령에는 동일한 세 가지 필수 정보가 포함되어 있습니다: program_id, accounts, data.

{
"accounts": [
{
"address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC",
"role": 3,
"signer": {
"address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC",
"keyPair": {
"privateKey": {},
"publicKey": {}
}
}
},
{
"address": "2mBY6CTgeyJNJDzo6d2Umipw2aGUquUA7hLdFttNEj7p",
"role": 1
}
],
"programAddress": "11111111111111111111111111111111",
"data": {
"0": 2,
"1": 0,
"2": 0,
"3": 0,
"4": 128,
"5": 150,
"6": 152,
"7": 0,
"8": 0,
"9": 0,
"10": 0,
"11": 0
}
}

아래 예제는 전송 명령을 수동으로 구축하는 방법을 보여줍니다. (Expanded Instruction 탭은 기능적으로 Instruction 탭과 동일합니다.)

실제로는 보통 Instruction를 수동으로 구성할 필요가 없습니다. 대부분의 프로그램은 명령을 생성하는 헬퍼 함수가 있는 클라이언트 라이브러리를 제공합니다. 라이브러리를 사용할 수 없는 경우 수동으로 명령을 구축할 수 있습니다.

const transferAmount = 0.01; // 0.01 SOL
const transferInstruction = getTransferSolInstruction({
source: sender,
destination: recipient.address,
amount: transferAmount * LAMPORTS_PER_SOL
});

Is this page helpful?

목차

페이지 편집

관리자

© 2025 솔라나 재단.
모든 권리 보유.