Skip to content

Commit 924289d

Browse files
add fetch_accounts, wip
1 parent fd560b2 commit 924289d

File tree

13 files changed

+330
-3
lines changed

13 files changed

+330
-3
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ members = [
5353
"sdk-tests/anchor-compressible",
5454
"sdk-tests/anchor-compressible-derived",
5555
"sdk-tests/native-compressible",
56+
"fetch-accounts",
5657
]
5758

5859
resolver = "2"

cli/accounts/test_batched_cpi_context_7Hp52chxaew8bW1ApR4fck2bh6Y8qA1pu3qwH6N9zaLj.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

fetch-accounts/Cargo.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "fetch_accounts"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[[bin]]
7+
name = "fetch_test"
8+
path = "src/main.rs"
9+
10+
[[bin]]
11+
name = "fetch_rpc"
12+
path = "src/main_rpc.rs"
13+
14+
[dependencies]
15+
solana-sdk = "2.2"
16+
solana-client = "2.2"
17+
solana-rpc-client = "2.2"
18+
solana-rpc-client-api = "2.2"
19+
light-client = { path = "../sdk-libs/client" }
20+
light-program-test = { path = "../sdk-libs/program-test", features = ["devenv"] }
21+
tokio = { version = "1.45.1", features = ["rt", "macros", "rt-multi-thread"] }
22+
base64 = "0.22"
23+
serde_json = "1.0"

fetch-accounts/README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Account Fetcher Scripts
2+
3+
Two standalone Rust scripts to fetch Solana accounts and save them as JSON files.
4+
5+
## Building
6+
7+
```bash
8+
cd fetch_accounts
9+
cargo build --release
10+
```
11+
12+
## Usage
13+
14+
### 1. Test Environment Fetcher (`fetch_test`)
15+
16+
This script uses the Light Protocol test environment to fetch accounts from test state trees:
17+
18+
```bash
19+
cargo run --bin fetch_test
20+
```
21+
22+
Or after building:
23+
24+
```bash
25+
./target/release/fetch_test
26+
```
27+
28+
This will:
29+
30+
- Initialize a test environment
31+
- Get all state tree infos
32+
- Fetch accounts from the first two trees' cpi_context addresses
33+
- Save them as JSON files in the current directory
34+
35+
### 2. RPC Fetcher (`fetch_rpc`)
36+
37+
This script fetches accounts from a live Solana RPC endpoint:
38+
39+
```bash
40+
# Using default localhost:8899
41+
cargo run --bin fetch_rpc <address1> <address2> ...
42+
43+
# Using custom RPC endpoint
44+
RPC_URL=https://api.mainnet-beta.solana.com cargo run --bin fetch_rpc <address1> <address2> ...
45+
```
46+
47+
Example:
48+
49+
```bash
50+
cargo run --bin fetch_rpc 11111111111111111111111111111111 TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
51+
```
52+
53+
## Output Format
54+
55+
Both scripts save accounts in the following JSON format:
56+
57+
```json
58+
{
59+
"pubkey": "...",
60+
"account": {
61+
"lamports": 1000000,
62+
"data": ["base64_encoded_data", "base64"],
63+
"owner": "...",
64+
"executable": false,
65+
"rentEpoch": 0,
66+
"space": 165
67+
}
68+
}
69+
```
70+
71+
## Notes
72+
73+
- The test fetcher (`fetch_test`) requires the Light Protocol development environment
74+
- The RPC fetcher (`fetch_rpc`) can connect to any Solana RPC endpoint
75+
- JSON files are saved in the current working directory

