Pay program loading fees from a system account (#4190)
This commit is contained in:
parent
2107e15bd3
commit
d9e18a71ec
|
@ -10,7 +10,7 @@ use serde_json::{json, Value};
|
||||||
use solana_sdk::account::Account;
|
use solana_sdk::account::Account;
|
||||||
use solana_sdk::hash::Hash;
|
use solana_sdk::hash::Hash;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
|
use solana_sdk::signature::{KeypairUtil, Signature};
|
||||||
use solana_sdk::timing::{DEFAULT_TICKS_PER_SLOT, NUM_TICKS_PER_SECOND};
|
use solana_sdk::timing::{DEFAULT_TICKS_PER_SLOT, NUM_TICKS_PER_SECOND};
|
||||||
use solana_sdk::transaction::{self, Transaction, TransactionError};
|
use solana_sdk::transaction::{self, Transaction, TransactionError};
|
||||||
use std::error;
|
use std::error;
|
||||||
|
@ -78,7 +78,7 @@ impl RpcClient {
|
||||||
pub fn send_and_confirm_transaction<T: KeypairUtil>(
|
pub fn send_and_confirm_transaction<T: KeypairUtil>(
|
||||||
&self,
|
&self,
|
||||||
transaction: &mut Transaction,
|
transaction: &mut Transaction,
|
||||||
signer: &T,
|
signer_keys: &[&T],
|
||||||
) -> Result<String, ClientError> {
|
) -> Result<String, ClientError> {
|
||||||
let mut send_retries = 5;
|
let mut send_retries = 5;
|
||||||
loop {
|
loop {
|
||||||
|
@ -106,7 +106,7 @@ impl RpcClient {
|
||||||
Ok(_) => return Ok(signature_str),
|
Ok(_) => return Ok(signature_str),
|
||||||
Err(TransactionError::AccountInUse) => {
|
Err(TransactionError::AccountInUse) => {
|
||||||
// Fetch a new blockhash and re-sign the transaction before sending it again
|
// Fetch a new blockhash and re-sign the transaction before sending it again
|
||||||
self.resign_transaction(transaction, signer)?;
|
self.resign_transaction(transaction, signer_keys)?;
|
||||||
send_retries - 1
|
send_retries - 1
|
||||||
}
|
}
|
||||||
Err(_) => 0,
|
Err(_) => 0,
|
||||||
|
@ -127,10 +127,10 @@ impl RpcClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_and_confirm_transactions(
|
pub fn send_and_confirm_transactions<T: KeypairUtil>(
|
||||||
&self,
|
&self,
|
||||||
mut transactions: Vec<Transaction>,
|
mut transactions: Vec<Transaction>,
|
||||||
signer: &Keypair,
|
signer_keys: &[&T],
|
||||||
) -> Result<(), Box<dyn error::Error>> {
|
) -> Result<(), Box<dyn error::Error>> {
|
||||||
let mut send_retries = 5;
|
let mut send_retries = 5;
|
||||||
loop {
|
loop {
|
||||||
|
@ -192,7 +192,7 @@ impl RpcClient {
|
||||||
transactions = transactions_signatures
|
transactions = transactions_signatures
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(mut transaction, _)| {
|
.map(|(mut transaction, _)| {
|
||||||
transaction.sign(&[signer], blockhash);
|
transaction.sign(signer_keys, blockhash);
|
||||||
transaction
|
transaction
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -202,10 +202,10 @@ impl RpcClient {
|
||||||
pub fn resign_transaction<T: KeypairUtil>(
|
pub fn resign_transaction<T: KeypairUtil>(
|
||||||
&self,
|
&self,
|
||||||
tx: &mut Transaction,
|
tx: &mut Transaction,
|
||||||
signer_key: &T,
|
signer_keys: &[&T],
|
||||||
) -> Result<(), ClientError> {
|
) -> Result<(), ClientError> {
|
||||||
let blockhash = self.get_new_blockhash(&tx.message().recent_blockhash)?;
|
let blockhash = self.get_new_blockhash(&tx.message().recent_blockhash)?;
|
||||||
tx.sign(&[signer_key], blockhash);
|
tx.sign(signer_keys, blockhash);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,15 +710,15 @@ mod tests {
|
||||||
let blockhash = Hash::default();
|
let blockhash = Hash::default();
|
||||||
let mut tx = system_transaction::create_user_account(&key, &to, 50, blockhash, 0);
|
let mut tx = system_transaction::create_user_account(&key, &to, 50, blockhash, 0);
|
||||||
|
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &key);
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]);
|
||||||
result.unwrap();
|
result.unwrap();
|
||||||
|
|
||||||
let rpc_client = RpcClient::new_mock("account_in_use".to_string());
|
let rpc_client = RpcClient::new_mock("account_in_use".to_string());
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &key);
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|
||||||
let rpc_client = RpcClient::new_mock("fails".to_string());
|
let rpc_client = RpcClient::new_mock("fails".to_string());
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &key);
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,7 +735,7 @@ mod tests {
|
||||||
let prev_tx = system_transaction::create_user_account(&key, &to, 50, blockhash, 0);
|
let prev_tx = system_transaction::create_user_account(&key, &to, 50, blockhash, 0);
|
||||||
let mut tx = system_transaction::create_user_account(&key, &to, 50, blockhash, 0);
|
let mut tx = system_transaction::create_user_account(&key, &to, 50, blockhash, 0);
|
||||||
|
|
||||||
rpc_client.resign_transaction(&mut tx, &key).unwrap();
|
rpc_client.resign_transaction(&mut tx, &[&key]).unwrap();
|
||||||
|
|
||||||
assert_ne!(prev_tx, tx);
|
assert_ne!(prev_tx, tx);
|
||||||
assert_ne!(prev_tx.signatures, tx.signatures);
|
assert_ne!(prev_tx.signatures, tx.signatures);
|
||||||
|
|
|
@ -206,7 +206,7 @@ fn new_update_manifest(
|
||||||
let mut transaction = Transaction::new_unsigned_instructions(vec![new_account]);
|
let mut transaction = Transaction::new_unsigned_instructions(vec![new_account]);
|
||||||
transaction.sign(&[from_keypair], recect_blockhash);
|
transaction.sign(&[from_keypair], recect_blockhash);
|
||||||
|
|
||||||
rpc_client.send_and_confirm_transaction(&mut transaction, from_keypair)?;
|
rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ fn store_update_manifest(
|
||||||
);
|
);
|
||||||
let mut transaction = Transaction::new_unsigned_instructions(vec![new_store]);
|
let mut transaction = Transaction::new_unsigned_instructions(vec![new_store]);
|
||||||
transaction.sign(&[from_keypair, update_manifest_keypair], recect_blockhash);
|
transaction.sign(&[from_keypair, update_manifest_keypair], recect_blockhash);
|
||||||
rpc_client.send_and_confirm_transaction(&mut transaction, from_keypair)?;
|
rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@ use serde::Serialize;
|
||||||
use solana_sdk::client::SyncClient;
|
use solana_sdk::client::SyncClient;
|
||||||
use solana_sdk::instruction::{AccountMeta, Instruction};
|
use solana_sdk::instruction::{AccountMeta, Instruction};
|
||||||
use solana_sdk::loader_instruction;
|
use solana_sdk::loader_instruction;
|
||||||
|
use solana_sdk::message::Message;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||||
|
|
||||||
use solana_sdk::system_instruction;
|
use solana_sdk::system_instruction;
|
||||||
|
|
||||||
pub fn load_program(
|
pub fn load_program(
|
||||||
|
@ -33,15 +33,17 @@ pub fn load_program(
|
||||||
for chunk in program.chunks(chunk_size) {
|
for chunk in program.chunks(chunk_size) {
|
||||||
let instruction =
|
let instruction =
|
||||||
loader_instruction::write(&program_pubkey, loader_id, offset, chunk.to_vec());
|
loader_instruction::write(&program_pubkey, loader_id, offset, chunk.to_vec());
|
||||||
|
let message = Message::new_with_payer(vec![instruction], Some(&from_keypair.pubkey()));
|
||||||
bank_client
|
bank_client
|
||||||
.send_instruction(&program_keypair, instruction)
|
.send_message(&[from_keypair, &program_keypair], message)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
offset += chunk_size as u32;
|
offset += chunk_size as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
let instruction = loader_instruction::finalize(&program_pubkey, loader_id);
|
let instruction = loader_instruction::finalize(&program_pubkey, loader_id);
|
||||||
|
let message = Message::new_with_payer(vec![instruction], Some(&from_keypair.pubkey()));
|
||||||
bank_client
|
bank_client
|
||||||
.send_instruction(&program_keypair, instruction)
|
.send_message(&[from_keypair, &program_keypair], message)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
program_pubkey
|
program_pubkey
|
||||||
|
|
|
@ -109,8 +109,17 @@ impl Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(instructions: Vec<Instruction>) -> Self {
|
pub fn new(instructions: Vec<Instruction>) -> Self {
|
||||||
|
Self::new_with_payer(instructions, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_payer(instructions: Vec<Instruction>, payer: Option<&Pubkey>) -> Self {
|
||||||
let program_ids = get_program_ids(&instructions);
|
let program_ids = get_program_ids(&instructions);
|
||||||
let (mut signed_keys, unsigned_keys) = get_keys(&instructions);
|
let (mut signed_keys, unsigned_keys) = get_keys(&instructions);
|
||||||
|
if let Some(payer) = payer {
|
||||||
|
if signed_keys.is_empty() || signed_keys[0] != *payer {
|
||||||
|
signed_keys.insert(0, *payer);
|
||||||
|
}
|
||||||
|
}
|
||||||
let num_required_signatures = signed_keys.len() as u8;
|
let num_required_signatures = signed_keys.len() as u8;
|
||||||
signed_keys.extend(&unsigned_keys);
|
signed_keys.extend(&unsigned_keys);
|
||||||
let instructions = compile_instructions(instructions, &signed_keys, &program_ids);
|
let instructions = compile_instructions(instructions, &signed_keys, &program_ids);
|
||||||
|
@ -266,4 +275,28 @@ mod tests {
|
||||||
CompiledInstruction::new(0, &0, vec![0])
|
CompiledInstruction::new(0, &0, vec![0])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_message_payer_first() {
|
||||||
|
let program_id = Pubkey::default();
|
||||||
|
let payer = Pubkey::new_rand();
|
||||||
|
let id0 = Pubkey::default();
|
||||||
|
|
||||||
|
let ix = Instruction::new(program_id, &0, vec![AccountMeta::new(id0, false)]);
|
||||||
|
let message = Message::new_with_payer(vec![ix], Some(&payer));
|
||||||
|
assert_eq!(message.num_required_signatures, 1);
|
||||||
|
|
||||||
|
let ix = Instruction::new(program_id, &0, vec![AccountMeta::new(id0, true)]);
|
||||||
|
let message = Message::new_with_payer(vec![ix], Some(&payer));
|
||||||
|
assert_eq!(message.num_required_signatures, 2);
|
||||||
|
|
||||||
|
let ix = Instruction::new(
|
||||||
|
program_id,
|
||||||
|
&0,
|
||||||
|
vec![AccountMeta::new(payer, true), AccountMeta::new(id0, true)],
|
||||||
|
);
|
||||||
|
let message = Message::new_with_payer(vec![ix], Some(&payer));
|
||||||
|
assert_eq!(message.num_required_signatures, 2);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ use solana_sdk::hash::Hash;
|
||||||
use solana_sdk::instruction::InstructionError;
|
use solana_sdk::instruction::InstructionError;
|
||||||
use solana_sdk::instruction_processor_utils::DecodeError;
|
use solana_sdk::instruction_processor_utils::DecodeError;
|
||||||
use solana_sdk::loader_instruction;
|
use solana_sdk::loader_instruction;
|
||||||
|
use solana_sdk::message::Message;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
|
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
|
||||||
use solana_sdk::system_instruction::SystemError;
|
use solana_sdk::system_instruction::SystemError;
|
||||||
|
@ -31,7 +32,7 @@ use std::io::Read;
|
||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, SocketAddr};
|
||||||
use std::{error, fmt, mem};
|
use std::{error, fmt, mem};
|
||||||
|
|
||||||
const USERDATA_CHUNK_SIZE: usize = 256;
|
const USERDATA_CHUNK_SIZE: usize = 229; // Keep program chunks under PACKET_DATA_SIZE
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum WalletCommand {
|
pub enum WalletCommand {
|
||||||
|
@ -352,7 +353,7 @@ fn process_authorize_voter(
|
||||||
)];
|
)];
|
||||||
|
|
||||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair)?;
|
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?;
|
||||||
Ok(signature_str.to_string())
|
Ok(signature_str.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,7 +374,7 @@ fn process_create_staking(
|
||||||
lamports,
|
lamports,
|
||||||
);
|
);
|
||||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair)?;
|
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair])?;
|
||||||
Ok(signature_str.to_string())
|
Ok(signature_str.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,12 +453,13 @@ fn process_deploy(
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
trace!("Creating program account");
|
trace!("Creating program account");
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
log_instruction_custom_error::<SystemError>(result).map_err(|_| {
|
log_instruction_custom_error::<SystemError>(result).map_err(|_| {
|
||||||
WalletError::DynamicProgramError("Program allocate space failed".to_string())
|
WalletError::DynamicProgramError("Program allocate space failed".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
trace!("Writing program data");
|
trace!("Writing program data");
|
||||||
|
let signers = [&config.keypair, &program_id];
|
||||||
let write_transactions: Vec<_> = program_data
|
let write_transactions: Vec<_> = program_data
|
||||||
.chunks(USERDATA_CHUNK_SIZE)
|
.chunks(USERDATA_CHUNK_SIZE)
|
||||||
.zip(0..)
|
.zip(0..)
|
||||||
|
@ -468,16 +470,18 @@ fn process_deploy(
|
||||||
(i * USERDATA_CHUNK_SIZE) as u32,
|
(i * USERDATA_CHUNK_SIZE) as u32,
|
||||||
chunk.to_vec(),
|
chunk.to_vec(),
|
||||||
);
|
);
|
||||||
Transaction::new_signed_instructions(&[&program_id], vec![instruction], blockhash)
|
let message = Message::new_with_payer(vec![instruction], Some(&signers[0].pubkey()));
|
||||||
|
Transaction::new(&signers, message, blockhash)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
rpc_client.send_and_confirm_transactions(write_transactions, &program_id)?;
|
rpc_client.send_and_confirm_transactions(write_transactions, &signers)?;
|
||||||
|
|
||||||
trace!("Finalizing program account");
|
trace!("Finalizing program account");
|
||||||
let instruction = loader_instruction::finalize(&program_id.pubkey(), &bpf_loader::id());
|
let instruction = loader_instruction::finalize(&program_id.pubkey(), &bpf_loader::id());
|
||||||
let mut tx = Transaction::new_signed_instructions(&[&program_id], vec![instruction], blockhash);
|
let message = Message::new_with_payer(vec![instruction], Some(&signers[0].pubkey()));
|
||||||
|
let mut tx = Transaction::new(&signers, message, blockhash);
|
||||||
rpc_client
|
rpc_client
|
||||||
.send_and_confirm_transaction(&mut tx, &program_id)
|
.send_and_confirm_transaction(&mut tx, &signers)
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
WalletError::DynamicProgramError("Program finalize transaction failed".to_string())
|
WalletError::DynamicProgramError("Program finalize transaction failed".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
@ -502,7 +506,7 @@ fn process_pay(
|
||||||
|
|
||||||
if timestamp == None && *witnesses == None {
|
if timestamp == None && *witnesses == None {
|
||||||
let mut tx = system_transaction::transfer(&config.keypair, to, lamports, blockhash, 0);
|
let mut tx = system_transaction::transfer(&config.keypair, to, lamports, blockhash, 0);
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
let signature_str = log_instruction_custom_error::<SystemError>(result)?;
|
let signature_str = log_instruction_custom_error::<SystemError>(result)?;
|
||||||
Ok(signature_str.to_string())
|
Ok(signature_str.to_string())
|
||||||
} else if *witnesses == None {
|
} else if *witnesses == None {
|
||||||
|
@ -525,7 +529,7 @@ fn process_pay(
|
||||||
lamports,
|
lamports,
|
||||||
);
|
);
|
||||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, blockhash);
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, blockhash);
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
||||||
|
|
||||||
Ok(json!({
|
Ok(json!({
|
||||||
|
@ -556,7 +560,7 @@ fn process_pay(
|
||||||
lamports,
|
lamports,
|
||||||
);
|
);
|
||||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, blockhash);
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, blockhash);
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
||||||
|
|
||||||
Ok(json!({
|
Ok(json!({
|
||||||
|
@ -577,7 +581,7 @@ fn process_cancel(rpc_client: &RpcClient, config: &WalletConfig, pubkey: &Pubkey
|
||||||
&config.keypair.pubkey(),
|
&config.keypair.pubkey(),
|
||||||
);
|
);
|
||||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash);
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash);
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
||||||
Ok(signature_str.to_string())
|
Ok(signature_str.to_string())
|
||||||
}
|
}
|
||||||
|
@ -605,7 +609,7 @@ fn process_time_elapsed(
|
||||||
|
|
||||||
let ix = budget_instruction::apply_timestamp(&config.keypair.pubkey(), pubkey, to, dt);
|
let ix = budget_instruction::apply_timestamp(&config.keypair.pubkey(), pubkey, to, dt);
|
||||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash);
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash);
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
||||||
|
|
||||||
Ok(signature_str.to_string())
|
Ok(signature_str.to_string())
|
||||||
|
@ -627,7 +631,7 @@ fn process_witness(
|
||||||
let blockhash = rpc_client.get_recent_blockhash()?;
|
let blockhash = rpc_client.get_recent_blockhash()?;
|
||||||
let ix = budget_instruction::apply_signature(&config.keypair.pubkey(), pubkey, to);
|
let ix = budget_instruction::apply_signature(&config.keypair.pubkey(), pubkey, to);
|
||||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash);
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash);
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
||||||
|
|
||||||
Ok(signature_str.to_string())
|
Ok(signature_str.to_string())
|
||||||
|
@ -774,7 +778,7 @@ pub fn request_and_confirm_airdrop(
|
||||||
let blockhash = rpc_client.get_recent_blockhash()?;
|
let blockhash = rpc_client.get_recent_blockhash()?;
|
||||||
let keypair = DroneKeypair::new_keypair(drone_addr, to_pubkey, lamports, blockhash)?;
|
let keypair = DroneKeypair::new_keypair(drone_addr, to_pubkey, lamports, blockhash)?;
|
||||||
let mut tx = keypair.airdrop_transaction();
|
let mut tx = keypair.airdrop_transaction();
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &keypair);
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&keypair]);
|
||||||
log_instruction_custom_error::<SystemError>(result)?;
|
log_instruction_custom_error::<SystemError>(result)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue