3

I know that deploy a solana program will send many transactions because each tx has a limited size, most transactions are just for uploading program codes.

So I tried to copy program code on chain, but it doesn't work:

first

  1. deploy a program A, the program data account of A contains all executable codes
  2. deploy a helper program, it will do copy(src_account, dst_account, data_len)

then try to build a single tx to deploy a new program

  1. create a buffer account, assign to helper program
  2. in helper program, copy all program A's codes to newly created buffer account
  3. set BPFLoader to be owner of buffer account (FAILED)
  4. create new program account
  5. call deployMaxLen to deploy new program

sadly, I failed at step 5, we can only assign an all-zeroed account to another program.

So I want to know is it possible to deploy a program in only one tx? no matter what the program contents are

1 Answer 1

2

Yes you can do that.

Program deploy is split into 3 phases.

  1. create buffer account.
  2. Bunch of transactions (1232 max size) to fill the buffer
  3. Transfer the buffer account to the executable data of the program using the bpf loader program instruction deploy_with_max_program_len.

You can see exactly what is happening here:

https://github.com/anza-xyz/agave/blob/master/cli/src/program.rs#L2421

To pass the buffer account to the loader programm you need to call an instruction on the program because only the program can change PDAs it owns:

let instructions = bpf_loader_upgradeable::deploy_with_max_program_len(
            &fee_payer_signer.pubkey(),
            &program_signers[0].pubkey(),
            buffer_pubkey,
            &program_signers[1].pubkey(),
            rpc_client
                .get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::size_of_program())?,
            program_data_max_len,
        )?
        .with_compute_unit_config(&ComputeUnitConfig {
            compute_unit_price,
            compute_unit_limit,
        });

To do what you want to do. You basically need to decouple the uploading part from the write buffer part.

As a funny side note you can also have a program that is smaller than 1232 bytes and deploy that in one transaction: This one for example only has 973 bytes ;) https://github.com/solana-developers/cu_optimizations/blob/main/counterC/counter/src/lib.rs

4
  • in deploy_with_max_program_len, bpf_loader requires buffer account is writeable, so the owner of buffer account must be bpf_loader, failed at the question step 5 again.
    – OneMOre14
    Commented Oct 30 at 11:48
  • you would need to use bpf_loader_upgradeable::create_buffer and bpf_loader_upgradeable::write
    – Jonas H.
    Commented Oct 30 at 14:04
  • 1
    I have tried it before, actually you can't invoke bpf_loader_upgradeable::write by CPI, so if the program data is large, still have to spilt into many transactions. But, thanks for your link to cu_optimizations, I found a small program with only 300+ bytes
    – OneMOre14
    Commented Oct 30 at 15:27
  • Oh i didnt know you cant CPI it. :-/
    – Jonas H.
    Commented Oct 30 at 17:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.