fetch-accounts/src/main.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use base64::encode;
2+
use light_client::indexer::Indexer;
3+
use light_program_test::{LightProgramTest, ProgramTestConfig, Rpc};
4+
use serde_json::json;
5+
use solana_sdk::pubkey::Pubkey;
6+
use std::fs::File;
7+
use std::io::Write;
8+
9+
#[tokio::main]
10+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
11+
println!("Starting to fetch accounts...");
12+
13+
// Initialize test environment
14+
// You can adjust the config based on your needs
15+
let config = ProgramTestConfig::new_v2(false, None);
16+
let rpc = LightProgramTest::new(config).await?;
17+
18+
// Get tree infos
19+
let tree_infos = rpc.get_state_tree_infos();
20+
println!("Found {} tree infos", tree_infos.len());
21+
22+
// Get a random state tree info
23+
let random_info = rpc.get_random_state_tree_info();
24+
match random_info {
25+
Ok(info) => println!("Random info: {:?}", info),
26+
Err(e) => println!("Error getting random info: {:?}", e),
27+
}
28+
29+
// Check if we have at least 2 tree infos
30+
if tree_infos.len() < 2 {
31+
println!("Warning: Less than 2 tree infos available");
32+
return Ok(());
33+
}
34+
35+
// Get the cpi_context addresses
36+
let address_0 = tree_infos[0]
37+
.cpi_context
38+
.ok_or("No cpi_context for tree_info[0]")?;
39+
let address_1 = tree_infos[1]
40+
.cpi_context
41+
.ok_or("No cpi_context for tree_info[1]")?;
42+
43+
println!("Address 0: {}", address_0);
44+
println!("Address 1: {}", address_1);
45+
46+
// Fetch accounts
47+
let account_0 = rpc
48+
.get_account(address_0)
49+
.await?
50+
.ok_or("Account 0 not found")?;
51+
let account_1 = rpc
52+
.get_account(address_1)
53+
.await?
54+
.ok_or("Account 1 not found")?;
55+
56+
println!("Fetched account_0: {} bytes", account_0.data.len());
57+
println!("Fetched account_1: {} bytes", account_1.data.len());
58+
59+
// Write accounts to JSON files
60+
write_account_json(
61+
&account_0,
62+
&address_0,
63+
&format!("test_batched_cpi_context_{}.json", address_0),
64+
)?;
65+
write_account_json(
66+
&account_1,
67+
&address_1,
68+
&format!("test_batched_cpi_context_{}.json", address_1),
69+
)?;
70+
71+
println!("Successfully wrote account JSON files");
72+
println!("Account 0 details: lamports={}, owner={}, executable={}, data_len={}",
73+
account_0.lamports, account_0.owner, account_0.executable, account_0.data.len());
74+
println!("Account 1 details: lamports={}, owner={}, executable={}, data_len={}",
75+
account_1.lamports, account_1.owner, account_1.executable, account_1.data.len());
76+
77+
Ok(())
78+
}
79+
80+
fn write_account_json(
81+
account: &solana_sdk::account::Account,
82+
pubkey: &Pubkey,
83+
filename: &str,
84+
) -> Result<(), Box<dyn std::error::Error>> {
85+
let data_base64 = encode(&account.data);
86+
let json_obj = json!({
87+
"pubkey": pubkey.to_string(),
88+
"account": {
89+
"lamports": account.lamports,
90+
"data": [data_base64, "base64"],
91+
"owner": account.owner.to_string(),
92+
"executable": account.executable,
93+
"rentEpoch": account.rent_epoch,
94+
"space": account.data.len(),
95+
}
96+
});
97+
98+
let mut file = File::create(filename)?;
99+
file.write_all(json_obj.to_string().as_bytes())?;
100+
101+
Ok(())
102+
}

