Browse Source

lang: Add `AccountNotInitialized` error (#1024)

Mikhail Gorbachev 3 years ago
parent
commit
2d44654a4b

+ 5 - 1
CHANGELOG.md

@@ -13,7 +13,11 @@ incremented for features.
 
 ### Fixes
 
-lang: Add `deprecated` attribute to `ProgramAccount` ([#1014](https://github.com/project-serum/anchor/pull/1014)).
+* lang: Add `deprecated` attribute to `ProgramAccount` ([#1014](https://github.com/project-serum/anchor/pull/1014)).
+
+### Features
+
+* lang: Add `ErrorCode::AccountNotInitialized` error to separate the situation when the account has the wrong owner from when it does not exist (#[1024](https://github.com/project-serum/anchor/pull/1024))
 
 ## [0.18.2] - 2021-11-14
 

+ 6 - 0
lang/src/account.rs

@@ -22,6 +22,9 @@ impl<'a, T: AccountSerialize + AccountDeserialize + Owner + Clone> Account<'a, T
     /// Deserializes the given `info` into a `Account`.
     #[inline(never)]
     pub fn try_from(info: &AccountInfo<'a>) -> Result<Account<'a, T>, ProgramError> {
+        if info.owner == &system_program::ID && info.lamports() == 0 {
+            return Err(ErrorCode::AccountNotInitialized.into());
+        }
         if info.owner != &T::owner() {
             return Err(ErrorCode::AccountNotProgramOwned.into());
         }
@@ -34,6 +37,9 @@ impl<'a, T: AccountSerialize + AccountDeserialize + Owner + Clone> Account<'a, T
     /// possible.
     #[inline(never)]
     pub fn try_from_unchecked(info: &AccountInfo<'a>) -> Result<Account<'a, T>, ProgramError> {
+        if info.owner == &system_program::ID && info.lamports() == 0 {
+            return Err(ErrorCode::AccountNotInitialized.into());
+        }
         if info.owner != &T::owner() {
             return Err(ErrorCode::AccountNotProgramOwned.into());
         }

+ 2 - 0
lang/src/error.rs

@@ -74,6 +74,8 @@ pub enum ErrorCode {
     AccountNotSigner,
     #[msg("The given account is not owned by the system program")]
     AccountNotSystemOwned,
+    #[msg("The program expected this account to be already initialized")]
+    AccountNotInitialized,
 
     // State.
     #[msg("The given state account does not have the correct address")]

+ 13 - 1
tests/errors/programs/errors/src/lib.rs

@@ -36,6 +36,10 @@ mod errors {
     pub fn raw_custom_error(_ctx: Context<RawCustomError>) -> Result<()> {
         Ok(())
     }
+
+    pub fn account_not_initialized_error(_ctx: Context<AccountNotInitializedError>) -> Result<()> {
+        Ok(())
+    }
 }
 
 #[derive(Accounts)]
@@ -68,7 +72,15 @@ pub struct HasOneAccount {
 #[derive(Accounts)]
 pub struct RawCustomError<'info> {
     #[account(constraint = *my_account.key == ID @ MyError::HelloCustom)]
-    my_account: AccountInfo<'info>
+    my_account: AccountInfo<'info>,
+}
+
+#[account]
+pub struct AnyAccount {}
+
+#[derive(Accounts)]
+pub struct AccountNotInitializedError<'info> {
+    not_initialized_account: Account<'info, AnyAccount>,
 }
 
 #[error]

+ 14 - 0
tests/errors/tests/errors.js

@@ -128,4 +128,18 @@ describe("errors", () => {
       assert.equal(err.code, 300 + 125);
     }
   });
+
+  it("Emits a account not initialized error", async () => {
+    try {
+      const tx = await program.rpc.accountNotInitializedError({
+        accounts: {
+          notInitializedAccount: (new anchor.web3.Keypair()).publicKey
+        },
+      });
+      assert.fail("Unexpected success in creating a transaction that should have fail with `AccountNotInitialized` error");
+    } catch (err) {
+      const errMsg = "The program expected this account to be already initialized";
+      assert.equal(err.toString(), errMsg);
+    }
+  });
 });

+ 5 - 0
ts/src/error.ts

@@ -89,6 +89,7 @@ const LangErrorCode = {
   InvalidProgramExecutable: 169,
   AccountNotSigner: 170,
   AccountNotSystemOwned: 171,
+  AccountNotInitialized: 172,
 
   // State.
   StateInvalidAddress: 180,
@@ -175,6 +176,10 @@ const LangErrorMessage = new Map([
     LangErrorCode.AccountNotSystemOwned,
     "The given account is not owned by the system program",
   ],
+  [
+    LangErrorCode.AccountNotInitialized,
+    "The program expected this account to be already initialized",
+  ],
 
   // State.
   [