From 785c2574cda8d74507cce5a8b7ff96af307afb21 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 18 Oct 2019 21:39:05 -0600 Subject: [PATCH] Check that transaction fee-payer is a debitable account (#6454) automerge --- cli/src/stake.rs | 35 ++++++++++++++++++++++++++++++----- cli/src/vote.rs | 7 ++++++- core/src/sigverify.rs | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/cli/src/stake.rs b/cli/src/stake.rs index 7eddc13681..bcb96fe364 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -371,7 +371,12 @@ pub fn process_create_stake_account( lamports, ); let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?; - let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash); + let mut tx = Transaction::new_signed_with_payer( + ixs, + Some(&config.keypair.pubkey()), + &[&config.keypair], + recent_blockhash, + ); check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?; let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]); log_instruction_custom_error::(result) @@ -396,7 +401,12 @@ pub fn process_stake_authorize( stake_authorize, // stake or withdraw )]; - let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash); + let mut tx = Transaction::new_signed_with_payer( + ixs, + Some(&config.keypair.pubkey()), + &[&config.keypair], + recent_blockhash, + ); check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?; let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]); log_instruction_custom_error::(result) @@ -412,7 +422,12 @@ pub fn process_deactivate_stake_account( stake_account_pubkey, &config.keypair.pubkey(), )]; - let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash); + let mut tx = Transaction::new_signed_with_payer( + ixs, + Some(&config.keypair.pubkey()), + &[&config.keypair], + recent_blockhash, + ); check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?; let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]); log_instruction_custom_error::(result) @@ -434,7 +449,12 @@ pub fn process_withdraw_stake( lamports, )]; - let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash); + let mut tx = Transaction::new_signed_with_payer( + ixs, + Some(&config.keypair.pubkey()), + &[&config.keypair], + recent_blockhash, + ); check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?; let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]); log_instruction_custom_error::(result) @@ -587,7 +607,12 @@ pub fn process_delegate_stake( vote_account_pubkey, )]; - let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash); + let mut tx = Transaction::new_signed_with_payer( + ixs, + Some(&config.keypair.pubkey()), + &[&config.keypair], + recent_blockhash, + ); check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?; let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]); log_instruction_custom_error::(result) diff --git a/cli/src/vote.rs b/cli/src/vote.rs index be7f60d959..6b2d917325 100644 --- a/cli/src/vote.rs +++ b/cli/src/vote.rs @@ -271,7 +271,12 @@ pub fn process_vote_authorize( vote_authorize, // vote or withdraw )]; - let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash); + let mut tx = Transaction::new_signed_with_payer( + ixs, + Some(&config.keypair.pubkey()), + &[&config.keypair], + recent_blockhash, + ); check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?; let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]); log_instruction_custom_error::(result) diff --git a/core/src/sigverify.rs b/core/src/sigverify.rs index b1da32c6c8..d05aaa54bb 100644 --- a/core/src/sigverify.rs +++ b/core/src/sigverify.rs @@ -54,10 +54,11 @@ impl PacketOffsets { #[derive(Debug, PartialEq)] pub enum PacketError { InvalidLen, - InvalidSignatureLen, InvalidPubkeyLen, - MismatchSignatureLen, InvalidShortVec, + InvalidSignatureLen, + MismatchSignatureLen, + PayerNotDebitable, } impl std::convert::From> for PacketError { @@ -146,6 +147,14 @@ fn do_get_packet_offsets( let message_account_keys_len_offset = msg_start_offset + message_header_size; + // This reads and compares the MessageHeader num_required_signatures and + // num_credit_only_signed_accounts bytes. If num_required_signatures is not larger than + // num_credit_only_signed_accounts, the first account is not debitable, and cannot be charged + // required transaction fees. + if packet.data[msg_start_offset] <= packet.data[msg_start_offset + 1] { + return Err(PacketError::PayerNotDebitable); + } + // read the length of Message.account_keys (serialized with short_vec) let (pubkey_len, pubkey_len_size) = decode_len(&packet.data[message_account_keys_len_offset..])?; @@ -537,6 +546,26 @@ mod tests { assert_eq!(res, Err(PacketError::InvalidPubkeyLen)); } + #[test] + fn test_fee_payer_is_debitable() { + let message = Message { + header: MessageHeader { + num_required_signatures: 1, + num_credit_only_signed_accounts: 1, + num_credit_only_unsigned_accounts: 1, + }, + account_keys: vec![], + recent_blockhash: Hash::default(), + instructions: vec![], + }; + let mut tx = Transaction::new_unsigned(message); + tx.signatures = vec![Signature::default()]; + let packet = sigverify::make_packet_from_transaction(tx.clone()); + let res = sigverify::do_get_packet_offsets(&packet, 0); + + assert_eq!(res, Err(PacketError::PayerNotDebitable)); + } + #[test] fn test_system_transaction_data_layout() { use crate::packet::PACKET_DATA_SIZE;