Is there any way to increase compute unit in building on-chain program of Solana

2.1k Views Asked by At

I crashed with error of exceeding maximum unit of compute units while developing on-chain program of Solana. Is there any way to increase maximum compute unit?

3

There are 3 best solutions below

0
Jon C On

If you're using solana-program-test to test your application, you can set higher or lower compute units using set_compute_max_units(), ie:

use solana_program_test::ProgramTest;
use crate::id;
use crate::processor::process_instruction;

let mut pt = ProgramTest::new("my_program", id(), processor!(process_instruction));
pt.set_compute_max_units(5_000_000);

Full example at https://github.com/solana-labs/solana-program-library/blob/78e29e9238e555967b9125799d7d420d7d12b959/token/program/tests/assert_instruction_count.rs#L24

For solana-test-validator, this isn't supported for now, but PRs are welcome!

0
Frank C. On

The SDK for version 1.9.2 and greater does have changes for upping (or lowering) Compute Budget and Heap Size. In the solana repo in sdk/src/compute_budget.rs https://github.com/solana-labs/solana/blob/master/sdk/src/compute_budget.rs#L35

This should work for local testing but not yet enabled for devnet, mainnet-beta, etc.

The way it works is to create a request_units Instruction and put at the first instruction in the transaction:

/// Submits the program instruction as per the
/// instruction definition
fn submit_transaction(
    rpc_client: &RpcClient,
    wallet_signer: &dyn Signer,
    instructions: Vec<Instruction>,
) -> Result<Signature, Box<dyn std::error::Error>> {
    let mut transaction =
        Transaction::new_unsigned(Message::new(&instructions, Some(&wallet_signer.pubkey())));
    let recent_blockhash = rpc_client
        .get_latest_blockhash()
        .map_err(|err| format!("error: unable to get recent blockhash: {}", err))?;
    transaction
        .try_sign(&vec![wallet_signer], recent_blockhash)
        .map_err(|err| format!("error: failed to sign transaction: {}", err))?;

    let signature = rpc_client
        .send_and_confirm_transaction(&transaction)
        .map_err(|err| format!("error: send transaction: {}", err))?;
    Ok(signature)
}

/// 
fn foo() {
    // Other details omitted
    let accounts = &[];
    let instruction = Instruction::new_with_borsh(PROG_KEY, &0u8, accounts.to_vec());
    let bump_budget = ComputeBudgetInstruction::request_units(400_000u32);
    let txn = submit_transaction(
        &connection,
        &main_payer,
        [bump_budget, instruction.clone(), instruction.clone()].to_vec(),
    );

Notice in the log output that there is a drawdown for each instruction in rows 3 and 7:

[2022-02-05T09:08:49.715294000Z DEBUG solana_runtime::message_processor::stable_log] Program PWDnx8LkjJUn9bAVzG6Fp6BuvB41x7DkBZdo9YLMGcc invoke [1]
[2022-02-05T09:08:49.715522000Z DEBUG solana_runtime::message_processor::stable_log] Program log: process_instruction: PWDnx8LkjJUn9bAVzG6Fp6BuvB41x7DkBZdo9YLMGcc: 0 accounts, data=[0]
[2022-02-05T09:08:49.715551000Z DEBUG solana_runtime::message_processor::stable_log] Program PWDnx8LkjJUn9bAVzG6Fp6BuvB41x7DkBZdo9YLMGcc consumed 12843 of 400000 compute units
[2022-02-05T09:08:49.715675000Z DEBUG solana_runtime::message_processor::stable_log] Program PWDnx8LkjJUn9bAVzG6Fp6BuvB41x7DkBZdo9YLMGcc success
[2022-02-05T09:08:49.723680000Z DEBUG solana_runtime::message_processor::stable_log] Program PWDnx8LkjJUn9bAVzG6Fp6BuvB41x7DkBZdo9YLMGcc invoke [1]
[2022-02-05T09:08:49.723818000Z DEBUG solana_runtime::message_processor::stable_log] Program log: process_instruction: PWDnx8LkjJUn9bAVzG6Fp6BuvB41x7DkBZdo9YLMGcc: 0 accounts, data=[0]
[2022-02-05T09:08:49.723837000Z DEBUG solana_runtime::message_processor::stable_log] Program PWDnx8LkjJUn9bAVzG6Fp6BuvB41x7DkBZdo9YLMGcc consumed 12843 of 387157 compute units
[2022-02-05T09:08:49.724017000Z DEBUG solana_runtime::message_processor::stable_log] Program PWDnx8LkjJUn9bAVzG6Fp6BuvB41x7DkBZdo9YLMGcc success
0
Lorenzo Ampil On

You can refer to this tutorial from Solana Cookbook.

Note that you'll have to make the first instruction the one that sets the budget.

Sample snippet for Typescript:

const data = Buffer.from(
  Uint8Array.of(0, ...new BN(256000).toArray("le", 4))
);
const additionalComputeBudgetInstruction = new TransactionInstruction({
  keys: [],
  programId: new PublicKey("ComputeBudget111111111111111111111111111111"),
  data,
});
const transaction = new Transaction()
  .add(additionalComputeBudgetInstruction);