anchor-book/anchor_in_depth/the_accounts_struct.html

307 lines
23 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>The Accounts Struct - The Anchor Book v0.29.0</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded "><a href="../introduction/introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../introduction/what_is_anchor.html"><strong aria-hidden="true">1.1.</strong> What is Anchor</a></li><li class="chapter-item expanded "><a href="../introduction/anchor_documentation.html"><strong aria-hidden="true">1.2.</strong> Anchor Documentation</a></li></ol></li><li class="chapter-item expanded "><a href="../prerequisites/prerequisites.html"><strong aria-hidden="true">2.</strong> Prerequisites</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../prerequisites/useful_resources.html"><strong aria-hidden="true">2.1.</strong> Useful Resources</a></li><li class="chapter-item expanded "><a href="../prerequisites/intro_to_solana.html"><strong aria-hidden="true">2.2.</strong> Intro to Solana</a></li></ol></li><li class="chapter-item expanded "><a href="../getting_started/getting_started.html"><strong aria-hidden="true">3.</strong> Getting Started</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../getting_started/installation.html"><strong aria-hidden="true">3.1.</strong> Installation</a></li><li class="chapter-item expanded "><a href="../getting_started/hello_anchor.html"><strong aria-hidden="true">3.2.</strong> Hello, Anchor!</a></li></ol></li><li class="chapter-item expanded "><a href="../anchor_in_depth/anchor_programs_in-depth.html"><strong aria-hidden="true">4.</strong> Anchor Programs In-Depth</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../anchor_in_depth/essentials.html"><strong aria-hidden="true">4.1.</strong> Essentials</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../anchor_in_depth/high-level_overview.html"><strong aria-hidden="true">4.1.1.</strong> High-level Overview</a></li><li class="chapter-item expanded "><a href="../anchor_in_depth/the_accounts_struct.html" class="active"><strong aria-hidden="true">4.1.2.</strong> The Accounts Struct</a></li><li class="chapter-item expanded "><a href="../anchor_in_depth/the_program_module.html"><strong aria-hidden="true">4.1.3.</strong> The Program Module</a></li><li class="chapter-item expanded "><a href="../anchor_in_depth/errors.html"><strong aria-hidden="true">4.1.4.</strong> Errors</a></li><li class="chapter-item expanded "><a href="../anchor_in_depth/milestone_project_tic-tac-toe.html"><strong aria-hidden="true">4.1.5.</strong> Milestone Project - Tic-Tac-Toe</a></li></ol></li><li class="chapter-item expanded "><a href="../anchor_in_depth/intermediate.html"><strong aria-hidden="true">4.2.</strong> Intermediate</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../anchor_in_depth/CPIs.html"><strong aria-hidden="true">4.2.1.</strong> Cross-Program Invocations</a></li><li class="chapter-item expanded "><a href="../anchor_in_depth/PDAs.html"><strong aria-hidden="true">4.2.2.</strong> PDAs</a></li><li class="chapter-item expanded "><a href="../anchor_in_depth/events.html"><strong aria-hidden="true">4.2.3.</strong> Events</a></li><li class="chapter-item expanded "><div><strong aria-hidden="true">4.2.4.</strong> Constants</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">4.2.5.</strong> Zero-Copy</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">4.2.6.</strong> Access Control</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">4.2.7.</strong> Building &amp; Testing</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">4.2.8.</strong> Milestone Project - The Nightclub</div></li></ol></li></ol></li><li class="chapter-item expanded "><div><strong aria-hidden="true">5.</strong> Anchor BTS</div></li><li><ol class="section"><li class="chapter-item expanded "><a href="../anchor_bts/discriminator.html"><strong aria-hidden="true">5.1.</strong> The Discriminator</a></li><li class="chapter-item expanded "><div><strong aria-hidden="true">5.2.</strong> Dispatch</div></li><li class="spacer"></li></ol></li><li class="chapter-item expanded "><a href="../anchor_references/anchor_references.html"><strong aria-hidden="true">6.</strong> Anchor References</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../anchor_references/space.html"><strong aria-hidden="true">6.1.</strong> Space Reference</a></li><li class="chapter-item expanded "><a href="../anchor_references/javascript_anchor_types_reference.html"><strong aria-hidden="true">6.2.</strong> Javascript Anchor Types Reference</a></li><li class="chapter-item expanded "><a href="../anchor_references/cli.html"><strong aria-hidden="true">6.3.</strong> CLI Reference</a></li><li class="chapter-item expanded "><a href="../anchor_references/avm.html"><strong aria-hidden="true">6.4.</strong> AVM Reference</a></li><li class="chapter-item expanded "><a href="../anchor_references/anchor-toml_reference.html"><strong aria-hidden="true">6.5.</strong> Anchor.toml Reference</a></li><li class="chapter-item expanded "><a href="../anchor_references/reference_links.html"><strong aria-hidden="true">6.6.</strong> Code References</a></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">The Anchor Book v0.29.0</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="the-accounts-struct"><a class="header" href="#the-accounts-struct">The Accounts Struct</a></h1>
<p>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.</p>
<h2 id="types"><a class="header" href="#types">Types</a></h2>
<blockquote>
<p><a href="https://docs.rs/anchor-lang/0.29.0/anchor_lang/accounts/index.html">Account Types Reference</a></p>
</blockquote>
<p>Each type has a specific use case in mind. Detailed explanations for the types can be found in the <a href="https://docs.rs/anchor-lang/0.29.0/anchor_lang/accounts/index.html">reference</a>. We will briefly explain the most important type here, the <code>Account</code> type.</p>
<h3 id="the-account-type"><a class="header" href="#the-account-type">The Account Type</a></h3>
<blockquote>
<p><a href="https://docs.rs/anchor-lang/0.29.0/anchor_lang/accounts/account/struct.Account.html">Account Reference</a></p>
</blockquote>
<p>The <code>Account</code> 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:</p>
<pre><code class="language-rust ignore">use anchor_lang::prelude::*;
declare_id!(&quot;Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS&quot;);
#[program]
mod hello_anchor {
use super::*;
pub fn set_data(ctx: Context&lt;SetData&gt;, data: u64) -&gt; Result&lt;()&gt; {
ctx.accounts.my_account.data = data;
Ok(())
}
}
#[account]
#[derive(Default)]
pub struct MyAccount {
data: u64
}
#[derive(Accounts)]
pub struct SetData&lt;'info&gt; {
#[account(mut)]
pub my_account: Account&lt;'info, MyAccount&gt;
}
</code></pre>
<p><code>Account</code> is generic over <code>T</code>. This <code>T</code> is a type you can create yourself to store data. In this example, we have created a struct <code>MyAccount</code> with a single <code>data</code> field to store a <code>u64</code>. Account requires <code>T</code> to implement certain functions (e.g. functions that (de)serialize <code>T</code>). Most of the time, you can use the <code>#[account]</code> attribute to add these functions to your data, as is done in the example.</p>
<p>Most importantly, the <code>#[account]</code> attribute sets the owner of that data to the <code>ID</code> (the one we created earlier with <code>declare_id</code>) of the crate <code>#[account]</code> is used in. The Account type can then check for you that the <code>AccountInfo</code> passed into your instruction has its <code>owner</code> field set to the correct program. In this example, <code>MyAccount</code> is declared in our own crate so <code>Account</code> will verify that the owner of <code>my_account</code> equals the address we declared with <code>declare_id</code>.</p>
<h4 id="using-accounta-t-with-non-anchor-program-accounts"><a class="header" href="#using-accounta-t-with-non-anchor-program-accounts">Using <code>Account&lt;'a, T&gt;</code> with non-anchor program accounts</a></h4>
<p>There may be cases where you want your program to interact with a non-Anchor program. You can still get all the benefits of <code>Account</code> but you have to write a custom wrapper type instead of using <code>#[account]</code>. For instance, Anchor provides wrapper types for the token program accounts so they can be used with <code>Account</code>.</p>
<pre><code class="language-rust ignore">use anchor_lang::prelude::*;
use anchor_spl::token::TokenAccount;
declare_id!(&quot;Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS&quot;);
#[program]
mod hello_anchor {
use super::*;
pub fn set_data(ctx: Context&lt;SetData&gt;, data: u64) -&gt; Result&lt;()&gt; {
if ctx.accounts.token_account.amount &gt; 0 {
ctx.accounts.my_account.data = data;
}
Ok(())
}
}
#[account]
#[derive(Default)]
pub struct MyAccount {
data: u64,
mint: Pubkey
}
#[derive(Accounts)]
pub struct SetData&lt;'info&gt; {
#[account(mut)]
pub my_account: Account&lt;'info, MyAccount&gt;,
#[account(
constraint = my_account.mint == token_account.mint,
has_one = owner
)]
pub token_account: Account&lt;'info, TokenAccount&gt;,
pub owner: Signer&lt;'info&gt;
}
</code></pre>
<p>To run this example, add <code>anchor-spl = &quot;&lt;version&gt;&quot;</code> to the dependencies section in your <code>Cargo.toml</code>, located in the <code>programs/&lt;your-project-name&gt;/</code> directory. <code>&lt;version&gt;</code> should be equal to the <code>anchor-lang</code> version you're using.</p>
<p>In this example, we set the <code>data</code> 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 <code>TokenAccount</code> type (that wraps around the token program's <code>Account</code> struct and adds the required functions) to make anchor ensure that the incoming account is owned by the token program and to make anchor deserialize it. This means we can use the <code>TokenAccount</code> properties inside our constraints (e.g. <code>token_account.mint</code>) as well as in the instruction function.</p>
<p>Check out the <a href="https://docs.rs/anchor-lang/0.29.0/anchor_lang/accounts/account/struct.Account.html">reference for the Account type</a> to learn how to implement your own wrapper types for non-anchor programs.</p>
<h2 id="constraints"><a class="header" href="#constraints">Constraints</a></h2>
<blockquote>
<p><a href="https://docs.rs/anchor-lang/0.29.0/anchor_lang/derive.Accounts.html">Constraints reference</a></p>
</blockquote>
<p>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.</p>
<p>Add constraints to an account with the following format:</p>
<pre><code class="language-rust ignore">#[account(&lt;constraints&gt;)]
pub account: AccountType
</code></pre>
<p>Some constraints support custom Errors (we will explore errors <a href="./errors.html">later</a>):</p>
<pre><code class="language-rust ignore">#[account(...,&lt;constraint&gt; @ MyError::MyErrorVariant, ...)]
pub account: AccountType
</code></pre>
<p>For example, in the examples above, we used the <code>mut</code> constraint to indicate that <code>my_account</code> should be mutable. We used <code>has_one</code> to check that <code>token_account.owner == owner.key()</code>. And finally we used <code>constraint</code> to check an arbitrary expression; in this case, whether the incoming <code>TokenAccount</code> belongs to the admin mint.</p>
<pre><code class="language-rust ignore">#[derive(Accounts)]
pub struct SetData&lt;'info&gt; {
#[account(mut)]
pub my_account: Account&lt;'info, MyAccount&gt;,
#[account(
constraint = my_account.mint == token_account.mint,
has_one = owner
)]
pub token_account: Account&lt;'info, TokenAccount&gt;,
pub owner: Signer&lt;'info&gt;
}
</code></pre>
<p>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.</p>
<h2 id="safety-checks"><a class="header" href="#safety-checks">Safety checks</a></h2>
<p>Two of the Anchor account types, <a href="https://docs.rs/anchor-lang/0.29.0/anchor_lang/accounts/account_info/index.html">AccountInfo</a> and <a href="https://docs.rs/anchor-lang/0.29.0/anchor_lang/accounts/unchecked_account/index.html">UncheckedAccount</a> do not implement any checks on the account being passed. Anchor implements safety checks that encourage additional documentation describing why additional checks are not necessary.</p>
<p>Attempting to build a program containing the following excerpt with <code>anchor build</code>:</p>
<pre><code class="language-rust ignore">#[derive(Accounts)]
pub struct Initialize&lt;'info&gt; {
pub potentially_dangerous: UncheckedAccount&lt;'info&gt;
}
</code></pre>
<p>will result in an error similar to the following:</p>
<pre><code>Error:
/anchor/tests/unchecked/programs/unchecked/src/lib.rs:15:8
Struct field &quot;potentially_dangerous&quot; is unsafe, but is not documented.
Please add a `/// CHECK:` doc comment explaining why no checks through types are necessary.
See https://book.anchor-lang.com/anchor_in_depth/the_accounts_struct.html#safety-checks for more information.
</code></pre>
<p>To fix this, write a doc comment describing the potential security implications, e.g.:</p>
<pre><code class="language-rust ignore">#[derive(Accounts)]
pub struct Initialize&lt;'info&gt; {
/// CHECK: This is not dangerous because we don't read or write from this account
pub potentially_dangerous: UncheckedAccount&lt;'info&gt;
}
</code></pre>
<p>Note the doc comment needs to be a <a href="https://doc.rust-lang.org/reference/comments.html#doc-comments">line or block doc comment</a> (/// or /**) to be interpreted as doc attribute by Rust. Double slash comments (//) are not interpreted as such.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../anchor_in_depth/high-level_overview.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../anchor_in_depth/the_program_module.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../anchor_in_depth/high-level_overview.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../anchor_in_depth/the_program_module.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="../book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>