Skip to content

Commit db5dd48

Browse files
author
Nikita Khateev
authored
Merge pull request #412 from Artemkaaas/payment-extra
IS-1379: Extra Param doesn't work on build_payment_req
2 parents 2c5c72e + 951dd94 commit db5dd48

8 files changed

Lines changed: 99 additions & 36 deletions

File tree

libsovtoken/src/logic/api_internals/add_request_fees.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ pub fn closure_cb_response(command_handle: i32, cb: JsonCallbackUnwrapped) -> im
129129
KEEP all public methods above
130130
*/
131131

132-
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> {
132+
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> {
133133
let txn_serialized = serialize_signature(request_json_map.clone().into())?;
134134
let mut hasher = Sha256::default();
135135
hasher.input(txn_serialized.as_bytes());

libsovtoken/src/logic/build_payment.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ pub fn deserialize_inputs(
5252
debug!("Converted extra pointer to string >>> {:?}", extra);
5353

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

libsovtoken/src/logic/parsers/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub enum ResponseOperations {
2626
2727
used by [`ParsePaymentReply`], [`ParseResponseWithFeesReply`]
2828
*/
29-
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
29+
#[derive(Serialize, Deserialize, Debug, PartialEq)]
3030
#[serde(rename_all = "camelCase")]
3131
pub struct UTXO {
3232
pub recipient: String,

libsovtoken/src/logic/parsers/parse_payment_response.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ use logic::parsers::common::{ResponseOperations,
1010
TransactionMetaData,
1111
RequireSignature};
1212
use logic::parsers::error_code_parser;
13-
use logic::type_aliases::{ProtocolVersion};
13+
use logic::type_aliases::ProtocolVersion;
14+
use logic::xfer_payload::Extra;
1415

1516
/**
1617
for parse_payment_response_handler input resp_json
1718
*/
18-
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
19+
#[derive(Serialize, Deserialize, Debug, PartialEq)]
1920
#[serde(rename_all = "camelCase")]
2021
pub struct ParsePaymentResponse {
2122
pub op: ResponseOperations,
@@ -27,7 +28,7 @@ pub struct ParsePaymentResponse {
2728
/**
2829
The nested type named "result in ParsePaymentResponse
2930
*/
30-
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
31+
#[derive(Serialize, Deserialize, Debug, PartialEq)]
3132
#[serde(rename_all = "camelCase")]
3233
pub struct ParsePaymentResponseResult {
3334
pub txn: Transaction,
@@ -42,7 +43,7 @@ pub struct ParsePaymentResponseResult {
4243
/**
4344
the nested type "tnx" in ParsePaymentResponseResult
4445
*/
45-
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
46+
#[derive(Serialize, Deserialize, Debug, PartialEq)]
4647
#[serde(rename_all = "camelCase")]
4748
pub struct Transaction {
4849
#[serde(rename = "type")]
@@ -56,10 +57,10 @@ pub struct Transaction {
5657
/**
5758
the nested type "data" in Transaction
5859
*/
59-
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
60+
#[derive(Serialize, Deserialize, Debug, PartialEq)]
6061
#[serde(rename_all = "camelCase")]
6162
pub struct TransactionData {
62-
pub extra: Option<String>,
63+
pub extra: Option<Extra>,
6364
pub inputs: Inputs,
6465
pub outputs: Outputs,
6566
}
@@ -89,15 +90,16 @@ pub type ParsePaymentReply = Vec<UTXO>;
8990
pub fn from_response(base: ParsePaymentResponse) -> Result<ParsePaymentReply, ErrorCode> {
9091
match base.op {
9192
ResponseOperations::REPLY => {
92-
let result = base.result.ok_or(ErrorCode::CommonInvalidStructure)?;
93+
let result: ParsePaymentResponseResult = base.result.ok_or(ErrorCode::CommonInvalidStructure)?;
94+
let extra = result.txn.data.extra.map(|extra|extra.to_string()).unwrap_or_default();
9395
let mut utxos: Vec<UTXO> = vec![];
9496
for unspent_output in result.txn.data.outputs {
9597
let address = unspent_output.recipient;
96-
let amount = unspent_output.amount;
98+
let amount = unspent_output.amount;
9799
let qualified_address: String = add_qualifer_to_address(&address);
98100
let seq_no: u64 = result.tnx_meta_data.seq_no;
99101
let txo = (TXO { address: qualified_address.to_string(), seq_no }).to_libindy_string()?;
100-
let utxo: UTXO = UTXO { recipient: qualified_address, receipt: txo, amount, extra: "".to_string() };
102+
let utxo: UTXO = UTXO { recipient: qualified_address, receipt: txo, amount, extra: extra.clone() };
101103

102104
utxos.push(utxo);
103105
}

libsovtoken/src/logic/parsers/parse_verify.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use logic::type_aliases::ProtocolVersion;
44
use logic::parsers::common::ResponseOperations;
55
use logic::output::Outputs;
66
use logic::input::Inputs;
7+
use logic::xfer_payload::Extra;
78
use ErrorCode;
89
use logic::parsers::common::UTXO;
910
use logic::parsers::common::TXO;
@@ -52,7 +53,7 @@ pub struct ParseVerifyResponseResultDataTxn {
5253
pub struct ParseVerifyResponseResultDataTxnData {
5354
pub outputs: Option<Outputs>,
5455
pub inputs: Option<Inputs>,
55-
pub extra: Option<String>
56+
pub extra: Option<Extra>
5657
}
5758

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

8586
let mut sources: Vec<String> = vec![];
8687
let mut receipts: Vec<UTXO> = vec![];
87-
let extra = data.extra;
88+
89+
let extra = data.extra.map(|extra|extra.to_string());
8890

8991
if let Some(inputs) = data.inputs {
9092
for input in inputs {
@@ -100,15 +102,15 @@ fn parse_verify(resp: &str) -> Result<VerifyResult, ErrorCode> {
100102
recipient: address.clone(),
101103
receipt: TXO { address, seq_no }.to_libindy_string()?,
102104
amount: output.amount,
103-
extra: extra.as_ref().unwrap_or(&"".to_string()).to_string(),
105+
extra: extra.clone().unwrap_or_default(),
104106
})
105107
}
106108
}
107109

108110
Ok(VerifyResult {
109111
sources: Some(sources),
110112
receipts: Some(receipts),
111-
extra,
113+
extra: extra.clone(),
112114
})
113115
}
114116

libsovtoken/src/logic/xfer_payload.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,18 @@ pub struct XferPayload {
6363
pub signatures: Option<Vec<String>>
6464
}
6565

66-
pub type Extra = serde_json::Value;
66+
#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)]
67+
pub struct Extra(pub serde_json::Value);
68+
69+
impl ::std::string::ToString for Extra{
70+
fn to_string(&self) -> String {
71+
match self.0 {
72+
::serde_json::Value::Object(ref extra_obj) => json!(extra_obj).to_string(),
73+
serde_json::Value::String(ref extra_str) => extra_str.to_string(),
74+
_ => String::default()
75+
}
76+
}
77+
}
6778

6879
unsafe impl Send for XferPayload {}
6980

@@ -116,7 +127,7 @@ impl XferPayload {
116127

117128
debug!("Indicator stripped from inputs");
118129

119-
let (extra, taa_acceptance) = extract_taa_acceptance_from_extra(self.extra.clone())?;
130+
let (extra, taa_acceptance) = extract_taa_acceptance_from_extra(self.extra)?;
120131
self.extra = extra;
121132

122133
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| {

libsovtoken/src/utils/txn_author_agreement.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
use serde_json;
22
use ErrorCode;
3+
use logic::xfer_payload::Extra;
34

45
pub type TaaAcceptance = serde_json::Value;
56

67
const META_FIELD_NAME: &str = "taaAcceptance";
78

8-
pub fn extract_taa_acceptance_from_extra(extra: Option<serde_json::Value>) -> Result<(Option<serde_json::Value>, Option<TaaAcceptance>), ErrorCode> {
9+
pub fn extract_taa_acceptance_from_extra(extra: Option<Extra>) -> Result<(Option<Extra>, Option<TaaAcceptance>), ErrorCode> {
910
match extra {
10-
Some(serde_json::Value::Object(mut extra)) => {
11+
Some(Extra(serde_json::Value::Object(mut extra))) => {
1112
let meta = extra.remove(META_FIELD_NAME);
12-
let extra = if extra.is_empty() { None } else { Some(json!(extra)) };
13+
let extra = if extra.is_empty() { None } else { Some(Extra(json!(extra))) };
1314
Ok((extra, meta))
1415
}
1516
Some(extra) => {
@@ -31,9 +32,9 @@ mod test {
3132
"time": 123456789,
3233
});
3334

34-
let extra = json!({
35+
let extra = Extra(json!({
3536
"taaAcceptance": taa_acceptance.clone()
36-
});
37+
}));
3738

3839
let expected_taa = taa_acceptance.clone();
3940

@@ -50,12 +51,12 @@ mod test {
5051
"time": 123456789,
5152
});
5253

53-
let extra = json!({
54+
let extra = Extra(json!({
5455
"data": "some data",
5556
"taaAcceptance": taa_acceptance.clone()
56-
});
57+
}));
5758

58-
let expected_extra = json!({"data": "some data"});
59+
let expected_extra = Extra(json!({"data": "some data"}));
5960
let expected_taa = taa_acceptance.clone();
6061

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

6667
#[test]
6768
pub fn extract_taa_acceptance_from_extra_works_for_no_taa_acceptance() {
68-
let extra = json!({
69+
let extra = Extra(json!({
6970
"data": "some data",
70-
});
71+
}));
7172

72-
let expected_extra = json!({"data": "some data"});
73+
let expected_extra = Extra(json!({"data": "some data"}));
7374

7475
let (extra, taa_acceptance) = extract_taa_acceptance_from_extra(Some(extra)).unwrap();
7576
assert_eq!(expected_extra, extra.unwrap());

libsovtoken/tests/build_payment_req_handler_test.rs

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ fn generate_payment_addresses(wallet: &Wallet) -> (Vec<String>, Vec<String>) {
9090
}
9191

9292
fn get_resp_for_payment_req(pool_handle: i32, wallet_handle: i32, did: &str,
93-
inputs: &str, outputs: &str) -> Result<String, ErrorCode> {
94-
let req = build_payment_req(wallet_handle, did, inputs, outputs, None).unwrap();
93+
inputs: &str, outputs: &str, extra: Option<String>) -> Result<String, ErrorCode> {
94+
let req = build_payment_req(wallet_handle, did, inputs, outputs, extra).unwrap();
9595
let res = indy::ledger::submit_request(pool_handle, &req).wait().unwrap();
9696
parse_payment_response(&res)
9797
}
@@ -316,7 +316,7 @@ pub fn build_and_submit_payment_req() {
316316
"amount": 10
317317
}
318318
]).to_string();
319-
let res = get_resp_for_payment_req(pool_handle, wallet.handle, dids[0], &inputs, &outputs).unwrap();
319+
let res = get_resp_for_payment_req(pool_handle, wallet.handle, dids[0], &inputs, &outputs, None).unwrap();
320320

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

379379
let outputs_2 = json!([
@@ -387,7 +387,7 @@ pub fn build_and_submit_payment_req_incorrect_funds() {
387387
}
388388
]).to_string();
389389
let res = get_resp_for_payment_req(pool_handle, wallet.handle, dids[0],
390-
&inputs, &outputs_2).unwrap_err();
390+
&inputs, &outputs_2, None).unwrap_err();
391391
assert_eq!(res, ErrorCode::PaymentExtraFundsError);
392392
}
393393

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

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

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

616616
assert_eq!(expected_operation, req_parsed["operation"]);
617+
}
618+
619+
#[test]
620+
pub fn build_and_submit_payment_req_for_extra() {
621+
let wallet = Wallet::new();
622+
let setup = Setup::new(&wallet, SetupConfig {
623+
num_addresses: 1,
624+
num_trustees: 4,
625+
num_users: 0,
626+
mint_tokens: Some(vec![20]),
627+
fees: None,
628+
});
629+
let payment_addresses = &setup.addresses;
630+
let pool_handle = setup.pool_handle;
631+
let dids = setup.trustees.dids();
632+
633+
for extra in ["some extra_json data as string", r#"{"data":"some extra data as string"}"#].iter()
634+
{
635+
let utxo = utils::payment::get_utxo::get_first_utxo_txo_for_payment_address(&wallet, pool_handle, dids[0], &payment_addresses[0]);
636+
637+
let inputs = json!([utxo]).to_string();
638+
let outputs = json!([
639+
{
640+
"recipient": payment_addresses[0],
641+
"amount": 20
642+
}
643+
]).to_string();
644+
645+
let res = get_resp_for_payment_req(pool_handle, wallet.handle, dids[0], &inputs, &outputs, Some(extra.to_string())).unwrap();
646+
let res_parsed: serde_json::Value = serde_json::from_str(&res).unwrap();
647+
let utxos = res_parsed.as_array().unwrap();
648+
assert_eq!(utxos.len(), 1);
649+
assert_eq!(*extra, utxos[0].clone()["extra"].as_str().unwrap());
650+
651+
let value = utxos.get(0).unwrap().as_object().unwrap();
652+
let r_1 = value.get("receipt").unwrap().as_str().unwrap();
653+
assert_eq!(value.get("amount").unwrap().as_i64().unwrap(), 20);
654+
655+
let (req, _) = indy::payments::build_verify_payment_req(wallet.handle, None, &r_1).wait().unwrap();
656+
let res = indy::ledger::submit_request(pool_handle, &req).wait().unwrap();
657+
let res = indy::payments::parse_verify_payment_response("sov", &res).wait().unwrap();
658+
let res_parsed: serde_json::Value = serde_json::from_str(&res).unwrap();
659+
assert_eq!(*extra, res_parsed["extra"].as_str().unwrap());
660+
}
617661
}

0 commit comments

Comments
 (0)