Skip to content

Commit cf51391

Browse files
committed
Add CI, justfile, and switch litesvm to git dep
- Add GitHub Actions CI with lint and test jobs using just commands - Add justfile for local dev (build, test, lint, format) - Switch litesvm from local path to Lightprotocol fork git dep - Apply nightly rustfmt formatting
1 parent 9868c13 commit cf51391

10 files changed

Lines changed: 178 additions & 33 deletions

File tree

.github/workflows/ci.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
env:
14+
SOLANA_CLI_VERSION: "2.2.13"
15+
RUST_TOOLCHAIN: "1.86.0"
16+
17+
jobs:
18+
lint:
19+
name: Lint
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v4
23+
- uses: actions-rust-lang/setup-rust-toolchain@v1
24+
with:
25+
toolchain: ${{ env.RUST_TOOLCHAIN }}
26+
components: clippy
27+
- uses: actions-rust-lang/setup-rust-toolchain@v1
28+
with:
29+
toolchain: nightly
30+
components: rustfmt
31+
- uses: extractions/setup-just@v2
32+
- run: just lint
33+
34+
test:
35+
name: Test
36+
runs-on: ubuntu-latest
37+
steps:
38+
- uses: actions/checkout@v4
39+
- uses: actions-rust-lang/setup-rust-toolchain@v1
40+
with:
41+
toolchain: ${{ env.RUST_TOOLCHAIN }}
42+
- name: Cache Solana CLI tools
43+
uses: actions/cache@v4
44+
with:
45+
path: |
46+
~/.cache/solana/
47+
~/.local/share/solana/
48+
key: solana-cli-${{ runner.os }}-${{ env.SOLANA_CLI_VERSION }}
49+
- name: Install Solana CLI
50+
run: |
51+
sh -c "$(curl -sSfL https://release.anza.xyz/v${{ env.SOLANA_CLI_VERSION }}/install)"
52+
echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH
53+
- uses: extractions/setup-just@v2
54+
- run: just test

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ syn = { version = "2.0", features = ["visit", "visit-mut", "full"] }
3535
darling = "0.21"
3636
heck = "0.5"
3737
sha2 = "0.10"
38-
# LiteSVM local fork + pinned transitive deps to match litesvm 3.0.x
39-
litesvm = { path = "/Users/ananas/dev/litesvm/crates/litesvm" }
38+
# LiteSVM fork + pinned transitive deps to match litesvm 3.0.x
39+
litesvm = { git = "https://github.com/Lightprotocol/litesvm.git", branch = "jorrit/feat-get-program-accounts-v3" }
4040
# Pin litesvm transitive deps to =3.0.5 (litesvm not yet compatible with 3.1.x)
4141
agave-feature-set = "=3.0.5"
4242
agave-reserved-account-keys = "=3.0.5"

justfile

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Instruction Decoder
2+
set dotenv-load
3+
4+
export SBF_OUT_DIR := "target/deploy"
5+
6+
default:
7+
@just --list
8+
9+
# === Build ===
10+
build:
11+
cargo build --workspace
12+
13+
build-sbf:
14+
cd examples/counter && cargo build-sbf
15+
16+
# === Test ===
17+
test: build-sbf
18+
cargo test --workspace
19+
20+
# === Lint & Format ===
21+
lint:
22+
cargo +nightly fmt --all -- --check
23+
cargo clippy --workspace \
24+
--no-deps \
25+
-- -A unexpected-cfgs \
26+
-D warnings
27+
28+
format:
29+
cargo +nightly fmt --all
30+
31+
# === Clean ===
32+
clean:
33+
cargo clean
34+
35+
# === Info ===
36+
info:
37+
@echo "Solana: $(solana --version)"
38+
@echo "Rust: $(rustc --version)"

light-instruction-decoder/src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ pub use formatter::{Colors, TransactionFormatter};
5252
#[cfg(not(target_os = "solana"))]
5353
pub use programs::{
5454
AccountCompressionInstructionDecoder, CTokenInstructionDecoder,
55-
ComputeBudgetInstructionDecoder, LightSystemInstructionDecoder,
56-
RegistryInstructionDecoder, SplTokenInstructionDecoder, SystemInstructionDecoder,
57-
Token2022InstructionDecoder,
55+
ComputeBudgetInstructionDecoder, LightSystemInstructionDecoder, RegistryInstructionDecoder,
56+
SplTokenInstructionDecoder, SystemInstructionDecoder, Token2022InstructionDecoder,
5857
};
5958
// Re-export registry
6059
#[cfg(not(target_os = "solana"))]

light-instruction-decoder/src/programs/light_system.rs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
// Allow the macro-generated code to reference types from this crate
1414
extern crate self as light_instruction_decoder;
1515

