tr -> tx
This commit is contained in:
parent
9f5a3d6064
commit
aaeb5ba52f
62
src/bank.rs
62
src/bank.rs
|
@ -158,31 +158,31 @@ impl Bank {
|
||||||
|
|
||||||
/// Deduct tokens from the 'from' address the account has sufficient
|
/// Deduct tokens from the 'from' address the account has sufficient
|
||||||
/// funds and isn't a duplicate.
|
/// funds and isn't a duplicate.
|
||||||
pub fn process_verified_transaction_debits(&self, tr: &Transaction) -> Result<()> {
|
pub fn process_verified_transaction_debits(&self, tx: &Transaction) -> Result<()> {
|
||||||
if let Instruction::NewContract(contract) = &tr.instruction {
|
if let Instruction::NewContract(contract) = &tx.instruction {
|
||||||
trace!("Transaction {}", contract.tokens);
|
trace!("Transaction {}", contract.tokens);
|
||||||
}
|
}
|
||||||
let bals = self.balances
|
let bals = self.balances
|
||||||
.read()
|
.read()
|
||||||
.expect("'balances' read lock in process_verified_transaction_debits");
|
.expect("'balances' read lock in process_verified_transaction_debits");
|
||||||
let option = bals.get(&tr.from);
|
let option = bals.get(&tx.from);
|
||||||
|
|
||||||
if option.is_none() {
|
if option.is_none() {
|
||||||
return Err(BankError::AccountNotFound(tr.from));
|
return Err(BankError::AccountNotFound(tx.from));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.reserve_signature_with_last_id(&tr.sig, &tr.last_id) {
|
if !self.reserve_signature_with_last_id(&tx.sig, &tx.last_id) {
|
||||||
return Err(BankError::InvalidTransferSignature(tr.sig));
|
return Err(BankError::InvalidTransferSignature(tx.sig));
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let result = if let Instruction::NewContract(contract) = &tr.instruction {
|
let result = if let Instruction::NewContract(contract) = &tx.instruction {
|
||||||
let bal = option.expect("assignment of option to bal");
|
let bal = option.expect("assignment of option to bal");
|
||||||
let current = bal.load(Ordering::Relaxed) as i64;
|
let current = bal.load(Ordering::Relaxed) as i64;
|
||||||
|
|
||||||
if current < contract.tokens {
|
if current < contract.tokens {
|
||||||
self.forget_signature_with_last_id(&tr.sig, &tr.last_id);
|
self.forget_signature_with_last_id(&tx.sig, &tx.last_id);
|
||||||
return Err(BankError::InsufficientFunds(tr.from));
|
return Err(BankError::InsufficientFunds(tx.from));
|
||||||
}
|
}
|
||||||
|
|
||||||
bal.compare_exchange(
|
bal.compare_exchange(
|
||||||
|
@ -205,8 +205,8 @@ impl Bank {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_verified_transaction_credits(&self, tr: &Transaction) {
|
pub fn process_verified_transaction_credits(&self, tx: &Transaction) {
|
||||||
match &tr.instruction {
|
match &tx.instruction {
|
||||||
Instruction::NewContract(contract) => {
|
Instruction::NewContract(contract) => {
|
||||||
let mut plan = contract.plan.clone();
|
let mut plan = contract.plan.clone();
|
||||||
plan.apply_witness(&Witness::Timestamp(*self.last_time
|
plan.apply_witness(&Witness::Timestamp(*self.last_time
|
||||||
|
@ -219,22 +219,22 @@ impl Bank {
|
||||||
let mut pending = self.pending
|
let mut pending = self.pending
|
||||||
.write()
|
.write()
|
||||||
.expect("'pending' write lock in process_verified_transaction_credits");
|
.expect("'pending' write lock in process_verified_transaction_credits");
|
||||||
pending.insert(tr.sig, plan);
|
pending.insert(tx.sig, plan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instruction::ApplyTimestamp(dt) => {
|
Instruction::ApplyTimestamp(dt) => {
|
||||||
let _ = self.process_verified_timestamp(tr.from, *dt);
|
let _ = self.process_verified_timestamp(tx.from, *dt);
|
||||||
}
|
}
|
||||||
Instruction::ApplySignature(tx_sig) => {
|
Instruction::ApplySignature(tx_sig) => {
|
||||||
let _ = self.process_verified_sig(tr.from, *tx_sig);
|
let _ = self.process_verified_sig(tx.from, *tx_sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process a Transaction that has already been verified.
|
/// Process a Transaction that has already been verified.
|
||||||
pub fn process_verified_transaction(&self, tr: &Transaction) -> Result<()> {
|
pub fn process_verified_transaction(&self, tx: &Transaction) -> Result<()> {
|
||||||
self.process_verified_transaction_debits(tr)?;
|
self.process_verified_transaction_debits(tx)?;
|
||||||
self.process_verified_transaction_credits(tr);
|
self.process_verified_transaction_credits(tx);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,15 +244,15 @@ impl Bank {
|
||||||
// in parallel deterministically.
|
// in parallel deterministically.
|
||||||
info!("processing Transactions {}", trs.len());
|
info!("processing Transactions {}", trs.len());
|
||||||
let results: Vec<_> = trs.into_par_iter()
|
let results: Vec<_> = trs.into_par_iter()
|
||||||
.map(|tr| self.process_verified_transaction_debits(&tr).map(|_| tr))
|
.map(|tx| self.process_verified_transaction_debits(&tx).map(|_| tx))
|
||||||
.collect(); // Calling collect() here forces all debits to complete before moving on.
|
.collect(); // Calling collect() here forces all debits to complete before moving on.
|
||||||
|
|
||||||
results
|
results
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|result| {
|
.map(|result| {
|
||||||
result.map(|tr| {
|
result.map(|tx| {
|
||||||
self.process_verified_transaction_credits(&tr);
|
self.process_verified_transaction_credits(&tx);
|
||||||
tr
|
tx
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -346,9 +346,9 @@ impl Bank {
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
last_id: Hash,
|
last_id: Hash,
|
||||||
) -> Result<Signature> {
|
) -> Result<Signature> {
|
||||||
let tr = Transaction::new(keypair, to, n, last_id);
|
let tx = Transaction::new(keypair, to, n, last_id);
|
||||||
let sig = tr.sig;
|
let sig = tx.sig;
|
||||||
self.process_verified_transaction(&tr).map(|_| sig)
|
self.process_verified_transaction(&tx).map(|_| sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create, sign, and process a postdated Transaction from `keypair`
|
/// Create, sign, and process a postdated Transaction from `keypair`
|
||||||
|
@ -362,9 +362,9 @@ impl Bank {
|
||||||
dt: DateTime<Utc>,
|
dt: DateTime<Utc>,
|
||||||
last_id: Hash,
|
last_id: Hash,
|
||||||
) -> Result<Signature> {
|
) -> Result<Signature> {
|
||||||
let tr = Transaction::new_on_date(keypair, to, dt, n, last_id);
|
let tx = Transaction::new_on_date(keypair, to, dt, n, last_id);
|
||||||
let sig = tr.sig;
|
let sig = tx.sig;
|
||||||
self.process_verified_transaction(&tr).map(|_| sig)
|
self.process_verified_transaction(&tx).map(|_| sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_balance(&self, pubkey: &PublicKey) -> Option<i64> {
|
pub fn get_balance(&self, pubkey: &PublicKey) -> Option<i64> {
|
||||||
|
@ -590,16 +590,16 @@ mod bench {
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
// Seed the 'from' account.
|
// Seed the 'from' account.
|
||||||
let rando0 = KeyPair::new();
|
let rando0 = KeyPair::new();
|
||||||
let tr = Transaction::new(&mint.keypair(), rando0.pubkey(), 1_000, mint.last_id());
|
let tx = Transaction::new(&mint.keypair(), rando0.pubkey(), 1_000, mint.last_id());
|
||||||
bank.process_verified_transaction(&tr).unwrap();
|
bank.process_verified_transaction(&tx).unwrap();
|
||||||
|
|
||||||
// Seed the 'to' account and a cell for its signature.
|
// Seed the 'to' account and a cell for its signature.
|
||||||
let last_id = hash(&serialize(&i).unwrap()); // Unique hash
|
let last_id = hash(&serialize(&i).unwrap()); // Unique hash
|
||||||
bank.register_entry_id(&last_id);
|
bank.register_entry_id(&last_id);
|
||||||
|
|
||||||
let rando1 = KeyPair::new();
|
let rando1 = KeyPair::new();
|
||||||
let tr = Transaction::new(&rando0, rando1.pubkey(), 1, last_id);
|
let tx = Transaction::new(&rando0, rando1.pubkey(), 1, last_id);
|
||||||
bank.process_verified_transaction(&tr).unwrap();
|
bank.process_verified_transaction(&tx).unwrap();
|
||||||
|
|
||||||
// Finally, return a transaction that's unique
|
// Finally, return a transaction that's unique
|
||||||
Transaction::new(&rando0, rando1.pubkey(), 1, last_id)
|
Transaction::new(&rando0, rando1.pubkey(), 1, last_id)
|
||||||
|
|
|
@ -149,13 +149,13 @@ impl BankingStage {
|
||||||
//
|
//
|
||||||
// // Process a batch that includes a transaction that receives two tokens.
|
// // Process a batch that includes a transaction that receives two tokens.
|
||||||
// let alice = KeyPair::new();
|
// let alice = KeyPair::new();
|
||||||
// let tr = Transaction::new(&mint.keypair(), alice.pubkey(), 2, mint.last_id());
|
// let tx = Transaction::new(&mint.keypair(), alice.pubkey(), 2, mint.last_id());
|
||||||
// let transactions = vec![tr];
|
// let transactions = vec![tx];
|
||||||
// let entry0 = banking_stage.process_transactions(transactions).unwrap();
|
// let entry0 = banking_stage.process_transactions(transactions).unwrap();
|
||||||
//
|
//
|
||||||
// // Process a second batch that spends one of those tokens.
|
// // Process a second batch that spends one of those tokens.
|
||||||
// let tr = Transaction::new(&alice, mint.pubkey(), 1, mint.last_id());
|
// let tx = Transaction::new(&alice, mint.pubkey(), 1, mint.last_id());
|
||||||
// let transactions = vec![tr];
|
// let transactions = vec![tx];
|
||||||
// let entry1 = banking_stage.process_transactions(transactions).unwrap();
|
// let entry1 = banking_stage.process_transactions(transactions).unwrap();
|
||||||
//
|
//
|
||||||
// // Collect the ledger and feed it to a new bank.
|
// // Collect the ledger and feed it to a new bank.
|
||||||
|
@ -214,12 +214,12 @@ impl BankingStage {
|
||||||
//
|
//
|
||||||
// // Seed the 'from' account.
|
// // Seed the 'from' account.
|
||||||
// let rando0 = KeyPair::new();
|
// let rando0 = KeyPair::new();
|
||||||
// let tr = Transaction::new(&mint.keypair(), rando0.pubkey(), 1_000, last_id);
|
// let tx = Transaction::new(&mint.keypair(), rando0.pubkey(), 1_000, last_id);
|
||||||
// bank.process_verified_transaction(&tr).unwrap();
|
// bank.process_verified_transaction(&tx).unwrap();
|
||||||
//
|
//
|
||||||
// let rando1 = KeyPair::new();
|
// let rando1 = KeyPair::new();
|
||||||
// let tr = Transaction::new(&rando0, rando1.pubkey(), 2, last_id);
|
// let tx = Transaction::new(&rando0, rando1.pubkey(), 2, last_id);
|
||||||
// bank.process_verified_transaction(&tr).unwrap();
|
// bank.process_verified_transaction(&tx).unwrap();
|
||||||
//
|
//
|
||||||
// // Finally, return a transaction that's unique
|
// // Finally, return a transaction that's unique
|
||||||
// Transaction::new(&rando0, rando1.pubkey(), 1, last_id)
|
// Transaction::new(&rando0, rando1.pubkey(), 1, last_id)
|
||||||
|
|
|
@ -137,8 +137,8 @@ fn main() {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let sz = transactions.len() / threads;
|
let sz = transactions.len() / threads;
|
||||||
let chunks: Vec<_> = transactions.chunks(sz).collect();
|
let chunks: Vec<_> = transactions.chunks(sz).collect();
|
||||||
chunks.into_par_iter().for_each(|trs| {
|
chunks.into_par_iter().for_each(|txs| {
|
||||||
println!("Transferring 1 unit {} times... to", trs.len());
|
println!("Transferring 1 unit {} times... to", txs.len());
|
||||||
let requests_addr: SocketAddr = server_addr.parse().unwrap();
|
let requests_addr: SocketAddr = server_addr.parse().unwrap();
|
||||||
let mut requests_cb_addr = requests_addr.clone();
|
let mut requests_cb_addr = requests_addr.clone();
|
||||||
requests_cb_addr.set_port(0);
|
requests_cb_addr.set_port(0);
|
||||||
|
@ -155,8 +155,8 @@ fn main() {
|
||||||
transactions_addr,
|
transactions_addr,
|
||||||
transactions_socket,
|
transactions_socket,
|
||||||
);
|
);
|
||||||
for tr in trs {
|
for tx in txs {
|
||||||
client.transfer_signed(tr.clone()).unwrap();
|
client.transfer_signed(tx.clone()).unwrap();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -145,11 +145,11 @@ fn main() {
|
||||||
println!("Transfering {} transactions in {} batches", txs, threads);
|
println!("Transfering {} transactions in {} batches", txs, threads);
|
||||||
let sz = transactions.len() / threads;
|
let sz = transactions.len() / threads;
|
||||||
let chunks: Vec<_> = transactions.chunks(sz).collect();
|
let chunks: Vec<_> = transactions.chunks(sz).collect();
|
||||||
chunks.into_par_iter().for_each(|trs| {
|
chunks.into_par_iter().for_each(|txs| {
|
||||||
println!("Transferring 1 unit {} times... to", trs.len());
|
println!("Transferring 1 unit {} times... to", txs.len());
|
||||||
let client = mk_client(&client_addr, &leader);
|
let client = mk_client(&client_addr, &leader);
|
||||||
for tr in trs {
|
for tx in txs {
|
||||||
client.transfer_signed(tr.clone()).unwrap();
|
client.transfer_signed(tx.clone()).unwrap();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -96,8 +96,8 @@ fn main() {
|
||||||
// fields are the same. That entry should be treated as a deposit, not a
|
// fields are the same. That entry should be treated as a deposit, not a
|
||||||
// transfer to oneself.
|
// transfer to oneself.
|
||||||
let entry1: Entry = entries.next().unwrap();
|
let entry1: Entry = entries.next().unwrap();
|
||||||
let tr = &entry1.transactions[0];
|
let tx = &entry1.transactions[0];
|
||||||
let deposit = if let Instruction::NewContract(contract) = &tr.instruction {
|
let deposit = if let Instruction::NewContract(contract) = &tx.instruction {
|
||||||
contract.plan.final_payment()
|
contract.plan.final_payment()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
20
src/ecdsa.rs
20
src/ecdsa.rs
|
@ -151,24 +151,24 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_layout() {
|
fn test_layout() {
|
||||||
let tr = test_tx();
|
let tx = test_tx();
|
||||||
let tx = serialize(&tr).unwrap();
|
let tx_bytes = serialize(&tx).unwrap();
|
||||||
let packet = serialize(&tr).unwrap();
|
let packet = serialize(&tx).unwrap();
|
||||||
assert_matches!(memfind(&packet, &tx), Some(ecdsa::TX_OFFSET));
|
assert_matches!(memfind(&packet, &tx_bytes), Some(ecdsa::TX_OFFSET));
|
||||||
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(tr: Transaction) -> Packet {
|
fn make_packet_from_transaction(tx: Transaction) -> Packet {
|
||||||
let tx = serialize(&tr).unwrap();
|
let tx_bytes = serialize(&tx).unwrap();
|
||||||
let mut packet = Packet::default();
|
let mut packet = Packet::default();
|
||||||
packet.meta.size = tx.len();
|
packet.meta.size = tx_bytes.len();
|
||||||
packet.data[..packet.meta.size].copy_from_slice(&tx);
|
packet.data[..packet.meta.size].copy_from_slice(&tx_bytes);
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_verify_n(n: usize, modify_data: bool) {
|
fn test_verify_n(n: usize, modify_data: bool) {
|
||||||
let tr = test_tx();
|
let tx = test_tx();
|
||||||
let mut packet = make_packet_from_transaction(tr);
|
let mut packet = make_packet_from_transaction(tx);
|
||||||
|
|
||||||
// jumble some data to test failure
|
// jumble some data to test failure
|
||||||
if modify_data {
|
if modify_data {
|
||||||
|
|
|
@ -66,9 +66,9 @@ impl Entry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_transaction_data(hash_data: &mut Vec<u8>, tr: &Transaction) {
|
fn add_transaction_data(hash_data: &mut Vec<u8>, tx: &Transaction) {
|
||||||
hash_data.push(0u8);
|
hash_data.push(0u8);
|
||||||
hash_data.extend_from_slice(&tr.sig);
|
hash_data.extend_from_slice(&tx.sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the hash `num_hashes` after `start_hash`. If the transaction contains
|
/// Creates the hash `num_hashes` after `start_hash`. If the transaction contains
|
||||||
|
|
10
src/mint.rs
10
src/mint.rs
|
@ -48,8 +48,8 @@ impl Mint {
|
||||||
|
|
||||||
pub fn create_transactions(&self) -> Vec<Transaction> {
|
pub fn create_transactions(&self) -> Vec<Transaction> {
|
||||||
let keypair = self.keypair();
|
let keypair = self.keypair();
|
||||||
let tr = Transaction::new(&keypair, self.pubkey(), self.tokens, self.seed());
|
let tx = Transaction::new(&keypair, self.pubkey(), self.tokens, self.seed());
|
||||||
vec![tr]
|
vec![tx]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_entries(&self) -> Vec<Entry> {
|
pub fn create_entries(&self) -> Vec<Entry> {
|
||||||
|
@ -75,10 +75,10 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_transactions() {
|
fn test_create_transactions() {
|
||||||
let mut transactions = Mint::new(100).create_transactions().into_iter();
|
let mut transactions = Mint::new(100).create_transactions().into_iter();
|
||||||
let tr = transactions.next().unwrap();
|
let tx = transactions.next().unwrap();
|
||||||
if let Instruction::NewContract(contract) = tr.instruction {
|
if let Instruction::NewContract(contract) = tx.instruction {
|
||||||
if let Plan::Pay(payment) = contract.plan {
|
if let Plan::Pay(payment) = contract.plan {
|
||||||
assert_eq!(tr.from, payment.to);
|
assert_eq!(tx.from, payment.to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert_eq!(transactions.next(), None);
|
assert_eq!(transactions.next(), None);
|
||||||
|
|
|
@ -378,17 +378,17 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_to_packets() {
|
fn test_to_packets() {
|
||||||
let tr = Request::GetTransactionCount;
|
let tx = Request::GetTransactionCount;
|
||||||
let re = PacketRecycler::default();
|
let re = PacketRecycler::default();
|
||||||
let rv = to_packets(&re, vec![tr.clone(); 1]);
|
let rv = to_packets(&re, vec![tx.clone(); 1]);
|
||||||
assert_eq!(rv.len(), 1);
|
assert_eq!(rv.len(), 1);
|
||||||
assert_eq!(rv[0].read().unwrap().packets.len(), 1);
|
assert_eq!(rv[0].read().unwrap().packets.len(), 1);
|
||||||
|
|
||||||
let rv = to_packets(&re, vec![tr.clone(); NUM_PACKETS]);
|
let rv = to_packets(&re, vec![tx.clone(); NUM_PACKETS]);
|
||||||
assert_eq!(rv.len(), 1);
|
assert_eq!(rv.len(), 1);
|
||||||
assert_eq!(rv[0].read().unwrap().packets.len(), NUM_PACKETS);
|
assert_eq!(rv[0].read().unwrap().packets.len(), NUM_PACKETS);
|
||||||
|
|
||||||
let rv = to_packets(&re, vec![tr.clone(); NUM_PACKETS + 1]);
|
let rv = to_packets(&re, vec![tx.clone(); NUM_PACKETS + 1]);
|
||||||
assert_eq!(rv.len(), 2);
|
assert_eq!(rv.len(), 2);
|
||||||
assert_eq!(rv[0].read().unwrap().packets.len(), NUM_PACKETS);
|
assert_eq!(rv[0].read().unwrap().packets.len(), NUM_PACKETS);
|
||||||
assert_eq!(rv[1].read().unwrap().packets.len(), 1);
|
assert_eq!(rv[1].read().unwrap().packets.len(), 1);
|
||||||
|
|
|
@ -73,8 +73,8 @@ impl ThinClient {
|
||||||
|
|
||||||
/// Send a signed Transaction to the server for processing. This method
|
/// Send a signed Transaction to the server for processing. This method
|
||||||
/// does not wait for a response.
|
/// does not wait for a response.
|
||||||
pub fn transfer_signed(&self, tr: Transaction) -> io::Result<usize> {
|
pub fn transfer_signed(&self, tx: Transaction) -> io::Result<usize> {
|
||||||
let data = serialize(&tr).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)
|
||||||
}
|
}
|
||||||
|
@ -87,9 +87,9 @@ impl ThinClient {
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
last_id: &Hash,
|
last_id: &Hash,
|
||||||
) -> io::Result<Signature> {
|
) -> io::Result<Signature> {
|
||||||
let tr = Transaction::new(keypair, to, n, *last_id);
|
let tx = Transaction::new(keypair, to, n, *last_id);
|
||||||
let sig = tr.sig;
|
let sig = tx.sig;
|
||||||
self.transfer_signed(tr).map(|_| sig)
|
self.transfer_signed(tx).map(|_| sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request the balance of the user holding `pubkey`. This method blocks
|
/// Request the balance of the user holding `pubkey`. This method blocks
|
||||||
|
@ -277,9 +277,9 @@ mod tests {
|
||||||
);
|
);
|
||||||
let last_id = client.get_last_id().wait().unwrap();
|
let last_id = client.get_last_id().wait().unwrap();
|
||||||
|
|
||||||
let tr = Transaction::new(&alice.keypair(), bob_pubkey, 500, last_id);
|
let tx = Transaction::new(&alice.keypair(), bob_pubkey, 500, last_id);
|
||||||
|
|
||||||
let _sig = client.transfer_signed(tr).unwrap();
|
let _sig = client.transfer_signed(tx).unwrap();
|
||||||
|
|
||||||
let last_id = client.get_last_id().wait().unwrap();
|
let last_id = client.get_last_id().wait().unwrap();
|
||||||
|
|
||||||
|
|
|
@ -39,14 +39,14 @@ impl Transaction {
|
||||||
last_id: Hash,
|
last_id: Hash,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let from = from_keypair.pubkey();
|
let from = from_keypair.pubkey();
|
||||||
let mut tr = Transaction {
|
let mut tx = Transaction {
|
||||||
sig: Signature::default(),
|
sig: Signature::default(),
|
||||||
instruction,
|
instruction,
|
||||||
last_id,
|
last_id,
|
||||||
from,
|
from,
|
||||||
};
|
};
|
||||||
tr.sign(from_keypair);
|
tx.sign(from_keypair);
|
||||||
tr
|
tx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create and sign a new Transaction. Used for unit-testing.
|
/// Create and sign a new Transaction. Used for unit-testing.
|
||||||
|
@ -82,14 +82,14 @@ impl Transaction {
|
||||||
(Condition::Signature(from), Payment { tokens, to: from }),
|
(Condition::Signature(from), Payment { tokens, to: from }),
|
||||||
);
|
);
|
||||||
let instruction = Instruction::NewContract(Contract { plan, tokens });
|
let instruction = Instruction::NewContract(Contract { plan, tokens });
|
||||||
let mut tr = Transaction {
|
let mut tx = Transaction {
|
||||||
instruction,
|
instruction,
|
||||||
from,
|
from,
|
||||||
last_id,
|
last_id,
|
||||||
sig: Signature::default(),
|
sig: Signature::default(),
|
||||||
};
|
};
|
||||||
tr.sign(from_keypair);
|
tx.sign(from_keypair);
|
||||||
tr
|
tx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_sign_data(&self) -> Vec<u8> {
|
fn get_sign_data(&self) -> Vec<u8> {
|
||||||
|
@ -140,12 +140,12 @@ pub fn memfind<A: Eq>(a: &[A], b: &[A]) -> Option<usize> {
|
||||||
|
|
||||||
/// Verify a batch of signatures.
|
/// Verify a batch of signatures.
|
||||||
pub fn verify_signatures(transactions: &[Transaction]) -> bool {
|
pub fn verify_signatures(transactions: &[Transaction]) -> bool {
|
||||||
transactions.par_iter().all(|tr| tr.verify_sig())
|
transactions.par_iter().all(|tx| tx.verify_sig())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a batch of spending plans.
|
/// Verify a batch of spending plans.
|
||||||
pub fn verify_plans(transactions: &[Transaction]) -> bool {
|
pub fn verify_plans(transactions: &[Transaction]) -> bool {
|
||||||
transactions.par_iter().all(|tr| tr.verify_plan())
|
transactions.par_iter().all(|tx| tx.verify_plan())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a batch of transactions.
|
/// Verify a batch of transactions.
|
||||||
|
@ -199,15 +199,15 @@ mod tests {
|
||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
let keypair = KeyPair::new();
|
let keypair = KeyPair::new();
|
||||||
let pubkey = keypair.pubkey();
|
let pubkey = keypair.pubkey();
|
||||||
let mut tr = Transaction::new(&keypair, pubkey, 42, zero);
|
let mut tx = Transaction::new(&keypair, pubkey, 42, zero);
|
||||||
if let Instruction::NewContract(contract) = &mut tr.instruction {
|
if let Instruction::NewContract(contract) = &mut tx.instruction {
|
||||||
contract.tokens = 1_000_000; // <-- attack, part 1!
|
contract.tokens = 1_000_000; // <-- attack, part 1!
|
||||||
if let Plan::Pay(ref mut payment) = contract.plan {
|
if let Plan::Pay(ref mut payment) = contract.plan {
|
||||||
payment.tokens = contract.tokens; // <-- attack, part 2!
|
payment.tokens = contract.tokens; // <-- attack, part 2!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert!(tr.verify_plan());
|
assert!(tx.verify_plan());
|
||||||
assert!(!tr.verify_sig());
|
assert!(!tx.verify_sig());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -217,23 +217,23 @@ mod tests {
|
||||||
let thief_keypair = KeyPair::new();
|
let thief_keypair = KeyPair::new();
|
||||||
let pubkey1 = keypair1.pubkey();
|
let pubkey1 = keypair1.pubkey();
|
||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
let mut tr = Transaction::new(&keypair0, pubkey1, 42, zero);
|
let mut tx = Transaction::new(&keypair0, pubkey1, 42, zero);
|
||||||
if let Instruction::NewContract(contract) = &mut tr.instruction {
|
if let Instruction::NewContract(contract) = &mut tx.instruction {
|
||||||
if let Plan::Pay(ref mut payment) = contract.plan {
|
if let Plan::Pay(ref mut payment) = contract.plan {
|
||||||
payment.to = thief_keypair.pubkey(); // <-- attack!
|
payment.to = thief_keypair.pubkey(); // <-- attack!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert!(tr.verify_plan());
|
assert!(tx.verify_plan());
|
||||||
assert!(!tr.verify_sig());
|
assert!(!tx.verify_sig());
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_layout() {
|
fn test_layout() {
|
||||||
let tr = test_tx();
|
let tx = test_tx();
|
||||||
let sign_data = tr.get_sign_data();
|
let sign_data = tx.get_sign_data();
|
||||||
let tx = serialize(&tr).unwrap();
|
let tx_bytes = serialize(&tx).unwrap();
|
||||||
assert_matches!(memfind(&tx, &sign_data), Some(SIGNED_DATA_OFFSET));
|
assert_matches!(memfind(&tx_bytes, &sign_data), Some(SIGNED_DATA_OFFSET));
|
||||||
assert_matches!(memfind(&tx, &tr.sig), Some(SIG_OFFSET));
|
assert_matches!(memfind(&tx_bytes, &tx.sig), Some(SIG_OFFSET));
|
||||||
assert_matches!(memfind(&tx, &tr.from), Some(PUB_KEY_OFFSET));
|
assert_matches!(memfind(&tx_bytes, &tx.from), Some(PUB_KEY_OFFSET));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -241,21 +241,21 @@ mod tests {
|
||||||
let keypair0 = KeyPair::new();
|
let keypair0 = KeyPair::new();
|
||||||
let keypair1 = KeyPair::new();
|
let keypair1 = KeyPair::new();
|
||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
let mut tr = Transaction::new(&keypair0, keypair1.pubkey(), 1, zero);
|
let mut tx = Transaction::new(&keypair0, keypair1.pubkey(), 1, zero);
|
||||||
if let Instruction::NewContract(contract) = &mut tr.instruction {
|
if let Instruction::NewContract(contract) = &mut tx.instruction {
|
||||||
if let Plan::Pay(ref mut payment) = contract.plan {
|
if let Plan::Pay(ref mut payment) = contract.plan {
|
||||||
payment.tokens = 2; // <-- attack!
|
payment.tokens = 2; // <-- attack!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert!(!tr.verify_plan());
|
assert!(!tx.verify_plan());
|
||||||
|
|
||||||
// Also, ensure all branchs of the plan spend all tokens
|
// Also, ensure all branchs of the plan spend all tokens
|
||||||
if let Instruction::NewContract(contract) = &mut tr.instruction {
|
if let Instruction::NewContract(contract) = &mut tx.instruction {
|
||||||
if let Plan::Pay(ref mut payment) = contract.plan {
|
if let Plan::Pay(ref mut payment) = contract.plan {
|
||||||
payment.tokens = 0; // <-- whoops!
|
payment.tokens = 0; // <-- whoops!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert!(!tr.verify_plan());
|
assert!(!tx.verify_plan());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in New Issue