Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@ spl-token = "4.0.0"
itertools = "0.13"
tokio-graceful-shutdown = "0.15"
solana-transaction-utils = { version = "0.4.2", path = "./solana-transaction-utils" }
tuktuk-sdk = { version = "0.3.6", path = "./tuktuk-sdk" }
tuktuk-sdk = { version = "0.4.0", path = "./tuktuk-sdk" }
tuktuk-program = { version = "0.3.2", path = "./tuktuk-program" }
solana-account-decoder = { version = "2.2.3" }
solana-clock = { version = "2.2.1" }
solana-transaction-status = "2.2.3"
bincode = { version = "1.3.3" }
async-trait = "0.1.89"

[profile.release]
debug = true
2 changes: 1 addition & 1 deletion tuktuk-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tuktuk-cli"
version = "0.2.13"
version = "0.2.14"
description = "A cli for tuktuk"
homepage.workspace = true
repository.workspace = true
Expand Down
2 changes: 2 additions & 0 deletions tuktuk-cli/src/cmd/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ pub enum Cmd {
async fn simulate_task(client: &CliClient, task_key: Pubkey) -> Result<Option<SimulationResult>> {
// Get the run instruction
let run_ix_res = tuktuk_sdk::compiled_transaction::run_ix(
client.as_ref(),
client.as_ref(),
task_key,
client.payer.pubkey(),
Expand Down Expand Up @@ -598,6 +599,7 @@ impl TaskCmd {
};
for (task_key, _) in tasks {
let run_ix_result = tuktuk_sdk::compiled_transaction::run_ix(
client.as_ref(),
client.as_ref(),
task_key,
client.payer.pubkey(),
Expand Down
3 changes: 2 additions & 1 deletion tuktuk-crank-turner/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tuktuk-crank-turner"
version = "0.2.24"
version = "0.2.25"
authors.workspace = true
edition.workspace = true
license.workspace = true
Expand All @@ -15,6 +15,7 @@ path = "src/main.rs"
[dependencies]
anchor-lang = { workspace = true }
anchor-client = { workspace = true, features = ["async"] }
async-trait = { workspace = true }
bincode = { workspace = true }
solana-sdk = { workspace = true }
tokio = { workspace = true }
Expand Down
13 changes: 13 additions & 0 deletions tuktuk-crank-turner/src/cache/lookup_tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use solana_sdk::{
};
use tokio_graceful_shutdown::SubsystemHandle;
use tracing::info;
use tuktuk_sdk::client::LookupTableResolver;

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

Expand All @@ -26,6 +27,18 @@ impl LookupTablesSender {
}
}

#[async_trait::async_trait]
impl LookupTableResolver for LookupTablesSender {
async fn resolve_lookup_tables(
&self,
lookup_tables: Vec<Pubkey>,
) -> Result<Vec<AddressLookupTableAccount>, tuktuk_sdk::error::Error> {
self.get_lookup_tables(lookup_tables).await.map_err(|_| {
tuktuk_sdk::error::Error::InvalidTransaction("lookup tables channel closed")
})
}
}

pub fn lookup_tables_channel() -> (LookupTablesSender, LookupTablesReceiver) {
let (tx, rx) = sync::message_channel(100);
(tx, rx)
Expand Down
8 changes: 2 additions & 6 deletions tuktuk-crank-turner/src/task_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,6 @@ impl TimedTask {

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

let lookup_tables = ctx
.lookup_tables_client
.get_lookup_tables(task_queue.lookup_tables)
.await
.map_err(|_| anyhow::anyhow!("lookup tables channel closed"))?;
let maybe_next_available = self.get_available_task_ids(ctx.clone()).await;
let next_available = match maybe_next_available {
Ok(next_available) => next_available,
Expand Down Expand Up @@ -163,7 +158,8 @@ impl TimedTask {
&self.task,
payer.pubkey(),
next_available,
lookup_tables,
task_queue.lookup_tables.clone(),
ctx.rpc_client.as_ref(),
)
.await
};
Expand Down
2 changes: 1 addition & 1 deletion tuktuk-program/src/write_return_tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ where
};

let mut total_tasks = 0;
let mut has_unprocessed_tasks = true;
let mut has_unprocessed_tasks: bool;
for AccountWithSeeds { account, seeds } in accounts.iter() {
// Store original size before any reallocation
original_sizes.push(account.data_len());
Expand Down
4 changes: 2 additions & 2 deletions tuktuk-sdk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tuktuk-sdk"
version = "0.3.6"
version = "0.4.0"
authors.workspace = true
edition.workspace = true
license.workspace = true
Expand Down Expand Up @@ -28,12 +28,12 @@ tokio = { workspace = true }
tokio-graceful-shutdown = { workspace = true }
bincode = { workspace = true }
itertools = { workspace = true }
async-trait = { version = "0" }
spl-associated-token-account = { workspace = true }
spl-token = { workspace = true }
tuktuk-program = { workspace = true }
base64 = "0.22.1"
serde_json = "1.0.135"
async-trait = { workspace = true }
bytemuck = "1.21.0"
rand = "0.9"
# For pubsub client
Expand Down
36 changes: 35 additions & 1 deletion tuktuk-sdk/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use anchor_lang::AccountDeserialize;
use futures::{stream, StreamExt, TryFutureExt, TryStreamExt};
use itertools::Itertools;
pub use solana_client::nonblocking::rpc_client::RpcClient as SolanaRpcClient;
use solana_sdk::{account::Account, pubkey::Pubkey};
use solana_sdk::{
account::Account, address_lookup_table::state::AddressLookupTable,
message::AddressLookupTableAccount, pubkey::Pubkey,
};

use crate::error::Error;

Expand Down Expand Up @@ -61,6 +64,37 @@ impl GetAccount for SolanaRpcClient {
}
}

#[async_trait::async_trait]
pub trait LookupTableResolver {
async fn resolve_lookup_tables(
&self,
lookup_tables: Vec<Pubkey>,
) -> Result<Vec<AddressLookupTableAccount>, Error>;
}

#[async_trait::async_trait]
impl LookupTableResolver for SolanaRpcClient {
async fn resolve_lookup_tables(
&self,
lookup_tables: Vec<Pubkey>,
) -> Result<Vec<AddressLookupTableAccount>, Error> {
let accounts = self.get_multiple_accounts(&lookup_tables).await?;
Ok(accounts
.into_iter()
.zip(lookup_tables.iter())
.filter_map(|(maybe_acc, pubkey)| {
maybe_acc.map(|acc| {
let lut = AddressLookupTable::deserialize(&acc.data).map_err(Error::from)?;
Ok(AddressLookupTableAccount {
key: *pubkey,
addresses: lut.addresses.to_vec(),
})
})
})
.collect::<Result<Vec<_>, Error>>()?)
}
}

#[async_trait::async_trait]
impl GetAnchorAccount for SolanaRpcClient {
async fn anchor_account<T: AccountDeserialize>(
Expand Down
54 changes: 35 additions & 19 deletions tuktuk-sdk/src/compiled_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ use bytemuck::{bytes_of, Pod, Zeroable};
use serde::Deserialize;
use solana_client::client_error::reqwest;
use solana_sdk::{
address_lookup_table::{state::AddressLookupTable, AddressLookupTableAccount},
address_lookup_table::AddressLookupTableAccount,
ed25519_instruction::{DATA_START, PUBKEY_SERIALIZED_SIZE, SIGNATURE_SERIALIZED_SIZE},
ed25519_program,
instruction::Instruction,
pubkey::Pubkey,
};
use tuktuk_program::{tuktuk, TaskQueueV0, TaskV0, TransactionSourceV0};

use crate::{client::GetAnchorAccount, error::Error};
use crate::{
client::{GetAnchorAccount, LookupTableResolver},
error::Error,
};

pub fn next_available_task_ids_excluding_in_progress(
capacity: u16,
Expand Down Expand Up @@ -68,7 +71,8 @@ pub async fn run_ix_with_free_tasks(
task: &TaskV0,
payer: Pubkey,
next_available: Vec<u16>,
lookup_tables: Vec<AddressLookupTableAccount>,
lookup_table_pubkeys: Vec<Pubkey>,
lut_resolver: &impl LookupTableResolver,
) -> Result<RunTaskResult, Error> {
let transaction = &task.transaction;

Expand Down Expand Up @@ -125,6 +129,10 @@ pub async fn run_ix_with_free_tasks(
]
.concat();

let lookup_tables = lut_resolver
.resolve_lookup_tables(lookup_table_pubkeys)
.await?;

Ok(RunTaskResult {
instructions: vec![Instruction {
program_id: tuktuk_program::tuktuk::ID,
Expand Down Expand Up @@ -176,6 +184,10 @@ pub async fn run_ix_with_free_tasks(
instruction_data.extend_from_slice(&signature);
instruction_data.extend_from_slice(&message);

// Combine lookup table pubkeys from task queue and remote transaction
let all_lut_pubkeys = [lookup_table_pubkeys, remote_transaction.lookup_tables].concat();
let lookup_tables = lut_resolver.resolve_lookup_tables(all_lut_pubkeys).await?;

Ok(RunTaskResult {
lookup_tables,
instructions: vec![
Expand Down Expand Up @@ -216,6 +228,7 @@ pub async fn run_ix_with_free_tasks(

pub async fn run_ix(
client: &impl GetAnchorAccount,
lut_resolver: &impl LookupTableResolver,
task_key: Pubkey,
payer: Pubkey,
in_progress_task_ids: &HashSet<u16>,
Expand All @@ -239,22 +252,15 @@ pub async fn run_ix(
rand::random_range(0..task_queue.task_bitmap.len()),
)?;

let lookup_tables = client
.accounts(&task_queue.lookup_tables)
.await?
.into_iter()
.filter_map(|(addr, raw)| {
raw.map(|acc| {
let lut = AddressLookupTable::deserialize(&acc.data).map_err(Error::from)?;
Ok::<AddressLookupTableAccount, Error>(AddressLookupTableAccount {
key: addr,
addresses: lut.addresses.to_vec(),
})
})
})
.collect::<Result<Vec<_>, _>>()?;

run_ix_with_free_tasks(task_key, &task, payer, next_available, lookup_tables).await
run_ix_with_free_tasks(
task_key,
&task,
payer,
next_available,
task_queue.lookup_tables.clone(),
lut_resolver,
)
.await
}

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

struct FetchedRemoteResponse {
transaction: Vec<u8>,
remaining_accounts: Vec<AccountMeta>,
signature: Vec<u8>,
lookup_tables: Vec<Pubkey>,
}

async fn fetch_remote_transaction(
Expand Down Expand Up @@ -327,9 +335,17 @@ async fn fetch_remote_transaction(
.decode(&json.signature)
.map_err(Error::from)?;

let lookup_tables = json
.lookup_tables
.unwrap_or_default()
.into_iter()
.map(|key| Pubkey::from_str(&key).map_err(Error::from))
.collect::<Result<Vec<_>, Error>>()?;

Ok(FetchedRemoteResponse {
transaction: transaction_bytes,
remaining_accounts,
signature: signature_bytes,
lookup_tables,
})
}