浏览代码

docs: Update tutorials for new init constraint (#670)

Armani Ferrante 4 年之前
父节点
当前提交
2cc82bc11a

+ 10 - 36
docs/src/tutorials/tutorial-1.md

@@ -31,27 +31,16 @@ Some new syntax elements are introduced here.
 First, let's start with the initialize instruction. Notice the `data` argument passed into the program. This argument and any other valid
 Rust types can be passed to the instruction to define inputs to the program.
 
-::: tip
-If you'd like to pass in your own type as an input to an instruction handler, then it must be
-defined in the same `src/lib.rs` file as the `#[program]` module, so that the IDL parser can
-pick it up.
-:::
-
 Additionally,
 notice how we take a mutable reference to `my_account` and assign the `data` to it. This leads us to
-the `Initialize` struct, deriving `Accounts`. There are three things to notice about `Initialize`.
+the `Initialize` struct, deriving `Accounts`. There are two things to notice about `Initialize`.
 
 1. The `my_account` field is of type `ProgramAccount<'info, MyAccount>`, telling the program it *must*
 be **owned** by the currently executing program, and the deserialized data structure is `MyAccount`.
-2. The `my_account` field is marked with the `#[account(init)]` attribute. This should be used
-in one situation: when a given `ProgramAccount` is newly created and is being used by the program
-for the first time (and thus its data field is all zero). If `#[account(init)]` is not used
-when account data is zero initialized, the transaction will be rejected.
-3. The `Rent` **sysvar** is required for the rent exemption check, which the framework enforces
-by default for any account marked with `#[account(init)]`. To be more explicit about the check,
-one can specify `#[account(init, rent_exempt = enforce)]`. To skip this check, (and thus
-allowing you to omit the `Rent` acccount), you can specify
-`#[account(init, rent_exempt = skip)]` on the account being initialized (here, `my_account`).
+2. The `my_account` field is marked with the `init` attribute. This will create a new
+account owned by the current program, zero initialized. When using `init`, one must also provider
+`payer`, which will fund the account creation, `space`, which defines how large the account should be,
+and the `system_program`, which is required by the runtime for creating the account.
 
 ::: details
 All accounts created with Anchor are laid out as follows: `8-byte-discriminator || borsh
@@ -81,15 +70,16 @@ for persisting changes.
 
 ## Creating and Initializing Accounts
 
-For a moment, assume an account of type `MyAccount` was created on Solana, in which case,
-we can invoke the above `initialize` instruction as follows.
+We can interact with the program as follows.
 
-<<< @/../examples/tutorial/basic-1/tests/basic-1.js#code-separated
+<<< @/../examples/tutorial/basic-1/tests/basic-1.js#code-simplified
 
 The last element passed into the method is common amongst all dynamically generated
 methods on the `rpc` namespace, containing several options for a transaction. Here,
 we specify the `accounts` field, an object of all the addresses the transaction
-needs to touch.
+needs to touch, and the `signers` array of all `Signer` objects needed to sign the
+transaction. Because `myAccount` is being created, the Solana runtime requries it
+to sign the transaction.
 
 ::: details
 If you've developed on Solana before, you might notice two things 1) the ordering of the accounts doesn't
@@ -98,22 +88,6 @@ options are not specified on the account anywhere. In both cases, the framework
 of these details for you, by reading the IDL.
 :::
 
-However it's common--and sometimes necessary for security purposes--to batch
-instructions together. We can extend the example above to both create an account
-and initialize it in one atomic transaction.
-
-<<< @/../examples/tutorial/basic-1/tests/basic-1.js#code
-
-Here, notice the **two** fields introduced: `signers` and `instructions`. `signers`
-is an array of all `Account` objects to sign the transaction and `instructions` is an
-array of all instructions to run **before** the explicitly specified program instruction,
-which in this case is `initialize`. Because we are creating `myAccount`, it needs to
-sign the transaction, as required by the Solana runtime.
-
-We can simplify this further.
-
-<<< @/../examples/tutorial/basic-1/tests/basic-1.js#code-simplified
-
 As before, we can run the example tests.
 
 ```

+ 1 - 2
docs/src/tutorials/tutorial-3.md

@@ -71,9 +71,8 @@ retrieve the return value. In future work, Anchor should do this transparently.
 
 ## Conclusion
 
-Now that you can have your programs call other programs, you should be able to access all the work being done by other developers in your own applications! 
+Now that you can have your programs call other programs, you should be able to access all the work being done by other developers in your own applications!
 
 ## Next Steps
 
 Up until now, we've treated programs on Solana as stateless. In the next tutorial we will learn how to add a global state to our program.
-

+ 3 - 1
examples/tutorial/basic-1/programs/basic-1/src/lib.rs

@@ -19,8 +19,10 @@ mod basic_1 {
 
 #[derive(Accounts)]
 pub struct Initialize<'info> {
-    #[account(zero)]
+    #[account(init, payer = user, space = 8 + 8)]
     pub my_account: ProgramAccount<'info, MyAccount>,
+    pub user: AccountInfo<'info>,
+    pub system_program: AccountInfo<'info>,
 }
 
 #[derive(Accounts)]

+ 5 - 83
examples/tutorial/basic-1/tests/basic-1.js

@@ -1,5 +1,6 @@
 const assert = require("assert");
 const anchor = require("@project-serum/anchor");
+const { SystemProgram } = anchor.web3;
 
 describe("basic-1", () => {
   // Use a local provider.
@@ -8,102 +9,23 @@ describe("basic-1", () => {
   // Configure the client to use the local cluster.
   anchor.setProvider(provider);
 
-  it("Creates and initializes an account in two different transactions", async () => {
-    // The program owning the account to create.
-    const program = anchor.workspace.Basic1;
-
-    // The Account to create.
-    const myAccount = anchor.web3.Keypair.generate();
-
-    // Create account transaction.
-    const tx = new anchor.web3.Transaction();
-    tx.add(
-      anchor.web3.SystemProgram.createAccount({
-        fromPubkey: provider.wallet.publicKey,
-        newAccountPubkey: myAccount.publicKey,
-        space: 8 + 8,
-        lamports: await provider.connection.getMinimumBalanceForRentExemption(
-          8 + 8
-        ),
-        programId: program.programId,
-      })
-    );
-
-    // Execute the transaction against the cluster.
-    await provider.send(tx, [myAccount]);
-
-    // Execute the RPC.
-    // #region code-separated
-    await program.rpc.initialize(new anchor.BN(1234), {
-      accounts: {
-        myAccount: myAccount.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-      },
-    });
-    // #endregion code-separated
-
-    // Fetch the newly created account from the cluster.
-    const account = await program.account.myAccount.fetch(myAccount.publicKey);
-
-    // Check it's state was initialized.
-    assert.ok(account.data.eq(new anchor.BN(1234)));
-  });
-
-  // Reference to an account to use between multiple tests.
-  let _myAccount = undefined;
-
-  it("Creates and initializes an account in a single atomic transaction", async () => {
-    // The program to execute.
-    const program = anchor.workspace.Basic1;
-
-    // #region code
-    // The Account to create.
-    const myAccount = anchor.web3.Keypair.generate();
-
-    // Atomically create the new account and initialize it with the program.
-    await program.rpc.initialize(new anchor.BN(1234), {
-      accounts: {
-        myAccount: myAccount.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-      },
-      signers: [myAccount],
-      instructions: [
-        anchor.web3.SystemProgram.createAccount({
-          fromPubkey: provider.wallet.publicKey,
-          newAccountPubkey: myAccount.publicKey,
-          space: 8 + 8, // Add 8 for the account discriminator.
-          lamports: await provider.connection.getMinimumBalanceForRentExemption(
-            8 + 8
-          ),
-          programId: program.programId,
-        }),
-      ],
-    });
-
-    // Fetch the newly created account from the cluster.
-    const account = await program.account.myAccount.fetch(myAccount.publicKey);
-
-    // Check it's state was initialized.
-    assert.ok(account.data.eq(new anchor.BN(1234)));
-    // #endregion code
-  });
-
   it("Creates and initializes an account in a single atomic transaction (simplified)", async () => {
+    // #region code-simplified
     // The program to execute.
     const program = anchor.workspace.Basic1;
 
     // The Account to create.
     const myAccount = anchor.web3.Keypair.generate();
 
-    // Atomically create the new account and initialize it with the program.
+    // Create the new account and initialize it with the program.
     // #region code-simplified
     await program.rpc.initialize(new anchor.BN(1234), {
       accounts: {
         myAccount: myAccount.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        user: provider.wallet.publicKey,
+        systemProgram: SystemProgram.programId,
       },
       signers: [myAccount],
-      instructions: [await program.account.myAccount.createInstruction(myAccount)],
     });
     // #endregion code-simplified
 

+ 6 - 1
examples/tutorial/basic-2/programs/basic-2/src/lib.rs

@@ -1,4 +1,5 @@
 use anchor_lang::prelude::*;
+use anchor_lang::solana_program::system_program;
 
 // Define the program's instruction handlers.
 
@@ -24,8 +25,12 @@ mod basic_2 {
 
 #[derive(Accounts)]
 pub struct Create<'info> {
-    #[account(zero)]
+    #[account(init, payer = user, space = 8 + 40)]
     pub counter: ProgramAccount<'info, Counter>,
+    #[account(signer)]
+    pub user: AccountInfo<'info>,
+    #[account(address = system_program::ID)]
+    pub system_program: AccountInfo<'info>,
 }
 
 #[derive(Accounts)]

+ 3 - 2
examples/tutorial/basic-2/tests/basic-2.js

@@ -1,5 +1,6 @@
 const assert = require('assert');
 const anchor = require('@project-serum/anchor');
+const { SystemProgram } = anchor.web3;
 
 describe('basic-2', () => {
   const provider = anchor.Provider.local()
@@ -17,10 +18,10 @@ describe('basic-2', () => {
     await program.rpc.create(provider.wallet.publicKey, {
       accounts: {
         counter: counter.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        user: provider.wallet.publicKey,
+        systemProgram: SystemProgram.programId,
       },
       signers: [counter],
-      instructions: [await program.account.counter.createInstruction(counter)],
     })
 
     let counterAccount = await program.account.counter.fetch(counter.publicKey)

+ 1 - 1
examples/tutorial/basic-3/programs/puppet-master/src/lib.rs

@@ -17,7 +17,7 @@ mod puppet_master {
 
 #[derive(Accounts)]
 pub struct PullStrings<'info> {
-    #[account(mut)]
+    #[account(mut, owner = puppet_program)]
     pub puppet: CpiAccount<'info, Puppet>,
     pub puppet_program: AccountInfo<'info>,
 }

+ 6 - 1
examples/tutorial/basic-3/programs/puppet/src/lib.rs

@@ -1,4 +1,5 @@
 use anchor_lang::prelude::*;
+use anchor_lang::solana_program::system_program;
 
 #[program]
 pub mod puppet {
@@ -16,8 +17,12 @@ pub mod puppet {
 
 #[derive(Accounts)]
 pub struct Initialize<'info> {
-    #[account(zero)]
+    #[account(init, payer = user, space = 8 + 8)]
     pub puppet: ProgramAccount<'info, Puppet>,
+    #[account(signer)]
+    pub user: AccountInfo<'info>,
+    #[account(address = system_program::ID)]
+    pub system_program: AccountInfo<'info>,
 }
 
 #[derive(Accounts)]

+ 7 - 6
examples/tutorial/basic-3/tests/basic-3.js

@@ -1,5 +1,6 @@
 const assert = require("assert");
 const anchor = require("@project-serum/anchor");
+const { SystemProgram } = anchor.web3;
 
 describe("basic-3", () => {
   const provider = anchor.Provider.local();
@@ -16,18 +17,18 @@ describe("basic-3", () => {
     const tx = await puppet.rpc.initialize({
       accounts: {
         puppet: newPuppetAccount.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        user: provider.wallet.publicKey,
+        systemProgram: SystemProgram.programId,
       },
       signers: [newPuppetAccount],
-      instructions: [await puppet.account.puppet.createInstruction(newPuppetAccount)],
     });
 
     // Invoke the puppet master to perform a CPI to the puppet.
     await puppetMaster.rpc.pullStrings(new anchor.BN(111), {
-        accounts: {
-            puppet: newPuppetAccount.publicKey,
-            puppetProgram: puppet.programId,
-        },
+       accounts: {
+          puppet: newPuppetAccount.publicKey,
+          puppetProgram: puppet.programId,
+       },
     });
 
     // Check the state updated.