feat: support restarting failed bpf loader deploys (#12163)
* feat: support restarting failed bpf loader deploys * chore: add error message if program already exists
This commit is contained in:
@ -31,6 +31,7 @@ export class BpfLoader {
|
||||
* @param program Account to load the program into
|
||||
* @param elf The entire ELF containing the BPF program
|
||||
* @param loaderProgramId The program id of the BPF loader to use
|
||||
* @return true if program was loaded successfully, false if program was already loaded
|
||||
*/
|
||||
static load(
|
||||
connection: Connection,
|
||||
@ -38,7 +39,7 @@ export class BpfLoader {
|
||||
program: Account,
|
||||
elf: Buffer | Uint8Array | Array<number>,
|
||||
loaderProgramId: PublicKey,
|
||||
): Promise<void> {
|
||||
): Promise<boolean> {
|
||||
return Loader.load(connection, payer, program, loaderProgramId, elf);
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ export class Loader {
|
||||
* @param program Account to load the program into
|
||||
* @param programId Public key that identifies the loader
|
||||
* @param data Program octets
|
||||
* @return true if program was loaded successfully, false if program was already loaded
|
||||
*/
|
||||
static async load(
|
||||
connection: Connection,
|
||||
@ -52,29 +53,80 @@ export class Loader {
|
||||
program: Account,
|
||||
programId: PublicKey,
|
||||
data: Buffer | Uint8Array | Array<number>,
|
||||
): Promise<void> {
|
||||
): Promise<boolean> {
|
||||
{
|
||||
const balanceNeeded = await connection.getMinimumBalanceForRentExemption(
|
||||
data.length,
|
||||
);
|
||||
const transaction = new Transaction().add(
|
||||
SystemProgram.createAccount({
|
||||
fromPubkey: payer.publicKey,
|
||||
newAccountPubkey: program.publicKey,
|
||||
lamports: balanceNeeded > 0 ? balanceNeeded : 1,
|
||||
space: data.length,
|
||||
programId,
|
||||
}),
|
||||
);
|
||||
await sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[payer, program],
|
||||
{
|
||||
commitment: 'single',
|
||||
skipPreflight: true,
|
||||
},
|
||||
|
||||
// Fetch program account info to check if it has already been created
|
||||
const programInfo = await connection.getAccountInfo(
|
||||
program.publicKey,
|
||||
'single',
|
||||
);
|
||||
|
||||
let transaction: Transaction | null = null;
|
||||
if (programInfo !== null) {
|
||||
if (programInfo.executable) {
|
||||
console.error('Program load failed, account is already executable');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (programInfo.data.length !== data.length) {
|
||||
transaction = transaction || new Transaction();
|
||||
transaction.add(
|
||||
SystemProgram.allocate({
|
||||
accountPubkey: program.publicKey,
|
||||
space: data.length,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (!programInfo.owner.equals(programId)) {
|
||||
transaction = transaction || new Transaction();
|
||||
transaction.add(
|
||||
SystemProgram.assign({
|
||||
accountPubkey: program.publicKey,
|
||||
programId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (programInfo.lamports < balanceNeeded) {
|
||||
transaction = transaction || new Transaction();
|
||||
transaction.add(
|
||||
SystemProgram.transfer({
|
||||
fromPubkey: payer.publicKey,
|
||||
toPubkey: program.publicKey,
|
||||
lamports: balanceNeeded - programInfo.lamports,
|
||||
}),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
transaction = new Transaction().add(
|
||||
SystemProgram.createAccount({
|
||||
fromPubkey: payer.publicKey,
|
||||
newAccountPubkey: program.publicKey,
|
||||
lamports: balanceNeeded > 0 ? balanceNeeded : 1,
|
||||
space: data.length,
|
||||
programId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// If the account is already created correctly, skip this step
|
||||
// and proceed directly to loading instructions
|
||||
if (transaction !== null) {
|
||||
await sendAndConfirmTransaction(
|
||||
connection,
|
||||
transaction,
|
||||
[payer, program],
|
||||
{
|
||||
commitment: 'single',
|
||||
skipPreflight: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const dataLayout = BufferLayout.struct([
|
||||
@ -165,5 +217,8 @@ export class Loader {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// success
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user