Skip to content

Commit

Permalink
Fix tx packing and requeue
Browse files Browse the repository at this point in the history
  • Loading branch information
ChewingGlass committed Jan 17, 2025
1 parent 2c8076b commit 8d71496
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 28 deletions.
6 changes: 3 additions & 3 deletions solana-programs/programs/tuktuk/src/utils/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::error::ErrorCode;
/// Verify Ed25519Program instruction and get the data from it
pub fn verify_ed25519_ix(ix: &Instruction, pubkey: &[u8]) -> Result<Vec<u8>> {
if ix.program_id != ED25519_ID {
return Err(ErrorCode::SigVerificationFailed.into());
return Err(error!(ErrorCode::SigVerificationFailed));
}

check_ed25519_data(&ix.data, pubkey)
Expand Down Expand Up @@ -45,12 +45,12 @@ pub fn check_ed25519_data(data: &[u8], pubkey: &[u8]) -> Result<Vec<u8>> {
|| public_key_instruction_index != u16::MAX.to_le_bytes()
|| message_instruction_index != u16::MAX.to_le_bytes()
{
return Err(ErrorCode::SigVerificationFailed.into());
return Err(error!(ErrorCode::SigVerificationFailed));
}

// Arguments
if data_pubkey != pubkey {
return Err(ErrorCode::SigVerificationFailed.into());
return Err(error!(ErrorCode::SigVerificationFailed));
}

Ok(data_msg.to_vec())
Expand Down
50 changes: 29 additions & 21 deletions solana-transaction-utils/src/pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,47 @@ pub fn pack_instructions_into_transactions(
instructions: Vec<Vec<Instruction>>,
payer: &Keypair,
) -> Vec<(Vec<Instruction>, Vec<usize>)> {
// Change return type
let mut transactions = Vec::new();
let compute_ixs = vec![
ComputeBudgetInstruction::set_compute_unit_limit(200000),
ComputeBudgetInstruction::set_compute_unit_price(1),
];
let mut curr_instructions: Vec<Instruction> = compute_ixs.clone();
let mut curr_indices: Vec<usize> = Vec::new(); // Track indices of instructions
let mut ix_queue: Vec<(Instruction, usize)> = instructions
.iter()
.enumerate()
.flat_map(|(i, group)| group.iter().map(move |ix| (ix.clone(), i)))
.collect();
ix_queue.reverse();

while let Some((ix, index)) = ix_queue.pop() {
curr_instructions.push(ix);
curr_indices.push(index);
let tx = Transaction::new_with_payer(&curr_instructions, Some(&payer.pubkey()));
println!("num instructions: {:?}", tx.message.instructions.len() - 2);
let len = bincode::serialize(&tx).unwrap().len();
if len > MAX_TRANSACTION_SIZE {
println!("len: {:?}", len);
ix_queue.push((
curr_instructions.pop().unwrap(),
curr_indices.pop().unwrap(),
));
let mut curr_indices: Vec<usize> = Vec::new();

// Instead of flattening all instructions, process them group by group
for (group_idx, group) in instructions.iter().enumerate() {
// Create a test transaction with current instructions + entire new group
let mut test_instructions = curr_instructions.clone();
test_instructions.extend(group.iter().cloned());
let test_tx = Transaction::new_with_payer(&test_instructions, Some(&payer.pubkey()));
let test_len = bincode::serialize(&test_tx).unwrap().len();

// If adding the entire group would exceed size limit, start a new transaction
// (but only if we already have instructions in the current batch)
if test_len > MAX_TRANSACTION_SIZE && !curr_indices.is_empty() {
transactions.push((curr_instructions.clone(), curr_indices.clone()));
curr_instructions = compute_ixs.clone();
curr_indices.clear();
}

// Add the entire group to current transaction
curr_instructions.extend(group.iter().cloned());
curr_indices.extend(vec![group_idx; group.len()]);

// If this single group alone exceeds transaction size, we have a problem
let tx = Transaction::new_with_payer(&curr_instructions, Some(&payer.pubkey()));
let len = bincode::serialize(&tx).unwrap().len();
if len > MAX_TRANSACTION_SIZE {
// TODO: How do we want to handle this case?
panic!(
"Instruction group {} is too large to fit in a single transaction",
group_idx
);
}
}

// Push final transaction if there are remaining instructions
if !curr_instructions.is_empty() {
transactions.push((curr_instructions.clone(), curr_indices.clone()));
}
Expand Down
2 changes: 1 addition & 1 deletion test-crons.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#! /bin/bash

cargo run -p tuktuk-cli -- -u http://127.0.0.1:8899 -w /Users/noahprince/.config/solana/id.json tuktuk-config create --min-deposit 10
cargo run -p tuktuk-cli -- -u http://127.0.0.1:8899 -w /Users/noahprince/.config/solana/id.json task-queue create --capacity 10 --name Noah --funding-amount 100000000 --min-crank-reward 100000000
cargo run -p tuktuk-cli -- -u http://127.0.0.1:8899 -w /Users/noahprince/.config/solana/id.json task-queue create --capacity 10 --name Noah --funding-amount 100000000 --min-crank-reward 10000
cargo run -p tuktuk-cli -- -u http://127.0.0.1:8899 -w /Users/noahprince/.config/solana/id.json cron create --name Noah --task-queue-name Noah --schedule "0 * * * * *" --free-tasks-per-transaction 0 --funding-amount 1000000000 --num-tasks-per-queue-call 8

cargo run -p tuktuk-cli -- -u http://127.0.0.1:8899 -w /Users/noahprince/.config/solana/id.json cron-transaction create-remote --url http://localhost:3002/remote --signer $(solana address) --cron-name Noah --index 0
Expand Down
12 changes: 9 additions & 3 deletions tuktuk-cli/src/cmd/cron.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ pub enum Cmd {
Requeue {
#[command(flatten)]
cron: CronArg,
#[arg(
long,
help = "Force requeue even if the cron job doesn't think it is removed from queue",
default_value = "false"
)]
force: bool,
},
Close {
#[command(flatten)]
Expand Down Expand Up @@ -152,7 +158,7 @@ impl CronCmd {
task_return_account_1: tuktuk::cron::task_return_account_1_key(
cron_job_key,
),
task_return_account_2: tuktuk::cron::task_return_account_1_key(
task_return_account_2: tuktuk::cron::task_return_account_2_key(
cron_job_key,
),
system_program: solana_sdk::system_program::ID,
Expand Down Expand Up @@ -281,7 +287,7 @@ impl CronCmd {
};
print_json(&serializable)?;
}
Cmd::Requeue { cron } => {
Cmd::Requeue { cron, force } => {
let client = opts.client().await?;
let cron_job_key = cron.get_pubkey(&client).await?.ok_or_else(|| {
anyhow::anyhow!("Must provide cron-name, cron-id, or cron-pubkey")
Expand All @@ -292,7 +298,7 @@ impl CronCmd {
.await?
.ok_or_else(|| anyhow::anyhow!("Cron job not found: {}", cron_job_key))?;

if cron_job.removed_from_queue {
if cron_job.removed_from_queue || *force {
let ix = Self::requeue_cron_job_ix(&client, &cron_job_key).await?;
send_instructions(
client.rpc_client.clone(),
Expand Down

0 comments on commit 8d71496

Please sign in to comment.