Solana DEV #01: Получение данных onchain правильным способом

Работа с децентрализованным приложением Solana со стороны клиента может быть основной частью разработки приложения Solana. До того, как я освоился с этим процессом, я думал, что программирование смарт-контрактов — это единственная и неповторимая задача, о которой мы должны тщательно заботиться. Однако, как и при разработке традиционных веб-сайтов, сбор данных на стороне клиента влияет на впечатления, получаемые пользователем. В этой статье я перечислю основные моменты, связанные с получением данных.

Получение отфильтрованных учетных записей программ

Первая и самая лучшая практика — это использование getProgramAccounts с фильтром. Этот метод getProgramAccounts в пакете @solana/web3.js чрезвычайно полезен для получения всех счетов заданного идентификатора программы. Однако, поскольку в смарт-контракте существует несколько типов счетов, для достижения наилучшей производительности необходима фильтрация.

/**
 * A filter object for getProgramAccounts
 */
export type GetProgramAccountsFilter = MemcmpFilter | DataSizeFilter;
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь мы немного поиграем с исходным кодом. Есть два типа фильтрации, которые мы можем использовать MemcmpFilter и DataSizeFilter.

DataSizeFilter

/**
 * Data size comparison filter for getProgramAccounts
 */
export type DataSizeFilter = {
  /** Size of data for program account data length comparison */
  dataSize: number;
};
Вход в полноэкранный режим Выход из полноэкранного режима

DataSizeFilter используется для фильтрации счетов программы, совпадающих с объявленным размером данных. Просто, верно? Этот тип фильтрации полезен для счетов с фиксированным размером данных. Счета содержат поля динамического размера, такие как vector или str.

MemcmpFilter

/**
 * Memory comparison filter for getProgramAccounts
 */
export type MemcmpFilter = {
  memcmp: {
    /** offset into program account data to start comparison */
    offset: number;
    /** data to match, as base-58 encoded string and limited to less than 129 bytes */
    bytes: string;
  };
};
Вход в полноэкранный режим Выйти из полноэкранного режима

Между двумя типами фильтрации, я нахожу, что этот подход используется чаще, так как он позволяет вам фильтровать учетные записи более динамично и избирательно. MemcmpFilter или Фильтр сравнения памяти имеет два поля: offset и bytes. Каждая учетная запись представляет собой набор байтов, вы можете использовать смещение для выбора конкретного поля данных для сравнения, а байты — это последующая часть сравнения.

Например, если я хочу получить все счета программы с определенным дискриминатором счетов, я могу установить смещение как 0 и получить байты сравниваемого дискриминатора счетов. Это трюк для получения программных счетов определенного типа без использования Anchor (поскольку фреймворк уже обрабатывает этот процесс под капотом).

Я обычно использую эту фильтрацию типов, чтобы отфильтровать, какие счета принадлежат определенному кошельку. Для этого в программе Rust необходимо хранить адрес кошелька владельца счета. Например, у меня есть такие данные о счетах (с использованием Anchor):

#[account]
pub struct WalletAddressContainer {
  pub address: PubKey
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Чтобы получить все счета WalletAddressContainer с определенным адресом кошелька, я бы сделал следующее

// using Anchor
await program.account.flow.all([
 {
  memcmp: {
    offset: 8,
    bytes: publicKey.toBase58(),
  },
 }
]);

// without Anchor
await connection.getProgramAccounts(
 programID,
 {
  ...,
  filters: [
   {
    memcmp: {
     offset: 0,
     bytes: /** Account discriminator bytes of WalletAddressContainer **/,
    }
   },
   {
    memcmp: {
     offset: 8,
     bytes: publicKey.toBase58()
    }
   }
  ]
 }
);
Войти в полноэкранный режим Выйти из полноэкранного режима

В способе Anchor, как уже упоминалось, фреймворк Anchor обрабатывает сравнение дискриминатора счетов под капотом, поэтому нам не нужно сравнивать его снова. Таким образом, нам нужен только один фильтр memcmp для сравнения открытого ключа кошелька, но смещение все еще должно быть 8, потому что первые 8 байт предназначены для дискриминатора счета.

С другой стороны, getProgramAccounts без Anchor требует двух сравнений. Первое — дискриминатор счета, второе — адрес кошелька.

Оцените статью
devanswers.ru
Добавить комментарий