Multiple signatures for transactions
With multiple instructions in a TX may need multiple signatures. Fixes #1531
This commit is contained in:
parent
928f375683
commit
cda9ad8565
|
@ -66,7 +66,7 @@ fn bench_banking_stage_multi_accounts(bencher: &mut Bencher) {
|
||||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
||||||
new.account_keys[0] = Pubkey::new(&from[0..32]);
|
new.account_keys[0] = Pubkey::new(&from[0..32]);
|
||||||
new.account_keys[1] = Pubkey::new(&to[0..32]);
|
new.account_keys[1] = Pubkey::new(&to[0..32]);
|
||||||
new.signature = Signature::new(&sig[0..64]);
|
new.signatures = vec![Signature::new(&sig[0..64])];
|
||||||
new
|
new
|
||||||
}).collect();
|
}).collect();
|
||||||
// fund all the accounts
|
// fund all the accounts
|
||||||
|
@ -128,7 +128,7 @@ fn bench_banking_stage_multi_accounts(bencher: &mut Bencher) {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_banking_stage_multi_programs(bencher: &mut Bencher) {
|
fn bench_banking_stage_multi_programs(bencher: &mut Bencher) {
|
||||||
let progs = 5;
|
let progs = 4;
|
||||||
let txes = 1000 * NUM_THREADS;
|
let txes = 1000 * NUM_THREADS;
|
||||||
let mint_total = 1_000_000_000_000;
|
let mint_total = 1_000_000_000_000;
|
||||||
let mint = Mint::new(mint_total);
|
let mint = Mint::new(mint_total);
|
||||||
|
@ -168,7 +168,7 @@ fn bench_banking_stage_multi_programs(bencher: &mut Bencher) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
assert_eq!(new.instructions.len(), progs);
|
assert_eq!(new.instructions.len(), progs);
|
||||||
new.signature = Signature::new(&sig[0..64]);
|
new.signatures = vec![Signature::new(&sig[0..64])];
|
||||||
new
|
new
|
||||||
}).collect();
|
}).collect();
|
||||||
transactions.iter().for_each(|tx| {
|
transactions.iter().for_each(|tx| {
|
||||||
|
|
29
src/bank.rs
29
src/bank.rs
|
@ -484,7 +484,7 @@ impl Bank {
|
||||||
for (i, tx) in txs.iter().enumerate() {
|
for (i, tx) in txs.iter().enumerate() {
|
||||||
Self::update_signature_status_with_last_id(
|
Self::update_signature_status_with_last_id(
|
||||||
&mut last_ids.entries,
|
&mut last_ids.entries,
|
||||||
&tx.signature,
|
&tx.signatures[0],
|
||||||
&res[i],
|
&res[i],
|
||||||
&tx.last_id,
|
&tx.last_id,
|
||||||
);
|
);
|
||||||
|
@ -498,7 +498,7 @@ impl Bank {
|
||||||
Err(_) => RpcSignatureStatus::GenericFailure,
|
Err(_) => RpcSignatureStatus::GenericFailure,
|
||||||
};
|
};
|
||||||
if status != RpcSignatureStatus::SignatureNotFound {
|
if status != RpcSignatureStatus::SignatureNotFound {
|
||||||
self.check_signature_subscriptions(&tx.signature, status);
|
self.check_signature_subscriptions(&tx.signatures[0], status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -651,7 +651,8 @@ impl Bank {
|
||||||
|
|
||||||
// There is no way to predict what contract will execute without an error
|
// 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
|
// 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 {
|
if let Err(BankError::LastIdNotFound) = err {
|
||||||
error_counters.reserve_last_id += 1;
|
error_counters.reserve_last_id += 1;
|
||||||
} else if let Err(BankError::DuplicateSignature) = err {
|
} else if let Err(BankError::DuplicateSignature) = err {
|
||||||
|
@ -1292,7 +1293,7 @@ impl Bank {
|
||||||
last_id: Hash,
|
last_id: Hash,
|
||||||
) -> Result<Signature> {
|
) -> Result<Signature> {
|
||||||
let tx = Transaction::system_new(keypair, to, n, last_id);
|
let tx = Transaction::system_new(keypair, to, n, last_id);
|
||||||
let signature = tx.signature;
|
let signature = tx.signatures[0];
|
||||||
self.process_transaction(&tx).map(|_| signature)
|
self.process_transaction(&tx).map(|_| signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1550,10 +1551,13 @@ mod tests {
|
||||||
assert_eq!(bank.get_balance(&mint.pubkey()), 0);
|
assert_eq!(bank.get_balance(&mint.pubkey()), 0);
|
||||||
assert_eq!(bank.get_balance(&key1), 1);
|
assert_eq!(bank.get_balance(&key1), 1);
|
||||||
assert_eq!(bank.get_balance(&key2), 0);
|
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
|
// TODO: Transactions that fail to pay a fee could be dropped silently
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.get_signature(&t2.last_id, &t2.signature),
|
bank.get_signature(&t2.last_id, &t2.signatures[0]),
|
||||||
Some(Err(BankError::AccountInUse))
|
Some(Err(BankError::AccountInUse))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1579,7 +1583,7 @@ mod tests {
|
||||||
];
|
];
|
||||||
|
|
||||||
let t1 = Transaction::new_with_instructions(
|
let t1 = Transaction::new_with_instructions(
|
||||||
&mint.keypair(),
|
&[&mint.keypair()],
|
||||||
&[key1, key2],
|
&[key1, key2],
|
||||||
mint.last_id(),
|
mint.last_id(),
|
||||||
0,
|
0,
|
||||||
|
@ -1593,7 +1597,7 @@ mod tests {
|
||||||
assert_eq!(bank.get_balance(&key1), 0);
|
assert_eq!(bank.get_balance(&key1), 0);
|
||||||
assert_eq!(bank.get_balance(&key2), 0);
|
assert_eq!(bank.get_balance(&key2), 0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.get_signature(&t1.last_id, &t1.signature),
|
bank.get_signature(&t1.last_id, &t1.signatures[0]),
|
||||||
Some(Err(BankError::ResultWithNegativeTokens(1)))
|
Some(Err(BankError::ResultWithNegativeTokens(1)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1616,7 +1620,10 @@ mod tests {
|
||||||
assert_eq!(bank.get_balance(&mint.pubkey()), 0);
|
assert_eq!(bank.get_balance(&mint.pubkey()), 0);
|
||||||
assert_eq!(bank.get_balance(&key1), 1);
|
assert_eq!(bank.get_balance(&key1), 1);
|
||||||
assert_eq!(bank.get_balance(&key2), 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.
|
// TODO: This test demonstrates that fees are not paid when a program fails.
|
||||||
|
@ -1637,7 +1644,7 @@ mod tests {
|
||||||
Pubkey::default(),
|
Pubkey::default(),
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
let signature = tx.signature;
|
let signature = tx.signatures[0];
|
||||||
assert!(!bank.has_signature(&signature));
|
assert!(!bank.has_signature(&signature));
|
||||||
let res = bank.process_transaction(&tx);
|
let res = bank.process_transaction(&tx);
|
||||||
|
|
||||||
|
@ -2044,7 +2051,7 @@ mod tests {
|
||||||
let bank_sub_id = Keypair::new().pubkey();
|
let bank_sub_id = Keypair::new().pubkey();
|
||||||
let last_id = bank.last_id();
|
let last_id = bank.last_id();
|
||||||
let tx = Transaction::system_move(&mint.keypair(), alice.pubkey(), 20, last_id, 0);
|
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();
|
bank.process_transaction(&tx).unwrap();
|
||||||
|
|
||||||
let (subscriber, _id_receiver, mut transport_receiver) =
|
let (subscriber, _id_receiver, mut transport_receiver) =
|
||||||
|
|
|
@ -293,7 +293,7 @@ fn do_tx_transfers(
|
||||||
|
|
||||||
const MAX_SPENDS_PER_TX: usize = 5;
|
const MAX_SPENDS_PER_TX: usize = 5;
|
||||||
fn verify_transfer(client: &mut ThinClient, tx: &Transaction) -> bool {
|
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");
|
println!("no signature");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,14 @@ impl BudgetTransaction for Transaction {
|
||||||
transaction::Instruction::new(1, &budget_instruction, vec![1]),
|
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.
|
/// Create and sign a new Transaction. Used for unit-testing.
|
||||||
|
@ -258,9 +265,10 @@ mod tests {
|
||||||
let instruction = Instruction::NewBudget(expr);
|
let instruction = Instruction::NewBudget(expr);
|
||||||
let instructions = vec![transaction::Instruction::new(0, &instruction, vec![])];
|
let instructions = vec![transaction::Instruction::new(0, &instruction, vec![])];
|
||||||
let claim0 = Transaction {
|
let claim0 = Transaction {
|
||||||
|
signed_keys: vec![],
|
||||||
account_keys: vec![],
|
account_keys: vec![],
|
||||||
last_id: Default::default(),
|
last_id: Default::default(),
|
||||||
signature: Default::default(),
|
signatures: vec![],
|
||||||
program_ids: vec![],
|
program_ids: vec![],
|
||||||
instructions,
|
instructions,
|
||||||
fee: 0,
|
fee: 0,
|
||||||
|
|
12
src/rpc.rs
12
src/rpc.rs
|
@ -251,7 +251,7 @@ impl RpcSol for RpcSolImpl {
|
||||||
info!("send_transaction: send_to error: {:?}", err);
|
info!("send_transaction: send_to error: {:?}", err);
|
||||||
Error::internal_error()
|
Error::internal_error()
|
||||||
})?;
|
})?;
|
||||||
let signature = bs58::encode(tx.signature).into_string();
|
let signature = bs58::encode(tx.signatures[0]).into_string();
|
||||||
trace!(
|
trace!(
|
||||||
"send_transaction: sent {} bytes, signature={}",
|
"send_transaction: sent {} bytes, signature={}",
|
||||||
data.len(),
|
data.len(),
|
||||||
|
@ -504,7 +504,7 @@ mod tests {
|
||||||
|
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"confirmTransaction","params":["{}"]}}"#,
|
r#"{{"jsonrpc":"2.0","id":1,"method":"confirmTransaction","params":["{}"]}}"#,
|
||||||
tx.signature
|
tx.signatures[0]
|
||||||
);
|
);
|
||||||
let res = io.handle_request_sync(&req, meta);
|
let res = io.handle_request_sync(&req, meta);
|
||||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":true,"id":1}}"#);
|
let expected = format!(r#"{{"jsonrpc":"2.0","result":true,"id":1}}"#);
|
||||||
|
@ -523,7 +523,7 @@ mod tests {
|
||||||
|
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
||||||
tx.signature
|
tx.signatures[0]
|
||||||
);
|
);
|
||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":"Confirmed","id":1}}"#);
|
let expected = format!(r#"{{"jsonrpc":"2.0","result":"Confirmed","id":1}}"#);
|
||||||
|
@ -537,7 +537,7 @@ mod tests {
|
||||||
let tx = Transaction::system_move(&alice_keypair, bob_pubkey, 10, last_id, 0);
|
let tx = Transaction::system_move(&alice_keypair, bob_pubkey, 10, last_id, 0);
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
||||||
tx.signature
|
tx.signatures[0]
|
||||||
);
|
);
|
||||||
let res = io.handle_request_sync(&req, meta);
|
let res = io.handle_request_sync(&req, meta);
|
||||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":"SignatureNotFound","id":1}}"#);
|
let expected = format!(r#"{{"jsonrpc":"2.0","result":"SignatureNotFound","id":1}}"#);
|
||||||
|
@ -738,8 +738,8 @@ mod tests {
|
||||||
let tx =
|
let tx =
|
||||||
Transaction::system_move(&Keypair::new(), Keypair::new().pubkey(), 20, hash(&[0]), 0);
|
Transaction::system_move(&Keypair::new(), Keypair::new().pubkey(), 20, hash(&[0]), 0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_signature(&tx.signature.to_string()).unwrap(),
|
verify_signature(&tx.signatures[0].to_string()).unwrap(),
|
||||||
tx.signature
|
tx.signatures[0]
|
||||||
);
|
);
|
||||||
let bad_signature = "a1b2c3d4";
|
let bad_signature = "a1b2c3d4";
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -290,7 +290,7 @@ mod tests {
|
||||||
|
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"signatureSubscribe","params":["{}"]}}"#,
|
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 res = io.handle_request_sync(&req, session.clone());
|
||||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":0,"id":1}}"#);
|
let expected = format!(r#"{{"jsonrpc":"2.0","result":0,"id":1}}"#);
|
||||||
|
@ -331,7 +331,7 @@ mod tests {
|
||||||
let tx = Transaction::system_move(&alice.keypair(), bob_pubkey, 10, last_id, 0);
|
let tx = Transaction::system_move(&alice.keypair(), bob_pubkey, 10, last_id, 0);
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"signatureSubscribe","params":["{}"]}}"#,
|
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 res = io.handle_request_sync(&req, session.clone());
|
||||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":1,"id":1}}"#);
|
let expected = format!(r#"{{"jsonrpc":"2.0","result":1,"id":1}}"#);
|
||||||
|
@ -364,7 +364,7 @@ mod tests {
|
||||||
let tx = Transaction::system_move(&alice.keypair(), bob_pubkey, 20, last_id, 0);
|
let tx = Transaction::system_move(&alice.keypair(), bob_pubkey, 20, last_id, 0);
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"signatureSubscribe","params":["{}"]}}"#,
|
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 _res = io.handle_request_sync(&req, session.clone());
|
||||||
|
|
||||||
|
|
262
src/sigverify.rs
262
src/sigverify.rs
|
@ -4,15 +4,23 @@
|
||||||
//! offloaded to the GPU.
|
//! offloaded to the GPU.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
use counter::Counter;
|
use counter::Counter;
|
||||||
use log::Level;
|
use log::Level;
|
||||||
use packet::{Packet, SharedPackets};
|
use packet::{Packet, SharedPackets};
|
||||||
|
use result::Result;
|
||||||
|
use signature::Signature;
|
||||||
|
use solana_sdk::pubkey::Pubkey;
|
||||||
|
use std::io;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use transaction::{PUB_KEY_OFFSET, SIGNED_DATA_OFFSET, SIG_OFFSET};
|
#[cfg(test)]
|
||||||
|
use transaction::Transaction;
|
||||||
|
|
||||||
pub const TX_OFFSET: usize = 0;
|
pub const TX_OFFSET: usize = 0;
|
||||||
|
|
||||||
|
type TxOffsets = (Vec<u32>, Vec<u32>, Vec<u32>, Vec<u32>, Vec<Vec<u32>>);
|
||||||
|
|
||||||
#[cfg(feature = "cuda")]
|
#[cfg(feature = "cuda")]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Elems {
|
struct Elems {
|
||||||
|
@ -29,10 +37,12 @@ extern "C" {
|
||||||
vecs: *const Elems,
|
vecs: *const Elems,
|
||||||
num: u32, //number of vecs
|
num: u32, //number of vecs
|
||||||
message_size: u32, //size of each element inside the elems field of the vec
|
message_size: u32, //size of each element inside the elems field of the vec
|
||||||
pubkey_offset: u32,
|
total_packets: u32,
|
||||||
signature_offset: u32,
|
total_signatures: u32,
|
||||||
signed_message_offset: u32,
|
message_lens: *const u32,
|
||||||
signed_message_len_offset: u32,
|
pubkey_offsets: *const u32,
|
||||||
|
signature_offsets: *const u32,
|
||||||
|
signed_message_offsets: *const u32,
|
||||||
out: *mut u8, //combined length of all the items in vecs
|
out: *mut u8, //combined length of all the items in vecs
|
||||||
) -> u32;
|
) -> u32;
|
||||||
|
|
||||||
|
@ -64,23 +74,37 @@ fn verify_packet(packet: &Packet) -> u8 {
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use untrusted;
|
use untrusted;
|
||||||
|
|
||||||
let msg_start = TX_OFFSET + SIGNED_DATA_OFFSET;
|
let (sig_len, sig_start, msg_start, pubkey_start) = get_packet_offsets(packet, 0);
|
||||||
let sig_start = TX_OFFSET + SIG_OFFSET;
|
let mut sig_start = sig_start as usize;
|
||||||
let sig_end = sig_start + size_of::<Signature>();
|
let mut pubkey_start = pubkey_start as usize;
|
||||||
let pubkey_start = TX_OFFSET + PUB_KEY_OFFSET;
|
let msg_start = msg_start as usize;
|
||||||
let pubkey_end = pubkey_start + size_of::<Pubkey>();
|
|
||||||
|
|
||||||
if packet.meta.size <= msg_start {
|
if packet.meta.size <= msg_start {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg_end = packet.meta.size;
|
let msg_end = packet.meta.size;
|
||||||
signature::verify(
|
for _ in 0..sig_len {
|
||||||
|
let pubkey_end = pubkey_start as usize + size_of::<Pubkey>();
|
||||||
|
let sig_end = sig_start as usize + size_of::<Signature>();
|
||||||
|
|
||||||
|
if pubkey_end >= packet.meta.size || sig_end >= packet.meta.size {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if signature::verify(
|
||||||
&signature::ED25519,
|
&signature::ED25519,
|
||||||
untrusted::Input::from(&packet.data[pubkey_start..pubkey_end]),
|
untrusted::Input::from(&packet.data[pubkey_start..pubkey_end]),
|
||||||
untrusted::Input::from(&packet.data[msg_start..msg_end]),
|
untrusted::Input::from(&packet.data[msg_start..msg_end]),
|
||||||
untrusted::Input::from(&packet.data[sig_start..sig_end]),
|
untrusted::Input::from(&packet.data[sig_start..sig_end]),
|
||||||
).is_ok() as u8
|
).is_err()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pubkey_start += size_of::<Pubkey>();
|
||||||
|
sig_start += size_of::<Signature>();
|
||||||
|
}
|
||||||
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_packet_disabled(_packet: &Packet) -> u8 {
|
fn verify_packet_disabled(_packet: &Packet) -> u8 {
|
||||||
|
@ -100,6 +124,64 @@ pub fn ed25519_verify(batches: &[SharedPackets]) -> Vec<Vec<u8>> {
|
||||||
ed25519_verify_cpu(batches)
|
ed25519_verify_cpu(batches)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_packet_offsets(packet: &Packet, current_offset: u32) -> (u32, u32, u32, u32) {
|
||||||
|
// Read in u64 as the size of signatures array
|
||||||
|
let mut rdr = io::Cursor::new(&packet.data[TX_OFFSET..size_of::<u64>()]);
|
||||||
|
let sig_len = rdr.read_u64::<LittleEndian>().unwrap() as u32;
|
||||||
|
|
||||||
|
let msg_start_offset =
|
||||||
|
current_offset + size_of::<u64>() as u32 + sig_len * size_of::<Signature>() as u32;
|
||||||
|
let pubkey_offset = msg_start_offset + size_of::<u64>() as u32;
|
||||||
|
|
||||||
|
let sig_start = TX_OFFSET as u32 + size_of::<u64>() as u32;
|
||||||
|
|
||||||
|
(sig_len, sig_start, msg_start_offset, pubkey_offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_offsets(batches: &[SharedPackets]) -> Result<TxOffsets> {
|
||||||
|
let mut signature_offsets: Vec<_> = Vec::new();
|
||||||
|
let mut pubkey_offsets: Vec<_> = Vec::new();
|
||||||
|
let mut msg_start_offsets: Vec<_> = Vec::new();
|
||||||
|
let mut msg_sizes: Vec<_> = Vec::new();
|
||||||
|
let mut current_packet = 0;
|
||||||
|
let mut v_sig_lens = Vec::new();
|
||||||
|
batches.into_iter().for_each(|p| {
|
||||||
|
let mut sig_lens = Vec::new();
|
||||||
|
p.read().unwrap().packets.iter().for_each(|packet| {
|
||||||
|
let current_offset = current_packet as u32 * size_of::<Packet>() as u32;
|
||||||
|
|
||||||
|
let (sig_len, _sig_start, msg_start_offset, pubkey_offset) =
|
||||||
|
get_packet_offsets(packet, current_offset);
|
||||||
|
let mut pubkey_offset = pubkey_offset;
|
||||||
|
|
||||||
|
sig_lens.push(sig_len);
|
||||||
|
|
||||||
|
trace!("pubkey_offset: {}", pubkey_offset);
|
||||||
|
let mut sig_offset = current_offset + size_of::<u64>() as u32;
|
||||||
|
for _ in 0..sig_len {
|
||||||
|
signature_offsets.push(sig_offset);
|
||||||
|
sig_offset += size_of::<Signature>() as u32;
|
||||||
|
|
||||||
|
pubkey_offsets.push(pubkey_offset);
|
||||||
|
pubkey_offset += size_of::<Pubkey>() as u32;
|
||||||
|
|
||||||
|
msg_start_offsets.push(msg_start_offset);
|
||||||
|
|
||||||
|
msg_sizes.push(current_offset + (packet.meta.size as u32) - msg_start_offset);
|
||||||
|
}
|
||||||
|
current_packet += 1;
|
||||||
|
});
|
||||||
|
v_sig_lens.push(sig_lens);
|
||||||
|
});
|
||||||
|
Ok((
|
||||||
|
signature_offsets,
|
||||||
|
pubkey_offsets,
|
||||||
|
msg_start_offsets,
|
||||||
|
msg_sizes,
|
||||||
|
v_sig_lens,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ed25519_verify_cpu(batches: &[SharedPackets]) -> Vec<Vec<u8>> {
|
pub fn ed25519_verify_cpu(batches: &[SharedPackets]) -> Vec<Vec<u8>> {
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
let count = batch_size(batches);
|
let count = batch_size(batches);
|
||||||
|
@ -161,6 +243,9 @@ pub fn ed25519_verify(batches: &[SharedPackets]) -> Vec<Vec<u8>> {
|
||||||
return ed25519_verify_cpu(batches);
|
return ed25519_verify_cpu(batches);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (signature_offsets, pubkey_offsets, msg_start_offsets, msg_sizes, sig_lens) =
|
||||||
|
generate_offsets(batches).unwrap();
|
||||||
|
|
||||||
info!("CUDA ECDSA for {}", batch_size(batches));
|
info!("CUDA ECDSA for {}", batch_size(batches));
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
let mut elems = Vec::new();
|
let mut elems = Vec::new();
|
||||||
|
@ -170,7 +255,7 @@ pub fn ed25519_verify(batches: &[SharedPackets]) -> Vec<Vec<u8>> {
|
||||||
for packets in batches {
|
for packets in batches {
|
||||||
locks.push(packets.read().unwrap());
|
locks.push(packets.read().unwrap());
|
||||||
}
|
}
|
||||||
let mut num = 0;
|
let mut num_packets = 0;
|
||||||
for p in locks {
|
for p in locks {
|
||||||
elems.push(Elems {
|
elems.push(Elems {
|
||||||
elems: p.packets.as_ptr(),
|
elems: p.packets.as_ptr(),
|
||||||
|
@ -179,25 +264,24 @@ pub fn ed25519_verify(batches: &[SharedPackets]) -> Vec<Vec<u8>> {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
v.resize(p.packets.len(), 0);
|
v.resize(p.packets.len(), 0);
|
||||||
rvs.push(v);
|
rvs.push(v);
|
||||||
num += p.packets.len();
|
num_packets += p.packets.len();
|
||||||
}
|
}
|
||||||
out.resize(num, 0);
|
out.resize(signature_offsets.len(), 0);
|
||||||
trace!("Starting verify num packets: {}", num);
|
trace!("Starting verify num packets: {}", num_packets);
|
||||||
trace!("elem len: {}", elems.len() as u32);
|
trace!("elem len: {}", elems.len() as u32);
|
||||||
trace!("packet sizeof: {}", size_of::<Packet>() as u32);
|
trace!("packet sizeof: {}", size_of::<Packet>() as u32);
|
||||||
trace!("pubkey: {}", (TX_OFFSET + PUB_KEY_OFFSET) as u32);
|
|
||||||
trace!("signature offset: {}", (TX_OFFSET + SIG_OFFSET) as u32);
|
|
||||||
trace!("sign data: {}", (TX_OFFSET + SIGNED_DATA_OFFSET) as u32);
|
|
||||||
trace!("len offset: {}", PACKET_DATA_SIZE as u32);
|
trace!("len offset: {}", PACKET_DATA_SIZE as u32);
|
||||||
unsafe {
|
unsafe {
|
||||||
let res = ed25519_verify_many(
|
let res = ed25519_verify_many(
|
||||||
elems.as_ptr(),
|
elems.as_ptr(),
|
||||||
elems.len() as u32,
|
elems.len() as u32,
|
||||||
size_of::<Packet>() as u32,
|
size_of::<Packet>() as u32,
|
||||||
(TX_OFFSET + PUB_KEY_OFFSET) as u32,
|
num_packets as u32,
|
||||||
(TX_OFFSET + SIG_OFFSET) as u32,
|
signature_offsets.len() as u32,
|
||||||
(TX_OFFSET + SIGNED_DATA_OFFSET) as u32,
|
msg_sizes.as_ptr(),
|
||||||
PACKET_DATA_SIZE as u32,
|
pubkey_offsets.as_ptr(),
|
||||||
|
signature_offsets.as_ptr(),
|
||||||
|
msg_start_offsets.as_ptr(),
|
||||||
out.as_mut_ptr(),
|
out.as_mut_ptr(),
|
||||||
);
|
);
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
|
@ -206,25 +290,47 @@ pub fn ed25519_verify(batches: &[SharedPackets]) -> Vec<Vec<u8>> {
|
||||||
}
|
}
|
||||||
trace!("done verify");
|
trace!("done verify");
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
for vs in rvs.iter_mut() {
|
for (vs, sig_vs) in rvs.iter_mut().zip(sig_lens.iter()) {
|
||||||
for mut v in vs.iter_mut() {
|
for (mut v, sig_v) in vs.iter_mut().zip(sig_vs.iter()) {
|
||||||
*v = out[num];
|
let mut vout = 1;
|
||||||
|
for _ in 0..*sig_v {
|
||||||
|
if 0 == out[num] {
|
||||||
|
vout = 0;
|
||||||
|
}
|
||||||
|
num += 1;
|
||||||
|
}
|
||||||
|
*v = vout;
|
||||||
if *v != 0 {
|
if *v != 0 {
|
||||||
trace!("VERIFIED PACKET!!!!!");
|
trace!("VERIFIED PACKET!!!!!");
|
||||||
}
|
}
|
||||||
num += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inc_new_counter_info!("ed25519_verify_gpu", count);
|
inc_new_counter_info!("ed25519_verify_gpu", count);
|
||||||
rvs
|
rvs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn make_packet_from_transaction(tx: Transaction) -> Packet {
|
||||||
|
use bincode::serialize;
|
||||||
|
|
||||||
|
let tx_bytes = serialize(&tx).unwrap();
|
||||||
|
let mut packet = Packet::default();
|
||||||
|
packet.meta.size = tx_bytes.len();
|
||||||
|
packet.data[..packet.meta.size].copy_from_slice(&tx_bytes);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
|
use budget_program::BudgetState;
|
||||||
|
use hash::Hash;
|
||||||
use packet::{Packet, SharedPackets};
|
use packet::{Packet, SharedPackets};
|
||||||
|
use signature::{Keypair, KeypairUtil};
|
||||||
use sigverify;
|
use sigverify;
|
||||||
|
use system_program::SystemProgram;
|
||||||
use system_transaction::{memfind, test_tx};
|
use system_transaction::{memfind, test_tx};
|
||||||
|
use transaction;
|
||||||
use transaction::Transaction;
|
use transaction::Transaction;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -236,25 +342,25 @@ mod tests {
|
||||||
assert_matches!(memfind(&packet, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), None);
|
assert_matches!(memfind(&packet, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_packet_from_transaction(tx: Transaction) -> Packet {
|
#[test]
|
||||||
let tx_bytes = serialize(&tx).unwrap();
|
fn test_get_packet_offsets() {
|
||||||
let mut packet = Packet::default();
|
|
||||||
packet.meta.size = tx_bytes.len();
|
|
||||||
packet.data[..packet.meta.size].copy_from_slice(&tx_bytes);
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_verify_n(n: usize, modify_data: bool) {
|
|
||||||
let tx = test_tx();
|
let tx = test_tx();
|
||||||
let mut packet = make_packet_from_transaction(tx);
|
let packet = sigverify::make_packet_from_transaction(tx);
|
||||||
|
let (sig_len, sig_start, msg_start_offset, pubkey_offset) =
|
||||||
// jumble some data to test failure
|
sigverify::get_packet_offsets(&packet, 0);
|
||||||
if modify_data {
|
assert_eq!(sig_len, 1);
|
||||||
packet.data[20] = packet.data[20].wrapping_add(10);
|
assert_eq!(sig_start, 8);
|
||||||
|
assert_eq!(msg_start_offset, 72);
|
||||||
|
assert_eq!(pubkey_offset, 80);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_packet_vec(
|
||||||
|
packet: &Packet,
|
||||||
|
num_packets_per_batch: usize,
|
||||||
|
num_batches: usize,
|
||||||
|
) -> Vec<SharedPackets> {
|
||||||
// generate packet vector
|
// generate packet vector
|
||||||
let batches: Vec<_> = (0..2)
|
let batches: Vec<_> = (0..num_batches)
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
let packets = SharedPackets::default();
|
let packets = SharedPackets::default();
|
||||||
packets
|
packets
|
||||||
|
@ -262,13 +368,27 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.packets
|
.packets
|
||||||
.resize(0, Default::default());
|
.resize(0, Default::default());
|
||||||
for _ in 0..n {
|
for _ in 0..num_packets_per_batch {
|
||||||
packets.write().unwrap().packets.push(packet.clone());
|
packets.write().unwrap().packets.push(packet.clone());
|
||||||
}
|
}
|
||||||
assert_eq!(packets.read().unwrap().packets.len(), n);
|
assert_eq!(packets.read().unwrap().packets.len(), num_packets_per_batch);
|
||||||
packets
|
packets
|
||||||
}).collect();
|
}).collect();
|
||||||
assert_eq!(batches.len(), 2);
|
assert_eq!(batches.len(), num_batches);
|
||||||
|
|
||||||
|
batches
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_verify_n(n: usize, modify_data: bool) {
|
||||||
|
let tx = test_tx();
|
||||||
|
let mut packet = sigverify::make_packet_from_transaction(tx);
|
||||||
|
|
||||||
|
// jumble some data to test failure
|
||||||
|
if modify_data {
|
||||||
|
packet.data[20] = packet.data[20].wrapping_add(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
let batches = generate_packet_vec(&packet, n, 2);
|
||||||
|
|
||||||
// verify packets
|
// verify packets
|
||||||
let ans = sigverify::ed25519_verify(&batches);
|
let ans = sigverify::ed25519_verify(&batches);
|
||||||
|
@ -293,6 +413,58 @@ mod tests {
|
||||||
test_verify_n(71, false);
|
test_verify_n(71, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_verify_multi_sig() {
|
||||||
|
use logger;
|
||||||
|
logger::setup();
|
||||||
|
let keypair0 = Keypair::new();
|
||||||
|
let keypair1 = Keypair::new();
|
||||||
|
let keypairs = vec![&keypair0, &keypair1];
|
||||||
|
let tokens = 5;
|
||||||
|
let fee = 2;
|
||||||
|
let last_id = Hash::default();
|
||||||
|
|
||||||
|
let keys = vec![keypair0.pubkey(), keypair1.pubkey()];
|
||||||
|
|
||||||
|
let system_instruction = SystemProgram::Move { tokens };
|
||||||
|
|
||||||
|
let program_ids = vec![SystemProgram::id(), BudgetState::id()];
|
||||||
|
|
||||||
|
let instructions = vec![transaction::Instruction::new(
|
||||||
|
0,
|
||||||
|
&system_instruction,
|
||||||
|
vec![0, 1],
|
||||||
|
)];
|
||||||
|
|
||||||
|
let tx = Transaction::new_with_instructions(
|
||||||
|
&keypairs,
|
||||||
|
&keys,
|
||||||
|
last_id,
|
||||||
|
fee,
|
||||||
|
program_ids,
|
||||||
|
instructions,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut packet = sigverify::make_packet_from_transaction(tx);
|
||||||
|
|
||||||
|
let n = 4;
|
||||||
|
let num_batches = 3;
|
||||||
|
let batches = generate_packet_vec(&packet, n, num_batches);
|
||||||
|
|
||||||
|
packet.data[40] = packet.data[40].wrapping_add(8);
|
||||||
|
|
||||||
|
batches[0].write().unwrap().packets.push(packet);
|
||||||
|
|
||||||
|
// verify packets
|
||||||
|
let ans = sigverify::ed25519_verify(&batches);
|
||||||
|
|
||||||
|
// check result
|
||||||
|
let ref_ans = 1u8;
|
||||||
|
let mut ref_vec = vec![vec![ref_ans; n]; num_batches];
|
||||||
|
ref_vec[0].push(0u8);
|
||||||
|
assert_eq!(ans, ref_vec);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_verify_fail() {
|
fn test_verify_fail() {
|
||||||
test_verify_n(5, true);
|
test_verify_n(5, true);
|
||||||
|
|
|
@ -222,7 +222,7 @@ impl StorageStage {
|
||||||
);
|
);
|
||||||
let mut storage_keys = storage_keys.write().unwrap();
|
let mut storage_keys = storage_keys.write().unwrap();
|
||||||
storage_keys[*current_key_idx..*current_key_idx + size_of::<Signature>()]
|
storage_keys[*current_key_idx..*current_key_idx + size_of::<Signature>()]
|
||||||
.copy_from_slice(tx.signature.as_ref());
|
.copy_from_slice(tx.signatures[0].as_ref());
|
||||||
*current_key_idx += size_of::<Signature>();
|
*current_key_idx += size_of::<Signature>();
|
||||||
*current_key_idx %= storage_keys.len();
|
*current_key_idx %= storage_keys.len();
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,7 @@ impl SystemTransaction for Transaction {
|
||||||
let to_keys: Vec<_> = moves.iter().map(|(to_key, _)| *to_key).collect();
|
let to_keys: Vec<_> = moves.iter().map(|(to_key, _)| *to_key).collect();
|
||||||
|
|
||||||
Transaction::new_with_instructions(
|
Transaction::new_with_instructions(
|
||||||
from,
|
&[from],
|
||||||
&to_keys,
|
&to_keys,
|
||||||
last_id,
|
last_id,
|
||||||
fee,
|
fee,
|
||||||
|
@ -149,19 +149,36 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use bincode::{deserialize, serialize};
|
use bincode::{deserialize, serialize};
|
||||||
use packet::PACKET_DATA_SIZE;
|
use packet::PACKET_DATA_SIZE;
|
||||||
use transaction::{PUB_KEY_OFFSET, SIGNED_DATA_OFFSET, SIG_OFFSET};
|
use sigverify;
|
||||||
|
use transaction::SIG_OFFSET;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_layout() {
|
fn test_layout() {
|
||||||
let tx = test_tx();
|
let tx = test_tx();
|
||||||
let sign_data = tx.get_sign_data();
|
|
||||||
let tx_bytes = serialize(&tx).unwrap();
|
let tx_bytes = serialize(&tx).unwrap();
|
||||||
assert_eq!(memfind(&tx_bytes, &sign_data), Some(SIGNED_DATA_OFFSET));
|
let sign_data = tx.get_sign_data();
|
||||||
assert_eq!(memfind(&tx_bytes, &tx.signature.as_ref()), Some(SIG_OFFSET));
|
let packet = sigverify::make_packet_from_transaction(tx.clone());
|
||||||
|
|
||||||
|
let (sig_len, sig_start, msg_start_offset, pubkey_offset) =
|
||||||
|
sigverify::get_packet_offsets(&packet, 0);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
memfind(&tx_bytes, &tx.signatures[0].as_ref()),
|
||||||
|
Some(SIG_OFFSET)
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
memfind(&tx_bytes, &tx.account_keys[0].as_ref()),
|
memfind(&tx_bytes, &tx.account_keys[0].as_ref()),
|
||||||
Some(PUB_KEY_OFFSET)
|
Some(pubkey_offset as usize)
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
memfind(&tx_bytes, &sign_data),
|
||||||
|
Some(msg_start_offset as usize)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
memfind(&tx_bytes, &tx.signatures[0].as_ref()),
|
||||||
|
Some(sig_start as usize)
|
||||||
|
);
|
||||||
|
assert_eq!(sig_len, 1);
|
||||||
assert!(tx.verify_signature());
|
assert!(tx.verify_signature());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,15 +189,10 @@ mod tests {
|
||||||
let sign_data0a = tx0.get_sign_data();
|
let sign_data0a = tx0.get_sign_data();
|
||||||
let tx_bytes = serialize(&tx0).unwrap();
|
let tx_bytes = serialize(&tx0).unwrap();
|
||||||
assert!(tx_bytes.len() < PACKET_DATA_SIZE);
|
assert!(tx_bytes.len() < PACKET_DATA_SIZE);
|
||||||
assert_eq!(memfind(&tx_bytes, &sign_data0a), Some(SIGNED_DATA_OFFSET));
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
memfind(&tx_bytes, &tx0.signature.as_ref()),
|
memfind(&tx_bytes, &tx0.signatures[0].as_ref()),
|
||||||
Some(SIG_OFFSET)
|
Some(SIG_OFFSET)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
|
||||||
memfind(&tx_bytes, &tx0.account_keys[0].as_ref()),
|
|
||||||
Some(PUB_KEY_OFFSET)
|
|
||||||
);
|
|
||||||
let tx1 = deserialize(&tx_bytes).unwrap();
|
let tx1 = deserialize(&tx_bytes).unwrap();
|
||||||
assert_eq!(tx0, tx1);
|
assert_eq!(tx0, tx1);
|
||||||
assert_eq!(tx1.instructions[0].userdata, vec![1, 2, 3]);
|
assert_eq!(tx1.instructions[0].userdata, vec![1, 2, 3]);
|
||||||
|
|
|
@ -71,7 +71,7 @@ impl ThinClient {
|
||||||
let data = serialize(&tx).expect("serialize Transaction in pub fn transfer_signed");
|
let data = serialize(&tx).expect("serialize Transaction in pub fn transfer_signed");
|
||||||
self.transactions_socket
|
self.transactions_socket
|
||||||
.send_to(&data, &self.transactions_addr)?;
|
.send_to(&data, &self.transactions_addr)?;
|
||||||
Ok(tx.signature)
|
Ok(tx.signatures[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retry a sending a signed Transaction to the server for processing.
|
/// Retry a sending a signed Transaction to the server for processing.
|
||||||
|
@ -82,12 +82,12 @@ impl ThinClient {
|
||||||
tries: usize,
|
tries: usize,
|
||||||
) -> io::Result<Signature> {
|
) -> io::Result<Signature> {
|
||||||
for x in 0..tries {
|
for x in 0..tries {
|
||||||
tx.sign(&keypair, self.get_last_id());
|
tx.sign(&[&keypair], self.get_last_id());
|
||||||
let data = serialize(&tx).expect("serialize Transaction in pub fn transfer_signed");
|
let data = serialize(&tx).expect("serialize Transaction in pub fn transfer_signed");
|
||||||
self.transactions_socket
|
self.transactions_socket
|
||||||
.send_to(&data, &self.transactions_addr)?;
|
.send_to(&data, &self.transactions_addr)?;
|
||||||
if self.poll_for_signature(&tx.signature).is_ok() {
|
if self.poll_for_signature(&tx.signatures[0]).is_ok() {
|
||||||
return Ok(tx.signature);
|
return Ok(tx.signatures[0]);
|
||||||
}
|
}
|
||||||
info!("{} tries failed transfer to {}", x, self.transactions_addr);
|
info!("{} tries failed transfer to {}", x, self.transactions_addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,7 @@ use signature::{Keypair, KeypairUtil, Signature};
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
|
||||||
pub const SIGNED_DATA_OFFSET: usize = size_of::<Signature>();
|
pub const SIG_OFFSET: usize = size_of::<u64>();
|
||||||
pub const SIG_OFFSET: usize = 0;
|
|
||||||
pub const PUB_KEY_OFFSET: usize = size_of::<Signature>() + size_of::<u64>();
|
|
||||||
|
|
||||||
/// An instruction to execute a program under the `program_id` of `program_ids_index` with the
|
/// An instruction to execute a program under the `program_id` of `program_ids_index` with the
|
||||||
/// specified accounts and userdata
|
/// specified accounts and userdata
|
||||||
|
@ -38,8 +36,11 @@ impl Instruction {
|
||||||
/// An atomic transaction
|
/// An atomic transaction
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
/// A digital signature of `account_keys`, `program_ids`, `last_id`, `fee` and `instructions`, signed by `Pubkey`.
|
/// A set of digital signature of `account_keys`, `program_ids`, `last_id`, `fee` and `instructions`, signed by `signed_keys`.
|
||||||
pub signature: Signature,
|
pub signatures: Vec<Signature>,
|
||||||
|
|
||||||
|
/// The `Pubkeys` that correspond to signature in `signatures`
|
||||||
|
pub signed_keys: Vec<Pubkey>,
|
||||||
|
|
||||||
/// The `Pubkeys` that are executing this transaction userdata. The meaning of each key is
|
/// The `Pubkeys` that are executing this transaction userdata. The meaning of each key is
|
||||||
/// program-specific.
|
/// program-specific.
|
||||||
|
@ -74,7 +75,7 @@ impl Transaction {
|
||||||
let accounts = (0..=transaction_keys.len() as u8).collect();
|
let accounts = (0..=transaction_keys.len() as u8).collect();
|
||||||
let instructions = vec![Instruction::new(0, userdata, accounts)];
|
let instructions = vec![Instruction::new(0, userdata, accounts)];
|
||||||
Self::new_with_instructions(
|
Self::new_with_instructions(
|
||||||
from_keypair,
|
&[from_keypair],
|
||||||
transaction_keys,
|
transaction_keys,
|
||||||
last_id,
|
last_id,
|
||||||
fee,
|
fee,
|
||||||
|
@ -91,25 +92,31 @@ impl Transaction {
|
||||||
/// * `program_ids` - The keys that identify programs used in the `instruction` vector.
|
/// * `program_ids` - The keys that identify programs used in the `instruction` vector.
|
||||||
/// * `instructions` - The programs and their arguments that the transaction will execute atomically
|
/// * `instructions` - The programs and their arguments that the transaction will execute atomically
|
||||||
pub fn new_with_instructions(
|
pub fn new_with_instructions(
|
||||||
from_keypair: &Keypair,
|
from_keypairs: &[&Keypair],
|
||||||
keys: &[Pubkey],
|
keys: &[Pubkey],
|
||||||
last_id: Hash,
|
last_id: Hash,
|
||||||
fee: u64,
|
fee: u64,
|
||||||
program_ids: Vec<Pubkey>,
|
program_ids: Vec<Pubkey>,
|
||||||
instructions: Vec<Instruction>,
|
instructions: Vec<Instruction>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let from = from_keypair.pubkey();
|
let from = from_keypairs[0].pubkey();
|
||||||
let mut account_keys = vec![from];
|
let mut account_keys = Vec::with_capacity(keys.len() + 1);
|
||||||
|
account_keys.push(from);
|
||||||
account_keys.extend_from_slice(keys);
|
account_keys.extend_from_slice(keys);
|
||||||
|
let signed_keys = from_keypairs
|
||||||
|
.iter()
|
||||||
|
.map(|keypair| keypair.pubkey())
|
||||||
|
.collect();
|
||||||
let mut tx = Transaction {
|
let mut tx = Transaction {
|
||||||
signature: Signature::default(),
|
signatures: vec![],
|
||||||
|
signed_keys,
|
||||||
account_keys,
|
account_keys,
|
||||||
last_id: Hash::default(),
|
last_id: Hash::default(),
|
||||||
fee,
|
fee,
|
||||||
program_ids,
|
program_ids,
|
||||||
instructions,
|
instructions,
|
||||||
};
|
};
|
||||||
tx.sign(from_keypair, last_id);
|
tx.sign(from_keypairs, last_id);
|
||||||
tx
|
tx
|
||||||
}
|
}
|
||||||
pub fn userdata(&self, instruction_index: usize) -> &[u8] {
|
pub fn userdata(&self, instruction_index: usize) -> &[u8] {
|
||||||
|
@ -138,7 +145,10 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
/// Get the transaction data to sign.
|
/// Get the transaction data to sign.
|
||||||
pub fn get_sign_data(&self) -> Vec<u8> {
|
pub fn get_sign_data(&self) -> Vec<u8> {
|
||||||
let mut data = serialize(&self.account_keys).expect("serialize account_keys");
|
let mut data = serialize(&self.signed_keys).expect("serialize signed keys");
|
||||||
|
|
||||||
|
let account_keys_data = serialize(&self.account_keys).expect("serialize account_keys");
|
||||||
|
data.extend_from_slice(&account_keys_data);
|
||||||
|
|
||||||
let last_id_data = serialize(&self.last_id).expect("serialize last_id");
|
let last_id_data = serialize(&self.last_id).expect("serialize last_id");
|
||||||
data.extend_from_slice(&last_id_data);
|
data.extend_from_slice(&last_id_data);
|
||||||
|
@ -155,17 +165,21 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sign this transaction.
|
/// Sign this transaction.
|
||||||
pub fn sign(&mut self, keypair: &Keypair, last_id: Hash) {
|
pub fn sign(&mut self, keypairs: &[&Keypair], last_id: Hash) {
|
||||||
self.last_id = last_id;
|
self.last_id = last_id;
|
||||||
let sign_data = self.get_sign_data();
|
let sign_data = self.get_sign_data();
|
||||||
self.signature = Signature::new(keypair.sign(&sign_data).as_ref());
|
self.signatures = keypairs
|
||||||
|
.iter()
|
||||||
|
.map(|keypair| Signature::new(&keypair.sign(&sign_data).as_ref()))
|
||||||
|
.collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify only the transaction signature.
|
/// Verify only the transaction signature.
|
||||||
pub fn verify_signature(&self) -> bool {
|
pub fn verify_signature(&self) -> bool {
|
||||||
warn!("transaction signature verification called");
|
warn!("transaction signature verification called");
|
||||||
self.signature
|
self.signatures
|
||||||
.verify(&self.from().as_ref(), &self.get_sign_data())
|
.iter()
|
||||||
|
.all(|s| s.verify(&self.from().as_ref(), &self.get_sign_data()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify that references in the instructions are valid
|
/// Verify that references in the instructions are valid
|
||||||
|
@ -192,7 +206,7 @@ impl Transaction {
|
||||||
let mut hasher = Hasher::default();
|
let mut hasher = Hasher::default();
|
||||||
transactions
|
transactions
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|tx| hasher.hash(&tx.signature.as_ref()));
|
.for_each(|tx| hasher.hash(&tx.signatures[0].as_ref()));
|
||||||
hasher.result()
|
hasher.result()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,7 +229,7 @@ mod tests {
|
||||||
Instruction::new(1, &(), vec![0, 2]),
|
Instruction::new(1, &(), vec![0, 2]),
|
||||||
];
|
];
|
||||||
let tx = Transaction::new_with_instructions(
|
let tx = Transaction::new_with_instructions(
|
||||||
&key,
|
&[&key],
|
||||||
&[key1, key2],
|
&[key1, key2],
|
||||||
Default::default(),
|
Default::default(),
|
||||||
0,
|
0,
|
||||||
|
@ -250,7 +264,7 @@ mod tests {
|
||||||
let key = Keypair::new();
|
let key = Keypair::new();
|
||||||
let instructions = vec![Instruction::new(1, &(), vec![])];
|
let instructions = vec![Instruction::new(1, &(), vec![])];
|
||||||
let tx = Transaction::new_with_instructions(
|
let tx = Transaction::new_with_instructions(
|
||||||
&key,
|
&[&key],
|
||||||
&[],
|
&[],
|
||||||
Default::default(),
|
Default::default(),
|
||||||
0,
|
0,
|
||||||
|
@ -264,7 +278,7 @@ mod tests {
|
||||||
let key = Keypair::new();
|
let key = Keypair::new();
|
||||||
let instructions = vec![Instruction::new(0, &(), vec![1])];
|
let instructions = vec![Instruction::new(0, &(), vec![1])];
|
||||||
let tx = Transaction::new_with_instructions(
|
let tx = Transaction::new_with_instructions(
|
||||||
&key,
|
&[&key],
|
||||||
&[],
|
&[],
|
||||||
Default::default(),
|
Default::default(),
|
||||||
0,
|
0,
|
||||||
|
@ -301,19 +315,22 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
serialize(&tx).unwrap(),
|
serialize(&tx).unwrap(),
|
||||||
vec![
|
vec![
|
||||||
234, 139, 34, 5, 120, 28, 107, 203, 69, 25, 236, 200, 164, 1, 12, 47, 147, 53, 41,
|
1, 0, 0, 0, 0, 0, 0, 0, 199, 111, 28, 46, 13, 235, 122, 203, 210, 118, 158, 0, 59,
|
||||||
143, 23, 116, 230, 203, 59, 228, 153, 14, 22, 241, 103, 226, 186, 169, 181, 65, 49,
|
175, 148, 175, 225, 134, 90, 155, 188, 232, 218, 54, 199, 116, 67, 99, 65, 84, 164,
|
||||||
215, 44, 2, 61, 214, 113, 216, 184, 206, 147, 104, 140, 225, 138, 21, 172, 135,
|
94, 224, 60, 187, 249, 92, 210, 242, 99, 58, 121, 202, 5, 140, 152, 14, 166, 13,
|
||||||
211, 80, 103, 80, 216, 106, 249, 86, 194, 1, 3, 0, 0, 0, 0, 0, 0, 0, 32, 253, 186,
|
134, 103, 127, 216, 96, 217, 139, 5, 252, 40, 146, 48, 112, 59, 7, 1, 0, 0, 0, 0,
|
||||||
201, 177, 11, 117, 135, 187, 167, 181, 188, 22, 59, 206, 105, 231, 150, 215, 30,
|
0, 0, 0, 32, 253, 186, 201, 177, 11, 117, 135, 187, 167, 181, 188, 22, 59, 206,
|
||||||
78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161, 68, 32, 253, 186, 201, 177, 11,
|
105, 231, 150, 215, 30, 78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161, 68, 3,
|
||||||
117, 135, 187, 167, 181, 188, 22, 59, 206, 105, 231, 150, 215, 30, 78, 212, 76, 16,
|
0, 0, 0, 0, 0, 0, 0, 32, 253, 186, 201, 177, 11, 117, 135, 187, 167, 181, 188, 22,
|
||||||
252, 180, 72, 134, 137, 247, 161, 68, 1, 1, 1, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9,
|
59, 206, 105, 231, 150, 215, 30, 78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161,
|
||||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
68, 32, 253, 186, 201, 177, 11, 117, 135, 187, 167, 181, 188, 22, 59, 206, 105,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0,
|
231, 150, 215, 30, 78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161, 68, 1, 1, 1,
|
||||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 4, 5, 6, 7, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 7, 6, 5, 4, 1, 1,
|
||||||
1, 1, 1, 1, 1, 9, 8, 7, 6, 5, 4, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0,
|
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3
|
0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 4, 5, 6,
|
||||||
|
7, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 8, 7, 6, 5, 4, 2, 2, 2, 1, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 1, 2,
|
||||||
|
3
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,10 @@ fn create_bpf_path(name: &str) -> PathBuf {
|
||||||
fn check_tx_results(bank: &Bank, tx: &Transaction, result: Vec<solana::bank::Result<()>>) {
|
fn check_tx_results(bank: &Bank, tx: &Transaction, result: Vec<solana::bank::Result<()>>) {
|
||||||
assert_eq!(result.len(), 1);
|
assert_eq!(result.len(), 1);
|
||||||
assert_eq!(result[0], Ok(()));
|
assert_eq!(result[0], Ok(()));
|
||||||
assert_eq!(bank.get_signature(&tx.last_id, &tx.signature), Some(Ok(())));
|
assert_eq!(
|
||||||
|
bank.get_signature(&tx.last_id, &tx.signatures[0]),
|
||||||
|
Some(Ok(()))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Loader {
|
struct Loader {
|
||||||
|
|
Loading…
Reference in New Issue