diff --git a/src/system_contract.rs b/src/system_contract.rs index 828ec4d468..72faf8bc8d 100644 --- a/src/system_contract.rs +++ b/src/system_contract.rs @@ -48,13 +48,13 @@ impl SystemContract { space, contract_id, } => { - if !Self::check_id(&accounts[1].contract_id) { - return; - } if !Self::check_id(&accounts[0].contract_id) { return; } - if space > 0 && !accounts[1].userdata.is_empty() { + if space > 0 + && (!accounts[1].userdata.is_empty() + || !Self::check_id(&accounts[1].contract_id)) + { return; } accounts[0].tokens -= tokens; @@ -78,3 +78,113 @@ impl SystemContract { } } } +#[cfg(test)] +mod test { + use bank::Account; + use hash::Hash; + use signature::{Keypair, KeypairUtil}; + use system_contract::SystemContract; + use transaction::Transaction; + #[test] + fn test_create_noop() { + let from = Keypair::new(); + let to = Keypair::new(); + let mut accounts = vec![Account::default(), Account::default()]; + let tx = Transaction::system_new(&from, to.pubkey(), 0, Hash::default()); + SystemContract::process_transaction(&tx, &mut accounts); + assert_eq!(accounts[0].tokens, 0); + assert_eq!(accounts[1].tokens, 0); + } + #[test] + fn test_create_spend() { + let from = Keypair::new(); + let to = Keypair::new(); + let mut accounts = vec![Account::default(), Account::default()]; + accounts[0].tokens = 1; + let tx = Transaction::system_new(&from, to.pubkey(), 1, Hash::default()); + SystemContract::process_transaction(&tx, &mut accounts); + assert_eq!(accounts[0].tokens, 0); + assert_eq!(accounts[1].tokens, 1); + } + #[test] + fn test_create_spend_wrong_source() { + let from = Keypair::new(); + let to = Keypair::new(); + let mut accounts = vec![Account::default(), Account::default()]; + accounts[0].tokens = 1; + accounts[0].contract_id = from.pubkey(); + let tx = Transaction::system_new(&from, to.pubkey(), 1, Hash::default()); + SystemContract::process_transaction(&tx, &mut accounts); + assert_eq!(accounts[0].tokens, 1); + assert_eq!(accounts[1].tokens, 0); + } + #[test] + fn test_create_assign_and_allocate() { + let from = Keypair::new(); + let to = Keypair::new(); + let mut accounts = vec![Account::default(), Account::default()]; + let tx = Transaction::system_create( + &from, + to.pubkey(), + Hash::default(), + 0, + 1, + Some(to.pubkey()), + 0, + ); + SystemContract::process_transaction(&tx, &mut accounts); + assert!(accounts[0].userdata.is_empty()); + assert_eq!(accounts[1].userdata.len(), 1); + assert_eq!(accounts[1].contract_id, to.pubkey()); + } + #[test] + fn test_create_allocate_wrong_dest_contract() { + let from = Keypair::new(); + let to = Keypair::new(); + let mut accounts = vec![Account::default(), Account::default()]; + accounts[1].contract_id = to.pubkey(); + let tx = Transaction::system_create(&from, to.pubkey(), Hash::default(), 0, 1, None, 0); + SystemContract::process_transaction(&tx, &mut accounts); + assert!(accounts[1].userdata.is_empty()); + } + #[test] + fn test_create_allocate_wrong_source_contract() { + let from = Keypair::new(); + let to = Keypair::new(); + let mut accounts = vec![Account::default(), Account::default()]; + accounts[0].contract_id = to.pubkey(); + let tx = Transaction::system_create(&from, to.pubkey(), Hash::default(), 0, 1, None, 0); + SystemContract::process_transaction(&tx, &mut accounts); + assert!(accounts[1].userdata.is_empty()); + } + #[test] + fn test_create_allocate_already_allocated() { + let from = Keypair::new(); + let to = Keypair::new(); + let mut accounts = vec![Account::default(), Account::default()]; + accounts[1].userdata = vec![0, 0, 0]; + let tx = Transaction::system_create(&from, to.pubkey(), Hash::default(), 0, 2, None, 0); + SystemContract::process_transaction(&tx, &mut accounts); + assert_eq!(accounts[1].userdata.len(), 3); + } + #[test] + fn test_create_assign() { + let from = Keypair::new(); + let contract = Keypair::new(); + let mut accounts = vec![Account::default()]; + let tx = Transaction::system_assign(&from, Hash::default(), contract.pubkey(), 0); + SystemContract::process_transaction(&tx, &mut accounts); + assert_eq!(accounts[0].contract_id, contract.pubkey()); + } + #[test] + fn test_move() { + let from = Keypair::new(); + let to = Keypair::new(); + let mut accounts = vec![Account::default(), Account::default()]; + accounts[0].tokens = 1; + let tx = Transaction::new(&from, to.pubkey(), 1, Hash::default()); + SystemContract::process_transaction(&tx, &mut accounts); + assert_eq!(accounts[0].tokens, 0); + assert_eq!(accounts[1].tokens, 1); + } +} diff --git a/src/transaction.rs b/src/transaction.rs index 2e94fcb902..5cc9951768 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -181,7 +181,7 @@ impl Transaction { ) } /// Create and sign new SystemContract::CreateAccount transaction - pub fn system_new_create( + pub fn system_create( from_keypair: &Keypair, to: Pubkey, last_id: Hash, @@ -204,9 +204,26 @@ impl Transaction { fee, ) } + /// Create and sign new SystemContract::CreateAccount transaction + pub fn system_assign( + from_keypair: &Keypair, + last_id: Hash, + contract_id: Pubkey, + fee: i64, + ) -> Self { + let create = SystemContract::Assign { contract_id }; + Transaction::new_with_userdata( + from_keypair, + &[], + SystemContract::id(), + serialize(&create).unwrap(), + last_id, + fee, + ) + } /// Create and sign new SystemContract::CreateAccount transaction with some defaults pub fn system_new(from_keypair: &Keypair, to: Pubkey, tokens: i64, last_id: Hash) -> Self { - Transaction::system_new_create(from_keypair, to, last_id, tokens, 0, None, 0) + Transaction::system_create(from_keypair, to, last_id, tokens, 0, None, 0) } /// Create and sign new SystemContract::Move transaction pub fn system_move(