diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 78c2c46b8b..ef84f760b0 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -312,13 +312,19 @@ impl Bank { let mut status_cache = self.status_cache.write().unwrap(); for (i, tx) in txs.iter().enumerate() { match &res[i] { - Ok(_) => status_cache.add(&tx.signatures[0]), + Ok(_) => { + if !tx.signatures.is_empty() { + status_cache.add(&tx.signatures[0]); + } + } Err(BankError::BlockhashNotFound) => (), Err(BankError::DuplicateSignature) => (), Err(BankError::AccountNotFound) => (), Err(e) => { - status_cache.add(&tx.signatures[0]); - status_cache.save_failure_status(&tx.signatures[0], e.clone()); + if !tx.signatures.is_empty() { + status_cache.add(&tx.signatures[0]); + status_cache.save_failure_status(&tx.signatures[0], e.clone()); + } } } } @@ -447,6 +453,9 @@ impl Bank { txs.iter() .zip(lock_results.into_iter()) .map(|(tx, lock_res)| { + if tx.signatures.is_empty() { + return lock_res; + } if lock_res.is_ok() && StatusCache::has_signature_all(&caches, &tx.signatures[0]) { error_counters.duplicate_signature += 1; Err(BankError::DuplicateSignature) @@ -1517,4 +1526,35 @@ mod tests { assert!(child.epoch_vote_accounts(i).is_some()); } + #[test] + fn test_zero_signatures() { + solana_logger::setup(); + let (genesis_block, mint_keypair) = GenesisBlock::new(500); + let bank = Arc::new(Bank::new(&genesis_block)); + let key = Keypair::new(); + + let move_tokens = SystemInstruction::Move { tokens: 1 }; + + let mut tx = Transaction::new_unsigned( + &mint_keypair.pubkey(), + &[key.pubkey()], + system_program::id(), + &move_tokens, + bank.last_blockhash(), + 2, + ); + + assert_eq!( + bank.process_transaction(&tx), + Err(BankError::MissingSignatureForFee) + ); + + // Set the fee to 0, this should give a ProgramError + // but since no signature we cannot look up the error. + tx.fee = 0; + + assert_eq!(bank.process_transaction(&tx), Ok(())); + assert_eq!(bank.get_balance(&key.pubkey()), 0); + } + } diff --git a/sdk/src/transaction.rs b/sdk/src/transaction.rs index a19504292e..7e03171f8d 100644 --- a/sdk/src/transaction.rs +++ b/sdk/src/transaction.rs @@ -256,9 +256,11 @@ impl Transaction { // a hash of a slice of transactions only needs to hash the signatures pub fn hash(transactions: &[Transaction]) -> Hash { let mut hasher = Hasher::default(); - transactions - .iter() - .for_each(|tx| hasher.hash(&tx.signatures[0].as_ref())); + transactions.iter().for_each(|tx| { + if !tx.signatures.is_empty() { + hasher.hash(&tx.signatures[0].as_ref()); + } + }); hasher.result() }