1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
//! ## 📍 Overview
//!
//! `hpsvm` is a fast and lightweight library for testing Solana programs.
//! It works by creating an in-process Solana VM optimized for program developers.
//! This makes it much faster to run and compile than alternatives like `solana-program-test` and
//! `solana-test-validator`. In a further break from tradition, it has an ergonomic API with sane
//! defaults and extensive configurability for those who want it.
//!
//! ### 🤖 Minimal Example
//!
//! ```rust
//! use hpsvm::HPSVM;
//! use solana_address::Address;
//! use solana_keypair::Keypair;
//! use solana_message::Message;
//! use solana_signer::Signer;
//! use solana_system_interface::instruction::transfer;
//! use solana_transaction::Transaction;
//!
//! let from_keypair = Keypair::new();
//! let from = from_keypair.pubkey();
//! let to = Address::new_unique();
//!
//! let mut svm = HPSVM::new();
//! svm.airdrop(&from, 1_000_000_000).unwrap();
//! svm.airdrop(&to, 1_000_000_000).unwrap();
//!
//! let instruction = transfer(&from, &to, 64);
//! let tx = Transaction::new(
//! &[&from_keypair],
//! Message::new(&[instruction], Some(&from)),
//! svm.latest_blockhash(),
//! );
//! let tx_res = svm.send_transaction(tx).unwrap();
//!
//! let from_account = svm.get_account(&from);
//! let to_account = svm.get_account(&to);
//! assert_eq!(from_account.unwrap().lamports, 999994936);
//! assert_eq!(to_account.unwrap().lamports, 1000000064);
//! ```
//!
//! ## Deploying Programs
//!
//! Most of the time we want to do more than just mess around with token transfers -
//! we want to test our own programs.
//!
//! Tip**: if you want to pull a Solana program from mainnet or devnet, use the `solana program
//! dump` command from the Solana CLI.
//!
//! To add a compiled program to our tests we can use
//! [`.add_program_from_file`](HPSVM::add_program_from_file).
//!
//! Here's an example using a [simple program](https://github.com/solana-labs/solana-program-library/tree/bd216c8103cd8eb9f5f32e742973e7afb52f3b81/examples/rust/logging)
//! from the Solana Program Library that just does some logging:
//!
//! ```rust
//! use hpsvm::HPSVM;
//! use solana_address::{Address, address};
//! use solana_instruction::{Instruction, account_meta::AccountMeta};
//! use solana_keypair::Keypair;
//! use solana_message::{Message, VersionedMessage};
//! use solana_signer::Signer;
//! use solana_transaction::versioned::VersionedTransaction;
//!
//! fn test_logging() {
//! let program_id = address!("Logging111111111111111111111111111111111111");
//! let account_meta =
//! AccountMeta { pubkey: Address::new_unique(), is_signer: false, is_writable: true };
//! let ix = Instruction {
//! program_id,
//! accounts: vec![account_meta],
//! data: vec![5, 10, 11, 12, 13, 14],
//! };
//! let mut svm = HPSVM::new();
//! let payer = Keypair::new();
//! let bytes = include_bytes!("../test_programs/target/deploy/counter.so");
//! svm.add_program(program_id, &bytes[..]);
//! svm.airdrop(&payer.pubkey(), 1_000_000_000).unwrap();
//! let blockhash = svm.latest_blockhash();
//! let msg = Message::new_with_blockhash(&[ix], Some(&payer.pubkey()), &blockhash);
//! let tx = VersionedTransaction::try_new(VersionedMessage::Legacy(msg), &[&payer]).unwrap();
//! // Let's simulate it first
//! let sim_res = svm.simulate_transaction(tx.clone()).unwrap();
//! let meta = svm.send_transaction(tx).unwrap();
//! assert_eq!(sim_res.meta, meta);
//! // The program should log something
//! assert!(meta.logs.len() > 1);
//! assert!(meta.compute_units_consumed < 10_000); // not being precise here in case it changes
//! }
//! ```
//!
//! ## Time travel
//!
//! Many programs rely on the `Clock` sysvar: for example, a mint that doesn't become available
//! until after a certain time. With `hpsvm` you can dynamically overwrite the `Clock` sysvar
//! using [`svm.set_sysvar::<Clock>()`](HPSVM::set_sysvar).
//! Here's an example using a program that panics if `clock.unix_timestamp` is greater than 100
//! (which is on January 1st 1970):
//!
//! ```rust
//! use hpsvm::HPSVM;
//! use solana_address::Address;
//! use solana_clock::Clock;
//! use solana_instruction::Instruction;
//! use solana_keypair::Keypair;
//! use solana_message::{Message, VersionedMessage};
//! use solana_signer::Signer;
//! use solana_transaction::versioned::VersionedTransaction;
//!
//! fn test_set_clock() {
//! let program_id = Address::new_unique();
//! let mut svm = HPSVM::new();
//! let bytes = include_bytes!("../test_programs/target/deploy/hpsvm_clock_example.so");
//! svm.add_program(program_id, &bytes[..]);
//! let payer = Keypair::new();
//! let payer_address = payer.pubkey();
//! svm.airdrop(&payer.pubkey(), 1_000_000_000).unwrap();
//! let blockhash = svm.latest_blockhash();
//! let ixs = [Instruction { program_id, data: vec![], accounts: vec![] }];
//! let msg = Message::new_with_blockhash(&ixs, Some(&payer_address), &blockhash);
//! let versioned_msg = VersionedMessage::Legacy(msg);
//! let tx = VersionedTransaction::try_new(versioned_msg, &[&payer]).unwrap();
//! // Set the time to January 1st 2000
//! let mut initial_clock = svm.get_sysvar::<Clock>();
//! initial_clock.unix_timestamp = 1735689600;
//! svm.set_sysvar::<Clock>(&initial_clock).expect("clock sysvar override should succeed");
//! // This will fail because the program expects early 1970 timestamp
//! let _err = svm.send_transaction(tx.clone()).unwrap_err();
//! // So let's turn back time
//! let mut clock = svm.get_sysvar::<Clock>();
//! clock.unix_timestamp = 50;
//! svm.set_sysvar::<Clock>(&clock).expect("clock sysvar override should succeed");
//! let ixs2 = [Instruction {
//! program_id,
//! data: vec![1], // unused, this is just to dedup the transaction
//! accounts: vec![],
//! }];
//! let msg2 = Message::new_with_blockhash(&ixs2, Some(&payer_address), &blockhash);
//! let versioned_msg2 = VersionedMessage::Legacy(msg2);
//! let tx2 = VersionedTransaction::try_new(versioned_msg2, &[&payer]).unwrap();
//! // Now the transaction goes through
//! svm.send_transaction(tx2).unwrap();
//! }
//! ```
//!
//! See also: [`warp_to_slot`](HPSVM::warp_to_slot), which lets you jump to a future slot.
//!
//! ## Writing arbitrary accounts
//!
//! HPSVM lets you write any account data you want, regardless of
//! whether the account state would even be possible.
//!
//! Here's an example where we give an account a bunch of USDC,
//! even though we don't have the USDC mint keypair. This is
//! convenient for testing because it means we don't have to
//! work with fake USDC in our tests:
//!
//! ```rust
//! use hpsvm::HPSVM;
//! use solana_account::Account;
//! use solana_address::{Address, address};
//! use solana_program_option::COption;
//! use solana_program_pack::Pack;
//! use spl_associated_token_account_interface::address::get_associated_token_address;
//! use spl_token_interface::{
//! ID as TOKEN_PROGRAM_ID,
//! state::{Account as TokenAccount, AccountState},
//! };
//!
//! fn test_infinite_usdc_mint() {
//! let owner = Address::new_unique();
//! let usdc_mint = address!("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
//! let ata = get_associated_token_address(&owner, &usdc_mint);
//! let usdc_to_own = 1_000_000_000_000;
//! let token_acc = TokenAccount {
//! mint: usdc_mint,
//! owner,
//! amount: usdc_to_own,
//! delegate: COption::None,
//! state: AccountState::Initialized,
//! is_native: COption::None,
//! delegated_amount: 0,
//! close_authority: COption::None,
//! };
//! let mut svm = HPSVM::new();
//! let mut token_acc_bytes = [0u8; TokenAccount::LEN];
//! TokenAccount::pack(token_acc, &mut token_acc_bytes).unwrap();
//! svm.set_account(
//! ata,
//! Account {
//! lamports: 1_000_000_000,
//! data: token_acc_bytes.to_vec(),
//! owner: TOKEN_PROGRAM_ID,
//! executable: false,
//! rent_epoch: 0,
//! },
//! )
//! .unwrap();
//! let raw_account = svm.get_account(&ata).unwrap();
//! assert_eq!(TokenAccount::unpack(&raw_account.data).unwrap().amount, usdc_to_own)
//! }
//! ```
//!
//! ## Copying Accounts from a live environment
//!
//! If you want to copy accounts from mainnet or devnet, you can use the `solana account` command in
//! the Solana CLI to save account data to a file.
//!
//! ## Register tracing
//!
//! `hpsvm` can be instantiated with the capability to provide register tracing
//! data from processed transactions. This functionality is gated behind the
//! `register-tracing` feature flag, which in turn relies on the
//! `invocation-inspect-callback` flag. To enable it, users can either
//! construct `hpsvm` with the `HPSVM::new_debuggable` initializer - allowing
//! register tracing to be configured directly - or simply set the `SBF_TRACE_DIR`
//! environment variable, which `hpsvm` interprets as a signal to turn tracing on
//! upon instantiation. The latter allows users to take advantage of the
//! functionality without actually doing any changes to their code.
//!
//! A default post-instruction callback is provided for storing the
//! register tracing data in files. It persists the register sets,
//! the SBPF instructions, and a SHA-256 hash identifying the executable that
//! was used to generate the tracing data. If the `SBF_TRACE_DISASSEMBLE`
//! environment variable is set, a disassembled register trace will also be
//! produced for each collected register trace. The motivation behind providing the
//! SHA-256 identifier is that files may grow in number, and consumers need a
//! deterministic way to evaluate which shared object should be used when
//! analyzing the tracing data.
//!
//! Once enabled register tracing can't be changed afterwards because in nature
//! it's baked into the program executables at load time. Yet a user may want a
//! more fine-grained control over when register tracing data should be
//! collected - for example, only for a specific instruction. Such control could
//! be achieved by resetting the invocation callback to
//! `EmptyInvocationInspectCallback` and later by restoring it to
//! `DefaultRegisterTracingCallback`.
//!
//! ## Other features
//!
//! Other things you can do with `hpsvm` include:
//!
//! Changing the max compute units and other compute budget behaviour during construction with
//! [`HPSVM::builder`](HPSVM::builder) or later via [`HPSVM::set_compute_budget`]. Disable
//! transaction signature checking during construction with the builder or later via
//! [`HPSVM::set_sigverify`]. Find previous transactions using
//! [`.get_transaction`](`HPSVM::get_transaction`).
//!
//! ## When should I use `solana-test-validator`?
//!
//! While `hpsvm` is faster and more convenient, it is also less like a real RPC node.
//! So `solana-test-validator` is still useful when you need to call RPC methods that HPSVM
//! doesn't support, or when you want to test something that depends on real-life validator
//! behaviour rather than just testing your program and client code.
//!
//! In general though it is recommended to use `hpsvm` wherever possible, as it will make your life
//! much easier.
use ;
use ReservedAccountKeys;
use BuiltinFunctionRegisterer;
pub use crate*;
use crate::;
pub use hotpath_block;
/// A registered custom syscall paired with its loader function.
pub
/// Transaction batch planning and parallel execution.
/// Error types for the HPSVM.
/// RPC-backed account source for forking live cluster state.
/// Solana instruction types and helpers.
/// Loader v3 helpers (set_upgrade_authority, deploy_upgradeable_program).
/// SPL token operation helpers (transfer, mint, ATA, freeze, etc.).
/// Public return types and execution metadata.
/// Core `HPSVM` construction, account/sysvar state, and transaction API.
pub use ;
pub use AccountsView;
pub use ;
pub use ;
pub use ;
// Re-export crate-internal items at the root so child modules can reference
// them as `crate::X` (descendant modules can read root-private items, but the
// names must resolve via the crate root).
pub use crate;
pub use crateHPSVMError;
static NEXT_VM_INSTANCE_ID: AtomicU64 = new;
pub
/// The core Solana Virtual Machine simulator.
///
/// HPSVM manages account state, program execution, and transaction processing
/// in a deterministic, single-threaded environment.
use InvokeContext;
use SanitizedTransaction;
use IndexOfAccount;
;