Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit 41eb7ec

Browse files
mergify[bot]Tyera Eulbergjstarry
authored
Support jsonParsed address lookup table accounts (backport #26723) (#28134)
* Support jsonParsed address lookup table accounts (#26723) Parse address lookup table accounts (cherry picked from commit 80527e9) # Conflicts: # account-decoder/Cargo.toml * resolve conflicts Co-authored-by: Tyera Eulberg <[email protected]> Co-authored-by: Justin Starry <[email protected]>
1 parent 9e9f778 commit 41eb7ec

File tree

6 files changed

+131
-0
lines changed

6 files changed

+131
-0
lines changed

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.

account-decoder/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ lazy_static = "1.4.0"
1919
serde = "1.0.138"
2020
serde_derive = "1.0.103"
2121
serde_json = "1.0.81"
22+
solana-address-lookup-table-program = { path = "../programs/address-lookup-table", version = "=1.14.4" }
2223
solana-config-program = { path = "../programs/config", version = "=1.14.4" }
2324
solana-sdk = { path = "../sdk", version = "=1.14.4" }
2425
solana-vote-program = { path = "../programs/vote", version = "=1.14.4" }

account-decoder/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ extern crate lazy_static;
55
extern crate serde_derive;
66

77
pub mod parse_account_data;
8+
pub mod parse_address_lookup_table;
89
pub mod parse_bpf_loader;
910
pub mod parse_config;
1011
pub mod parse_nonce;

account-decoder/src/parse_account_data.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use {
22
crate::{
3+
parse_address_lookup_table::parse_address_lookup_table,
34
parse_bpf_loader::parse_bpf_upgradeable_loader,
45
parse_config::parse_config,
56
parse_nonce::parse_nonce,
@@ -16,6 +17,7 @@ use {
1617
};
1718

1819
lazy_static! {
20+
static ref ADDRESS_LOOKUP_PROGRAM_ID: Pubkey = solana_address_lookup_table_program::id();
1921
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
2022
static ref CONFIG_PROGRAM_ID: Pubkey = solana_config_program::id();
2123
static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id();
@@ -24,6 +26,10 @@ lazy_static! {
2426
static ref VOTE_PROGRAM_ID: Pubkey = solana_vote_program::id();
2527
pub static ref PARSABLE_PROGRAM_IDS: HashMap<Pubkey, ParsableAccount> = {
2628
let mut m = HashMap::new();
29+
m.insert(
30+
*ADDRESS_LOOKUP_PROGRAM_ID,
31+
ParsableAccount::AddressLookupTable,
32+
);
2733
m.insert(
2834
*BPF_UPGRADEABLE_LOADER_PROGRAM_ID,
2935
ParsableAccount::BpfUpgradeableLoader,
@@ -68,6 +74,7 @@ pub struct ParsedAccount {
6874
#[derive(Debug, Serialize, Deserialize)]
6975
#[serde(rename_all = "camelCase")]
7076
pub enum ParsableAccount {
77+
AddressLookupTable,
7178
BpfUpgradeableLoader,
7279
Config,
7380
Nonce,
@@ -94,6 +101,9 @@ pub fn parse_account_data(
94101
.ok_or(ParseAccountError::ProgramNotParsable)?;
95102
let additional_data = additional_data.unwrap_or_default();
96103
let parsed_json = match program_name {
104+
ParsableAccount::AddressLookupTable => {
105+
serde_json::to_value(parse_address_lookup_table(data)?)?
106+
}
97107
ParsableAccount::BpfUpgradeableLoader => {
98108
serde_json::to_value(parse_bpf_upgradeable_loader(data)?)?
99109
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use {
2+
crate::parse_account_data::{ParsableAccount, ParseAccountError},
3+
solana_address_lookup_table_program::state::AddressLookupTable,
4+
solana_sdk::instruction::InstructionError,
5+
};
6+
7+
pub fn parse_address_lookup_table(
8+
data: &[u8],
9+
) -> Result<LookupTableAccountType, ParseAccountError> {
10+
AddressLookupTable::deserialize(data)
11+
.map(|address_lookup_table| {
12+
LookupTableAccountType::LookupTable(address_lookup_table.into())
13+
})
14+
.or_else(|err| match err {
15+
InstructionError::UninitializedAccount => Ok(LookupTableAccountType::Uninitialized),
16+
_ => Err(ParseAccountError::AccountNotParsable(
17+
ParsableAccount::AddressLookupTable,
18+
)),
19+
})
20+
}
21+
22+
#[derive(Debug, Serialize, Deserialize, PartialEq)]
23+
#[serde(rename_all = "camelCase", tag = "type", content = "info")]
24+
pub enum LookupTableAccountType {
25+
Uninitialized,
26+
LookupTable(UiLookupTable),
27+
}
28+
29+
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
30+
#[serde(rename_all = "camelCase")]
31+
pub struct UiLookupTable {
32+
pub deactivation_slot: String,
33+
pub last_extended_slot: String,
34+
pub last_extended_slot_start_index: u8,
35+
#[serde(skip_serializing_if = "Option::is_none")]
36+
pub authority: Option<String>,
37+
pub addresses: Vec<String>,
38+
}
39+
40+
impl<'a> From<AddressLookupTable<'a>> for UiLookupTable {
41+
fn from(address_lookup_table: AddressLookupTable) -> Self {
42+
Self {
43+
deactivation_slot: address_lookup_table.meta.deactivation_slot.to_string(),
44+
last_extended_slot: address_lookup_table.meta.last_extended_slot.to_string(),
45+
last_extended_slot_start_index: address_lookup_table
46+
.meta
47+
.last_extended_slot_start_index,
48+
authority: address_lookup_table
49+
.meta
50+
.authority
51+
.map(|authority| authority.to_string()),
52+
addresses: address_lookup_table
53+
.addresses
54+
.iter()
55+
.map(|address| address.to_string())
56+
.collect(),
57+
}
58+
}
59+
}
60+
61+
#[cfg(test)]
62+
mod test {
63+
use {
64+
super::*,
65+
solana_address_lookup_table_program::state::{LookupTableMeta, LOOKUP_TABLE_META_SIZE},
66+
solana_sdk::pubkey::Pubkey,
67+
std::borrow::Cow,
68+
};
69+
70+
#[test]
71+
fn test_parse_address_lookup_table() {
72+
let authority = Pubkey::new_unique();
73+
let deactivation_slot = 1;
74+
let last_extended_slot = 2;
75+
let last_extended_slot_start_index = 3;
76+
let lookup_table_meta = LookupTableMeta {
77+
deactivation_slot,
78+
last_extended_slot,
79+
last_extended_slot_start_index,
80+
authority: Some(authority),
81+
..LookupTableMeta::default()
82+
};
83+
let num_addresses = 42;
84+
let mut addresses = Vec::with_capacity(num_addresses);
85+
addresses.resize_with(num_addresses, Pubkey::new_unique);
86+
let lookup_table = AddressLookupTable {
87+
meta: lookup_table_meta,
88+
addresses: Cow::Owned(addresses),
89+
};
90+
let lookup_table_data =
91+
AddressLookupTable::serialize_for_tests(lookup_table.clone()).unwrap();
92+
93+
let parsing_result = parse_address_lookup_table(&lookup_table_data).unwrap();
94+
if let LookupTableAccountType::LookupTable(ui_lookup_table) = parsing_result {
95+
assert_eq!(
96+
ui_lookup_table.deactivation_slot,
97+
deactivation_slot.to_string()
98+
);
99+
assert_eq!(
100+
ui_lookup_table.last_extended_slot,
101+
last_extended_slot.to_string()
102+
);
103+
assert_eq!(
104+
ui_lookup_table.last_extended_slot_start_index,
105+
last_extended_slot_start_index
106+
);
107+
assert_eq!(ui_lookup_table.authority, Some(authority.to_string()));
108+
assert_eq!(ui_lookup_table.addresses.len(), num_addresses);
109+
}
110+
111+
assert_eq!(
112+
parse_address_lookup_table(&[0u8; LOOKUP_TABLE_META_SIZE]).unwrap(),
113+
LookupTableAccountType::Uninitialized
114+
);
115+
assert!(parse_address_lookup_table(&[]).is_err());
116+
}
117+
}

programs/bpf/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.

0 commit comments

Comments
 (0)