Merge pull request #2084 from CriesofCarrots/fix-wallet-accountinuse
Fix wallet accountinuse
This commit is contained in:
parent
337c2bfd29
commit
4481efd51e
146
src/wallet.rs
146
src/wallet.rs
|
@ -340,10 +340,8 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<dyn error::E
|
||||||
))?,
|
))?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let last_id = get_last_id(&rpc_client)?;
|
request_and_confirm_airdrop(&rpc_client, &drone_addr, &config.id.pubkey(), tokens)
|
||||||
let transaction =
|
.unwrap();
|
||||||
request_airdrop_transaction(&drone_addr, &config.id.pubkey(), tokens, last_id)?;
|
|
||||||
send_and_confirm_tx(&rpc_client, &transaction)?;
|
|
||||||
|
|
||||||
let params = json!([format!("{}", config.id.pubkey())]);
|
let params = json!([format!("{}", config.id.pubkey())]);
|
||||||
let current_balance = RpcRequest::GetBalance
|
let current_balance = RpcRequest::GetBalance
|
||||||
|
@ -427,7 +425,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<dyn error::E
|
||||||
.data
|
.data
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
let tx = Transaction::system_create(
|
let mut tx = Transaction::system_create(
|
||||||
&config.id,
|
&config.id,
|
||||||
program.pubkey(),
|
program.pubkey(),
|
||||||
last_id,
|
last_id,
|
||||||
|
@ -436,13 +434,13 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<dyn error::E
|
||||||
bpf_loader::id(),
|
bpf_loader::id(),
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
send_and_confirm_tx(&rpc_client, &tx).map_err(|_| {
|
send_and_confirm_tx(&rpc_client, &mut tx, &config.id).map_err(|_| {
|
||||||
WalletError::DynamicProgramError("Program allocate space failed".to_string())
|
WalletError::DynamicProgramError("Program allocate space failed".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
for chunk in program_userdata.chunks(USERDATA_CHUNK_SIZE) {
|
for chunk in program_userdata.chunks(USERDATA_CHUNK_SIZE) {
|
||||||
let tx = Transaction::loader_write(
|
let mut tx = Transaction::loader_write(
|
||||||
&program,
|
&program,
|
||||||
bpf_loader::id(),
|
bpf_loader::id(),
|
||||||
offset,
|
offset,
|
||||||
|
@ -450,7 +448,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<dyn error::E
|
||||||
last_id,
|
last_id,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
send_and_confirm_tx(&rpc_client, &tx).map_err(|_| {
|
send_and_confirm_tx(&rpc_client, &mut tx, &program).map_err(|_| {
|
||||||
WalletError::DynamicProgramError(format!(
|
WalletError::DynamicProgramError(format!(
|
||||||
"Program write failed at offset {:?}",
|
"Program write failed at offset {:?}",
|
||||||
offset
|
offset
|
||||||
|
@ -460,13 +458,13 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<dyn error::E
|
||||||
}
|
}
|
||||||
|
|
||||||
let last_id = get_last_id(&rpc_client)?;
|
let last_id = get_last_id(&rpc_client)?;
|
||||||
let tx = Transaction::loader_finalize(&program, bpf_loader::id(), last_id, 0);
|
let mut tx = Transaction::loader_finalize(&program, bpf_loader::id(), last_id, 0);
|
||||||
send_and_confirm_tx(&rpc_client, &tx).map_err(|_| {
|
send_and_confirm_tx(&rpc_client, &mut tx, &program).map_err(|_| {
|
||||||
WalletError::DynamicProgramError("Program finalize transaction failed".to_string())
|
WalletError::DynamicProgramError("Program finalize transaction failed".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let tx = Transaction::system_spawn(&program, last_id, 0);
|
let mut tx = Transaction::system_spawn(&program, last_id, 0);
|
||||||
send_and_confirm_tx(&rpc_client, &tx).map_err(|_| {
|
send_and_confirm_tx(&rpc_client, &mut tx, &program).map_err(|_| {
|
||||||
WalletError::DynamicProgramError("Program spawn failed".to_string())
|
WalletError::DynamicProgramError("Program spawn failed".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
@ -729,7 +727,8 @@ fn confirm_tx(
|
||||||
|
|
||||||
fn send_and_confirm_tx(
|
fn send_and_confirm_tx(
|
||||||
rpc_client: &RpcClient,
|
rpc_client: &RpcClient,
|
||||||
tx: &Transaction,
|
tx: &mut Transaction,
|
||||||
|
signer: &Keypair,
|
||||||
) -> Result<(), Box<dyn error::Error>> {
|
) -> Result<(), Box<dyn error::Error>> {
|
||||||
let mut send_retries = 3;
|
let mut send_retries = 3;
|
||||||
while send_retries > 0 {
|
while send_retries > 0 {
|
||||||
|
@ -749,6 +748,64 @@ fn send_and_confirm_tx(
|
||||||
};
|
};
|
||||||
match status {
|
match status {
|
||||||
RpcSignatureStatus::AccountInUse => {
|
RpcSignatureStatus::AccountInUse => {
|
||||||
|
resign_tx(rpc_client, tx, signer)?;
|
||||||
|
send_retries -= 1;
|
||||||
|
}
|
||||||
|
RpcSignatureStatus::Confirmed => {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(WalletError::RpcRequestError(format!(
|
||||||
|
"Transaction {:?} failed: {:?}",
|
||||||
|
signature_str, status
|
||||||
|
)))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(WalletError::RpcRequestError(format!(
|
||||||
|
"AccountInUse after 3 retries: {:?}",
|
||||||
|
tx.account_keys[0]
|
||||||
|
)))?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resign_tx(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
tx: &mut Transaction,
|
||||||
|
signer_key: &Keypair,
|
||||||
|
) -> Result<(), Box<dyn error::Error>> {
|
||||||
|
let last_id = get_last_id(rpc_client)?;
|
||||||
|
tx.sign(&[signer_key], last_id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_and_confirm_airdrop(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
drone_addr: &SocketAddr,
|
||||||
|
id: &Pubkey,
|
||||||
|
tokens: u64,
|
||||||
|
) -> Result<(), Box<dyn error::Error>> {
|
||||||
|
let mut last_id = get_last_id(rpc_client)?;
|
||||||
|
let mut tx = request_airdrop_transaction(drone_addr, id, tokens, last_id)?;
|
||||||
|
let mut send_retries = 3;
|
||||||
|
while send_retries > 0 {
|
||||||
|
let mut status_retries = 4;
|
||||||
|
let signature_str = send_tx(rpc_client, &tx)?;
|
||||||
|
let status = loop {
|
||||||
|
let status = confirm_tx(rpc_client, &signature_str)?;
|
||||||
|
if status == RpcSignatureStatus::SignatureNotFound {
|
||||||
|
status_retries -= 1;
|
||||||
|
if status_retries == 0 {
|
||||||
|
break status;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break status;
|
||||||
|
}
|
||||||
|
sleep(Duration::from_secs(1));
|
||||||
|
};
|
||||||
|
match status {
|
||||||
|
RpcSignatureStatus::AccountInUse => {
|
||||||
|
last_id = get_last_id(rpc_client)?;
|
||||||
|
tx = request_airdrop_transaction(drone_addr, id, tokens, last_id)?;
|
||||||
send_retries -= 1;
|
send_retries -= 1;
|
||||||
}
|
}
|
||||||
RpcSignatureStatus::Confirmed => {
|
RpcSignatureStatus::Confirmed => {
|
||||||
|
@ -786,6 +843,54 @@ mod tests {
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_resign_tx() {
|
||||||
|
let leader_keypair = Arc::new(Keypair::new());
|
||||||
|
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
|
let leader_data = leader.info.clone();
|
||||||
|
let (alice, ledger_path) =
|
||||||
|
create_tmp_genesis("wallet_request_airdrop", 10_000_000, leader_data.id, 1000);
|
||||||
|
let mut bank = Bank::new(&alice);
|
||||||
|
|
||||||
|
let leader_scheduler = Arc::new(RwLock::new(LeaderScheduler::from_bootstrap_leader(
|
||||||
|
leader_data.id,
|
||||||
|
)));
|
||||||
|
bank.leader_scheduler = leader_scheduler;
|
||||||
|
let vote_account_keypair = Arc::new(Keypair::new());
|
||||||
|
let last_id = bank.last_id();
|
||||||
|
let entry_height = alice.create_entries().len() as u64;
|
||||||
|
let _server = Fullnode::new_with_bank(
|
||||||
|
leader_keypair,
|
||||||
|
vote_account_keypair,
|
||||||
|
bank,
|
||||||
|
entry_height,
|
||||||
|
&last_id,
|
||||||
|
leader,
|
||||||
|
None,
|
||||||
|
&ledger_path,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
sleep(Duration::from_millis(900));
|
||||||
|
|
||||||
|
let rpc_client = RpcClient::new_from_socket(leader_data.rpc);
|
||||||
|
|
||||||
|
let key = Keypair::new();
|
||||||
|
let to = Keypair::new().pubkey();
|
||||||
|
let last_id = Hash::default();
|
||||||
|
let prev_tx = Transaction::system_new(&key, to, 50, last_id);
|
||||||
|
let mut tx = Transaction::system_new(&key, to, 50, last_id);
|
||||||
|
|
||||||
|
resign_tx(&rpc_client, &mut tx, &key).unwrap();
|
||||||
|
|
||||||
|
assert_ne!(prev_tx, tx);
|
||||||
|
assert_ne!(prev_tx.signatures, tx.signatures);
|
||||||
|
assert_ne!(prev_tx.last_id, tx.last_id);
|
||||||
|
assert_eq!(prev_tx.fee, tx.fee);
|
||||||
|
assert_eq!(prev_tx.account_keys, tx.account_keys);
|
||||||
|
assert_eq!(prev_tx.instructions, tx.instructions);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_wallet_parse_command() {
|
fn test_wallet_parse_command() {
|
||||||
let test_commands = App::new("test")
|
let test_commands = App::new("test")
|
||||||
|
@ -1314,11 +1419,8 @@ mod tests {
|
||||||
|
|
||||||
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
||||||
|
|
||||||
let last_id = get_last_id(&rpc_client).unwrap();
|
request_and_confirm_airdrop(&rpc_client, &drone_addr, &config_payer.id.pubkey(), 50)
|
||||||
let transaction =
|
|
||||||
request_airdrop_transaction(&drone_addr, &config_payer.id.pubkey(), 50, last_id)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
send_and_confirm_tx(&rpc_client, &transaction).unwrap();
|
|
||||||
|
|
||||||
// Make transaction (from config_payer to bob_pubkey) requiring timestamp from config_witness
|
// Make transaction (from config_payer to bob_pubkey) requiring timestamp from config_witness
|
||||||
let date_string = "\"2018-09-19T17:30:59Z\"";
|
let date_string = "\"2018-09-19T17:30:59Z\"";
|
||||||
|
@ -1434,11 +1536,8 @@ mod tests {
|
||||||
|
|
||||||
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
||||||
|
|
||||||
let last_id = get_last_id(&rpc_client).unwrap();
|
request_and_confirm_airdrop(&rpc_client, &drone_addr, &config_payer.id.pubkey(), 50)
|
||||||
let transaction =
|
|
||||||
request_airdrop_transaction(&drone_addr, &config_payer.id.pubkey(), 50, last_id)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
send_and_confirm_tx(&rpc_client, &transaction).unwrap();
|
|
||||||
|
|
||||||
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
|
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
|
||||||
config_payer.command = WalletCommand::Pay(
|
config_payer.command = WalletCommand::Pay(
|
||||||
|
@ -1559,11 +1658,8 @@ mod tests {
|
||||||
|
|
||||||
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
||||||
|
|
||||||
let last_id = get_last_id(&rpc_client).unwrap();
|
request_and_confirm_airdrop(&rpc_client, &drone_addr, &config_payer.id.pubkey(), 50)
|
||||||
let transaction =
|
|
||||||
request_airdrop_transaction(&drone_addr, &config_payer.id.pubkey(), 50, last_id)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
send_and_confirm_tx(&rpc_client, &transaction).unwrap();
|
|
||||||
|
|
||||||
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
|
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
|
||||||
config_payer.command = WalletCommand::Pay(
|
config_payer.command = WalletCommand::Pay(
|
||||||
|
|
Loading…
Reference in New Issue