fetch-accounts/src/main_rpc.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use base64::encode;
2+
use serde_json::json;
3+
use solana_client::rpc_client::RpcClient;
4+
use solana_sdk::pubkey::Pubkey;
5+
use std::fs::File;
6+
use std::io::Write;
7+
use std::str::FromStr;
8+
9+
fn main() -> Result<(), Box<dyn std::error::Error>> {
10+
// Configure these based on your needs
11+
let rpc_url = std::env::var("RPC_URL").unwrap_or_else(|_| "http://localhost:8899".to_string());
12+
13+
// Replace these with actual addresses you want to fetch
14+
// You can pass them as command line arguments or environment variables
15+
let addresses: Vec<&str> = vec![
16+
// Add your addresses here, e.g.:
17+
// "11111111111111111111111111111111",
18+
// "22222222222222222222222222222222",
19+
];
20+
21+
if addresses.is_empty() {
22+
println!("Please add addresses to fetch in the source code or pass them as arguments");
23+
println!("Usage: cargo run --bin fetch_rpc <address1> <address2> ...");
24+
25+
// Check for command line arguments
26+
let args: Vec<String> = std::env::args().collect();
27+
if args.len() > 1 {
28+
fetch_accounts_from_args(&rpc_url, &args[1..])?;
29+
}
30+
return Ok(());
31+
}
32+
33+
let client = RpcClient::new(rpc_url.clone());
34+
println!("Connected to RPC: {}", rpc_url);
35+
36+
for address_str in addresses {
37+
fetch_and_save_account(&client, address_str)?;
38+
}
39+
40+
Ok(())
41+
}
42+
43+
fn fetch_accounts_from_args(rpc_url: &str, addresses: &[String]) -> Result<(), Box<dyn std::error::Error>> {
44+
let client = RpcClient::new(rpc_url.to_string());
45+
println!("Connected to RPC: {}", rpc_url);
46+
47+
for address_str in addresses {
48+
fetch_and_save_account(&client, address_str)?;
49+
}
50+
51+
Ok(())
52+
}
53+
54+
fn fetch_and_save_account(client: &RpcClient, address_str: &str) -> Result<(), Box<dyn std::error::Error>> {
55+
let pubkey = Pubkey::from_str(address_str)?;
56+
println!("Fetching account: {}", pubkey);
57+
58+
match client.get_account(&pubkey) {
59+
Ok(account) => {
60+
println!("Fetched account: {} bytes", account.data.len());
61+
62+
let filename = format!("account_{}.json", pubkey);
63+
write_account_json(&account, &pubkey, &filename)?;
64+
65+
println!("Saved to: {}", filename);
66+
println!(" Lamports: {}", account.lamports);
67+
println!(" Owner: {}", account.owner);
68+
println!(" Executable: {}", account.executable);
69+
println!(" Data length: {}", account.data.len());
70+
println!();
71+
}
72+
Err(e) => {
73+
println!("Error fetching account {}: {:?}", pubkey, e);
74+
}
75+
}
76+
77+
Ok(())
78+
}
79+
80+
fn write_account_json(
81+
account: &solana_sdk::account::Account,
82+
pubkey: &Pubkey,
83+
filename: &str,
84+
) -> Result<(), Box<dyn std::error::Error>> {
85+
let data_base64 = encode(&account.data);
86+
let json_obj = json!({
87+
"pubkey": pubkey.to_string(),
88+
"account": {
89+
"lamports": account.lamports,
90+
"data": [data_base64, "base64"],
91+
"owner": account.owner.to_string(),
92+
"executable": account.executable,
93+
"rentEpoch": account.rent_epoch,
94+
"space": account.data.len(),
95+
}
96+
});
97+
98+
let mut file = File::create(filename)?;
99+
file.write_all(json_obj.to_string().as_bytes())?;
100+
101+
Ok(())
102+
}

fetch-accounts/test_batched_cpi_context_HwtjxDvFEXiWnzeMeWkMBzpQN45A95rTJNZmz1Z3pe8R.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

js/stateless.js/src/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,8 @@ export const cpiContext2Pubkey = 'cpi2cdhkH5roePvcudTgUL8ppEBfTay1desGh8G8QxK';
258258
// V2 testing.
259259
export const batchMerkleTree = 'HLKs5NJ8FXkJg8BrzJt56adFYYuwg5etzDtBbQYTsixu'; // v2 merkle tree (includes nullifier queue)
260260
export const batchQueue = '6L7SzhYB3anwEQ9cphpJ1U7Scwj57bx2xueReg7R9cKU'; // v2 output queue
261-
// export const batchCpiContext = '7Hp52chxaew8bW1ApR4fck2bh6Y8qA1pu3qwH6N9zaLj';
262-
export const batchCpiContext = 'HwtjxDvFEXiWnzeMeWkMBzpQN45A95rTJNZmz1Z3pe8R';
261+
export const batchCpiContext = '7Hp52chxaew8bW1ApR4fck2bh6Y8qA1pu3qwH6N9zaLj';
262+
// export const batchCpiContext = 'HwtjxDvFEXiWnzeMeWkMBzpQN45A95rTJNZmz1Z3pe8R';
263263
export const confirmConfig: ConfirmOptions = {
264264
commitment: 'confirmed',
265265
preflightCommitment: 'confirmed',

program-tests/sdk-token-test/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ light-sdk = { workspace = true }
4040
light-compressed-account = { workspace = true, features = ["anchor"] }
4141
light-client = { workspace = true, features = ["devenv"] }
4242
light-token-client = { workspace = true }
43+
base64 = { workspace = true }
44+
serde_json = { workspace = true }
4345

4446
[lints.rust.unexpected_cfgs]
4547
level = "allow"

0 commit comments

Comments
 (0)