Huione Docs
White Paper
Developers
Developers
  • Learn
    • Introduction to Huione Chain
    • Getting started with Huione Chain
  • Architecture
    • What is a Huione Chain Cluster?
    • Clusters
      • Huione Chain Clusters
      • RPC Endpoints
      • Benchmark a Cluster
      • Performance Metrics
    • Consensus
      • Synchronization
      • Leader Rotation
      • Fork Generation
      • Managing Forks
      • Turbine Block Propagation
      • Commitment Status
      • Secure Vote Signing
      • Stake Delegation and Rewards
    • Validators
      • Overview
      • TPU
      • TVU
      • Blockstore
      • Gossip Service
      • The Runtime
    • Dex & Swap
      • Trade on dex
      • Trade on swap
  • CLI
    • Command-line Guide
    • Install the Huione Tool Suite
    • Command-line Wallets
      • Command Line Wallets
      • Paper Wallet
      • File System Wallet
      • Support / Troubleshooting
    • Using Huione Chain CLI
    • Connecting to a Cluster
    • Send and Receive Tokens
    • Staking
    • Deploy a Program
    • Offline Transaction Signing
    • Durable Transaction Nonces
    • CLI Usage Reference
  • Developers
    • Get Started
      • Hello World
      • Local development
      • Rust program
    • Core Concepts
      • Accounts
      • Transactions
        • Overview
        • Versioned Transactions
        • Address Lookup Tables
      • Programs
      • Rent
      • Calling between programs
      • Runtime
    • Clients
      • JSON RPC API -1
      • JSON RPC API -2
      • JSON RPC API -3
      • Web3 JavaScript API
      • Web3 API Reference
      • Rust API
    • Writing Programs
      • Overview
      • Developing with Rust
      • Deploying
      • Debugging
      • Program Examples
      • FAQ
    • Native Programs
      • Overview
      • Sysvar Cluster Data
    • Local Development
      • Huione Test Validator
    • Backward Compatibility Policy
    • Anchor Book
      • Introduction
        • What is Anchor
        • Anchor Documentation
        • Prerequisites
      • Getting Started
        • Installation
        • Hello, Anchor!
      • Anchor Programs In-Depth
        • Essentials
          • High-level Overview
          • The Accounts Struct
          • The Program Module
          • Errors
          • Milestone Project - Tic-Tac-Toe
        • Intermediate
          • Cross-Program Invocations
          • PDAs
          • Events
      • Anchor BTS
        • The Discriminator
      • Anchor References
        • Space Reference
        • Javascript Anchor Types Reference
        • CLI Reference
        • Code References
  • Validators
    • Running a Validator
    • Getting Started
      • Validator Requirements
    • Voting Setup
      • Starting a Validator
      • Vote Account Management
      • Staking
      • Monitoring a Validator
      • Publishing Validator Info
      • Failover Setup
      • Troubleshooting
    • Geyser
      • Geyser Plugins
  • Staking
    • Staking on Huione
    • Stake Account Structure
  • Integrations
    • Add Huione to Your Exchange
    • Retrying Transactions
  • Library
    • Introduction
    • Token Program
    • Associated Token Account Program
    • Memo Program
    • Name Service
    • Feature Proposal Program
    • NFT Program
      • Overview
      • Interface
      • Usage Guidelines
        • Create a new NFT-Mint
        • Cast NFT
        • Transfer an NFT
        • Change account status
        • Permission settings
        • Query Interface
        • Continuous casting
        • Change the Mint attribute
      • Operation Overview
        • Create a new NFT-Mint
        • Transfer NFT
        • Destroy
        • Freeze NFT accounts
        • Update
    • Huione multi-sign program
      • Overview
      • Interface
      • Usage Guidelines
        • Create a multi-signature account
        • Create a proposal account
        • Vote proposal
        • Verify Proposal
        • Add-singer
        • Remove-signer
      • Operation Overview
        • Create a multi-signature account
        • Create a proposal account
        • Vote
        • Verify
        • Add-singer
        • Remove-signer
Powered by GitBook
On this page
  • The Accounts Struct
  • Types
  • Constraints
  • Safety checks

Was this helpful?

  1. Developers
  2. Anchor Book
  3. Anchor Programs In-Depth
  4. Essentials

The Accounts Struct

PreviousHigh-level OverviewNextThe Program Module

Last updated 6 months ago

Was this helpful?

The Accounts Struct

The Accounts struct is where you define which accounts your instruction expects and which constraints these accounts should adhere to. You do this via two constructs: Types and constraints.

Types

Each type has a specific use case in mind. Detailed explanations for the types can be found in the . We will briefly explain the most important type here, the Account type.

The Account Type

The Account type is used when an instruction is interested in the deserialized data of the account. Consider the following example where we set some data in an account:

use huione_anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
mod hello_anchor {
    use super::*;
    pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
        ctx.accounts.my_account.data = data;
        Ok(())
    }
}

