Skip to content

Commit

Permalink
Multiple signatures for transactions
Browse files Browse the repository at this point in the history
With multiple instructions in a TX may need
multiple signatures.

Fixes solana-labs#1531
  • Loading branch information
sakridge committed Nov 8, 2018
1 parent 433fcef commit 14acdc3
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 94 deletions.
34 changes: 23 additions & 11 deletions src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ impl Bank {
for (i, tx) in txs.iter().enumerate() {
Self::update_signature_status_with_last_id(
&mut last_ids.entries,
&tx.signature,
&tx.signatures[0],
&res[i],
&tx.last_id,
);
Expand All @@ -497,7 +497,7 @@ impl Bank {
Err(_) => RpcSignatureStatus::GenericFailure,
};
if status != RpcSignatureStatus::SignatureNotFound {
self.check_signature_subscriptions(&tx.signature, status);
self.check_signature_subscriptions(&tx.signatures[0], status);
}
}
}
Expand Down Expand Up @@ -650,7 +650,8 @@ impl Bank {

// There is no way to predict what contract will execute without an error
// If a fee can pay for execution then the contract will be scheduled
let err = Self::reserve_signature_with_last_id(last_ids, &tx.last_id, &tx.signature);
let err =
Self::reserve_signature_with_last_id(last_ids, &tx.last_id, &tx.signatures[0]);
if let Err(BankError::LastIdNotFound) = err {
error_counters.reserve_last_id += 1;
} else if let Err(BankError::DuplicateSignature) = err {
Expand Down Expand Up @@ -894,6 +895,10 @@ impl Bank {
/// The accounts are committed back to the bank only if every instruction succeeds
fn execute_transaction(&self, tx: &Transaction, tx_accounts: &mut [Account]) -> Result<()> {
for (instruction_index, instruction) in tx.instructions.iter().enumerate() {
info!(
"tx_accounts: {:?} ix_accounts: {:?}",
tx_accounts, instruction.accounts
);
Self::with_subset(tx_accounts, &instruction.accounts, |program_accounts| {
self.execute_instruction(tx, instruction_index, program_accounts)
})?;
Expand Down Expand Up @@ -1303,7 +1308,8 @@ impl Bank {
last_id: Hash,
) -> Result<Signature> {
let tx = Transaction::system_new(keypair, to, n, last_id);
let signature = tx.signature;
info!("tx: {:?}", tx);
let signature = tx.signatures[0];
self.process_transaction(&tx).map(|_| signature)
}

Expand Down Expand Up @@ -1550,10 +1556,13 @@ mod tests {
assert_eq!(bank.get_balance(&mint.pubkey()), 0);
assert_eq!(bank.get_balance(&key1), 1);
assert_eq!(bank.get_balance(&key2), 0);
assert_eq!(bank.get_signature(&t1.last_id, &t1.signature), Some(Ok(())));
assert_eq!(
bank.get_signature(&t1.last_id, &t1.signatures[0]),
Some(Ok(()))
);
// TODO: Transactions that fail to pay a fee could be dropped silently
assert_eq!(
bank.get_signature(&t2.last_id, &t2.signature),
bank.get_signature(&t2.last_id, &t2.signatures[0]),
Some(Err(BankError::AccountInUse))
);
}
Expand All @@ -1579,7 +1588,7 @@ mod tests {
];

let t1 = Transaction::new_with_instructions(
&mint.keypair(),
&[&mint.keypair()],
&[key1, key2],
mint.last_id(),
0,
Expand All @@ -1593,7 +1602,7 @@ mod tests {
assert_eq!(bank.get_balance(&key1), 0);
assert_eq!(bank.get_balance(&key2), 0);
assert_eq!(
bank.get_signature(&t1.last_id, &t1.signature),
bank.get_signature(&t1.last_id, &t1.signatures[0]),
Some(Err(BankError::ResultWithNegativeTokens(1)))
);
}
Expand All @@ -1616,7 +1625,10 @@ mod tests {
assert_eq!(bank.get_balance(&mint.pubkey()), 0);
assert_eq!(bank.get_balance(&key1), 1);
assert_eq!(bank.get_balance(&key2), 1);
assert_eq!(bank.get_signature(&t1.last_id, &t1.signature), Some(Ok(())));
assert_eq!(
bank.get_signature(&t1.last_id, &t1.signatures[0]),
Some(Ok(()))
);
}

// TODO: This test demonstrates that fees are not paid when a program fails.
Expand All @@ -1637,7 +1649,7 @@ mod tests {
Pubkey::default(),
1,
);
let signature = tx.signature;
let signature = tx.signatures[0];
assert!(!bank.has_signature(&signature));
let res = bank.process_transaction(&tx);

Expand Down Expand Up @@ -2044,7 +2056,7 @@ mod tests {
let bank_sub_id = Keypair::new().pubkey();
let last_id = bank.last_id();
let tx = Transaction::system_move(&mint.keypair(), alice.pubkey(), 20, last_id, 0);
let signature = tx.signature;
let signature = tx.signatures[0];
bank.process_transaction(&tx).unwrap();

let (subscriber, _id_receiver, mut transport_receiver) =
Expand Down
2 changes: 1 addition & 1 deletion src/bin/bench-tps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ fn do_tx_transfers(

const MAX_SPENDS_PER_TX: usize = 5;
fn verify_transfer(client: &mut ThinClient, tx: &Transaction) -> bool {
if client.poll_for_signature(&tx.signature).is_err() {
if client.poll_for_signature(&tx.signatures[0]).is_err() {
println!("no signature");
return false;
}
Expand Down
12 changes: 10 additions & 2 deletions src/budget_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,14 @@ impl BudgetTransaction for Transaction {
transaction::Instruction::new(1, &budget_instruction, vec![1]),
];

Self::new_with_instructions(from_keypair, &keys, last_id, fee, program_ids, instructions)
Self::new_with_instructions(
&[from_keypair],
&keys,
last_id,
fee,
program_ids,
instructions,
)
}

/// Create and sign a new Transaction. Used for unit-testing.
Expand Down Expand Up @@ -258,9 +265,10 @@ mod tests {
let instruction = Instruction::NewBudget(expr);
let instructions = vec![transaction::Instruction::new(0, &instruction, vec![])];
let claim0 = Transaction {
signed_keys: vec![],
account_keys: vec![],
last_id: Default::default(),
signature: Default::default(),
signatures: vec![],
program_ids: vec![],
instructions,
fee: 0,
Expand Down
12 changes: 6 additions & 6 deletions src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ impl RpcSol for RpcSolImpl {
info!("send_transaction: send_to error: {:?}", err);
Error::internal_error()
})?;
let signature = bs58::encode(tx.signature).into_string();
let signature = bs58::encode(tx.signatures[0]).into_string();
trace!(
"send_transaction: sent {} bytes, signature={}",
data.len(),
Expand Down Expand Up @@ -507,7 +507,7 @@ mod tests {

let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"confirmTransaction","params":["{}"]}}"#,
tx.signature
tx.signatures[0]
);
let res = io.handle_request_sync(&req, meta);
let expected = format!(r#"{{"jsonrpc":"2.0","result":true,"id":1}}"#);
Expand All @@ -526,7 +526,7 @@ mod tests {

let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
tx.signature
tx.signatures[0]
);
let res = io.handle_request_sync(&req, meta.clone());
let expected = format!(r#"{{"jsonrpc":"2.0","result":"Confirmed","id":1}}"#);
Expand All @@ -540,7 +540,7 @@ mod tests {
let tx = Transaction::system_move(&alice_keypair, bob_pubkey, 10, last_id, 0);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
tx.signature
tx.signatures[0]
);
let res = io.handle_request_sync(&req, meta);
let expected = format!(r#"{{"jsonrpc":"2.0","result":"SignatureNotFound","id":1}}"#);
Expand Down Expand Up @@ -745,8 +745,8 @@ mod tests {
let tx =
Transaction::system_move(&Keypair::new(), Keypair::new().pubkey(), 20, hash(&[0]), 0);
assert_eq!(
verify_signature(&tx.signature.to_string()).unwrap(),
tx.signature
verify_signature(&tx.signatures[0].to_string()).unwrap(),
tx.signatures[0]
);
let bad_signature = "a1b2c3d4";
assert_eq!(
Expand Down
6 changes: 3 additions & 3 deletions src/rpc_pubsub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ mod tests {

let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"signatureSubscribe","params":["{}"]}}"#,
tx.signature.to_string()
tx.signatures[0].to_string()
);
let res = io.handle_request_sync(&req, session.clone());
let expected = format!(r#"{{"jsonrpc":"2.0","result":0,"id":1}}"#);
Expand Down Expand Up @@ -331,7 +331,7 @@ mod tests {
let tx = Transaction::system_move(&alice.keypair(), bob_pubkey, 10, last_id, 0);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"signatureSubscribe","params":["{}"]}}"#,
tx.signature.to_string()
tx.signatures[0].to_string()
);
let res = io.handle_request_sync(&req, session.clone());
let expected = format!(r#"{{"jsonrpc":"2.0","result":1,"id":1}}"#);
Expand Down Expand Up @@ -364,7 +364,7 @@ mod tests {
let tx = Transaction::system_move(&alice.keypair(), bob_pubkey, 20, last_id, 0);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"signatureSubscribe","params":["{}"]}}"#,
tx.signature.to_string()
tx.signatures[0].to_string()
);
let _res = io.handle_request_sync(&req, session.clone());

Expand Down
Loading

0 comments on commit 14acdc3

Please sign in to comment.