Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anchor AccountClient#fetchMultiple throw error when account on given Pubkeys have incorrect discriminator #2961

Open
FredoNook opened this issue May 11, 2024 · 2 comments

Comments

@FredoNook
Copy link

Greetings

When in AccountClient#fetchMultiple method passed Pubkeys with account not matching to AccountClient's account discriminator, BorschAccountDecoder throw error and that error not catched, so in this case any wrong Pubkey break AccountClient#fetchMultiple instead of return null for wrong Pubkey account as discribed in JSDoc to method AccountClient#fetchMultiple.

Method: AccountClient#fetchMultipleAndContext

  /**
   * Returns multiple deserialized accounts.
   * Accounts not found or with wrong discriminator are returned as null.
   *
   * @param addresses The addresses of the accounts to fetch.
   */
  async fetchMultipleAndContext(
    addresses: Address[],
    commitment?: Commitment
  ): Promise<({ data: T; context: Context } | null)[]> {
    const accounts = await rpcUtil.getMultipleAccountsAndContext(
      this._provider.connection,
      addresses.map((address) => translateAddress(address)),
      commitment
    );

    // Decode accounts where discriminator is correct, null otherwise
    return accounts.map((result) => {
      if (result == null) {
        return null;
      }
      const { account, context } = result;
      return {
        data: this._coder.accounts.decode(this._idlAccount.name, account.data),
        context,
      };
    });
  }

In line data: this._coder.accounts.decode(this._idlAccount.name, account.data), called BorschAccountDecoder#decode which throw error if discriminator.compare(data.slice(0, DISCRIMINATOR_SIZE)):

  public decode<T = any>(accountName: A, data: Buffer): T {
    // Assert the account discriminator is correct.
    const discriminator = this.accountDiscriminator(accountName);
    if (discriminator.compare(data.slice(0, DISCRIMINATOR_SIZE))) {
      throw new Error("Invalid account discriminator");
    }
    return this.decodeUnchecked(accountName, data);
  }

And this error not catched in AccountClient#fetchMultipleAndContext, so in this case this account not mapped as null but break execution with error.

@acheroncrypto
Copy link
Collaborator

To me, the behavior is expected, but the comment "Accounts not found or with wrong discriminator are returned as null." is half correct. Having different discriminator is an error in all cases, and null is only returned if the account doesn't exist.

@FredoNook
Copy link
Author

FredoNook commented May 13, 2024

What is benefit to get error in this case? Why not exist account less critical than account with different discriminator? Says we have program instruction that take bunch of same type accounts as input and that accounts isn't PDA so in this use case we have to fetch one by one to check that account exists and have expected type right? Why not to check them in one RPC request utilizing #fetchMultiple?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants