Browse Source

Added checks if a token account is initialized when checking validity (#2986)

* Added checks if an account is initialized when checking validity
Lijun Wang 3 years ago
parent
commit
2fbf73a4b4
1 changed files with 39 additions and 5 deletions
  1. 39 5
      program/src/state.rs

+ 39 - 5
program/src/state.rs

@@ -331,9 +331,21 @@ pub trait GenericTokenAccount {
     }
 }
 
+/// The offset of state field in Account's C representation
+pub const ACCOUNT_INITIALIZED_INDEX: usize = 108;
+
+/// Check if the account data buffer represents an initialized account.
+/// This is checking the `state` (AccountState) field of an Account object.
+pub fn is_initialized_account(account_data: &[u8]) -> bool {
+    *account_data
+        .get(ACCOUNT_INITIALIZED_INDEX)
+        .unwrap_or(&(AccountState::Uninitialized as u8))
+        != AccountState::Uninitialized as u8
+}
+
 impl GenericTokenAccount for Account {
     fn valid_account_data(account_data: &[u8]) -> bool {
-        account_data.len() == Account::LEN
+        account_data.len() == Account::LEN && is_initialized_account(account_data)
     }
 }
 
@@ -418,11 +430,22 @@ mod tests {
         let result = Account::unpack_account_owner(&src);
         assert_eq!(result, Option::None);
 
-        // The right account data size, unpack will return some key
-        let src: [u8; Account::LEN] = [0; Account::LEN];
+        // The right account data size and intialized, unpack will return some key
+        let mut src: [u8; Account::LEN] = [0; Account::LEN];
+        src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8;
         let result = Account::unpack_account_owner(&src);
         assert!(result.is_some());
 
+        // The right account data size and frozen, unpack will return some key
+        src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Frozen as u8;
+        let result = Account::unpack_account_owner(&src);
+        assert!(result.is_some());
+
+        // The right account data size and uninitialized, unpack will return None
+        src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Uninitialized as u8;
+        let result = Account::unpack_account_mint(&src);
+        assert_eq!(result, Option::None);
+
         // Account data length > account data size, unpack will not return a key
         let src: [u8; Account::LEN + 5] = [0; Account::LEN + 5];
         let result = Account::unpack_account_owner(&src);
@@ -436,11 +459,22 @@ mod tests {
         let result = Account::unpack_account_mint(&src);
         assert_eq!(result, Option::None);
 
-        // The right account data size, unpack will return some key
-        let src: [u8; Account::LEN] = [0; Account::LEN];
+        // The right account data size and initialized, unpack will return some key
+        let mut src: [u8; Account::LEN] = [0; Account::LEN];
+        src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8;
+        let result = Account::unpack_account_mint(&src);
+        assert!(result.is_some());
+
+        // The right account data size and frozen, unpack will return some key
+        src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Frozen as u8;
         let result = Account::unpack_account_mint(&src);
         assert!(result.is_some());
 
+        // The right account data size and uninitialized, unpack will return None
+        src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Uninitialized as u8;
+        let result = Account::unpack_account_mint(&src);
+        assert_eq!(result, Option::None);
+
         // Account data length > account data size, unpack will not return a key
         let src: [u8; Account::LEN + 5] = [0; Account::LEN + 5];
         let result = Account::unpack_account_mint(&src);