16-
use borsh::BorshDeserialize;
1716
use crate::programs::light_types::{
18-
InstructionDataInvoke, InstructionDataInvokeCpi,
17+
CompressedAccountInfo, InAccount, InstructionDataInvoke, InstructionDataInvokeCpi,
1918
InstructionDataInvokeCpiWithAccountInfo, InstructionDataInvokeCpiWithReadOnly,
19+
NewAddressParamsAssignedPacked, NewAddressParamsPacked,
2020
OutputCompressedAccountWithPackedContext, PackedCompressedAccountWithMerkleContext,
21-
NewAddressParamsPacked, NewAddressParamsAssignedPacked, PackedReadOnlyAddress,
22-
CompressedAccountInfo, InAccount,
21+
PackedReadOnlyAddress,
2322
};
23+
use borsh::BorshDeserialize;
2424
use light_instruction_decoder_derive::InstructionDecoder;
2525
use solana_instruction::AccountMeta;
2626
use solana_pubkey::Pubkey;
@@ -565,9 +565,24 @@ pub fn resolve_invoke_cpi_readonly_account_names(
565565
// Normal Mode: Fixed LightSystemAccounts (6 accounts)
566566
add_name("fee_payer", accounts, &mut idx, &mut known_pubkeys);
567567
add_name("authority", accounts, &mut idx, &mut known_pubkeys);
568-
add_name("registered_program_pda", accounts, &mut idx, &mut known_pubkeys);
569-
add_name("account_compression_authority", accounts, &mut idx, &mut known_pubkeys);
570-
add_name("account_compression_program", accounts, &mut idx, &mut known_pubkeys);
568+
add_name(
569+
"registered_program_pda",
570+
accounts,
571+
&mut idx,
572+
&mut known_pubkeys,
573+
);
574+
add_name(
575+
"account_compression_authority",
576+
accounts,
577+
&mut idx,
578+
&mut known_pubkeys,
579+
);
580+
add_name(
581+
"account_compression_program",
582+
accounts,
583+
&mut idx,
584+
&mut known_pubkeys,
585+
);
571586
add_name("system_program", accounts, &mut idx, &mut known_pubkeys);
572587

573588
names
@@ -650,9 +665,24 @@ pub fn resolve_invoke_cpi_account_info_account_names(
650665
// Normal Mode: Fixed LightSystemAccounts (6 accounts)
651666
add_name("fee_payer", accounts, &mut idx, &mut known_pubkeys);
652667
add_name("authority", accounts, &mut idx, &mut known_pubkeys);
653-
add_name("registered_program_pda", accounts, &mut idx, &mut known_pubkeys);
654-
add_name("account_compression_authority", accounts, &mut idx, &mut known_pubkeys);
655-
add_name("account_compression_program", accounts, &mut idx, &mut known_pubkeys);
668+
add_name(
669+
"registered_program_pda",
670+
accounts,
671+
&mut idx,
672+
&mut known_pubkeys,
673+
);
674+
add_name(
675+
"account_compression_authority",
676+
accounts,
677+
&mut idx,
678+
&mut known_pubkeys,
679+
);
680+
add_name(
681+
"account_compression_program",
682+
accounts,
683+
&mut idx,
684+
&mut known_pubkeys,
685+
);
656686
add_name("system_program", accounts, &mut idx, &mut known_pubkeys);
657687

658688
names

light-instruction-decoder/src/programs/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ pub mod light_token;
2727
pub mod registry;
2828

2929
pub use account_compression::AccountCompressionInstructionDecoder;
30-
pub use light_token::CTokenInstructionDecoder;
3130
pub use light_system::LightSystemInstructionDecoder;
31+
pub use light_token::CTokenInstructionDecoder;
3232
pub use registry::RegistryInstructionDecoder;

tests/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,11 @@ fn transaction_log_to_snapshot(log: &EnhancedTransactionLog) -> TransactionSnaps
143143
status: log.status.text(),
144144
fee: log.fee,
145145
compute_used: log.compute_used,
146-
instructions: log.instructions.iter().map(instruction_to_snapshot).collect(),
146+
instructions: log
147+
.instructions
148+
.iter()
149+
.map(instruction_to_snapshot)
150+
.collect(),
147151
}
148152
}
149153

