From f636408647bd4f9ca0dc3c652310ea2a2740b2c4 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Sat, 22 Sep 2018 17:51:21 -0600 Subject: [PATCH] Fix timestamp and cancel functionality - Also serialize and send helper fn --- src/bin/wallet.rs | 9 ++- src/budget_program.rs | 8 +-- src/transaction.rs | 5 +- src/wallet.rs | 159 ++++++++++++++++++++++-------------------- 4 files changed, 97 insertions(+), 84 deletions(-) diff --git a/src/bin/wallet.rs b/src/bin/wallet.rs index 367033804..6f9093928 100644 --- a/src/bin/wallet.rs +++ b/src/bin/wallet.rs @@ -208,8 +208,15 @@ fn main() -> Result<(), Box> { SubCommand::with_name("send-timestamp") .about("Send a timestamp to unlock a transfer") .arg( - Arg::with_name("process-id") + Arg::with_name("to") .index(1) + .value_name("PUBKEY") + .takes_value(true) + .required(true) + .help("The pubkey of recipient"), + ).arg( + Arg::with_name("process-id") + .index(2) .value_name("PROCESS_ID") .takes_value(true) .required(true) diff --git a/src/budget_program.rs b/src/budget_program.rs index 1206a0c6e..af3ef2d6d 100644 --- a/src/budget_program.rs +++ b/src/budget_program.rs @@ -333,7 +333,7 @@ mod test { contract.pubkey(), dt, from.pubkey(), - true, + None, 1, Hash::default(), ); @@ -408,7 +408,7 @@ mod test { contract.pubkey(), dt, from.pubkey(), - true, + Some(from.pubkey()), 1, Hash::default(), ); @@ -474,7 +474,7 @@ mod test { contract.pubkey(), Utc::now(), from.pubkey(), - true, + None, 1, Hash::default(), ); @@ -528,7 +528,7 @@ mod test { contract, date, keypair.pubkey(), - true, + Some(keypair.pubkey()), 192, Hash::default(), ); diff --git a/src/transaction.rs b/src/transaction.rs index 62f512574..36672a192 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -153,12 +153,11 @@ impl Transaction { contract: Pubkey, dt: DateTime, dt_pubkey: Pubkey, - cancelable: bool, + cancelable: Option, tokens: i64, last_id: Hash, ) -> Self { - let from = from_keypair.pubkey(); - let budget = if cancelable { + let budget = if let Some(from) = cancelable { Budget::Or( (Condition::Timestamp(dt, dt_pubkey), Payment { tokens, to }), (Condition::Signature(from), Payment { tokens, to: from }), diff --git a/src/wallet.rs b/src/wallet.rs index 851155017..62a060530 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -1,5 +1,6 @@ use bincode::{deserialize, serialize}; use bs58; +use budget_program::BudgetState; use chrono::prelude::*; use clap::ArgMatches; use crdt::NodeInfo; @@ -37,9 +38,10 @@ pub enum WalletCommand { Option>, Option, Option>, - Option, + Option, ), - TimeElapsed(Pubkey, DateTime), + // TimeElapsed(to, process_id, timestamp) + TimeElapsed(Pubkey, Pubkey, DateTime), Witness(Pubkey), } @@ -188,7 +190,7 @@ pub fn parse_command( None }; let cancelable = if pay_matches.is_present("cancelable") { - Some(true) + Some(pubkey) } else { None }; @@ -215,6 +217,16 @@ pub fn parse_command( Ok(WalletCommand::Witness(process_id)) } ("send-timestamp", Some(timestamp_matches)) => { + let pubkey_vec = bs58::decode(timestamp_matches.value_of("to").unwrap()) + .into_vec() + .expect("base58-encoded public key"); + + if pubkey_vec.len() != mem::size_of::() { + eprintln!("{}", timestamp_matches.usage()); + Err(WalletError::BadParameter("Invalid public key".to_string()))?; + } + let to = Pubkey::new(&pubkey_vec); + let pubkey_vec = bs58::decode(timestamp_matches.value_of("process-id").unwrap()) .into_vec() .expect("base58-encoded public key"); @@ -239,7 +251,7 @@ pub fn parse_command( } else { Utc::now() }; - Ok(WalletCommand::TimeElapsed(process_id, dt)) + Ok(WalletCommand::TimeElapsed(to, process_id, dt)) } ("", None) => { println!("{}", matches.usage()); @@ -312,33 +324,11 @@ pub fn process_command(config: &WalletConfig) -> Result { - let result = WalletRpcRequest::GetLastId.make_rpc_request(&config.rpc_addr, 1, None)?; - if result.as_str().is_none() { - Err(WalletError::RpcRequestError( - "Received bad last_id".to_string(), - ))? - } - let last_id_str = result.as_str().unwrap(); - let last_id_vec = bs58::decode(last_id_str) - .into_vec() - .map_err(|_| WalletError::RpcRequestError("Received bad last_id".to_string()))?; - let last_id = Hash::new(&last_id_vec); + let last_id = get_last_id(&config)?; let tx = Transaction::budget_new_signature(&config.id, pubkey, config.id.pubkey(), last_id); - let serialized = serialize(&tx).unwrap(); - let params = json!(serialized); - let signature = WalletRpcRequest::SendTransaction.make_rpc_request( - &config.rpc_addr, - 2, - Some(params), - )?; - if signature.as_str().is_none() { - Err(WalletError::RpcRequestError( - "Received result of an unexpected type".to_string(), - ))? - } - let signature_str = signature.as_str().unwrap(); + let signature_str = serialize_and_send_tx(&config, &tx)?; Ok(signature_str.to_string()) } @@ -364,58 +354,69 @@ pub fn process_command(config: &WalletConfig) -> Result { let last_id = get_last_id(&config)?; - let cancelable_bool = cancelable.is_some(); if timestamp == None && *witnesses == None { let tx = Transaction::new(&config.id, to, tokens, last_id); - let serialized = serialize(&tx).unwrap(); - let params = json!(serialized); - let signature = WalletRpcRequest::SendTransaction.make_rpc_request( - &config.rpc_addr, - 2, - Some(params), - )?; - if signature.as_str().is_none() { - Err(WalletError::RpcRequestError( - "Received result of an unexpected type".to_string(), - ))? - } - let signature_str = signature.as_str().unwrap(); - + let signature_str = serialize_and_send_tx(&config, &tx)?; Ok(signature_str.to_string()) } else if *witnesses == None { + // Amazingly, this works! let dt = timestamp.unwrap(); let dt_pubkey = match timestamp_pubkey { Some(pubkey) => pubkey, None => config.id.pubkey(), }; - let process_id = Keypair::new().pubkey(); - let tx = Transaction::budget_new_on_date( + + let contract_funds = Keypair::new(); + // println!("Contract Funds: {:?}", contract_funds.pubkey()); + let contract_state = Keypair::new(); + // println!("Contract State: {:?}", contract_state.pubkey()); + let budget_program_id = BudgetState::id(); + // println!("Budget ProgramId: {:?}", budget_program_id); + + // Create account for contract funds + let tx = Transaction::system_create( &config.id, + contract_funds.pubkey(), + last_id, + tokens, + 0, + budget_program_id, + 0 + ); + let _signature_str = serialize_and_send_tx(&config, &tx)?; + // println!("Create Contract Funds Acct: {:?}", signature_str); + + // Create account for contract state + let tx = Transaction::system_create( + &config.id, + contract_state.pubkey(), + last_id, + 1, + 196, + budget_program_id, + 0 + ); + let _signature_str = serialize_and_send_tx(&config, &tx)?; + // println!("Create Contract State Acct: {:?}", signature_str); + + // Initializing contract + let tx = Transaction::budget_new_on_date( + &contract_funds, to, - process_id, + contract_state.pubkey(), dt, dt_pubkey, - cancelable_bool, + cancelable, tokens, last_id, ); - let serialized = serialize(&tx).unwrap(); - let params = json!(serialized); - let signature = WalletRpcRequest::SendTransaction.make_rpc_request( - &config.rpc_addr, - 2, - Some(params), - )?; - if signature.as_str().is_none() { - Err(WalletError::RpcRequestError( - "Received result of an unexpected type".to_string(), - ))? - } - let signature_str = signature.as_str().unwrap(); + let signature_str = serialize_and_send_tx(&config, &tx)?; + // println!("Initialize Contract: {:?}", signature_str); + Ok(json!({ "signature": signature_str, - "processId": process_id, + "processId": format!("{}", contract_state.pubkey()), }).to_string()) } else if timestamp == None { Ok("Witness Txs not yet handled".to_string()) @@ -424,29 +425,18 @@ pub fn process_command(config: &WalletConfig) -> Result { + WalletCommand::TimeElapsed(to, pubkey, dt) => { let last_id = get_last_id(&config)?; let tx = Transaction::budget_new_timestamp( &config.id, pubkey, - config.id.pubkey(), + to, dt, last_id, ); - let serialized = serialize(&tx).unwrap(); - let params = json!(serialized); - let signature = WalletRpcRequest::SendTransaction.make_rpc_request( - &config.rpc_addr, - 2, - Some(params), - )?; - if signature.as_str().is_none() { - Err(WalletError::RpcRequestError( - "Received result of an unexpected type".to_string(), - ))? - } - let signature_str = signature.as_str().unwrap(); + // println!("{:?}", tx); + let signature_str = serialize_and_send_tx(&config, &tx)?; Ok(signature_str.to_string()) } @@ -600,6 +590,23 @@ fn get_last_id(config: &WalletConfig) -> Result> { Ok(Hash::new(&last_id_vec)) } +fn serialize_and_send_tx(config: &WalletConfig, tx: &Transaction) -> Result> { + // println!("{:?}", tx); + let serialized = serialize(tx).unwrap(); + let params = json!(serialized); + let signature = WalletRpcRequest::SendTransaction.make_rpc_request( + &config.rpc_addr, + 2, + Some(params), + )?; + if signature.as_str().is_none() { + Err(WalletError::RpcRequestError( + "Received result of an unexpected type".to_string(), + ))? + } + Ok(signature.as_str().unwrap().to_string()) +} + #[cfg(test)] mod tests { use super::*;