Deploy Program
\
编译
Cargo.toml 记得添加
[lib]
crate-type = ["cdylib", "lib"]
表示我们需要编译出一个 bpf lib。
cargo build-sbf 👈 旧版本的 build-bpf 会链接过来,但是似乎有点小问题,目前工具链的名字有点混乱。
每个工程都要下超多 dependence,所以最好不要在小分区上搞多个项目的编译。
命令会输出在 ./build/deploy/ 目录下输出两个文件 :
- suniswap.so : 要部署的 bpf so
- suniswap-keypair.json :如果不指定 --program-id ,则会在同级目录找 -keypair.json 文件作为 program-id 的 keypair。
部署
直接部署到 devnet:
solana program deploy -u d --program-id keys/program.json target/deploy/suniswap.so
log里显示发了 77 个 tx(主要还是因为单个tx的大小限制 the max size limit of 1232 bytes for Solana transactions ),部署过程有点复杂,而且耗费的sol巨大。program id 对应的 account 在 program depoly的过程中会被标记为特殊类型的 account。
具体部署过程,参考 program cli 的实现,主要是与 BPF Loader BPFLoaderUpgradeab1e11111111111111111111111 这个 native program的交互过程:
- 除了输入的 program-id keypair 外,还需要在最开始随机生成一个
buffer_keypair作为缓冲区使用,create_ephemeral_keypair,在加载完所需要的 pubkey 和 program 字节码之后,进入主要部署函数do_process_program_write_and_deploy - 首先 create account 一个足够大的 account,It also invokes the initialize buffer instruction to set the buffer authority to restrict writes to the deployer's chosen address. 之后将作为部署的
Buffer使用:
bpf_loader_upgradeable::create_buffer(
&fee_payer_signer.pubkey(),
buffer_pubkey,
&buffer_authority_signer.pubkey(),
min_rent_exempt_program_data_balance,
program_len, 👈 和程序大小一样大的buffer
)?,
a. 其实直接把 buffer account assign 给 BPF Loader就可以,主要是为了 BPF loader有写权限。
-
Buffer writes: Once the buffer account is initialized, the CLI breaks up the program byte-code into ~1KB chunks and sends transactions at a rate of 100 transactions per second to write each chunk with the write buffer instruction. These transactions are sent directly to the current leader's transaction processing (TPU) port and are processed in parallel with each other. Once all transactions have been sent, the CLI polls the RPC API with batches of transaction signatures to ensure that every write was successful and confirmed.
- IX:
UpgradeableLoaderInstruction::Write
- IX:
-
Finalization: Once writes are completed, the CLI sends a final transaction to either deploy a new program or upgrade an existing program. In either case, the byte-code written to the buffer account will be copied into a program data account and verified.
- IX:
UpgradeableLoaderInstruction::DeployWithMaxDataLen
- IX:
看一下 UpgradeableLoaderInstruction::DeployWithMaxDataLen 这个IX 发生了啥:
Program {
/// Address of the ProgramData account.
programdata_address: Pubkey, 👈 PDA: Pubkey::find_program_address(&[new_program_id.as_ref()], bpf_loader_program_id);
},
// A ProgramData account.
ProgramData {
/// Slot that the program was last modified.
slot: u64,
/// Address of the Program's upgrade authority.
upgrade_authority_address: Option<Pubkey>,
// The raw program data follows this serialized structure in the
// account's data.
},
Dump 之前部署的程序:
╰─ solana -u d account DzzyPTT9Dk9UYj1zxESgCjs7gk5fzLopYqTKL8g16XSN
Public Key: DzzyPTT9Dk9UYj1zxESgCjs7gk5fzLopYqTKL8g16XSN
Balance: 0.00114144 SOL
Owner: BPFLoaderUpgradeab1e11111111111111111111111
Executable: true
Rent Epoch: 18446744073709551615
Length: 36 (0x24) bytes
0000: 02 00 00 00 dc 92 d1 1b 6a 34 03 e6 88 b3 a4 3c ........j4.....<
0010: ed 52 ca 8d d0 84 14 b6 28 ba c5 6b 79 b4 49 8c .R......(..ky.I.
0020: 63 45 82 36 cE.6
╰─ echo Fr2YGNPvgbQfHoChu1KGj3aqyxSKbU9ecEiCqYx3XULm | base58 -d|xxd
00000000: dc92 d11b 6a34 03e6 88b3 a43c ed52 ca8d ....j4.....<.R..
00000010: d084 14b6 28ba c56b 79b4 498c 6345 8236 ....(..ky.I.cE.6
[TODO]
upgrade
在部署时会为 program 设置一个 signer 作为 upgrade_authority ,使用这个 signer可以调用 IX UpgradeableLoaderInstruction::Upgrade 升级程序,同样使用 solana program deploy 进行程序升级,不过升级时 --program-id 可以使用 pubkey而不是keypair。其余步骤和 deploy 基本一致。
--final 参数将会把 UpgradeableLoaderInstruction::SetAuthority 的 new_authority 参数设为 none,从而放弃 program 的升级权限。buffer account的 authority时不能设置为 none的。