데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      OpenLab 2기 - 누구나 하는 Smart Contract 개발 4회차 모임

      zzze37 24.10.27
      133 2 0
      DEVOTEE 요약
      이번 Smart Contract 스터디에서는 주로 Solana에서의 스마트 컨트랙트 개발에 대한 다양한 주제를 다룬다는 내용을 담고 있습니다. 특히, Solana에서 Program Derived Address(PDA)를 사용하여 계정에 서명하고, SOL을 전송하며, 계정 크기를 조정하는 방법을 코드 예시와 함께 설명하고 있습니다. 또한, 스마트 컨트랙트 개발이 처음에는 어렵지만, 이번 스터디를 통해 점점 이해도가 높아지고 있으며, 앞으로 남은 모임에서도 더욱 실력을 쌓고자 하는 의지를 다짐하고 있습니다.
      DEVOTEE 추천 블로그

      안녕하세요. “누구나 하는 Smart Contract” OpenLab 스터디 2기 스터디원 구정태입니다.

      벌써 4회차 모임에 스터디가 2번 밖에 안남았다니 벌써부터 아쉬움이 다가오는 것 같습니다.


      이번 스터디가 시작될 때는 ‘과연 스마트 컨트랙트를 내가 이해할 수 있을까?’ 하고 살짝 걱정도 됐었는데, 이렇게 하나씩 배워가면서 실력이 점점 쌓이는 걸 느끼고 있습니다.

      매번 다양한 주제로 진행되는 발표와 스터디원들의 열정적인 토론 덕분에 모임마다 배움이 깊어지고 있어요.

      특히 어려운 주제도 서로 나누고, 궁금한 부분은 편하게 질문하면서 배우니 부담감도 덜하고 재미있게 배우고 있습니다.


      이번 시간에는 How to Sign with a PDA’s Account부터 10개의 세션을 스터디하고 서로 발표 내용을 공유했었는데요.

      먼저 상현님께서 설명해주신 PDA Account부터 살펴보겠습니다.



      How to Sign with a PDA's Account

      Solana에서 Program Derived Address(PDA)는 프로그램이 소유한 계정이 트랜잭션에 서명할 수 있도록 해줍니다.

      이는 프로그램이 특정 토큰 계정을 소유하고, 그 계정에서 다른 계정으로 토큰을 전송해야 할 때 유용합니다.


      아래 코드 예시는 PDA 계정을 사용해 트랜잭션에 서명하는 방법을 보여줍니다. 이 예시에서는 프로그램이 PDA 계정으로부터 0.1 SOL을 다른 계정으로 전송합니다.

      코드 설명: sign-with-pda.rs

      use solana_program::{
          account_info::next_account_info, account_info::AccountInfo, entrypoint,
          entrypoint::ProgramResult, program::invoke_signed, pubkey::Pubkey, system_instruction,
      };

      필요한 라이브러리 불러오기:

      • solana_program에서 PDA 트랜잭션에 필요한 여러 모듈을 가져옵니다.

      • account_info: 계정 정보를 처리하기 위한 모듈.

      • entrypoint: Solana 프로그램의 진입점을 정의하는 모듈.

      • invoke_signed: PDA로 서명된 트랜잭션을 실행하는 함수.

      • Pubkey: Solana의 공개키 구조체.

      • system_instruction: SOL 전송과 같은 시스템 명령을 포함한 모듈.

      entrypoint!(process_instruction);

      프로그램의 진입점 정의:

      • Solana 프로그램은 process_instruction이라는 진입점 함수로 시작합니다. 이 함수가 호출될 때마다 프로그램이 수행할 동작이 여기에 정의됩니다.

      fn process_instruction(
          _program_id: &Pubkey,
          accounts: &[AccountInfo],
          instruction_data: &[u8],
      ) -> ProgramResult {

      프로세스 실행 함수 정의:

      • _program_id: 프로그램 자체의 공개키를 의미합니다.

      • accounts: 트랜잭션에 포함된 계정들의 정보입니다.

      • instruction_data: 추가로 필요한 명령 데이터를 담고 있습니다.

          let account_info_iter = &mut accounts.iter();

      계정 정보를 반복 처리하기 위한 iterator 생성:

      • account_info_iter는 accounts 리스트를 반복 처리할 수 있도록 만들어줍니다.

          let pda_account_info = next_account_info(account_info_iter)?;
          let to_account_info = next_account_info(account_info_iter)?;
          let system_program_account_info = next_account_info(account_info_iter)?;

      계정 정보 가져오기:

      • pda_account_info: PDA 계정 정보입니다. 여기서 SOL을 보낼 계정입니다.

      • to_account_info: SOL을 받을 계정 정보입니다.

      • system_program_account_info: Solana 시스템 프로그램 계정 정보입니다. 이는 transfer 명령을 수행하기 위해 필요합니다.

          let bump_seed = instruction_data[0];

      bump seed 추출:

      • bump_seed는 PDA를 생성할 때 사용된 **시드(seed)**의 일부로, 프로그램이 이 정보를 이용해 PDA를 서명에 사용할 수 있게 합니다. 여기서는 명령 데이터의 첫 번째 바이트로부터 가져옵니다.

          invoke_signed(
              &system_instruction::transfer(
                  &pda_account_info.key,
                  &to_account_info.key,
                  100_000_000, // 0.1 SOL
              ),

      invoke_signed로 서명된 전송 명령 호출:

      • system_instruction::transfer: Solana의 기본 시스템 명령으로, 한 계정에서 다른 계정으로 SOL을 전송합니다.

      • pda_account_info.key: 전송을 시작하는 계정의 공개키(PDA).

      • to_account_info.key: SOL을 받을 계정의 공개키.

      • 100_000_000: 전송할 금액(단위는 lamports, 0.1 SOL = 100,000,000 lamports).

              &[
                  pda_account_info.clone(),
                  to_account_info.clone(),
                  system_program_account_info.clone(),
              ],
              &[&[b"escrow", &[bump_seed]]],
          )?;

      계정 및 서명 정보 전달:

      • PDA 서명에 필요한 정보들을 전달합니다.

      • [b"escrow", &[bump_seed]]: PDA가 유도된 시드 값과 bump_seed를 이용해 서명합니다.

          Ok(())
      }

      프로그램 종료:

      • 모든 작업이 성공적으로 완료되면 Ok(())를 반환하며 프로그램이 종료됩니다.



      이번 코드에서는 Solana 프로그램이 PDA를 통해 서명하여 0.1 SOL을 다른 계정으로 전송하는 과정을 보여줍니다.

      invoke_signed 함수를 사용해, 프로그램이 PDA 소유 계정을 대신하여 트랜잭션에 서명하고, SOL을 전송할 수 있게 됩니다.

      PDA는 비밀키 없이도 프로그램이 계정을 제어할 수 있게 해주는 강력한 기능입니다.


      이 코드의 주요 개념은 다음과 같습니다:

      • PDA 서명: PDA는 비밀키가 없지만, 프로그램이 적절한 시드(seed)와 bump seed를 제공하면 트랜잭션에 서명할 수 있습니다.

      • invoke_signed: Solana에서 프로그램이 PDA로 서명된 트랜잭션을 실행할 때 사용하는 함수입니다.

      • bump seed 최적화: bump seed를 직접 명령 데이터로 전달함으로써 계산에 필요한 리소스를 절약할 수 있습니다.


      How to Close an Account

      블록체인에서는 계정을 제거하는 것이 단순히 삭제가 아니라, 그 계정의 자금을 복구하고 트랜잭션의 불변성을 유지하는 중요한 과정입니다.

      Rust의 checked_add 같은 함수는 오버플로우를 방지해 안전하게 연산을 수행하는 데 큰 도움이 됩니다.

      이 예시는 Rust의 철저한 타입 및 안전성 체크가 블록체인 보안에 어떻게 기여할 수 있는지를 잘 보여줍니다.


      Solana에서 계정을 닫으면 계정을 열 때 사용한 SOL을 다시 회수할 수 있습니다. 이때 중요한 점은 계정 안의 모든 정보를 삭제해야 한다는 것입니다.

      동일한 트랜잭션에서 데이터를 0으로 설정하지 않으면, 누군가 같은 트랜잭션에서 계정을 재사용하여 기존 데이터를 접근할 수 있는 위험이 있기 때문입니다.

      트랜잭션이 완료되기 전까지는 계정이 완전히 닫히지 않으므로 주의가 필요합니다.

      close-account.rs 코드 설명

      이 Rust 코드는 Solana 프로그램의 진입점을 정의하며, 계정을 닫고 잔액을 다른 계정으로 전송하는 기능을 제공합니다.

      use solana_program::{
          account_info::next_account_info, account_info::AccountInfo, entrypoint,
          entrypoint::ProgramResult, pubkey::Pubkey,
      };
      • solana_program::account_info::next_account_info: 계정 정보를 가져오는 데 사용됩니다.

      • AccountInfo: Solana에서 계정 데이터를 다루기 위한 구조체입니다.

      • entrypoint 및 ProgramResult: Solana 프로그램의 진입점과 결과를 정의합니다.

      • Pubkey: Solana에서 사용되는 공개 키를 나타냅니다.

      entrypoint!(process_instruction);
      • entrypoint!(process_instruction): 이 매크로는 process_instruction을 프로그램의 주요 진입점으로 설정합니다.

      fn process_instruction(
          _program_id: &Pubkey,
          accounts: &[AccountInfo],
          _instruction_data: &[u8],
      ) -> ProgramResult {
      • process_instruction: 계정을 닫는 작업을 처리하는 주요 함수입니다.

      • _program_id: 프로그램의 공개 키입니다.

      • accounts: 트랜잭션에 포함된 계정 배열입니다.

      • _instruction_data: 추가 데이터를 저장하지만, 여기서는 사용되지 않습니다.

      let account_info_iter = &mut accounts.iter();
      
      let source_account_info = next_account_info(account_info_iter)?;
      let dest_account_info = next_account_info(account_info_iter)?;
      • account_info_iter: 계정 배열을 위한 반복자를 생성합니다.

      • source_account_info: 닫으려는 계정입니다.

      • dest_account_info: 남은 잔액을 받는 계정입니다.

      let dest_starting_lamports = dest_account_info.lamports();
      **dest_account_info.lamports.borrow_mut() = dest_starting_lamports
          .checked_add(source_account_info.lamports())
          .unwrap();
      **source_account_info.lamports.borrow_mut() = 0;
      • dest_starting_lamports: 대상 계정의 초기 잔액을 저장합니다.

      • source_account_info의 모든 SOL을 dest_account_info로 전송합니다.

      • source_account_info의 잔액을 0으로 설정합니다.

      source_account_info.assign(&system_program::ID);
      source_account_info.realloc(0, false).map_err(Into::into)
      
      Ok(())
      • source_account_info.assign(&system_program::ID): 계정 소유권을 Solana 시스템 프로그램으로 변경하여 계정을 실질적으로 닫습니다.

      • source_account_info.realloc(0, false): 계정의 공간을 0으로 재할당하여 데이터를 완전히 지웁니다.


      How to Get Account Balance

      블록체인 상의 잔액 확인은 기본 중의 기본 작업입니다.

      LAMPORTS_PER_SOL을 사용해 기본 단위인 lamports를 SOL로 변환할 수 있는데, 이는 블록체인의 정밀한 계산 방식을 이해하는 데 필수적입니다.

      또한, RPC를 통한 연결은 블록체인 노드와 통신할 때 기본이 되므로, 이 코드로 블록체인과의 첫 인터랙션을 경험할 수 있습니다.


      특정 계정의 잔액을 확인하려면 이 JavaScript 코드를 사용하여 Solana devnet에 연결하고 SOL 단위로 잔액을 가져올 수 있습니다.

      get-account-balance.ts 코드 설명

      이 코드는 주어진 지갑의 잔액을 SOL 단위로 조회하는 코드입니다.

      import {
        clusterApiUrl,
        Connection,
        PublicKey,
        LAMPORTS_PER_SOL,
      } from "@solana/web3.js";
      • clusterApiUrl: 특정 Solana 클러스터에 연결하기 위해 사용됩니다(여기서는 devnet).

      • Connection: Solana 클러스터와의 연결을 관리합니다.

      • PublicKey: 지갑의 공개 키를 나타냅니다.

      • LAMPORTS_PER_SOL: 1 SOL에 해당하는 lamports 수를 나타내는 상수입니다.

      (async () => {
        const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
      • connection: Solana devnet에 대한 연결을 설정합니다.

      • confirmed: 연결의 커밋 수준을 설정합니다.

      let wallet = new PublicKey("G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY");
      console.log(
        `${(await connection.getBalance(wallet)) / LAMPORTS_PER_SOL} SOL`,
      );
      })();
      • wallet: 조회할 대상 지갑의 공개 키입니다.

      • connection.getBalance(wallet): 지갑의 잔액을 lamports 단위로 가져옵니다.

      • LAMPORTS_PER_SOL: 잔액을 lamports에서 SOL로 변환하여 가독성을 높입니다.


      How to Transfer SOL in a Solana Program

      일반적인 트랜잭션과는 달리, 프로그램 소유 계정에서 SOL을 전송하려면 보안에 더욱 신경을 써야 합니다.

      Rust에서는 borrow_mut와 같은 메서드로 메모리 접근을 제어하는데, 이는 트랜잭션 중에도 데이터의 일관성을 유지하는 데 매우 유용합니다.

      블록체인에서는 실수로 잘못된 수량을 전송하면 되돌릴 수 없으므로, 자바스크립트와 같은 언어에서 보다 조금 더 깐깐한 Rust의 특징을 체감할 수 있습니다.

      /// Transfers lamports from one account (must be program owned)
      /// to another account. The recipient can by any account
      fn transfer_service_fee_lamports(
          from_account: &AccountInfo,
          to_account: &AccountInfo,
          amount_of_lamports: u64,
      ) -> ProgramResult {
          if **from_account.try_borrow_lamports()? < amount_of_lamports {
              return Err(CustomError::InsufficientFundsForTransaction.into());
          }
          **from_account.try_borrow_mut_lamports()? -= amount_of_lamports;
          **to_account.try_borrow_mut_lamports()? += amount_of_lamports;
          Ok(())
      }
       
      fn instruction_handler(accounts: &[AccountInfo]) -> ProgramResult {
          let account_info_iter = &mut accounts.iter();
          let from_account = next_account_info(account_info_iter)?;
          let to_service_account = next_account_info(account_info_iter)?;
       
          transfer_service_fee_lamports(from_account, to_service_account, 5u64)?;
          Ok(())
      }

      How to get clock in a program


      블록체인에서는 시간 개념이 중요합니다. 이 예제에서는 Clock 객체를 사용해 트랜잭션 시간에 접근하는 방법을 보여주는데, 이는 스마트 계약이 시간에 따라 다른 동작을 하도록 설정할 때 유용합니다. Rust에서는 Sysvar 같은 모듈을 사용해 시스템 변수를 쉽게 다룰 수 있으며, 이는 블록체인의 특성상 일정한 시간에 민감한 작업을 처리할 때 특히 중요합니다.

      use borsh::{BorshDeserialize, BorshSerialize};
      use solana_program::{
          account_info::{next_account_info, AccountInfo},
          clock::Clock,
          entrypoint,
          entrypoint::ProgramResult,
          msg,
          pubkey::Pubkey,
          sysvar::Sysvar,
      };
       
      entrypoint!(process_instruction);
       
      #[derive(BorshSerialize, BorshDeserialize, Debug)]
      pub struct HelloState {
          is_initialized: bool,
      }
      
      pub fn process_instruction(
          _program_id: &Pubkey,
          accounts: &[AccountInfo],
          _instruction_data: &[u8],
      ) -> ProgramResult {
          let accounts_iter = &mut accounts.iter();
          let _payer_account = next_account_info(accounts_iter)?;
          let hello_state_account = next_account_info(accounts_iter)?;
          let sysvar_clock_pubkey = next_account_info(accounts_iter)?;
       
          let mut hello_state = HelloState::try_from_slice(&hello_state_account.data.borrow())?;
          hello_state.is_initialized = true;
          hello_state.serialize(&mut &mut hello_state_account.data.borrow_mut()[..])?;
          msg!("Account initialized :)");
      
          let clock = Clock::from_account_info(&sysvar_clock_pubkey)?;
          let current_timestamp = clock.unix_timestamp;
          msg!("Current Timestamp: {}", current_timestamp);
      
          Ok(())
      }

      방법2: 직접 Clock 호출하기

      use borsh::{BorshDeserialize, BorshSerialize};
      use solana_program::{
          account_info::{next_account_info, AccountInfo},
          clock::Clock,
          entrypoint,
          entrypoint::ProgramResult,
          msg,
          pubkey::Pubkey,
          sysvar::Sysvar,
      };
       
      entrypoint!(process_instruction);
       
      #[derive(BorshSerialize, BorshDeserialize, Debug)]
      pub struct HelloState {
          is_initialized: bool,
      }
      
      pub fn process_instruction(
          _program_id: &Pubkey,
          accounts: &[AccountInfo],
          _instruction_data: &[u8],
      ) -> ProgramResult {
          let accounts_iter = &mut accounts.iter();
          let _payer_account = next_account_info(accounts_iter)?;
          let hello_state_account = next_account_info(accounts_iter)?;
      
          let clock = Clock::get()?;
      
          let mut hello_state = HelloState::try_from_slice(&hello_state_account.data.borrow())?;
          hello_state.is_initialized = true;
          hello_state.serialize(&mut &mut hello_state_account.data.borrow_mut()[..])?;
          msg!("Account initialized :)");
      
          let current_timestamp = clock.unix_timestamp;
          msg!("Current Timestamp: {}", current_timestamp);
      
          Ok(())
      }

      How to change account size

      블록체인에서는 데이터를 효율적으로 저장하고 비용을 최소화하는 것이 중요합니다.

      realloc을 통해 계정의 크기를 조정하면서 저장 공간을 절약할 수 있습니다.

      Rust는 메모리 관리와 관련된 기능이 뛰어나며, 이 예제를 통해 Rust에서 메모리를 동적으로 관리하는 방법을 경험해볼 수 있습니다.

      use {
        crate::{
            instruction::WhitelistInstruction,
            state::WhiteListData,
        },
        borsh::{BorshDeserialize, BorshSerialize},
        solana_program::{
            account_info::{next_account_info, AccountInfo},
            entrypoint::ProgramResult,
            msg,
            program::invoke_signed,
            program::invoke,
            program_error::ProgramError,
            pubkey::Pubkey,
            sysvar::Sysvar,
            sysvar::rent::Rent,
            system_instruction,
        },
        std::convert::TryInto,
      };
       
      pub fn process_instruction(
        _program_id: &Pubkey,
        accounts: &[AccountInfo],
        input: &[u8],
      ) -> ProgramResult {
        // Length = BOOL + VEC + Pubkey * n (n = number of keys)
        const INITIAL_ACCOUNT_LEN: usize = 1 + 4 + 0 ;
        msg!("input: {:?}", input);
       
        let instruction = WhitelistInstruction::try_from_slice(input)?;
       
        let accounts_iter = &mut accounts.iter();
       
        let funding_account = next_account_info(accounts_iter)?;
        let pda_account = next_account_info(accounts_iter)?;
        let system_program = next_account_info(accounts_iter)?;
       
        match instruction {
          WhitelistInstruction::Initialize => {
            msg!("Initialize");
       
            let (pda, pda_bump) = Pubkey::find_program_address(
                &[
                  b"customaddress",
                  &funding_account.key.to_bytes(),
                ],
                _program_id,
            );
       
            let signers_seeds: &[&[u8]; 3] = &[
                b"customaddress",
                &funding_account.key.to_bytes(),
                &[pda_bump],
            ];
       
            if pda.ne(&pda_account.key) {
                return Err(ProgramError::InvalidAccountData);
            }
       
            let lamports_required = Rent::get()?.minimum_balance(INITIAL_ACCOUNT_LEN);
            let create_pda_account_ix = system_instruction::create_account(
                &funding_account.key,
                &pda_account.key,
                lamports_required,
                INITIAL_ACCOUNT_LEN.try_into().unwrap(),
                &_program_id,
            );
       
            invoke_signed(
                &create_pda_account_ix,
                &[
                    funding_account.clone(),
                    pda_account.clone(),
                    system_program.clone(),
                ],
                &[signers_seeds],
            )?;
       
            let mut pda_account_state = WhiteListData::try_from_slice(&pda_account.data.borrow())?;
       
            pda_account_state.is_initialized = true;
            pda_account_state.white_list = Vec::new();
            pda_account_state.serialize(&mut &mut pda_account.data.borrow_mut()[..])?;
            Ok(())
          }
          WhitelistInstruction::AddKey { key } => {
            msg!("AddKey");
       
            let mut pda_account_state = WhiteListData::try_from_slice(&pda_account.data.borrow())?;
       
            if !pda_account_state.is_initialized {
                return Err(ProgramError::InvalidAccountData);
            }
       
            let new_size = pda_account.data.borrow().len() + 32;
       
            let rent = Rent::get()?;
            let new_minimum_balance = rent.minimum_balance(new_size);
       
            let lamports_diff = new_minimum_balance.saturating_sub(pda_account.lamports());
            invoke(
                &system_instruction::transfer(funding_account.key, pda_account.key, lamports_diff),
                &[
                    funding_account.clone(),
                    pda_account.clone(),
                    system_program.clone(),
                ],
            )?;
       
            pda_account.realloc(new_size, false)?;
       
            pda_account_state.white_list.push(key);
            pda_account_state.serialize(&mut &mut pda_account.data.borrow_mut()[..])?;
       
            Ok(())
          }
        }
      }

      How to do Cross Program Invocation

      CPI는 스마트 계약 내에서 외부 계약을 호출할 때 매우 유용합니다.

      자산을 이동하거나 외부 상태를 업데이트할 때 CPI를 활용하여 다른 프로그램의 권한을 빌려 사용자가 트랜잭션을 안전하게 수행할 수 있습니다.


      How to create a Program Derived Address

      PDA는 프로그램이 소유하는 계정이지만, 개인 키가 없어서 사용자 서명 없이도 프로그램 자체에서 관리할 수 있는 특별한 계정입니다.

      PDA의 주소는 Pubkey::find_program_address를 사용해 생성하며, "오프 커브(off-curve)" 방식으로 만들어져 일반적인 공개 키가 될 수 없게 됩니다.

      PDA는 특정 seed 값과 bump라는 파라미터로 유효한 고유 주소가 생성됩니다.

      PDA 계정은 프로그램에서 직접 초기화하여 상태 설정을 완료해야 하므로, invoke_signed 함수가 필요합니다.


      PDA는 자체 서명이 불가능해 invoke_signed를 통해 프로그램이 추가 서명을 대신해 주므로, 이를 통해 계정 생성을 수행합니다.


      How to read accounts in a program

      Solana에서는 instruction sysvar를 통해 현재 트랜잭션의 모든 instruction을 확인할 수 있습니다.

      이렇게 하면 여러 작업을 한 번에 모니터링할 수 있으며, 프로그램 ID를 검사하여 권한 없는 동작을 필터링할 수도 있습니다.

      예를 들어, 특정 프로그램 ID와 일치하는지 확인하여 잠재적인 의심스러운 트랜잭션을 감지할 수 있습니다.


      다중 instruction을 효율적으로 처리하면 트랜잭션 내 여러 프로그램 간의 상호작용을 검증하거나 동기화할 때 유용합니다.


      Reading Multiple Instructions

      Solana의 대부분의 instruction은 여러 계정을 요구하며, 특정 순서로 계정을 전달해야 합니다.

      Rust의 iterator 기능과 next_account_info 메서드를 사용하면 순서에 맞춰 계정들을 효율적으로 가져올 수 있어 코드가 더욱 가독성이 좋고 유지 관리가 용이합니다.


      next_account_info 함수와 iterator를 사용하여 필요한 계정을 간편하게 읽을 수 있어, 인덱스를 통한 접근 방식을 줄여 코드 오류를 줄이고 효율성을 높일 수 있습니다.




      이렇게 해서 이번 스터디에서 다룬 몇 가지 중요한 개념과 코드 예시들을 살펴보았습니다.

      처음에는 생소하고 어렵게 느껴졌던 스마트 컨트랙트 개발이지만,

      이번 스터디를 통해 점점 더 깊이 이해하게 되어 뿌듯합니다. 남은 두 번의 모임 동안에도 더 많은 것을 배우고, 실력을 쌓을 수 있도록 최선을 다해보겠습니다.

      이 글이 스마트 컨트랙트에 관심 있는 분들께 작은 도움이 되길 바랍니다. 감사합니다!

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      zzze37 님의 최신 블로그

      더보기

      DEVOTEE 추천 블로그

      동영상 기고하기