@@ -231,8 +235,7 @@ fn parse_inner_instructions(
231235

232236
let mut ix_log = EnhancedInstructionLog::new(inner_idx, program_id, program_name);
233237
ix_log.data = inner_ix.instruction.data.clone();
234-
ix_log.accounts =
235-
resolve_accounts(&inner_ix.instruction.accounts, account_keys, message);
238+
ix_log.accounts = resolve_accounts(&inner_ix.instruction.accounts, account_keys, message);
236239

237240
// stack_height 1 = top-level, 2 = direct CPI child, 3+ = deeper nesting
238241
let depth = (inner_ix.stack_height as usize).saturating_sub(1);

tests/tests/counter_program.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,25 @@ fn setup() -> (LiteSVM, Keypair) {
1919
let program_bytes = include_bytes!("../../target/deploy/counter.so");
2020
let _ = svm.add_program(COUNTER_PROGRAM_ID, program_bytes);
2121
let payer = deterministic_keypair(10);
22-
svm.airdrop(&payer.pubkey(), 10 * LAMPORTS_PER_SOL)
23-
.unwrap();
22+
svm.airdrop(&payer.pubkey(), 10 * LAMPORTS_PER_SOL).unwrap();
2423
(svm, payer)
2524
}
2625

2726
/// Build an Anchor instruction: 8-byte discriminator + borsh-serialized args
28-
fn anchor_ix(program_id: &Pubkey, discriminator: &[u8; 8], data: &[u8], accounts: Vec<solana_instruction::AccountMeta>) -> solana_instruction::Instruction {
27+
fn anchor_ix(
28+
program_id: &Pubkey,
29+
discriminator: &[u8; 8],
30+
data: &[u8],
31+
accounts: Vec<solana_instruction::AccountMeta>,
32+
) -> solana_instruction::Instruction {
2933
let mut ix_data = discriminator.to_vec();
3034
ix_data.extend_from_slice(data);
3135
solana_instruction::Instruction::new_with_bytes(*program_id, &ix_data, accounts)
3236
}
3337

3438
/// Compute Anchor discriminator: sha256("global:<name>")[..8]
3539
fn anchor_discriminator(name: &str) -> [u8; 8] {
36-
use sha2::{Sha256, Digest};
40+
use sha2::{Digest, Sha256};
3741
let mut hasher = Sha256::new();
3842
hasher.update(format!("global:{name}").as_bytes());
3943
let hash = hasher.finalize();
@@ -56,7 +60,10 @@ fn test_decode_initialize() {
5660
vec![
5761
solana_instruction::AccountMeta::new(counter.pubkey(), true),
5862
solana_instruction::AccountMeta::new(payer.pubkey(), true),
59-
solana_instruction::AccountMeta::new_readonly(solana_pubkey::pubkey!("11111111111111111111111111111111"), false),
63+
solana_instruction::AccountMeta::new_readonly(
64+
solana_pubkey::pubkey!("11111111111111111111111111111111"),
65+
false,
66+
),
6067
],
6168
);
6269

@@ -94,12 +101,18 @@ fn test_decode_increment_and_set() {
94101
vec![
95102
solana_instruction::AccountMeta::new(counter.pubkey(), true),
96103
solana_instruction::AccountMeta::new(payer.pubkey(), true),
97-
solana_instruction::AccountMeta::new_readonly(solana_pubkey::pubkey!("11111111111111111111111111111111"), false),
104+
solana_instruction::AccountMeta::new_readonly(
105+
solana_pubkey::pubkey!("11111111111111111111111111111111"),
106+
false,
107+
),
98108
],
99109
);
100110
let msg = Message::new(&[init_ix], Some(&payer.pubkey()));
101111
let tx = Transaction::new(&[&payer, &counter], msg, svm.latest_blockhash());
102-
svm.send_transaction(solana_transaction::versioned::VersionedTransaction::from(tx)).unwrap();
112+
svm.send_transaction(solana_transaction::versioned::VersionedTransaction::from(
113+
tx,
114+
))
115+
.unwrap();
103116

104117
// Increment
105118
let inc_ix = anchor_ix(
@@ -180,8 +193,10 @@ fn test_decode_configure() {
180193
);
181194
let msg = Message::new(&[init_ix], Some(&payer.pubkey()));
182195
let tx = Transaction::new(&[&payer, &counter], msg, svm.latest_blockhash());
183-
svm.send_transaction(solana_transaction::versioned::VersionedTransaction::from(tx))
184-
.unwrap();
196+
svm.send_transaction(solana_transaction::versioned::VersionedTransaction::from(
197+
tx,
198+
))
199+
.unwrap();
185200

186201
// Build configure instruction data:
187202
// new_value: u64, multiplier: u16, enabled: bool, label: [u8; 32], nonce: u64
@@ -243,9 +258,15 @@ fn test_decode_configure() {
243258

244259
// Verify decoded fields
245260
let fields = snapshot.instructions[0].decoded_fields.as_ref().unwrap();
246-
assert!(fields.iter().any(|f| f.name == "new_value" && f.value == "999"));
247-
assert!(fields.iter().any(|f| f.name == "multiplier" && f.value == "7"));
248-
assert!(fields.iter().any(|f| f.name == "nonce" && f.value == "12345"));
261+
assert!(fields
262+
.iter()
263+
.any(|f| f.name == "new_value" && f.value == "999"));
264+
assert!(fields
265+
.iter()
266+
.any(|f| f.name == "multiplier" && f.value == "7"));
267+
assert!(fields
268+
.iter()
269+
.any(|f| f.name == "nonce" && f.value == "12345"));
249270

250271
insta::assert_json_snapshot!("counter_configure", snapshot);
251272
}

tests/tests/system_program.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ fn deterministic_keypair(seed_byte: u8) -> Keypair {
1717
fn setup() -> (LiteSVM, Keypair) {
1818
let mut svm = LiteSVM::new();
1919
let payer = deterministic_keypair(1);
20-
svm.airdrop(&payer.pubkey(), 10 * LAMPORTS_PER_SOL)
21-
.unwrap();
20+
svm.airdrop(&payer.pubkey(), 10 * LAMPORTS_PER_SOL).unwrap();
2221
(svm, payer)
2322
}
2423

0 commit comments

Comments
 (0)