Skip to content

Commit 1b5cde6

Browse files
committed
feat: Allow remote servers to return additional LUTs
1 parent 74f1180 commit 1b5cde6

File tree

10 files changed

+94
-30
lines changed

10 files changed

+94
-30
lines changed

Cargo.lock

Lines changed: 3 additions & 2 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
@@ -64,6 +64,7 @@ solana-account-decoder = { version = "2.2.3" }
6464
solana-clock = { version = "2.2.1" }
6565
solana-transaction-status = "2.2.3"
6666
bincode = { version = "1.3.3" }
67+
async-trait = "0.1.89"
6768

6869
[profile.release]
6970
debug = true

tuktuk-cli/src/cmd/task.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ pub enum Cmd {
123123
async fn simulate_task(client: &CliClient, task_key: Pubkey) -> Result<Option<SimulationResult>> {
124124
// Get the run instruction
125125
let run_ix_res = tuktuk_sdk::compiled_transaction::run_ix(
126+
client.as_ref(),
126127
client.as_ref(),
127128
task_key,
128129
client.payer.pubkey(),
@@ -598,6 +599,7 @@ impl TaskCmd {
598599
};
599600
for (task_key, _) in tasks {
600601
let run_ix_result = tuktuk_sdk::compiled_transaction::run_ix(
602+
client.as_ref(),
601603
client.as_ref(),
602604
task_key,
603605
client.payer.pubkey(),

tuktuk-crank-turner/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ path = "src/main.rs"
1515
[dependencies]
1616
anchor-lang = { workspace = true }
1717
anchor-client = { workspace = true, features = ["async"] }
18+
async-trait = { workspace = true }
1819
bincode = { workspace = true }
1920
solana-sdk = { workspace = true }
2021
tokio = { workspace = true }

tuktuk-crank-turner/src/cache/lookup_tables.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use solana_sdk::{
77
};
88
use tokio_graceful_shutdown::SubsystemHandle;
99
use tracing::info;
10+
use tuktuk_sdk::client::LookupTableResolver;
1011

1112
use crate::{cache::LookupTableRequest, sync};
1213

@@ -26,6 +27,18 @@ impl LookupTablesSender {
2627
}
2728
}
2829

30+
#[async_trait::async_trait]
31+
impl LookupTableResolver for LookupTablesSender {
32+
async fn resolve_lookup_tables(
33+
&self,
34+
lookup_tables: Vec<Pubkey>,
35+
) -> Result<Vec<AddressLookupTableAccount>, tuktuk_sdk::error::Error> {
36+
self.get_lookup_tables(lookup_tables).await.map_err(|_| {
37+
tuktuk_sdk::error::Error::InvalidTransaction("lookup tables channel closed")
38+
})
39+
}
40+
}
41+
2942
pub fn lookup_tables_channel() -> (LookupTablesSender, LookupTablesReceiver) {
3043
let (tx, rx) = sync::message_channel(100);
3144
(tx, rx)

tuktuk-crank-turner/src/task_processor.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,6 @@ impl TimedTask {
117117

118118
let task_queue = self.get_task_queue(ctx.clone()).await?;
119119

120-
let lookup_tables = ctx
121-
.lookup_tables_client
122-
.get_lookup_tables(task_queue.lookup_tables)
123-
.await
124-
.map_err(|_| anyhow::anyhow!("lookup tables channel closed"))?;
125120
let maybe_next_available = self.get_available_task_ids(ctx.clone()).await;
126121
let next_available = match maybe_next_available {
127122
Ok(next_available) => next_available,
@@ -163,7 +158,8 @@ impl TimedTask {
163158
&self.task,
164159
payer.pubkey(),
165160
next_available,
166-
lookup_tables,
161+
task_queue.lookup_tables.clone(),
162+
ctx.rpc_client.as_ref(),
167163
)
168164
.await
169165
};

tuktuk-program/src/write_return_tasks.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ where
6868
};
6969

7070
let mut total_tasks = 0;
71-
let mut has_unprocessed_tasks = true;
71+
let mut has_unprocessed_tasks: bool;
7272
for AccountWithSeeds { account, seeds } in accounts.iter() {
7373
// Store original size before any reallocation
7474
original_sizes.push(account.data_len());

tuktuk-sdk/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ tokio = { workspace = true }
2828
tokio-graceful-shutdown = { workspace = true }
2929
bincode = { workspace = true }
3030
itertools = { workspace = true }
31-
async-trait = { version = "0" }
3231
spl-associated-token-account = { workspace = true }
3332
spl-token = { workspace = true }
3433
tuktuk-program = { workspace = true }
3534
base64 = "0.22.1"
3635
serde_json = "1.0.135"
36+
async-trait = { workspace = true }
3737
bytemuck = "1.21.0"
3838
rand = "0.9"
3939
# For pubsub client

tuktuk-sdk/src/client.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use anchor_lang::AccountDeserialize;
44
use futures::{stream, StreamExt, TryFutureExt, TryStreamExt};
55
use itertools::Itertools;
66
pub use solana_client::nonblocking::rpc_client::RpcClient as SolanaRpcClient;
7-
use solana_sdk::{account::Account, pubkey::Pubkey};
7+
use solana_sdk::{
8+
account::Account, address_lookup_table::state::AddressLookupTable,
9+
message::AddressLookupTableAccount, pubkey::Pubkey,
10+
};
811

912
use crate::error::Error;
1013

@@ -61,6 +64,37 @@ impl GetAccount for SolanaRpcClient {
6164
}
6265
}
6366

67+
#[async_trait::async_trait]
68+
pub trait LookupTableResolver {
69+
async fn resolve_lookup_tables(
70+
&self,
71+
lookup_tables: Vec<Pubkey>,
72+
) -> Result<Vec<AddressLookupTableAccount>, Error>;
73+
}
74+
75+
#[async_trait::async_trait]
76+
impl LookupTableResolver for SolanaRpcClient {
77+
async fn resolve_lookup_tables(
78+
&self,
79+
lookup_tables: Vec<Pubkey>,
80+
) -> Result<Vec<AddressLookupTableAccount>, Error> {
81+
let accounts = self.get_multiple_accounts(&lookup_tables).await?;
82+
Ok(accounts
83+
.into_iter()
84+
.zip(lookup_tables.iter())
85+
.filter_map(|(maybe_acc, pubkey)| {
86+
maybe_acc.map(|acc| {
87+
let lut = AddressLookupTable::deserialize(&acc.data).map_err(Error::from)?;
88+
Ok(AddressLookupTableAccount {
89+
key: *pubkey,
90+
addresses: lut.addresses.to_vec(),
91+
})
92+
})
93+
})
94+
.collect::<Result<Vec<_>, Error>>()?)
95+
}
96+
}
97+
6498
#[async_trait::async_trait]
6599
impl GetAnchorAccount for SolanaRpcClient {
66100
async fn anchor_account<T: AccountDeserialize>(

tuktuk-sdk/src/compiled_transaction.rs

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@ use bytemuck::{bytes_of, Pod, Zeroable};
66
use serde::Deserialize;
77
use solana_client::client_error::reqwest;
88
use solana_sdk::{
9-
address_lookup_table::{state::AddressLookupTable, AddressLookupTableAccount},
9+
address_lookup_table::AddressLookupTableAccount,
1010
ed25519_instruction::{DATA_START, PUBKEY_SERIALIZED_SIZE, SIGNATURE_SERIALIZED_SIZE},
1111
ed25519_program,
1212
instruction::Instruction,
1313
pubkey::Pubkey,
1414
};
1515
use tuktuk_program::{tuktuk, TaskQueueV0, TaskV0, TransactionSourceV0};
1616

17-
use crate::{client::GetAnchorAccount, error::Error};
17+
use crate::{
18+
client::{GetAnchorAccount, LookupTableResolver},
19+
error::Error,
20+
};
1821

1922
pub fn next_available_task_ids_excluding_in_progress(
2023
capacity: u16,
@@ -68,7 +71,8 @@ pub async fn run_ix_with_free_tasks(
6871
task: &TaskV0,
6972
payer: Pubkey,
7073
next_available: Vec<u16>,
71-
lookup_tables: Vec<AddressLookupTableAccount>,
74+
lookup_table_pubkeys: Vec<Pubkey>,
75+
lut_resolver: &impl LookupTableResolver,
7276
) -> Result<RunTaskResult, Error> {
7377
let transaction = &task.transaction;
7478

@@ -125,6 +129,10 @@ pub async fn run_ix_with_free_tasks(
125129
]
126130
.concat();
127131

132+
let lookup_tables = lut_resolver
133+
.resolve_lookup_tables(lookup_table_pubkeys)
134+
.await?;
135+
128136
Ok(RunTaskResult {
129137
instructions: vec![Instruction {
130138
program_id: tuktuk_program::tuktuk::ID,
@@ -176,6 +184,10 @@ pub async fn run_ix_with_free_tasks(
176184
instruction_data.extend_from_slice(&signature);
177185
instruction_data.extend_from_slice(&message);
178186

187+
// Combine lookup table pubkeys from task queue and remote transaction
188+
let all_lut_pubkeys = [lookup_table_pubkeys, remote_transaction.lookup_tables].concat();
189+
let lookup_tables = lut_resolver.resolve_lookup_tables(all_lut_pubkeys).await?;
190+
179191
Ok(RunTaskResult {
180192
lookup_tables,
181193
instructions: vec![
@@ -216,6 +228,7 @@ pub async fn run_ix_with_free_tasks(
216228

217229
pub async fn run_ix(
218230
client: &impl GetAnchorAccount,
231+
lut_resolver: &impl LookupTableResolver,
219232
task_key: Pubkey,
220233
payer: Pubkey,
221234
in_progress_task_ids: &HashSet<u16>,
@@ -239,22 +252,15 @@ pub async fn run_ix(
239252
rand::random_range(0..task_queue.task_bitmap.len()),
240253
)?;
241254

242-
let lookup_tables = client
243-
.accounts(&task_queue.lookup_tables)
244-
.await?
245-
.into_iter()
246-
.filter_map(|(addr, raw)| {
247-
raw.map(|acc| {
248-
let lut = AddressLookupTable::deserialize(&acc.data).map_err(Error::from)?;
249-
Ok::<AddressLookupTableAccount, Error>(AddressLookupTableAccount {
250-
key: addr,
251-
addresses: lut.addresses.to_vec(),
252-
})
253-
})
254-
})
255-
.collect::<Result<Vec<_>, _>>()?;
256-
257-
run_ix_with_free_tasks(task_key, &task, payer, next_available, lookup_tables).await
255+
run_ix_with_free_tasks(
256+
task_key,
257+
&task,
258+
payer,
259+
next_available,
260+
task_queue.lookup_tables.clone(),
261+
lut_resolver,
262+
)
263+
.await
258264
}
259265

260266
#[derive(Default, Debug, Copy, Clone, Zeroable, Pod, Eq, PartialEq)]
@@ -281,12 +287,14 @@ struct RemoteResponse {
281287
transaction: String,
282288
remaining_accounts: Vec<RemoteAccountMeta>,
283289
signature: String,
290+
lookup_tables: Option<Vec<String>>,
284291
}
285292

286293
struct FetchedRemoteResponse {
287294
transaction: Vec<u8>,
288295
remaining_accounts: Vec<AccountMeta>,
289296
signature: Vec<u8>,
297+
lookup_tables: Vec<Pubkey>,
290298
}
291299

292300
async fn fetch_remote_transaction(
@@ -327,9 +335,17 @@ async fn fetch_remote_transaction(
327335
.decode(&json.signature)
328336
.map_err(Error::from)?;
329337

338+
let lookup_tables = json
339+
.lookup_tables
340+
.unwrap_or_default()
341+
.into_iter()
342+
.map(|key| Pubkey::from_str(&key).map_err(Error::from))
343+
.collect::<Result<Vec<_>, Error>>()?;
344+
330345
Ok(FetchedRemoteResponse {
331346
transaction: transaction_bytes,
332347
remaining_accounts,
333348
signature: signature_bytes,
349+
lookup_tables,
334350
})
335351
}

0 commit comments

Comments
 (0)