Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libsovtoken/src/logic/api_internals/add_request_fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ pub fn closure_cb_response(command_handle: i32, cb: JsonCallbackUnwrapped) -> im
KEEP all public methods above
*/

fn add_fees(wallet_handle: i32, inputs: Inputs, outputs: Outputs, extra: Option<serde_json::Value>, request_json_map: SerdeMap, cb: Box<Fn(Result<SerdeMap, ErrorCode>) + Send + Sync>) -> Result<(), ErrorCode> {
fn add_fees(wallet_handle: i32, inputs: Inputs, outputs: Outputs, extra: Option<Extra>, request_json_map: SerdeMap, cb: Box<Fn(Result<SerdeMap, ErrorCode>) + Send + Sync>) -> Result<(), ErrorCode> {
let txn_serialized = serialize_signature(request_json_map.clone().into())?;
let mut hasher = Sha256::default();
hasher.input(txn_serialized.as_bytes());
Expand Down
5 changes: 4 additions & 1 deletion libsovtoken/src/logic/build_payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ pub fn deserialize_inputs(
debug!("Converted extra pointer to string >>> {:?}", extra);

let extra: Option<Extra> = if let Some(extra_) = extra {
serde_json::from_str(&extra_).map_err(map_err_err!()).or(Err(ErrorCode::CommonInvalidStructure))?
match serde_json::from_str(&extra_) {
Ok(extra_obj) => Some(extra_obj),
Err(_) => Some(Extra(serde_json::Value::String(extra_)))
}
} else { None };
debug!("Deserialized extra >>> {:?}", secret!(&extra));

Expand Down
2 changes: 1 addition & 1 deletion libsovtoken/src/logic/parsers/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub enum ResponseOperations {

used by [`ParsePaymentReply`], [`ParseResponseWithFeesReply`]
*/
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct UTXO {
pub recipient: String,
Expand Down
20 changes: 11 additions & 9 deletions libsovtoken/src/logic/parsers/parse_payment_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ use logic::parsers::common::{ResponseOperations,
TransactionMetaData,
RequireSignature};
use logic::parsers::error_code_parser;
use logic::type_aliases::{ProtocolVersion};
use logic::type_aliases::ProtocolVersion;
use logic::xfer_payload::Extra;

/**
for parse_payment_response_handler input resp_json
*/
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ParsePaymentResponse {
pub op: ResponseOperations,
Expand All @@ -27,7 +28,7 @@ pub struct ParsePaymentResponse {
/**
The nested type named "result in ParsePaymentResponse
*/
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ParsePaymentResponseResult {
pub txn: Transaction,
Expand All @@ -42,7 +43,7 @@ pub struct ParsePaymentResponseResult {
/**
the nested type "tnx" in ParsePaymentResponseResult
*/
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Transaction {
#[serde(rename = "type")]
Expand All @@ -56,10 +57,10 @@ pub struct Transaction {
/**
the nested type "data" in Transaction
*/
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct TransactionData {
pub extra: Option<String>,
pub extra: Option<Extra>,
pub inputs: Inputs,
pub outputs: Outputs,
}
Expand Down Expand Up @@ -89,15 +90,16 @@ pub type ParsePaymentReply = Vec<UTXO>;
pub fn from_response(base: ParsePaymentResponse) -> Result<ParsePaymentReply, ErrorCode> {
match base.op {
ResponseOperations::REPLY => {
let result = base.result.ok_or(ErrorCode::CommonInvalidStructure)?;
let result: ParsePaymentResponseResult = base.result.ok_or(ErrorCode::CommonInvalidStructure)?;
let extra = result.txn.data.extra.map(|extra|extra.to_string()).unwrap_or_default();
let mut utxos: Vec<UTXO> = vec![];
for unspent_output in result.txn.data.outputs {
let address = unspent_output.recipient;
let amount = unspent_output.amount;
let amount = unspent_output.amount;
let qualified_address: String = add_qualifer_to_address(&address);
let seq_no: u64 = result.tnx_meta_data.seq_no;
let txo = (TXO { address: qualified_address.to_string(), seq_no }).to_libindy_string()?;
let utxo: UTXO = UTXO { recipient: qualified_address, receipt: txo, amount, extra: "".to_string() };
let utxo: UTXO = UTXO { recipient: qualified_address, receipt: txo, amount, extra: extra.clone() };

utxos.push(utxo);
}
Expand Down
10 changes: 6 additions & 4 deletions libsovtoken/src/logic/parsers/parse_verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use logic::type_aliases::ProtocolVersion;
use logic::parsers::common::ResponseOperations;
use logic::output::Outputs;
use logic::input::Inputs;
use logic::xfer_payload::Extra;
use ErrorCode;
use logic::parsers::common::UTXO;
use logic::parsers::common::TXO;
Expand Down Expand Up @@ -52,7 +53,7 @@ pub struct ParseVerifyResponseResultDataTxn {
pub struct ParseVerifyResponseResultDataTxnData {
pub outputs: Option<Outputs>,
pub inputs: Option<Inputs>,
pub extra: Option<String>
pub extra: Option<Extra>
}

#[derive(Serialize, Deserialize, Debug)]
Expand Down Expand Up @@ -84,7 +85,8 @@ fn parse_verify(resp: &str) -> Result<VerifyResult, ErrorCode> {

let mut sources: Vec<String> = vec![];
let mut receipts: Vec<UTXO> = vec![];
let extra = data.extra;

let extra = data.extra.map(|extra|extra.to_string());

if let Some(inputs) = data.inputs {
for input in inputs {
Expand All @@ -100,15 +102,15 @@ fn parse_verify(resp: &str) -> Result<VerifyResult, ErrorCode> {
recipient: address.clone(),
receipt: TXO { address, seq_no }.to_libindy_string()?,
amount: output.amount,
extra: extra.as_ref().unwrap_or(&"".to_string()).to_string(),
extra: extra.clone().unwrap_or_default(),
})
}
}

Ok(VerifyResult {
sources: Some(sources),
receipts: Some(receipts),
extra,
extra: extra.clone(),
})
}

Expand Down
15 changes: 13 additions & 2 deletions libsovtoken/src/logic/xfer_payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,18 @@ pub struct XferPayload {
pub signatures: Option<Vec<String>>
}

pub type Extra = serde_json::Value;
#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)]
pub struct Extra(pub serde_json::Value);

impl ::std::string::ToString for Extra{
fn to_string(&self) -> String {
match self.0 {
::serde_json::Value::Object(ref extra_obj) => json!(extra_obj).to_string(),
serde_json::Value::String(ref extra_str) => extra_str.to_string(),
_ => String::default()
}
}
}

unsafe impl Send for XferPayload {}

Expand Down Expand Up @@ -116,7 +127,7 @@ impl XferPayload {

debug!("Indicator stripped from inputs");

let (extra, taa_acceptance) = extract_taa_acceptance_from_extra(self.extra.clone())?;
let (extra, taa_acceptance) = extract_taa_acceptance_from_extra(self.extra)?;
self.extra = extra;

XferPayload::sign_inputs(crypto_api, wallet_handle, &self.inputs.clone(), &self.outputs.clone(), txn_digest, &self.extra.clone(), &taa_acceptance.clone(), Box::new(move |signatures| {
Expand Down
23 changes: 12 additions & 11 deletions libsovtoken/src/utils/txn_author_agreement.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use serde_json;
use ErrorCode;
use logic::xfer_payload::Extra;

pub type TaaAcceptance = serde_json::Value;

const META_FIELD_NAME: &str = "taaAcceptance";

pub fn extract_taa_acceptance_from_extra(extra: Option<serde_json::Value>) -> Result<(Option<serde_json::Value>, Option<TaaAcceptance>), ErrorCode> {
pub fn extract_taa_acceptance_from_extra(extra: Option<Extra>) -> Result<(Option<Extra>, Option<TaaAcceptance>), ErrorCode> {
match extra {
Some(serde_json::Value::Object(mut extra)) => {
Some(Extra(serde_json::Value::Object(mut extra))) => {
let meta = extra.remove(META_FIELD_NAME);
let extra = if extra.is_empty() { None } else { Some(json!(extra)) };
let extra = if extra.is_empty() { None } else { Some(Extra(json!(extra))) };
Ok((extra, meta))
}
Some(extra) => {
Expand All @@ -31,9 +32,9 @@ mod test {
"time": 123456789,
});

let extra = json!({
let extra = Extra(json!({
"taaAcceptance": taa_acceptance.clone()
});
}));

let expected_taa = taa_acceptance.clone();

Expand All @@ -50,12 +51,12 @@ mod test {
"time": 123456789,
});

let extra = json!({
let extra = Extra(json!({
"data": "some data",
"taaAcceptance": taa_acceptance.clone()
});
}));

let expected_extra = json!({"data": "some data"});
let expected_extra = Extra(json!({"data": "some data"}));
let expected_taa = taa_acceptance.clone();

let (extra, taa_acceptance) = extract_taa_acceptance_from_extra(Some(extra)).unwrap();
Expand All @@ -65,11 +66,11 @@ mod test {

#[test]
pub fn extract_taa_acceptance_from_extra_works_for_no_taa_acceptance() {
let extra = json!({
let extra = Extra(json!({
"data": "some data",
});
}));

let expected_extra = json!({"data": "some data"});
let expected_extra = Extra(json!({"data": "some data"}));

let (extra, taa_acceptance) = extract_taa_acceptance_from_extra(Some(extra)).unwrap();
assert_eq!(expected_extra, extra.unwrap());
Expand Down
58 changes: 51 additions & 7 deletions libsovtoken/tests/build_payment_req_handler_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ fn generate_payment_addresses(wallet: &Wallet) -> (Vec<String>, Vec<String>) {
}

fn get_resp_for_payment_req(pool_handle: i32, wallet_handle: i32, did: &str,
inputs: &str, outputs: &str) -> Result<String, ErrorCode> {
let req = build_payment_req(wallet_handle, did, inputs, outputs, None).unwrap();
inputs: &str, outputs: &str, extra: Option<String>) -> Result<String, ErrorCode> {
let req = build_payment_req(wallet_handle, did, inputs, outputs, extra).unwrap();
let res = indy::ledger::submit_request(pool_handle, &req).wait().unwrap();
parse_payment_response(&res)
}
Expand Down Expand Up @@ -316,7 +316,7 @@ pub fn build_and_submit_payment_req() {
"amount": 10
}
]).to_string();
let res = get_resp_for_payment_req(pool_handle, wallet.handle, dids[0], &inputs, &outputs).unwrap();
let res = get_resp_for_payment_req(pool_handle, wallet.handle, dids[0], &inputs, &outputs, None).unwrap();

let res_parsed: serde_json::Value = serde_json::from_str(&res).unwrap();
let utxos = res_parsed.as_array().unwrap();
Expand Down Expand Up @@ -373,7 +373,7 @@ pub fn build_and_submit_payment_req_incorrect_funds() {
}
]).to_string();
let res = get_resp_for_payment_req(pool_handle, wallet.handle, dids[0],
&inputs, &outputs_1).unwrap_err();
&inputs, &outputs_1, None).unwrap_err();
assert_eq!(res, ErrorCode::PaymentInsufficientFundsError);

let outputs_2 = json!([
Expand All @@ -387,7 +387,7 @@ pub fn build_and_submit_payment_req_incorrect_funds() {
}
]).to_string();
let res = get_resp_for_payment_req(pool_handle, wallet.handle, dids[0],
&inputs, &outputs_2).unwrap_err();
&inputs, &outputs_2, None).unwrap_err();
assert_eq!(res, ErrorCode::PaymentExtraFundsError);
}

Expand Down Expand Up @@ -415,15 +415,15 @@ pub fn build_and_submit_payment_req_with_spent_utxo() {
"amount": 10
}
]).to_string();
get_resp_for_payment_req(pool_handle, wallet.handle, dids[0], &inputs, &outputs).unwrap();
get_resp_for_payment_req(pool_handle, wallet.handle, dids[0], &inputs, &outputs, None).unwrap();

//lets try to spend spent utxo while there are enough funds on the unspent one
let inputs = json!([utxo_2, utxo]).to_string();
let outputs = json!([{
"recipient": addresses[2],
"amount": 20
}]).to_string();
let err = get_resp_for_payment_req(pool_handle, wallet.handle, dids[0], &inputs, &outputs).unwrap_err();
let err = get_resp_for_payment_req(pool_handle, wallet.handle, dids[0], &inputs, &outputs, None).unwrap_err();
assert_eq!(err, ErrorCode::PaymentSourceDoesNotExistError);

//utxo should stay unspent!
Expand Down Expand Up @@ -614,4 +614,48 @@ pub fn build_payment_req_with_taa_acceptance_and_additional_extra() {
assert_eq!(req_parsed["taaAcceptance"], taa_acceptance);

assert_eq!(expected_operation, req_parsed["operation"]);
}

#[test]
pub fn build_and_submit_payment_req_for_extra() {
let wallet = Wallet::new();
let setup = Setup::new(&wallet, SetupConfig {
num_addresses: 1,
num_trustees: 4,
num_users: 0,
mint_tokens: Some(vec![20]),
fees: None,
});
let payment_addresses = &setup.addresses;
let pool_handle = setup.pool_handle;
let dids = setup.trustees.dids();

for extra in ["some extra_json data as string", r#"{"data":"some extra data as string"}"#].iter()
{
let utxo = utils::payment::get_utxo::get_first_utxo_txo_for_payment_address(&wallet, pool_handle, dids[0], &payment_addresses[0]);

let inputs = json!([utxo]).to_string();
let outputs = json!([
{
"recipient": payment_addresses[0],
"amount": 20
}
]).to_string();

let res = get_resp_for_payment_req(pool_handle, wallet.handle, dids[0], &inputs, &outputs, Some(extra.to_string())).unwrap();
let res_parsed: serde_json::Value = serde_json::from_str(&res).unwrap();
let utxos = res_parsed.as_array().unwrap();
assert_eq!(utxos.len(), 1);
assert_eq!(*extra, utxos[0].clone()["extra"].as_str().unwrap());

let value = utxos.get(0).unwrap().as_object().unwrap();
let r_1 = value.get("receipt").unwrap().as_str().unwrap();
assert_eq!(value.get("amount").unwrap().as_i64().unwrap(), 20);

let (req, _) = indy::payments::build_verify_payment_req(wallet.handle, None, &r_1).wait().unwrap();
let res = indy::ledger::submit_request(pool_handle, &req).wait().unwrap();
let res = indy::payments::parse_verify_payment_response("sov", &res).wait().unwrap();
let res_parsed: serde_json::Value = serde_json::from_str(&res).unwrap();
assert_eq!(*extra, res_parsed["extra"].as_str().unwrap());
}
}