Тестові набори Solana, що запускають solana-test-validator, витрачають секунди на кожен тест —
ви очікуєте запуску процесу, RPC-з'єднань і мережевих запитів.
LiteSVM виконує ті самі тести за мілісекунди. Жодних зовнішніх процесів, жодної мережі —
усе в пам'яті всередині вашого тест-ранера.
litesvm-go — це офіційне прив'язання для Go. Основні типи (PublicKey, Hash,
Signature) беруться безпосередньо з
gagliardetto/solana-go, тому значення
природно передаються між litesvm-go і рештою екосистеми Go Solana.
Вимоги: Go 1.24+. Інструментальний ланцюжок Rust не потрібен — попередньо зібрані статичні
архіви вендоруються в модулі та автоматично вибираються за GOOS /
GOARCH. Підтримувані платформи: macOS (amd64, arm64), Linux (amd64, arm64;
glibc або musl), Windows (amd64).
Новий дескриптор LiteSVM надає доступ до аірдропів, транзакцій (legacy + v0),
симуляції, читання/запису акаунтів, sysvar-ів, бюджету обчислень, feature gates, переміщення в часі,
кастомних програм і історії транзакцій — усе на основі того самого ядра Rust,
яке живить SDK для Rust і TypeScript.
Швидкий старт
Встановлення модуля
go get розв'язує залежності в Go-модуль, тому спочатку ініціалізуйте його, якщо у вас ще немає go.mod:
go mod init mytest
Потім додайте модуль:
go get github.com/LiteSVM/litesvm-go
Також підключіть solana-go для роботи з keypair, інструкціями та побудовою транзакцій:
go get github.com/gagliardetto/solana-go
Користувачі Alpine / musl: додайте -tags musl до виклику go build / go test,
щоб підключився правильний вендорований архів.
Створення вашого SVM
package mytestimport ("testing"litesvm "github.com/LiteSVM/litesvm-go"solana "github.com/gagliardetto/solana-go")func TestSetup(t *testing.T) {svm, err := litesvm.New()if err != nil {t.Fatal(err)}defer svm.Close()// Fund a payerpriv, err := solana.NewRandomPrivateKey()if err != nil {t.Fatal(err)}payer := priv.PublicKey()if err := svm.Airdrop(payer, 5_000_000_000); err != nil {t.Fatal(err)}// Check the balancelamports, ok, err := svm.Balance(payer)if err != nil {t.Fatal(err)}if !ok {t.Fatal("payer account missing")}t.Logf("balance: %d lamports", lamports)}
litesvm.New() повертає *LiteSVM і error. Кожна точка входу в
litesvm-go дотримується однієї форми (value, error); паніки на стороні Rust
перехоплюються і перетворюються на помилки. Завжди використовуйте defer svm.Close(), щоб
звільнити дескриптор Rust — або покладайтеся на фіналайзер, хоча явний
Close є кращим варіантом для передбачуваного очищення ресурсів.
Розуміння дескриптора
Після litesvm.New() повернутий *LiteSVM надає такі групи можливостей:
| Група | Методи |
|---|---|
| Акаунти | Airdrop, Balance, GetAccount, SetAccount, MinimumBalanceForRentExemption |
| Транзакції | SendLegacyTransaction, SendVersionedTransaction, SimulateLegacyTransaction, SimulateVersionedTransaction, GetTransaction |
| Блокхеш | LatestBlockhash, ExpireBlockhash |
| Програми | AddProgram, AddProgramFromFile, AddProgramWithLoader |
| Час і sysvar-и | WarpToSlot, Clock, SetClock, Rent, SetRent, EpochSchedule, SetEpochSchedule, EpochRewards, ... |
| Конфігурація | SetSigverify, SetBlockhashCheck, SetTransactionHistory, SetLogBytesLimit, SetSysvars, SetBuiltins, ... |
| Обчислення та функції | ComputeBudget, SetComputeBudget, SetFeatureSet |
Новий LiteSVM постачається з попередньо завантаженими основними програмами Solana (System Program, SPL
Token тощо), тому прості перекази працюють одразу після налаштування.
Надсилання транзакцій
Будуйте інструкції за допомогою solana-go, серіалізуйте транзакцію та надсилайте
байти. litesvm-go приймає байти в кодуванні bincode, що їх створює
(*solana.Transaction).MarshalBinary:
package mytestimport ("testing"litesvm "github.com/LiteSVM/litesvm-go"solana "github.com/gagliardetto/solana-go""github.com/gagliardetto/solana-go/programs/system")func TestTransfer(t *testing.T) {svm, err := litesvm.New()if err != nil {t.Fatal(err)}defer svm.Close()priv, err := solana.NewRandomPrivateKey()if err != nil {t.Fatal(err)}payer := priv.PublicKey()recipient := solana.NewWallet().PublicKey()if err := svm.Airdrop(payer, 2_000_000_000); err != nil {t.Fatal(err)}blockhash, err := svm.LatestBlockhash()if err != nil {t.Fatal(err)}ix := system.NewTransferInstruction(1_000_000_000, payer, recipient).Build()tx, err := solana.NewTransaction([]solana.Instruction{ix},blockhash,solana.TransactionPayer(payer),)if err != nil {t.Fatal(err)}if _, err := tx.Sign(func(k solana.PublicKey) *solana.PrivateKey {if k.Equals(payer) {return &priv}return nil}); err != nil {t.Fatal(err)}txBytes, err := tx.MarshalBinary()if err != nil {t.Fatal(err)}out, err := svm.SendLegacyTransaction(txBytes)if err != nil {t.Fatal(err)}defer out.Close()if !out.IsOk() {t.Fatalf("tx failed: %s\nlogs: %v", out.Error(), out.Logs())}lamports, _, err := svm.Balance(recipient)if err != nil {t.Fatal(err)}if lamports != 1_000_000_000 {t.Fatalf("recipient balance = %d, want 1_000_000_000", lamports)}}
SendLegacyTransaction і SendVersionedTransaction обидва повертають
*TxOutcome незалежно від того, чи транзакція успішна, чи ні. Викликайте IsOk() перед
зверненням до полів, доступних лише при успіху, і завжди використовуйте defer out.Close() для звільнення
дескриптора Rust.
Робота з TxOutcome
Кожна точка входу send / simulate повертає *TxOutcome. Той самий дескриптор
містить метадані як для успіху, так і для помилки:
out, err := svm.SendLegacyTransaction(txBytes)if err != nil {t.Fatal(err)}defer out.Close()if !out.IsOk() {t.Fatalf("error: %s", out.Error())}_ = out.Signature() // solana.Signature_ = out.ComputeUnits() // uint64_ = out.Fee() // uint64_ = out.Logs() // []string_ = out.InnerInstructions()// Programs that call set_return_data expose it here.if pid, data, ok := out.ReturnData(); ok {_ = pid_ = data}
Для SimulateLegacyTransaction / SimulateVersionedTransaction той самий
*TxOutcome додатково надає PostAccounts() — стан акаунтів після гіпотетичного виконання:
sim, err := svm.SimulateLegacyTransaction(txBytes)if err != nil {t.Fatal(err)}defer sim.Close()posts, err := sim.PostAccounts()if err != nil {t.Fatal(err)}for _, p := range posts {_ = p.Address_ = p.Account.Lamports()p.Account.Close()}
Конфігурація
litesvm-go надає ті самі перемикачі конструктора, що й крейт Rust, у вигляді
методів Set*:
// Each setter returns an error. In tests where the values are known good,// the calls are infallible and assigning to _ keeps the example readable;// in production code, check the error or wrap with require.NoError(t, ...)._ = svm.SetSigverify(false) // accept unsigned / badly-signed txs_ = svm.SetBlockhashCheck(false) // skip recent-blockhash enforcement_ = svm.SetTransactionHistory(0) // 0 disables dedup; any N caps history_ = svm.SetLogBytesLimit(-1) // negative = unlimited_ = svm.SetLamports(1 << 40) // default lamports for new accounts_ = svm.SetSysvars() // reset sysvars to defaults_ = svm.SetBuiltins() // reload built-in programs_ = svm.SetDefaultPrograms() // reload SPL Token, Memo, etc._ = svm.SetPrecompiles() // enable ed25519 / secp256k1 precompiles_ = svm.WithNativeMints() // seed wrapped-SOL mint
Примітки
Безпека потоків. Дескриптор *LiteSVM не є безпечним для одночасного використання з
кількох горутин (базовий тип Rust не є Sync, і більшість методів
змінюють внутрішній стан). Обмежуйте дескриптор однією горутиною або захищайте його за допомогою
sync.Mutex.
Поведінка при паніці. Вендоровані архіви релізів зібрані з immediate-abort:
будь-яка паніка в Rust одразу завершує хост-процес без розмотування стека. Це
навмисний компроміс заради менших архівів. Якщо ви колись натрапите на таке на практиці,
будь ласка, відкрийте issue з відтворювачем.
Що далі
Це охоплює основний дескриптор — створення акаунтів, надсилання інструкцій і читання стану. Для повного довідника методів дивіться документацію API. Для виконуваних прикладів (переказ SOL, налаштування акаунтів, тестування програм, логіка на основі часу) дивіться Приклади.
Is this page helpful?