#[account]
#[derive(Default)]
pub struct MyAccount {
    data: u64
}

#[derive(Accounts)]
pub struct SetData<'info> {
    #[account(mut)]
    pub my_account: Account<'info, MyAccount>
}

Account is generic over T. This T is a type you can create yourself to store data. In this example, we have created a struct MyAccount with a single data field to store a u64. Account requires T to implement certain functions (e.g. functions that (de)serialize T). Most of the time, you can use the #[account] attribute to add these functions to your data, as is done in the example.

Most importantly, the #[account] attribute sets the owner of that data to the ID (the one we created earlier with declareId) of the crate #[account] is used in. The Account type can then check for you that the AccountInfo passed into your instruction has its owner field set to the correct program. In this example, MyAccount is declared in our own crate so Account will verify that the owner of my_account equals the address we declared with declareId.

Using Account<'a, T> with non-huione-anchor program accounts

There may be cases where you want your program to interact with a non-Anchor program. You can still get all the benefits of Account but you have to write a custom wrapper type instead of using #[account]. For instance, Anchor provides wrapper types for the token program accounts so they can be used with Account.

use huione_anchor_lang::prelude::*;
use huione_anchor_spl::token::TokenAccount;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
mod hello_anchor {
    use super::*;
    pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
        if ctx.accounts.token_account.amount > 0 {
            ctx.accounts.my_account.data = data;
        }
        Ok(())
    }
}

#[account]
#[derive(Default)]
pub struct MyAccount {
    data: u64,
    mint: Pubkey
}

#[derive(Accounts)]
pub struct SetData<'info> {
    #[account(mut)]
    pub my_account: Account<'info, MyAccount>,
    #[account(
        constraint = my_account.mint == token_account.mint,
        has_one = owner
    )]
    pub token_account: Account<'info, TokenAccount>,
    pub owner: Signer<'info>
}

To run this example, add huione-anchor-spl = "<version>" to the dependencies section in your Cargo.toml, located in the programs/<your-project-name>/ directory. <version> should be equal to the huione-anchor-lang version you're using.

In this example, we set the data field of an account if the caller has admin rights. We decide whether the caller is an admin by checking whether they own admin tokens for the account they want to change. We do most of this via constraints which we will look at in the next section. The important thing to take away is that we use the TokenAccount type (that wraps around the token program's Account struct and adds the required functions) to make huione-anchor ensure that the incoming account is owned by the token program and to make huione-anchor deserialize it. This means we can use the TokenAccount properties inside our constraints (e.g. token_account.mint) as well as in the instruction function.

Constraints

Account types can do a lot of work for you but they're not dynamic enough to handle all the security checks a secure program requires.

Add constraints to an account with the following format:

#[account(<constraints>)]
pub account: AccountType

Some constraints support custom Errors (we will explore errors later):

#[account(...,<constraint> @ MyError::MyErrorVariant, ...)]
pub account: AccountType

For example, in the examples above, we used the mut constraint to indicate that my_account should be mutable. We used has_one to check that token_account.owner == owner.key(). And finally we used constraint to check an arbitrary expression; in this case, whether the incoming TokenAccount belongs to the admin mint.

#[derive(Accounts)]
pub struct SetData<'info> {
    #[account(mut)]
    pub my_account: Account<'info, MyAccount>,
    #[account(
        constraint = my_account.mint == token_account.mint,
        has_one = owner
    )]
    pub token_account: Account<'info, TokenAccount>,
    pub owner: Signer<'info>
}

You can find information about all constraints in the reference. We will cover some of the most important ones in the milestone project at the end of the Essentials section.

Safety checks

Attempting to build a program containing the following excerpt with huione-anchor build:

#[derive(Accounts)]
pub struct Initialize<'info> {
    pub potentially_dangerous: UncheckedAccount<'info>
}

will result in an error similar to the following:

Error:
        /huione-anchor/tests/unchecked/programs/unchecked/src/lib.rs:15:8
        Struct field "potentially_dangerous" is unsafe, but is not documented.
        Please add a `/// CHECK:` doc comment explaining why no checks through types are necessary.
        See https://book.huione-anchor-lang.com/chapter_3/the_accounts_struct.html#safety-checks for more information.

To fix this, write a doc comment describing the potential security implications, e.g.:

#[derive(Accounts)]
pub struct Initialize<'info> {
    /// CHECK: This is not dangerous because we don't read or write from this account
    pub potentially_dangerous: UncheckedAccount<'info>
}

Check out the to learn how to implement your own wrapper types for non-huione-anchor programs.

Two of the Anchor account types, and do not implement any checks on the account being passed. Anchor implements safety checks that encourage additional documentation describing why additional checks are not necesssary.

Note the doc comment needs to be a (/// or /**) to be interepreted as doc attribute by Rust. Double slash comments (//) are not interpreted as such.

Account Types Reference
reference
Account Reference
reference for the Account type
Constraints reference
AccountInfo
UncheckedAccount
line or block doc comment