diff --git a/src/bank.rs b/src/bank.rs index a952e100e..a7fdd9469 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -24,9 +24,10 @@ use std::sync::RwLock; use std::time::Instant; use storage_program::StorageProgram; use system_program::SystemProgram; +use system_transaction::SystemTransaction; use tictactoe_program::TicTacToeProgram; use timing::{duration_as_us, timestamp}; -use transaction::{SystemTransaction, Transaction}; +use transaction::Transaction; use window::WINDOW_SIZE; /// An Account with userdata that is stored on chain diff --git a/src/banking_stage.rs b/src/banking_stage.rs index 5312a2de6..a1d2d0fff 100644 --- a/src/banking_stage.rs +++ b/src/banking_stage.rs @@ -248,7 +248,8 @@ mod tests { use packet::{to_packets, PacketRecycler}; use signature::{Keypair, KeypairUtil}; use std::thread::sleep; - use transaction::{SystemTransaction, Transaction}; + use system_transaction::SystemTransaction; + use transaction::Transaction; #[test] fn test_banking_stage_shutdown() { diff --git a/src/bin/bench-tps.rs b/src/bin/bench-tps.rs index c34bd614c..97fb238c7 100644 --- a/src/bin/bench-tps.rs +++ b/src/bin/bench-tps.rs @@ -19,9 +19,10 @@ use solana::metrics; use solana::ncp::Ncp; use solana::service::Service; use solana::signature::{read_keypair, GenKeys, Keypair, KeypairUtil}; +use solana::system_transaction::SystemTransaction; use solana::thin_client::{poll_gossip_for_leader, ThinClient}; use solana::timing::{duration_as_ms, duration_as_s}; -use solana::transaction::{SystemTransaction, Transaction}; +use solana::transaction::Transaction; use solana::wallet::request_airdrop; use solana::window::default_window; use std::collections::VecDeque; diff --git a/src/drone.rs b/src/drone.rs index 40693c240..c3db59b66 100644 --- a/src/drone.rs +++ b/src/drone.rs @@ -17,12 +17,13 @@ use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; +use system_transaction::SystemTransaction; use thin_client::{poll_gossip_for_leader, ThinClient}; use tokio; use tokio::net::TcpListener; use tokio::prelude::*; use tokio_codec::{BytesCodec, Decoder}; -use transaction::{SystemTransaction, Transaction}; +use transaction::Transaction; pub const TIME_SLICE: u64 = 60; pub const REQUEST_CAP: u64 = 500_000_000; diff --git a/src/entry.rs b/src/entry.rs index 9639ebecb..16bc955a4 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -230,7 +230,8 @@ mod tests { use entry::Entry; use hash::hash; use signature::{Keypair, KeypairUtil}; - use transaction::{BudgetTransaction, SystemTransaction, Transaction}; + use system_transaction::SystemTransaction; + use transaction::{BudgetTransaction, Transaction}; #[test] fn test_entry_verify() { diff --git a/src/lib.rs b/src/lib.rs index 5005116c3..aba65f3aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,7 @@ pub mod storage_program; pub mod store_ledger_stage; pub mod streamer; pub mod system_program; +pub mod system_transaction; pub mod thin_client; pub mod tictactoe_program; pub mod timing; diff --git a/src/mint.rs b/src/mint.rs index 203f1490a..044957db2 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -4,7 +4,8 @@ use entry::Entry; use hash::{hash, Hash}; use ring::rand::SystemRandom; use signature::{Keypair, KeypairUtil, Pubkey}; -use transaction::{SystemTransaction, Transaction}; +use system_transaction::SystemTransaction; +use transaction::Transaction; use untrusted::Input; #[derive(Serialize, Deserialize, Debug)] diff --git a/src/rpc.rs b/src/rpc.rs index 8680c362d..524274390 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -241,7 +241,8 @@ mod tests { use signature::{Keypair, KeypairUtil}; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::sync::Arc; - use transaction::{SystemTransaction, Transaction}; + use system_transaction::SystemTransaction; + use transaction::Transaction; #[test] fn test_rpc_request() { diff --git a/src/sigverify.rs b/src/sigverify.rs index 6c520e0d0..9aa5323c7 100644 --- a/src/sigverify.rs +++ b/src/sigverify.rs @@ -197,8 +197,8 @@ mod tests { use bincode::serialize; use packet::{Packet, PacketRecycler}; use sigverify; + use system_transaction::{memfind, test_tx}; use transaction::Transaction; - use transaction::{memfind, test_tx}; #[test] fn test_layout() { diff --git a/src/system_program.rs b/src/system_program.rs index cfbf41dfb..21922fb23 100644 --- a/src/system_program.rs +++ b/src/system_program.rs @@ -106,7 +106,8 @@ mod test { use std::sync::RwLock; use std::thread; use system_program::SystemProgram; - use transaction::{SystemTransaction, Transaction}; + use system_transaction::SystemTransaction; + use transaction::Transaction; #[test] fn test_create_noop() { diff --git a/src/system_transaction.rs b/src/system_transaction.rs new file mode 100644 index 000000000..90822d19a --- /dev/null +++ b/src/system_transaction.rs @@ -0,0 +1,184 @@ +//! The `system_transaction` module provides functionality for creating system transactions. + +use bincode::serialize; +use hash::Hash; +use signature::{Keypair, KeypairUtil, Pubkey}; +use system_program::SystemProgram; +use transaction::Transaction; + +pub trait SystemTransaction { + fn system_create( + from_keypair: &Keypair, + to: Pubkey, + last_id: Hash, + tokens: i64, + space: u64, + program_id: Pubkey, + fee: i64, + ) -> Self; + + fn system_assign(from_keypair: &Keypair, last_id: Hash, program_id: Pubkey, fee: i64) -> Self; + + fn system_new(from_keypair: &Keypair, to: Pubkey, tokens: i64, last_id: Hash) -> Self; + + fn system_move( + from_keypair: &Keypair, + to: Pubkey, + tokens: i64, + last_id: Hash, + fee: i64, + ) -> Self; + + fn system_load( + from_keypair: &Keypair, + last_id: Hash, + fee: i64, + program_id: Pubkey, + name: String, + ) -> Self; +} + +impl SystemTransaction for Transaction { + /// Create and sign new SystemProgram::CreateAccount transaction + fn system_create( + from_keypair: &Keypair, + to: Pubkey, + last_id: Hash, + tokens: i64, + space: u64, + program_id: Pubkey, + fee: i64, + ) -> Self { + let create = SystemProgram::CreateAccount { + tokens, //TODO, the tokens to allocate might need to be higher then 0 in the future + space, + program_id, + }; + Transaction::new( + from_keypair, + &[to], + SystemProgram::id(), + serialize(&create).unwrap(), + last_id, + fee, + ) + } + /// Create and sign new SystemProgram::CreateAccount transaction + fn system_assign(from_keypair: &Keypair, last_id: Hash, program_id: Pubkey, fee: i64) -> Self { + let create = SystemProgram::Assign { program_id }; + Transaction::new( + from_keypair, + &[], + SystemProgram::id(), + serialize(&create).unwrap(), + last_id, + fee, + ) + } + /// Create and sign new SystemProgram::CreateAccount transaction with some defaults + fn system_new(from_keypair: &Keypair, to: Pubkey, tokens: i64, last_id: Hash) -> Self { + Transaction::system_create(from_keypair, to, last_id, tokens, 0, Pubkey::default(), 0) + } + /// Create and sign new SystemProgram::Move transaction + fn system_move( + from_keypair: &Keypair, + to: Pubkey, + tokens: i64, + last_id: Hash, + fee: i64, + ) -> Self { + let create = SystemProgram::Move { tokens }; + Transaction::new( + from_keypair, + &[to], + SystemProgram::id(), + serialize(&create).unwrap(), + last_id, + fee, + ) + } + /// Create and sign new SystemProgram::Load transaction + fn system_load( + from_keypair: &Keypair, + last_id: Hash, + fee: i64, + program_id: Pubkey, + name: String, + ) -> Self { + let load = SystemProgram::Load { program_id, name }; + Transaction::new( + from_keypair, + &[], + SystemProgram::id(), + serialize(&load).unwrap(), + last_id, + fee, + ) + } +} + +pub fn test_tx() -> Transaction { + let keypair1 = Keypair::new(); + let pubkey1 = keypair1.pubkey(); + let zero = Hash::default(); + Transaction::system_new(&keypair1, pubkey1, 42, zero) +} + +#[cfg(test)] +pub fn memfind(a: &[A], b: &[A]) -> Option { + assert!(a.len() >= b.len()); + let end = a.len() - b.len() + 1; + for i in 0..end { + if a[i..i + b.len()] == b[..] { + return Some(i); + } + } + None +} + +#[cfg(test)] +mod tests { + use super::*; + use bincode::{deserialize, serialize}; + use packet::PACKET_DATA_SIZE; + use transaction::{PUB_KEY_OFFSET, SIGNED_DATA_OFFSET, SIG_OFFSET}; + + #[test] + fn test_layout() { + let tx = test_tx(); + let sign_data = tx.get_sign_data(); + let tx_bytes = serialize(&tx).unwrap(); + assert_eq!(memfind(&tx_bytes, &sign_data), Some(SIGNED_DATA_OFFSET)); + assert_eq!(memfind(&tx_bytes, &tx.signature.as_ref()), Some(SIG_OFFSET)); + assert_eq!( + memfind(&tx_bytes, &tx.from().as_ref()), + Some(PUB_KEY_OFFSET) + ); + assert!(tx.verify_signature()); + } + + #[test] + fn test_userdata_layout() { + let mut tx0 = test_tx(); + tx0.userdata = vec![1, 2, 3]; + let sign_data0a = tx0.get_sign_data(); + let tx_bytes = serialize(&tx0).unwrap(); + assert!(tx_bytes.len() < PACKET_DATA_SIZE); + assert_eq!(memfind(&tx_bytes, &sign_data0a), Some(SIGNED_DATA_OFFSET)); + assert_eq!( + memfind(&tx_bytes, &tx0.signature.as_ref()), + Some(SIG_OFFSET) + ); + assert_eq!( + memfind(&tx_bytes, &tx0.from().as_ref()), + Some(PUB_KEY_OFFSET) + ); + let tx1 = deserialize(&tx_bytes).unwrap(); + assert_eq!(tx0, tx1); + assert_eq!(tx1.userdata, vec![1, 2, 3]); + + tx0.userdata = vec![1, 2, 4]; + let sign_data0b = tx0.get_sign_data(); + assert_ne!(sign_data0a, sign_data0b); + } +} diff --git a/src/thin_client.rs b/src/thin_client.rs index aa6f0f649..be432236c 100644 --- a/src/thin_client.rs +++ b/src/thin_client.rs @@ -21,8 +21,9 @@ use std::sync::{Arc, RwLock}; use std::thread::sleep; use std::time::Duration; use std::time::Instant; +use system_transaction::SystemTransaction; use timing; -use transaction::{SystemTransaction, Transaction}; +use transaction::Transaction; use influx_db_client as influxdb; use metrics; diff --git a/src/transaction.rs b/src/transaction.rs index b7a2bb8bf..f2cb74dd1 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -9,7 +9,6 @@ use instruction::{Contract, Instruction, Vote}; use payment_plan::Payment; use signature::{Keypair, KeypairUtil, Pubkey, Signature}; use std::mem::size_of; -use system_program::SystemProgram; pub const SIGNED_DATA_OFFSET: usize = size_of::(); pub const SIG_OFFSET: usize = 0; @@ -73,7 +72,7 @@ impl Transaction { } /// Get the transaction data to sign. - fn get_sign_data(&self) -> Vec { + pub fn get_sign_data(&self) -> Vec { let mut data = serialize(&(&self.keys)).expect("serialize keys"); let program_id = serialize(&(&self.program_id)).expect("serialize program_id"); @@ -323,141 +322,10 @@ impl BudgetTransaction for Transaction { } } -pub trait SystemTransaction { - fn system_create( - from_keypair: &Keypair, - to: Pubkey, - last_id: Hash, - tokens: i64, - space: u64, - program_id: Pubkey, - fee: i64, - ) -> Self; - - fn system_assign(from_keypair: &Keypair, last_id: Hash, program_id: Pubkey, fee: i64) -> Self; - - fn system_new(from_keypair: &Keypair, to: Pubkey, tokens: i64, last_id: Hash) -> Self; - - fn system_move( - from_keypair: &Keypair, - to: Pubkey, - tokens: i64, - last_id: Hash, - fee: i64, - ) -> Self; - - fn system_load( - from_keypair: &Keypair, - last_id: Hash, - fee: i64, - program_id: Pubkey, - name: String, - ) -> Self; -} - -impl SystemTransaction for Transaction { - /// Create and sign new SystemProgram::CreateAccount transaction - fn system_create( - from_keypair: &Keypair, - to: Pubkey, - last_id: Hash, - tokens: i64, - space: u64, - program_id: Pubkey, - fee: i64, - ) -> Self { - let create = SystemProgram::CreateAccount { - tokens, //TODO, the tokens to allocate might need to be higher then 0 in the future - space, - program_id, - }; - Transaction::new( - from_keypair, - &[to], - SystemProgram::id(), - serialize(&create).unwrap(), - last_id, - fee, - ) - } - /// Create and sign new SystemProgram::CreateAccount transaction - fn system_assign(from_keypair: &Keypair, last_id: Hash, program_id: Pubkey, fee: i64) -> Self { - let create = SystemProgram::Assign { program_id }; - Transaction::new( - from_keypair, - &[], - SystemProgram::id(), - serialize(&create).unwrap(), - last_id, - fee, - ) - } - /// Create and sign new SystemProgram::CreateAccount transaction with some defaults - fn system_new(from_keypair: &Keypair, to: Pubkey, tokens: i64, last_id: Hash) -> Self { - Transaction::system_create(from_keypair, to, last_id, tokens, 0, Pubkey::default(), 0) - } - /// Create and sign new SystemProgram::Move transaction - fn system_move( - from_keypair: &Keypair, - to: Pubkey, - tokens: i64, - last_id: Hash, - fee: i64, - ) -> Self { - let create = SystemProgram::Move { tokens }; - Transaction::new( - from_keypair, - &[to], - SystemProgram::id(), - serialize(&create).unwrap(), - last_id, - fee, - ) - } - /// Create and sign new SystemProgram::Load transaction - fn system_load( - from_keypair: &Keypair, - last_id: Hash, - fee: i64, - program_id: Pubkey, - name: String, - ) -> Self { - let load = SystemProgram::Load { program_id, name }; - Transaction::new( - from_keypair, - &[], - SystemProgram::id(), - serialize(&load).unwrap(), - last_id, - fee, - ) - } -} - -pub fn test_tx() -> Transaction { - let keypair1 = Keypair::new(); - let pubkey1 = keypair1.pubkey(); - let zero = Hash::default(); - Transaction::system_new(&keypair1, pubkey1, 42, zero) -} - -#[cfg(test)] -pub fn memfind(a: &[A], b: &[A]) -> Option { - assert!(a.len() >= b.len()); - let end = a.len() - b.len() + 1; - for i in 0..end { - if a[i..i + b.len()] == b[..] { - return Some(i); - } - } - None -} - #[cfg(test)] mod tests { use super::*; use bincode::{deserialize, serialize}; - use packet::PACKET_DATA_SIZE; use signature::GenKeys; #[test] @@ -545,43 +413,6 @@ mod tests { assert!(tx.verify_plan()); assert!(!tx.verify_signature()); } - #[test] - fn test_layout() { - let tx = test_tx(); - let sign_data = tx.get_sign_data(); - let tx_bytes = serialize(&tx).unwrap(); - assert_eq!(memfind(&tx_bytes, &sign_data), Some(SIGNED_DATA_OFFSET)); - assert_eq!(memfind(&tx_bytes, &tx.signature.as_ref()), Some(SIG_OFFSET)); - assert_eq!( - memfind(&tx_bytes, &tx.from().as_ref()), - Some(PUB_KEY_OFFSET) - ); - assert!(tx.verify_signature()); - } - #[test] - fn test_userdata_layout() { - let mut tx0 = test_tx(); - tx0.userdata = vec![1, 2, 3]; - let sign_data0a = tx0.get_sign_data(); - let tx_bytes = serialize(&tx0).unwrap(); - assert!(tx_bytes.len() < PACKET_DATA_SIZE); - assert_eq!(memfind(&tx_bytes, &sign_data0a), Some(SIGNED_DATA_OFFSET)); - assert_eq!( - memfind(&tx_bytes, &tx0.signature.as_ref()), - Some(SIG_OFFSET) - ); - assert_eq!( - memfind(&tx_bytes, &tx0.from().as_ref()), - Some(PUB_KEY_OFFSET) - ); - let tx1 = deserialize(&tx_bytes).unwrap(); - assert_eq!(tx0, tx1); - assert_eq!(tx1.userdata, vec![1, 2, 3]); - - tx0.userdata = vec![1, 2, 4]; - let sign_data0b = tx0.get_sign_data(); - assert_ne!(sign_data0a, sign_data0b); - } #[test] fn test_overspend_attack() { diff --git a/src/tvu.rs b/src/tvu.rs index 1637ce828..002be45f3 100644 --- a/src/tvu.rs +++ b/src/tvu.rs @@ -166,7 +166,8 @@ pub mod tests { use std::sync::{Arc, RwLock}; use std::time::Duration; use streamer; - use transaction::{SystemTransaction, Transaction}; + use system_transaction::SystemTransaction; + use transaction::Transaction; use tvu::Tvu; use window::{self, SharedWindow}; diff --git a/src/vote_stage.rs b/src/vote_stage.rs index bda99acfe..c2e9c5771 100644 --- a/src/vote_stage.rs +++ b/src/vote_stage.rs @@ -177,7 +177,8 @@ pub mod tests { use std::sync::{Arc, RwLock}; use std::thread::sleep; use std::time::Duration; - use transaction::{SystemTransaction, Transaction}; + use system_transaction::SystemTransaction; + use transaction::Transaction; #[test] fn test_send_leader_vote() { diff --git a/src/wallet.rs b/src/wallet.rs index f7bd8810c..56dc0f627 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -22,7 +22,8 @@ use std::path::Path; use std::thread::sleep; use std::time::Duration; use std::{error, fmt, mem}; -use transaction::{BudgetTransaction, SystemTransaction, Transaction}; +use system_transaction::SystemTransaction; +use transaction::{BudgetTransaction, Transaction}; #[derive(Debug, PartialEq)] pub enum WalletCommand {