Транзакции в Solana
Сегодня мы разберемся в работе транзакции на солане
Вольный перевод данной статьи ТЫК
Структура Solana транзакции
По сути, транзакция состоит из нескольких частей:
Signature — это список подписей ed25519
хэша сообщения, где «сообщение» состоит из метаданных и «инструкций». В отличие от Ethereum, в транзакциях Solana может быть несколько подписантов (это будет более понятно позже), и для этого поля подписи нужны все их подписи. Любая учетная запись, которая разрешает любое обновление состояния в транзакции, должна подписать эту транзакцию
Metadata — в сообщение входят некоторые метаданные. Сообщение имеет header, который включает 3 uint8
, описывающих, сколько учетных записей будет подписывать payload, сколько нет и сколько доступно только для чтения. Метаданные также содержат список учетных записей, на которые будут использоваться в этой транзакции, и «recent» хэш блока. Я не уверен, каковы точные правила для этого хэша, но это не обязательно должен быть самый последний блок, он просто должен быть недавним блоком
Instructions — когда вы совершаете транзакцию в Solana, вы передаете серию «инструкций», каждая из которых выполняет разные действия для обновления состояния в глобальной системе Solana. Инструкция содержит три основных элемента информации: набор используемых учетных записей и является ли каждая из них подписывающей и/или доступной для записи, идентификатор программы, который ссылается на расположение кода, который вы будете вызывать, буфер с некоторыми данными в нем, которые функционируют как calldata
Accounts и Programs
«account» — это, по сути, область памяти в системе Solana со связанным адресом. «program» — это особый тип аккаунта который содержит исполняемый код
Ps: на самом деле существует два типа «адресов», которые могут сбивать с толку, если вы пришли из Ethereum. Solana использует ed25519
с 32-байтными публичными ключами — это один из типов «адреса» (т. е. он не хэшируется). Если вы создаете учетную запись, с которой хотите иметь возможность подписывать, ваш адрес должен быть точкой на кривой ed25519 (также известной как действительный открытый ключ). Однако вы также можете создать «program derived address» (PDA), который должен быть нестандартным, что означает отсутствие соответствующего закрытого ключа. Вы не можете создать учетную запись с PDA напрямую — вместо этого учетная запись, принадлежащая программе, должна вызывать системную программу с помощью функции программы. PDA обычно используются, когда программам необходимо внутренне управлять учетными записями для более сложных вещей (например, DeFi), и мы не будем использовать их в транзакции минта токенов
Чтобы «install» программу в системе Solana, вы должны создать новую учетную запись (с парой открытого/закрытого ключа) и отправить набор скомпилированных байт-кодов в качестве calldata. Код будет развернут по адресу, соответствующему предоставленному вами открытому ключу. В Solana есть несколько программ системного уровня, и одна из них — загрузчик BPF (BPF расшифровывается как «Berkeley Packet Filter») — это программа, которую вы вызываете для создания новой программы, и она становится «владельцем» вашей новой программы
Так что вы можете думать о «программе» как об области памяти в Solana, которая содержит неизменяемый исполняемый код без сохранения состояния. После развертывания программного кода вы создаете новую учетную запись и отмечаете программу как ее «владельца» — с этого момента я буду называть это «учетной записью, принадлежащей программе». Обратите внимание, что если вы создаете учетную запись с парой открытого/закрытого ключа и назначаете программу владельцем, вы не можете напрямую изменить состояние этой учетной записи — для этого вы должны использовать API связанной программы, аналогично шаблону прокси-контракта в Ethereum. Чтобы было ясно, это означает, что закрытый ключ, который вы создаете для создания учетной записи, принадлежащей программе, может быть выброшен после того, как он подпишет транзакцию для создания учетной записи — этот ключ ничего не может сделать после создания учетной записи
Пример: минт токена
Разбирать будем на примере данной транзакции ТЫК
Вот такой набор инструкций был передан в этой транзакции
{ "instructions": [ // instruction 1/5 { "keys": [ { "pubkey": { "_bn": "63e8ee43a8583013ba6fef5c09181f26720d0621debe8c57eaf4ed87e704843b" }, "isSigner": true, "isWritable": true }, { "pubkey": { "_bn": "f7fa7a4d4e8dda19a3afbec13a5fb4a540289b869b6a5a46162b7c3e3d9161ab" }, "isSigner": true, "isWritable": true } ], "programId": { "_bn": "00" }, "data": { "type": "Buffer", "data": [ 0, 0, 0, 0, 96, 77, 22, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 6, 221, 246, 225, 215, 101, 161, 147, 217, 203, 225, 70, 206, 235, 121, 172, 28, 180, 133, 237, 95, 91, 55, 145, 58, 140, 245, 133, 126, 255, 0, 169 ] } }, // instruction 2/5 { "keys": [ { "pubkey": { "_bn": "f7fa7a4d4e8dda19a3afbec13a5fb4a540289b869b6a5a46162b7c3e3d9161ab" }, "isSigner": false, "isWritable": true }, { "pubkey": { "_bn": "06a7d517192c5c51218cc94c3d4af17f58daee089ba1fd44e3dbd98a00000000" }, "isSigner": false, "isWritable": false } ], "programId": { "_bn": "06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" }, "data": { "type": "Buffer", "data": [ 0, 2, 99, 232, 238, 67, 168, 88, 48, 19, 186, 111, 239, 92, 9, 24, 31, 38, 114, 13, 6, 33, 222, 190, 140, 87, 234, 244, 237, 135, 231, 4, 132, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] } }, // instruction 3/5 { "keys": [ { "pubkey": { "_bn": "63e8ee43a8583013ba6fef5c09181f26720d0621debe8c57eaf4ed87e704843b" }, "isSigner": true, "isWritable": true }, { "pubkey": { "_bn": "f2560320922ee24d0086e5769e8b3cdf261c646f4f17184532ec7380220b980c" }, "isSigner": true, "isWritable": true } ], "programId": { "_bn": "00" }, "data": { "type": "Buffer", "data": [ 0, 0, 0, 0, 240, 29, 31, 0, 0, 0, 0, 0, 165, 0, 0, 0, 0, 0, 0, 0, 6, 221, 246, 225, 215, 101, 161, 147, 217, 203, 225, 70, 206, 235, 121, 172, 28, 180, 133, 237, 95, 91, 55, 145, 58, 140, 245, 133, 126, 255, 0, 169 ] } }, // instruction 4/5 { "keys": [ { "pubkey": { "_bn": "f2560320922ee24d0086e5769e8b3cdf261c646f4f17184532ec7380220b980c" }, "isSigner": false, "isWritable": true }, { "pubkey": { "_bn": "f7fa7a4d4e8dda19a3afbec13a5fb4a540289b869b6a5a46162b7c3e3d9161ab" }, "isSigner": false, "isWritable": false }, { "pubkey": { "_bn": "63e8ee43a8583013ba6fef5c09181f26720d0621debe8c57eaf4ed87e704843b" }, "isSigner": false, "isWritable": false }, { "pubkey": { "_bn": "06a7d517192c5c51218cc94c3d4af17f58daee089ba1fd44e3dbd98a00000000" }, "isSigner": false, "isWritable": false } ], "programId": { "_bn": "06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" }, "data": { "type": "Buffer", "data": [ 1 ] } }, // instruction 5/5 { "keys": [ { "pubkey": { "_bn": "f7fa7a4d4e8dda19a3afbec13a5fb4a540289b869b6a5a46162b7c3e3d9161ab" }, "isSigner": false, "isWritable": true }, { "pubkey": { "_bn": "f2560320922ee24d0086e5769e8b3cdf261c646f4f17184532ec7380220b980c" }, "isSigner": false, "isWritable": true }, { "pubkey": { "_bn": "63e8ee43a8583013ba6fef5c09181f26720d0621debe8c57eaf4ed87e704843b" }, "isSigner": true, "isWritable": false } ], "programId": { "_bn": "06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" }, "data": { "type": "Buffer", "data": [ 7, 232, 3, 0, 0, 0, 0, 0, 0 ] } } ], "signatures": [ { "signature": { "type": "Buffer", "data": [ 20, ... // omitting because sigdata isn't important 5 ] }, "publicKey": { "_bn": "63e8ee43a8583013ba6fef5c09181f26720d0621debe8c57eaf4ed87e704843b" } }, { "signature": { "type": "Buffer", "data": [ 0, ... 15 ] }, "publicKey": { "_bn": "f7fa7a4d4e8dda19a3afbec13a5fb4a540289b869b6a5a46162b7c3e3d9161ab" } }, { "signature": { "type": "Buffer", "data": [ 230, ... 8 ] }, "publicKey": { "_bn": "f2560320922ee24d0086e5769e8b3cdf261c646f4f17184532ec7380220b980c" } } ] }
Это не идеальное отображение структуры транзакции, описанной выше, но оно содержит всю необходимую нам информацию. Важно отметить, что все записи _bn
представляют собой шестнадцатеричные строковые представления адресов. Адреса обычно отображаются как строки base58, как это мы видим в Solscan. Был также recentBlockhash
, но я его пропустил, потому что он не имеет отношения к этой транзакции
— Instruction #1/5 —
Первая инструкция создает производную от программы учетную запись, которая будет принадлежать Token Program. Эта инструкция содержит два ключа:
- 7j1NJDkeg35gtRt4nco9fN4wak6M6rD16okMYgvLJeHp: это подписант, и он должен быть доступен для записи, чтобы вычесть SOL из моего баланса
- Hh1E4LwRxAiJdLV4gzKX3BpdbNXJ2AYVdv8UDrfTZAbL: подписант и доступен для записи. Далее мы более подробно разберем это
ProgramId
имеет значение 00
, что означает, что мы вызываем System Program
, единственную программу Solana, которая может создавать новые учетные записи в системе
[ 0, 0, 0, 0, 96, 77, 22, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 6, 221, 246, 225, 215, 101, 161, 147, 217, 203, 225, 70, 206, 235, 121, 172, 28, 180, 133, 237, 95, 91, 55, 145, 58, 140, 245, 133, 126, 255, 0, 169 ]
Все первые четыре байта равны 0. Программные функции индексируются с помощью перечислений, поэтому первый параметр calldata каждой инструкции указывает, какая функция в данном программном API вызывается. Поскольку первый u32 равен 0, это означает, что мы вызываем функцию системной программы 0, то есть CreateAccount
Ps: программы системного уровня Solana используют u32 в качестве типов индексов перечисления, но размер этого параметра зависит от автора программы. Программа Token, которую мы рассмотрим далее, использует тип индекса перечисления u8, поэтому нам нужно проверить только первый байт, чтобы определить, какую функцию мы вызываем
Первое поле в наших calldata — тип u64, описывающий, сколько лэмпортов нужно перевести на новый аккаунт:
[96, 77, 22, 0, 0, 0, 0, 0]
Вау, это огромное число… или нет? Оказывается, солана использует кодировку с прямым порядком байтов
0x0000000000164d60 -> 1461600 lamports
Но зачем эта плата? Это «арендная плата» за поддержание программы в системе Solana. Вот официальная документация по аренде. Похоже, стоимость аренды пропорциональна размеру хранилища. Вы также можете оплатить аренду за 2 года вперед, и ваша программа останется в силе навсегда, что и происходит здесь. Не знаю, как они пришли к такому решению, но ладно
Следующее поле — еще одно u64, указывающее, сколько байтов памяти выделить для этой программы:
[82, 0, 0, 0, 0, 0, 0, 0]
Итак… 82
в байтах - кажется маленьким числом, но то связано с тем, что фактическая память, которую мы выделяем, предназначена только для указателя на Token Program, десятичного числа и, возможно, еще чего-то. Важно отметить, что эта программа не будет хранить балансы для пользователей — вместо этого пользователи создают свои собственные программы для взаимодействия с этой. Это чуть-чуть сложно, поэтому мы вернемся к этому позже
Последним полем в этом вызове системной программы для создания учетной записи является «владелец», которым в данном случае будет Token Program. Это очень распространенная программа, развернутая в каждой сети Solana (т. е. в основной и тестовой сетях), потому что каждый хочет ссылаться на нее для создания своих собственных токенов
[ 6, 221, 246, 225, 215, 101, 161, 147, 217, 203, 225, 70, 206, 235, 121, 172, 28, 180, 133, 237, 95, 91, 55, 145, 58, 140, 245, 133, 126, 255, 0, 169 ]
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Это адрес программы Token Program
в тестовой сети, которую я использовал (ссылка)
Мы вызвали Create Account
с System Program
при помощи нашего кошелька (7j1NJDkeg35gtRt4nco9fN4wak6M6rD16okMYgvLJeHp
)— это создало новый аккаунт, которым владеет программа, а находится это дело по адресу Hh1E4LwRxAiJdLV4gzKX3BpdbNXJ2AYVdv8UDrfTZAbL
в котором сейчас лежит 1461600 лампортов и он находится под владением TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
(Token Program в тестнете). Эта учетная запись помечена как подписывающая, поскольку ей необходимо выйти при создании собственной области памяти, которая впоследствии будет использоваться для хранения состояния. Однако после этой транзакции закрытый ключ может быть выброшен, поскольку учетная запись принадлежит программе токенов и, следовательно, не может изменять свое собственное состояние
— Instruction #2/5 —
В этой инструкции мы вызываем Token Program напрямую:
programId = 06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9 base58 -> TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Hh1E4LwRxAiJdLV4gzKX3BpdbNXJ2AYVdv8UDrfTZAbL (!signer, writable) SysvarRent111111111111111111111111111111111 (!signer, !writable)
Глядя на комментарии в справочнике InitializeMint:
/// Accounts expected by this instruction: /// 0. `[writable]` The mint to initialize. /// 1. `[]` Rent sysvar
Первый адрес это учетная запись, с которой мы будем «минтить» — та, которую мы создали в предыдущей инструкции. Эта концепция станет яснее позже, но в основном эта учетная запись является (своего рода) экземпляром программы токенов — она описывает токен, который вы создаете. Он будет использоваться для «минта» токенов, которые будут отправлены на другую учетную запись (подробнее об этом позже). Эта учетная запись Mint должна быть доступна для записи в этой инструкции, потому что ее состояние необходимо обновить
Второй адрес это «Rent sysvar» — похоже, он требуется для каких-то низкоуровневых вещей в среде выполнения Solana, и я понятия не имею, почему он включен сюда, за исключением, возможно, разрешения на оплату аренды, но это не кажется важным, так что давайте двигаться дальше
Мы можем посмотреть на API программы Token, чтобы выяснить, как структурирована calldata. Запись Solscan указывает, что это вызывает InitializeMint, о чем свидетельствует первый байт, равный 0, соответствующий 0-му индексу функции в перечислении в API Token Program (который, как я упоминал ранее, является u8, а не u32, потому что это то, чего хотели авторы Token Program)
[ 0, 2, 99, 232, 238, 67, 168, 88, 48, 19, 186, 111, 239, 92, 9, 24, 31, 38, 114, 13, 6, 33, 222, 190, 140, 87, 234, 244, 237, 135, 231, 4, 132, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
Первый 0 — это индекс функции в наборе перечислений API программы. В данном случае это InitializeMint (подробнее тут ТЫК)
Второй байт — 2, это u8, указывающий количество десятичных знаков для нашего токена. Обратите внимание, что должно быть довольно небольшое ограничение на десятичную точность, потому что суммы передачи токенов имеют тип u64, но я не уверен, что это за ограничение и как оно применяется — это все вещи, специфичные для программы
Следующие 32 байта — это mint_authority, это просто учетная запись, которая создает этот минт токенов. Вот это аккаунт моего кошелька 7j1NJDkeg35gtRt4nco9fN4wak6M6rD16okMYgvLJeHp
Последние 32 байта пусты и соответствуют необязательному параметру freeze_authority , который, как я предполагаю, является учетной записью, которая может заморозить передачу этого токена
Мы вызвали InitializeMint из программы токенов, чтобы сообщить, где мы будем минтить токены. В ключах этой инструкции мы ссылались на сторонние программы: на нашу учетную запись mint (созданную в инструкции №1) и SysvarRent. Опять же, понятия не имею, что последняя здесь делает
Мы сообщаем Программе токенов, что наш токен будет иметь 2 десятичных знака и что учетная запись получателя минта токена будет принадлежать моей «авторитетной» учетной записи, которая является моей учетной записью кошелька SOL. Мы также сообщаем, что нет учетной записи, которая может заморозить этот экземпляр токена
— Instruction #3/5 —
Двигаемся дальше… теперь мы создадим еще одну учетную запись с помощью системной программы. Глядя на наши ключи, мы видим, что первый такой же, как и раньше (мой аккаунт кошелька 7j1N..), а второй новый:
HJyjV883iDC3C3vBkqSXiRqCrmFWsk9ER3MFc3KqgF8f
Быстро пробежимся по calldata:
Первые четыре байта снова равны 0. Мы уже рассмотрели это. Мы вызываем CreateAccount (индекс функции 0)
owner
снова TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Итак, мы создали еще одну учетную запись, принадлежащую Token Program, со 165 байтами space
вместо 82 байтов. Если вам интересно, почему для этих двух созданных нами аккаунтов разное соотношение ламппорт/space
(2039280/165 = 12359, 1461600/82 = 17824)… Извините, у меня нет для вас ответа...)
По сути, это было то же самое, что и инструкция №1. Мы создали еще одну учетную запись в HJyjV883iDC3C3vBkqSXiRqCrmFWsk9ER3MFc3KqgF8f но с большим объемом памяти и тем же владельцем. Это показывает, как разные учетные записи, принадлежащие программе, могут взаимодействовать (и обновлять состояние) с различными частями кода программы, поэтому в Solana program:program-owned-account
отношение равно 1:many
— Instruction #4/5 —
Теперь мы собираемся сделать еще один вызов инструкции TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA. На этот раз наша calldata намного короче:
[ 1 ]
Это означает, что мы вызываем функцию по индексу 1, у которой не должно быть аргументов. Эта функция называется InitializeAccount (ТЫК)
Без реальной calldata, суть этой инструкции заключается в том, какие учетные записи передаются. Давайте посмотрим на наши ключи для этой инструкции:
HJyjV883iDC3C3vBkqSXiRqCrmFWsk9ER3MFc3KqgF8f (!signer, writable) Hh1E4LwRxAiJdLV4gzKX3BpdbNXJ2AYVdv8UDrfTZAbL (!signer, !writable) 7j1NJDkeg35gtRt4nco9fN4wak6M6rD16okMYgvLJeHp (!signer, !writable) SysvarRent111111111111111111111111111111111 (!signer, !writable)
Я просто продублирую документацию по Token Program:
/// 0. `[writable]` The account to initialize. /// 1. `[]` The mint this account will be associated with. /// 2. `[]` The new account's owner/multisignature. /// 3. `[]` Rent sysvar
У нас есть новый моментики, связанная с этими учетными записями:
HJyjV883iDC3C3vBkqSXiRqCrmFWsk9ER3MFc3KqgF8f
— вторая созданная нами учетная запись (инструкция 3). Это учетная запись токена, состояние которой мы инициализируем. Он должен быть доступен для записи, чтобы что-то делать с данными состояния. Это учетная запись, которая получит сминченные токеныHh1E4LwRxAiJdLV4gzKX3BpdbNXJ2AYVdv8UDrfTZAbL
— первая созданная нами учетная запись (инструкция 1). Это учетная запись «минта токена», которая содержит информацию об этом экземпляре токена. Мы уже настроили состояние для этой учетной записи в инструкции 27j1NJDkeg35gtRt4nco9fN4wak6M6rD16okMYgvLJeHp
— является владельцем этого удерживающего счета. Лучший способ представить это сейчас — это моя учетная запись SOL. Она может хранить SOL и делать подписи, но не может хранить токены. Для этого мне нужна отдельная учетная запись токена, которую мы инициализируем здесь- Арендная учетная запись sysvar снова здесь. Я до сих пор не знаю почему, но полагаю, что ответы кроются во внутренностях системы Solana, о которых я сейчас не буду беспокоиться
В основном мы просто использовали Token Program для определения учетной записи, для которой мы будем минтить токены, и ссылались на учетную запись минта, которая является другой учетной записью с другой структурой для ее данных о состоянии. На данный момент мы готовы к минту!
— Instruction #5/5 —
В последней инструкции мы вызываем Token Program в последний раз. Наша calldata:
[7, 232, 3, 0, 0, 0, 0, 0, 0]
Мы вызываем функцию № 7, это MintTo (ТЫК). Здесь есть один параметр u64, который называется «amount» — он говорит сам за себя. Мы минтим 1000 единиц токенов, и, поскольку у нас 2 десятичных знака, мы чеканим 10 целых токенов
/// * Single authority /// 0. `[writable]` The mint. /// 1. `[writable]` The account to mint tokens to. /// 2. `[signer]` The mint's minting authority.
Hh1E4LwRxAiJdLV4gzKX3BpdbNXJ2AYVdv8UDrfTZAbL (!signer, writable) HJyjV883iDC3C3vBkqSXiRqCrmFWsk9ER3MFc3KqgF8f (!signer, writable) 7j1NJDkeg35gtRt4nco9fN4wak6M6rD16okMYgvLJeHp (signer, !writable)
Мы подписываемся этот перевод с аккаунта владельца (7j1N..
), затем минтим с нашей учетной записи «минта токенов» Hh1E…
и отправляем эти токены на нашу новую учетную запись «хранения токенов» HJyj…
. Оба они должны быть помечены как доступные для записи в этой инструкции, потому что их данные состояния изменяются
Наконец-то мы это сделали! Мы сминтили 1000 единиц токенов с нашей учетной записи минта и перевели их на нашу учетную запись хранения токенов. На этом этапе мы можем потратить эти токены с нашей удерживающей учетной записи, используя нашу учетную запись SOL в качестве подписывающей стороны, поскольку она была определена как владелец этой удерживающей учетной записи в программном пространстве (инструкция № 4)
— signers —
Я не буду подробно описывать это, но на этом этапе вы берете набор инструкций, метаданных, ключей подписей и т. д. и сериализуете «сообщение». Затем вы хэшируете это сообщение и подписываете его со всех необходимых учетных записей (помните, что при создании любой учетной записи у вас есть ее закрытый ключ). Этот набор ключей подписи можно определить, найдя все уникальные учетные записи, отмеченные параметром isSigner=true хотя бы в одной инструкции. В этом примере подписавшими являются учетные записи спонсора (моя учетная запись SOL), минта и держателя токенов
Часть подписей, приведенных выше, содержит в JSON payload три подписи, связанные с тремя разными адресами:
63e8ee43a8583013ba6fef5c09181f26720d0621debe8c57eaf4ed87e704843b f7fa7a4d4e8dda19a3afbec13a5fb4a540289b869b6a5a46162b7c3e3d9161ab f2560320922ee24d0086e5769e8b3cdf261c646f4f17184532ec7380220b980c
7j1NJDkeg35gtRt4nco9fN4wak6M6rD16okMYgvLJeHp Hh1E4LwRxAiJdLV4gzKX3BpdbNXJ2AYVdv8UDrfTZAbL HJyjV883iDC3C3vBkqSXiRqCrmFWsk9ER3MFc3KqgF8f
Вы уже должны узнать все это. Если вы просматриваете объект JSON, вы должны убедиться, что это полный набор учетных записей, отмеченных isSigner=true, по крайней мере, в инструкции. Также, если вы откроете запись Solscan, то увидите те же самые адреса
Заключение
- Учетные записи «кошелька» на самом деле мало что могут сделать напрямую; они могут хранить SOL, взаимодействовать с программами системного уровня (например, системной программой) и выступать в качестве полномочий для учетных записей, принадлежащих программе (связанных в программном пространстве). В этом примере мы создали учетную запись для хранения токенов, которую программа токенов считает «принадлежащей» моей учетной записи SOL (инструкция № 4) — это то, что я имею в виду под «авторитетом», и эта ссылка существует только в программном пространстве, т. на уровне системы Солана
- Вы должны платить арендную плату за заполнение учетных записей данными, хотя точный процесс на самом деле не раскрывается на уровне транзакции. Арендная плата пропорциональна объему хранилища, занимаемому аккаунтом. Если вы заплатите какую-то произвольную сумму (на 2 года) вперед, ваша программа будет жить вечно. В противном случае она исчезнет, когда больше не сможет платить арендную плату
- Инструкции могут быть объединены в атомарную транзакцию и не должны быть связаны друг с другом. Мы также могли бы добавить инструкцию по переводу SOL на рандомную учетную запись, если бы захотели
- Функции программного уровня индексируются перечислением. Каждая инструкция имеет собственный буфер calldata, первый параметр которого всегда представляет собой целое число без знака, соответствующее индексу вызываемой функции. Как ни странно, это целое число может быть любого размера, которого захочет автор программы (u8-u64)
- Calldata не нужно кодировать с помощью ABI, как в Ethereum, а Solana не использует 256-битные слова, поэтому payloads обычно оказывается довольно коротким
- Среда выполнения Solana, вероятно, более эффективна, чем EVM, но мне кажется, что реальный выигрыш в производительности заключается в том, что вам не нужно ссылаться на самый последний хэш транзакции в вашей транзакции — вам просто нужен один из последних. Это означает, что вы можете распараллелить транзакции, которые не влияют на одно и то же состояние
В целом, архитектура Solana сильно отличается от архитектуры Ethereum. Это, конечно, более запутанно, но я также вижу в этом и преимущества!