From 360db8f6fe946be910abca24d47773b3c2298e84 Mon Sep 17 00:00:00 2001 From: jeffro256 Date: Thu, 14 Mar 2024 13:39:34 -0500 Subject: [PATCH] unit_tests: test every single field of JSON tx repr Co-authored-by: selsta --- tests/data/txs/rct_bp_compact_tx_10312fd4.bin | Bin 0 -> 1774 bytes tests/data/txs/rct_bp_tx_a685d68e.bin | Bin 0 -> 2716 bytes tests/data/txs/rct_clsag_tx_200c3215.bin | Bin 0 -> 1966 bytes tests/data/txs/rct_full_tx_14056427.bin | Bin 0 -> 12925 bytes tests/data/txs/rct_simple_tx_c69861bf.bin | Bin 0 -> 13524 bytes tests/data/txs/v1_coinbase_tx_bf4c0300.bin | Bin 0 -> 170 bytes tests/data/txs/v1_tx_hf3_effcceb9.bin | Bin 0 -> 710 bytes tests/data/txs/v2_coinbase_tx_7f88a52a.bin | Bin 0 -> 106 bytes tests/unit_tests/json_serialization.cpp | 444 +++++++++++++++++- 9 files changed, 443 insertions(+), 1 deletion(-) create mode 100644 tests/data/txs/rct_bp_compact_tx_10312fd4.bin create mode 100644 tests/data/txs/rct_bp_tx_a685d68e.bin create mode 100644 tests/data/txs/rct_clsag_tx_200c3215.bin create mode 100644 tests/data/txs/rct_full_tx_14056427.bin create mode 100644 tests/data/txs/rct_simple_tx_c69861bf.bin create mode 100644 tests/data/txs/v1_coinbase_tx_bf4c0300.bin create mode 100644 tests/data/txs/v1_tx_hf3_effcceb9.bin create mode 100644 tests/data/txs/v2_coinbase_tx_7f88a52a.bin diff --git a/tests/data/txs/rct_bp_compact_tx_10312fd4.bin b/tests/data/txs/rct_bp_compact_tx_10312fd4.bin new file mode 100644 index 0000000000000000000000000000000000000000..1131b48bdb546f2abdbda6ce5ed7ae4a368d62f1 GIT binary patch literal 1774 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 WwWNUi&OtllA_O25s!T+Kv|rq$dKx(Z literal 0 HcmV?d00001 diff --git a/tests/data/txs/rct_clsag_tx_200c3215.bin b/tests/data/txs/rct_clsag_tx_200c3215.bin new file mode 100644 index 0000000000000000000000000000000000000000..3914e1652d3e56ea3c645c378085bc84c890bede GIT binary patch literal 1966 zcmV;f2T}L}00II43!w0V1)HLS1(4?*((M7_!vv{;61xx6sR70zz!>@h$Md(HC}kgD zUn3r@*tS=%W<>2RH)?)4VYiwY4Gx2H0ssr?+pY?P#sQqr2Bg*n;$o)~mm=E&x`w5D_R=!&l{{VC`dB>PDI#EI?#cjVQ&ib3 z0k>LLiGdh?x9E>6$e0%OkPmqqk}&k{7otencd{a6qyh;6dPu`xA-q3E1)#r?)d3Gf zTyZG(91y}+&bQs1wtYfc3#Y8xNg;=c;m>H@Wzh!ztaz?ff|RUd4Gscz*i2x@749mF z6&|v}qblvaoyUDXFiT!&!Z1`_{Qj~mJfi`-g}#bQCm!GoR3h<6SLQQU+GDOu$|t?R ze+R<)%OParQA8!M?VAY^rNOevAs|zVa6KR1?WAXp7bF}6REQlag`-gF`wL7L`b8+p z_R4OtIr2Fjm(NUYP(39%qpE3ycL9Y)A3b}MrH2BwzSR&Us!wz%H>!rcnGk%I=jOiz zO}KM$nbfvNi-=shp`-hkp;bu+U?DvmfFGb!2$ls}ps9qJ5N?Vt3B z=rf1LbSgwdQUSZe;=JI@3j>R*peZ^56{7{!Thz$0JO8vhQw`Z+*q%3_Q{pqyPe(&s zmDvFOXul*+AbG7PcFD-P3qVCk)O4s;gxUNT2PJh*2R5Td3=S)cqNn{T&K!AN8>(UU z5`9_tA6k2?PMPHOVk~*&Za^Ty}_J51i!*M#f?X@s42OmPtc|7dA!y-;456 z68HFO&h7$Nkj-?&7-yfP@o zOGE>R)H;yHg6B-)rH8!nMNFOlvpg`$sE5~XKaGF>Sp$g=@_H$B8t?Ot^vJ~+Pq(bu z+#jS<#>AopE&VVSQPI@SvNm@SfoPD%MiGE^0Z;<%jIvN_u#Q&QH@?{kTY@?GrNi-- zcoLLkXN)_H{(uJ>A-P~$6?bm#*?~7-1^HIW?RT*uPIlX+bQ3rZ9ZoB%`geTyGHM zZ&>YpAXiG^4(YO2ARAwSVVo0#QzA`p=S@mb?`8yJBX*m``Rb=$0&if=H^|+xC*ASg zqnc%7x&5GQx5LNSwFVIrA$#En>?Rri(NgErBW|3=IH-)^v4X z2^ZuAJa-7D+u7yaBCgE6F&KCh>31chddIZ%*B8Od3?570bRZbtI#whpv!bQ+9^4ZB zGdfyhvXV^w5FU_P2SuRC6FM{&nTT0T{a;eP}-3 zapJaD4;tw_sjxIv_a9qwQd+a$c(*dC0&5ik{W^zZ#W=?dXF}t15Tcf7pDmSYop?K? zgJ~6e2Z%hnY5?-@+`r-Nxh>Sen%wB{`Xx!*mMndr25ta*?p`7e(MfMHFFLX0U+J*C z0qSm|4#IlX)Sa&+T&}0+1?Qs%H0eJdjZnsa^&$L9YK`>|@oiR6z_NvCX9v_>3|&`0 z9s?*gwU+4zj@cgDF{i>YJAWmwetBd6fBb6_19((QG7K^V|2y3;Z@IeH3M7iQ@P2^* zdghPSbet_;0!?O5V*NiVjJ>*6un@yhN@sq_R#kB7CTR585P0QZJ1-q)Jx6O0$iBkRVH%rg7Xq3K>wq_X-$oiP0!!$A4S)T2p92A?Gd5$!iEI$9 z?Rb+`VQx;%M35L52V%c*Lnq~ps&XJr7fa0@PbQ5hKp(Qkn8M>%SAzR=0C>~@+eHd{ zkRHF&{Ty^rZZ`eLb{oM`qIDswBG*YF4`z8o1yShAWb2=iEb71O1-4s_q~bOjnP1ry zH^34E2SaPck+xAGFlO%Njuqw&n_Riz{DAQ@A AmH+?% literal 0 HcmV?d00001 diff --git a/tests/data/txs/rct_full_tx_14056427.bin b/tests/data/txs/rct_full_tx_14056427.bin new file mode 100644 index 0000000000000000000000000000000000000000..4eaaeecea3bae27e809e5828d45cf4101028c52c GIT binary patch literal 12925 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 literal 0 HcmV?d00001 diff --git a/tests/data/txs/rct_simple_tx_c69861bf.bin b/tests/data/txs/rct_simple_tx_c69861bf.bin new file mode 100644 index 0000000000000000000000000000000000000000..bbbe53db2b4aa850b0fb497c3cd05a42c3bee57f GIT binary patch literal 13524 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 OK>qt!{f17AF zwa0*9)}YDGZX0)X7 YyH)T9*Yf$$HRnwN2mk;8M0AI&y(Jn>?f?J) literal 0 HcmV?d00001 diff --git a/tests/data/txs/v1_tx_hf3_effcceb9.bin b/tests/data/txs/v1_tx_hf3_effcceb9.bin new file mode 100644 index 0000000000000000000000000000000000000000..55f7f1aa1ba6fea7bac1f303cc8f508826e2e320 GIT binary patch literal 710 zcmV;%0y+Hw00IJlfYFq-bOZn41)_!r>y81q$iG}65M_Y)W#;tB57*C8L$UQW!SlUU zv_jU+q*e(6fWYpK(hCEJ@D#A35}UXIEOyIxb4AlQ+}}%<3#S>8!@dr~+LQ4;|9U~! zd&Fl|1c0E~<{biYUaIL3Uww);BVHIbPSIwD`^-|=@_|c(Hw+ENH!{+Ih^(W}0s?rk zsy1j=oz-2`-w8i#>FTR*IHEfq$}x0Dz;8mRa{z$wlFQu)0+nL^w?*<{;mo73Jl`IT z(SH>wKiFsgpl*CME8|Kp7l44#l(lpMB;GqueS|Ju{NA&e;Y=0Bw!(d0Li|=X3STd5 z&RtyZL;@iIis|2uT-IaW>$sO){yF-acvPosiA|^ksW+7;WN*St0ZC@Rc6r6MHo91= z8Ejoy`f>8l>2WL5b0F|;{+F+K_0~E~#rMCQPAH!tEV?`N)6c|Xlthw(e{yfU$3^$M z4{=%`M|ZPI`b>Gls~%JY{f^7{OcJne<``VQ*|iR#2VrRY$%tigzX2CE5~dlIKHr7?GT?1F)qw7z`r8BtEln+lZj`tMkPq3UA@Tx9=E| zULPADq!lVkpH$c)h&v1pI7~rQ-(fl}4TcXtY9#_;_*%MT9jIJXd+HvxH0V&sm&h>; zB`OgU4gw-Sxwb6(e#|~*o$1S`T6x~iAbJq>$^&ro+C#6l0qHxU>Y5rVZR3A$30L3u z5wFM=qIR4s=xP*3G6?eY4?B)p{a%}}PSabnwUtb#ZfN(B#^YLxYs^7T#n|cb1DTVl z&5#2viJMKc%~gtugvb$33YxD^mS!p5h~1?a0;p$LunI7yQ2 s>-zXC{D6((0U4tyk7vl*jGc%K$21D8JO`LcKCPLa0}T(aYZd#x3)FF0(*OVf literal 0 HcmV?d00001 diff --git a/tests/data/txs/v2_coinbase_tx_7f88a52a.bin b/tests/data/txs/v2_coinbase_tx_7f88a52a.bin new file mode 100644 index 0000000000000000000000000000000000000000..b91fbfcb45a09c3d0e05077f5f18b6d37bd50d50 GIT binary patch literal 106 zcmZSj)4QFK@&5r3*|7J~!jpo`@`~ODekCveIoF((Pufymt>F8r>hBL1C*Grqo`vsw zb3U6emO8KZuiSTLo^3nh{$od2GqZxOF&ky7Gyhs^Qu<)U`6o<*3=9l~?n~6efHV{U E01rGWs{jB1 literal 0 HcmV?d00001 diff --git a/tests/unit_tests/json_serialization.cpp b/tests/unit_tests/json_serialization.cpp index aa46b68dc..e43456ab8 100644 --- a/tests/unit_tests/json_serialization.cpp +++ b/tests/unit_tests/json_serialization.cpp @@ -12,9 +12,14 @@ #include "cryptonote_basic/cryptonote_basic.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_core/cryptonote_tx_utils.h" -#include "serialization/json_object.h" +#include "file_io_utils.h" #include "rpc/daemon_messages.h" +#include "serialization/json_object.h" +#include "string_tools.h" +#include "unit_tests_utils.h" +#undef MONERO_DEFAULT_LOG_CATEGORY +#define MONERO_DEFAULT_LOG_CATEGORY "cn" namespace test { @@ -107,6 +112,430 @@ namespace cryptonote::json::fromJsonValue(doc, out); return out; } + + bool compare_tx_to_json_tx(const cryptonote::transaction &tx, const std::string &tx_json) + { + using namespace epee::string_tools; // for pod_to_hex() + + const crypto::hash txid = get_transaction_hash(tx); + MINFO("Asserting validity of JSON representation of tx " << txid); + + rapidjson::Document tx_document; + tx_document.Parse(tx_json.data()); + CHECK_AND_ASSERT_MES(!tx_document.HasParseError(), false, "compare_tx_to_json_tx: failed to parse json"); + + // check existence of prefix members + CHECK_AND_ASSERT_MES(tx_document.HasMember("version") && tx_document.HasMember("unlock_time") && + tx_document.HasMember("vin") && tx_document.HasMember("vout") && tx_document.HasMember("extra"), + false, "compare_tx_to_json_tx: missing prefix members"); + + // version + CHECK_AND_ASSERT_MES(tx_document["version"].IsInt(), false, "compare_tx_to_json_tx: version isnt integer"); + CHECK_AND_ASSERT_MES(tx_document["version"].GetInt() == tx.version, false, "compare_tx_to_json_tx: wrong version"); + + // unlock_time + CHECK_AND_ASSERT_MES(tx_document["unlock_time"].IsUint64(), false, "compare_tx_to_json_tx: wrong unlock time"); + CHECK_AND_ASSERT_MES(tx_document["unlock_time"].GetUint64() == tx.unlock_time, false, "compare_tx_to_json_tx: wrong unlock time"); + + // extra + CHECK_AND_ASSERT_MES(tx_document["extra"].IsArray(), false, "compare_tx_to_json_tx: extra is not array"); + CHECK_AND_ASSERT_MES(tx_document["extra"].Size() == tx.extra.size(), false, "compare_tx_to_json_tx: wrong extra size"); + for (size_t i = 0; i < tx.extra.size(); ++i) + { + CHECK_AND_ASSERT_MES(tx_document["extra"][i].IsInt(), false, "compare_tx_to_json_tx: extra array contains non-int"); + CHECK_AND_ASSERT_MES(tx_document["extra"][i].GetInt() == tx.extra[i], false, "compare_tx_to_json_tx: extra array contains wrong int"); + } + + // vin + const size_t num_inputs = tx.vin.size(); + size_t ring_size = 0; + CHECK_AND_ASSERT_MES(tx_document["vin"].IsArray(), false, "compare_tx_to_json_tx: vin is not array"); + CHECK_AND_ASSERT_MES(tx_document["vin"].Size() == tx.vin.size(), false, "compare_tx_to_json_tx: vin wrong size"); + for (size_t i = 0; i < tx_document["vin"].Size(); i++) + { + CHECK_AND_ASSERT_MES(tx_document["vin"][i].IsObject(), false, "compare_tx_to_json_tx: txin not object"); + if (tx.vin[i].type() == typeid(cryptonote::txin_to_key)) + { + const cryptonote::txin_to_key &k = boost::get(tx.vin[i]); + ring_size = k.key_offsets.size(); + CHECK_AND_ASSERT_MES(tx_document["vin"][i].HasMember("key"), false, "compare_tx_to_json_tx: txin wrong type"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"].IsObject(), false, "compare_tx_to_json_tx: txin is not object"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"].HasMember("amount"), false, "compare_tx_to_json_tx: txin does not have amount"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"]["amount"].IsUint64(), false, "compare_tx_to_json_tx: txin amount is not int"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"]["amount"].GetUint64() == k.amount, false, "compare_tx_to_json_tx: txin wrong amount"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"].HasMember("k_image"), false, "compare_tx_to_json_tx: txin does not have k_image"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"]["k_image"].IsString(), false, "compare_tx_to_json_tx: txin kimage is not string"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"]["k_image"].GetString() == pod_to_hex(k.k_image), false, "compare_tx_to_json_tx: txin wrong k_image"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"].HasMember("key_offsets"), false, "compare_tx_to_json_tx: txin does not have key_offsets"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"]["key_offsets"].IsArray(), false, "compare_tx_to_json_tx: txin key_offsets is not array"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"]["key_offsets"].Size() == k.key_offsets.size(), false, "compare_tx_to_json_tx: txin wrong key_offsets size"); + for (size_t o = 0; o < k.key_offsets.size(); ++o) + { + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"]["key_offsets"][o].IsUint64(), false, "compare_tx_to_json_tx: txin key offset is not int"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["key"]["key_offsets"][o].GetUint64() == k.key_offsets[o], false, "compare_tx_to_json_tx: wrong key_offsets entry in txin"); + } + } + else if (tx.vin[i].type() == typeid(cryptonote::txin_gen)) + { + const cryptonote::txin_gen &g = boost::get(tx.vin[i]); + CHECK_AND_ASSERT_MES(tx_document["vin"][i].HasMember("gen"), false, "compare_tx_to_json_tx: txin wrong type"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["gen"].IsObject(), false, "compare_tx_to_json_tx: txin is not object"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["gen"].HasMember("height"), false, "compare_tx_to_json_tx: txin does not have height"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["gen"]["height"].IsInt(), false, "compare_tx_to_json_tx: txin height is not int"); + CHECK_AND_ASSERT_MES(tx_document["vin"][i]["gen"]["height"].GetInt() == g.height, false, "compare_tx_to_json_tx: txin wrong amount"); + } + else + { + CHECK_AND_ASSERT_MES(false, false, "compare_tx_to_json_tx: can't check non to_key and gen inputs"); + } + } + + // vout + CHECK_AND_ASSERT_MES(tx_document["vout"].IsArray(), false, "compare_tx_to_json_tx: vout is not array"); + CHECK_AND_ASSERT_MES(tx_document["vout"].Size() == tx.vout.size(), false, "compare_tx_to_json_tx: vout wrong size"); + for (size_t i = 0; i < tx_document["vout"].Size(); i++) + { + CHECK_AND_ASSERT_MES(tx_document["vout"][i].IsObject(), false, "compare_tx_to_json_tx: txout not object"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i].HasMember("amount"), false, "compare_tx_to_json_tx: txout does not have amount"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["amount"].IsUint64(), false, "compare_tx_to_json_tx: txout amount is not int"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["amount"].GetUint64() == tx.vout[i].amount, false, "compare_tx_to_json_tx: txout wrong amount"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i].HasMember("target"), false, "compare_tx_to_json_tx: txout has no target"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"].IsObject(), false, "compare_tx_to_json_tx: txout target is not an object"); + if (tx.vout[i].target.type() == typeid(cryptonote::txout_to_key)) + { + const cryptonote::txout_to_key &k = boost::get(tx.vout[i].target); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"].HasMember("key"), false, "compare_tx_to_json_tx: txout target wrong type"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"]["key"].IsString(), false, "compare_tx_to_json_tx: txout target onetime-address not string"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"]["key"].GetString() == pod_to_hex(k.key), false, "compare_tx_to_json_tx: txout target wrong onetime-address"); + } + else if (tx.vout[i].target.type() == typeid(cryptonote::txout_to_tagged_key)) + { + const cryptonote::txout_to_tagged_key &k = boost::get(tx.vout[i].target); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"].HasMember("tagged_key"), false, "compare_tx_to_json_tx: txout target wrong type"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"]["tagged_key"].IsObject(), false, "compare_tx_to_json_tx: txout target tagged key not object"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"]["tagged_key"].HasMember("key"), false, "compare_tx_to_json_tx: txout target tagged key does not have onetime-address"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"]["tagged_key"]["key"].IsString(), false, "compare_tx_to_json_tx: txout target tagged key onetime-address not string"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"]["tagged_key"]["key"].GetString() == pod_to_hex(k.key), false, "compare_tx_to_json_tx: txout target tagged key wrong onetime-address"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"]["tagged_key"].HasMember("view_tag"), false, "compare_tx_to_json_tx: txout target tagged key does not have view tag"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"]["tagged_key"]["view_tag"].IsString(), false, "compare_tx_to_json_tx: txout target tagged key view_tag not string"); + CHECK_AND_ASSERT_MES(tx_document["vout"][i]["target"]["tagged_key"]["view_tag"].GetString() == pod_to_hex(k.view_tag), false, "compare_tx_to_json_tx: txout target tagged key wrong view_tag"); + } + else + { + CHECK_AND_ASSERT_MES(false, false, "compare_tx_to_json_tx: can't check non to_key and to_tagged_key outputs"); + } + } + + if (tx.version == 1) + { + // signatures + CHECK_AND_ASSERT_MES(tx_document.HasMember("signatures"), false, "compare_tx_to_json_tx: missing signatures"); + CHECK_AND_ASSERT_MES(tx_document["signatures"].IsArray(), false, "compare_tx_to_json_tx: signatures is not array"); + + if (!cryptonote::is_coinbase(tx)) + { + CHECK_AND_ASSERT_MES(tx_document["signatures"].Size() == tx.signatures.size(), false, "compare_tx_to_json_tx: signatures wrong size"); + for (size_t i = 0; i < tx.signatures.size(); ++i) + { + CHECK_AND_ASSERT_MES(tx_document["signatures"][i].IsString(), false, "compare_tx_to_json_tx: signatures element not string"); + const std::string sig_hexbuffer{epee::to_hex::string({reinterpret_cast(tx.signatures[i].data()), tx.signatures[i].size() * sizeof(crypto::signature)})}; + CHECK_AND_ASSERT_MES(tx_document["signatures"][i].GetString() == sig_hexbuffer, false, "compare_tx_to_json_tx: signatures element wrong"); + } + } + else // coinbase + { + CHECK_AND_ASSERT_MES(tx_document["signatures"].Size() == 0, false, "compare_tx_to_json_tx: coinbase signatures not size 0"); + } + } + else // v2 tx + { + // rct_signatures + CHECK_AND_ASSERT_MES(tx_document.HasMember("rct_signatures"), false, "compare_tx_to_json_tx: missing rct_signatures"); + const rapidjson::Value &jrv = tx_document["rct_signatures"]; + CHECK_AND_ASSERT_MES(jrv.IsObject(), false, "compare_tx_to_json_tx: rct_signatures is not object"); + + // type + CHECK_AND_ASSERT_MES(jrv.HasMember("type"), false, "compare_tx_to_json_tx: rct_signatures has no type"); + CHECK_AND_ASSERT_MES(jrv["type"].IsUint(), false, "compare_tx_to_json_tx: rct_signatures type is not int"); + CHECK_AND_ASSERT_MES(jrv["type"].GetUint() == tx.rct_signatures.type, false, "compare_tx_to_json_tx: rct_signatures wrong type"); + + if (!cryptonote::is_coinbase(tx)) + { + // txnFee + CHECK_AND_ASSERT_MES(jrv.HasMember("txnFee"), false, "compare_tx_to_json_tx: rct_signatures has no fee"); + CHECK_AND_ASSERT_MES(jrv["txnFee"].IsUint64(), false, "compare_tx_to_json_tx: rct_signatures txnFee is not uint64"); + CHECK_AND_ASSERT_MES(jrv["txnFee"].GetUint64() == tx.rct_signatures.txnFee, false, "compare_tx_to_json_tx: rct_signatures wrong fee"); + + // outPk + CHECK_AND_ASSERT_MES(jrv.HasMember("outPk"), false, "compare_tx_to_json_tx: rct_signatures has no outPk"); + CHECK_AND_ASSERT_MES(jrv["outPk"].IsArray(), false, "compare_tx_to_json_tx: rct_signatures outPk is not array"); + CHECK_AND_ASSERT_MES(jrv["outPk"].Size() == tx.rct_signatures.outPk.size(), false, "compare_tx_to_json_tx: rct_signatures wrong outPk size"); + for (size_t i = 0; i < tx.rct_signatures.outPk.size(); ++i) + { + CHECK_AND_ASSERT_MES(jrv["outPk"][i].IsString(), false, "compare_tx_to_json_tx: rct_signatures outPk entry not string"); + CHECK_AND_ASSERT_MES(jrv["outPk"][i].GetString() == pod_to_hex(tx.rct_signatures.outPk[i].mask), false, "compare_tx_to_json_tx: rct_signatures outPk wrong mask"); + } + + // ecdhInfo + const bool short_ecdh_info = tx.rct_signatures.type >= rct::RCTTypeBulletproof2; + const size_t ecdh_amount_hexlength = 2 * (short_ecdh_info ? 8 : 32); + CHECK_AND_ASSERT_MES(jrv.HasMember("ecdhInfo"), false, "compare_tx_to_json_tx: rct_signatures has no ecdhInfo"); + CHECK_AND_ASSERT_MES(jrv["ecdhInfo"].IsArray(), false, "compare_tx_to_json_tx: rct_signatures ecdhInfo is not array"); + CHECK_AND_ASSERT_MES(jrv["ecdhInfo"].Size() == tx.rct_signatures.ecdhInfo.size(), false, "compare_tx_to_json_tx: rct_signatures wrong ecdhInfo size"); + for (size_t i = 0; i < tx.rct_signatures.ecdhInfo.size(); ++i) + { + CHECK_AND_ASSERT_MES(jrv["ecdhInfo"][i].IsObject(), false, "compare_tx_to_json_tx: rct_signatures ecdhInfo entry not object"); + // amount (encrypted) + CHECK_AND_ASSERT_MES(jrv["ecdhInfo"][i].HasMember("amount"), false, "compare_tx_to_json_tx: rct_signatures ecdhInfo entry missing amount"); + CHECK_AND_ASSERT_MES(jrv["ecdhInfo"][i]["amount"].IsString(), false, "compare_tx_to_json_tx: rct_signatures ecdhInfo entry amount info not string"); + CHECK_AND_ASSERT_MES(jrv["ecdhInfo"][i]["amount"].GetStringLength() == ecdh_amount_hexlength, false, "compare_tx_to_json_tx: rct_signatures ecdhInfo entry amount string wrong size"); + const auto hex_amount{pod_to_hex(tx.rct_signatures.ecdhInfo[i].amount).substr(0, ecdh_amount_hexlength)}; + CHECK_AND_ASSERT_MES(jrv["ecdhInfo"][i]["amount"].GetString() == hex_amount, false, "compare_tx_to_json_tx: rct_signatures ecdhInfo entry wrong amount"); + if (!short_ecdh_info) + { + // mask (encrypted blinding factor) + CHECK_AND_ASSERT_MES(jrv["ecdhInfo"][i].HasMember("mask"), false, "compare_tx_to_json_tx: rct_signatures ecdhInfo entry missing mask"); + CHECK_AND_ASSERT_MES(jrv["ecdhInfo"][i]["mask"].IsString(), false, "compare_tx_to_json_tx: rct_signatures ecdhInfo entry mask not string"); + CHECK_AND_ASSERT_MES(jrv["ecdhInfo"][i]["mask"].GetString() == pod_to_hex(tx.rct_signatures.ecdhInfo[i].mask), false, "compare_tx_to_json_tx: rct_signatures ecdhInfo entry wrong mask"); + } + } + + // pseudoOuts (not pruned w/ v2 RingCT) + if (tx.rct_signatures.type == rct::RCTTypeSimple) + { + CHECK_AND_ASSERT_MES(tx.rct_signatures.pseudoOuts.size() == tx.vin.size(), false, "sanity check pseudoOuts size"); + CHECK_AND_ASSERT_MES(jrv.HasMember("pseudoOuts"), false, "compare_tx_to_json_tx: rct_signatures missing pseudoOuts"); + CHECK_AND_ASSERT_MES(jrv["pseudoOuts"].IsArray(), false, "compare_tx_to_json_tx: rct_signatures pseudoOuts is not array"); + CHECK_AND_ASSERT_MES(jrv["pseudoOuts"].Size() == tx.rct_signatures.pseudoOuts.size(), false, "compare_tx_to_json_tx: rct_signatures pseudoOuts wrong size"); + for (size_t i = 0; i < tx.rct_signatures.pseudoOuts.size(); ++i) + { + CHECK_AND_ASSERT_MES(jrv["pseudoOuts"][i].IsString(), false, "compare_tx_to_json_tx: rct_signatures pseudoOuts entry not string"); + CHECK_AND_ASSERT_MES(jrv["pseudoOuts"][i].GetString() == pod_to_hex(tx.rct_signatures.pseudoOuts[i]), false, "compare_tx_to_json_tx: rct_signatures pseudoOuts wrong entry"); + } + } + + // rctsig_prunable + CHECK_AND_ASSERT_MES(tx_document.HasMember("rctsig_prunable"), false, "compare_tx_to_json_tx: rct_signatures missing rctsig_prunable"); + const rapidjson::Value &jrvp = tx_document["rctsig_prunable"]; + const rct::rctSigPrunable &rvp = tx.rct_signatures.p; + + // range proofs + switch (tx.rct_signatures.type) + { + case rct::RCTTypeFull: + case rct::RCTTypeSimple: + // boro sig + CHECK_AND_ASSERT_MES(rvp.rangeSigs.size() == tx.vout.size(), false, "sanity check rangeSigs length"); + CHECK_AND_ASSERT_MES(jrvp.HasMember("rangeSigs"), false, "compare_tx_to_json_tx: rctsig_prunable missing rangeSigs"); + CHECK_AND_ASSERT_MES(jrvp["rangeSigs"].IsArray(), false, "compare_tx_to_json_tx: rctsig_prunable rangeSigs not array"); + CHECK_AND_ASSERT_MES(jrvp["rangeSigs"].Size() == rvp.rangeSigs.size(), false, "compare_tx_to_json_tx: rctsig_prunable rangeSigs wrong size"); + for (size_t i = 0; i < rvp.rangeSigs.size(); ++i) + { + CHECK_AND_ASSERT_MES(jrvp["rangeSigs"][i].IsObject(), false, "compare_tx_to_json_tx: rctsig_prunable rangeSig not object"); + // asig + CHECK_AND_ASSERT_MES(jrvp["rangeSigs"][i].HasMember("asig"), false, "compare_tx_to_json_tx: rctsig_prunable rangeSig missing asig"); + CHECK_AND_ASSERT_MES(jrvp["rangeSigs"][i]["asig"].IsString(), false, "compare_tx_to_json_tx: rctsig_prunable rangeSig asig is not string"); + CHECK_AND_ASSERT_MES(jrvp["rangeSigs"][i]["asig"].GetString() == pod_to_hex(rvp.rangeSigs[i].asig), false, "compare_tx_to_json_tx: rctsig_prunable rangeSig wrong asig"); + // Ci + CHECK_AND_ASSERT_MES(jrvp["rangeSigs"][i].HasMember("Ci"), false, "compare_tx_to_json_tx: rctsig_prunable rangeSig missing Ci"); + CHECK_AND_ASSERT_MES(jrvp["rangeSigs"][i]["Ci"].IsString(), false, "compare_tx_to_json_tx: rctsig_prunable rangeSig Ci is not string"); + CHECK_AND_ASSERT_MES(jrvp["rangeSigs"][i]["Ci"].GetString() == pod_to_hex(rvp.rangeSigs[i].Ci), false, "compare_tx_to_json_tx: rctsig_prunable rangeSig wrong Ci"); + } + break; + case rct::RCTTypeBulletproof: + case rct::RCTTypeBulletproof2: + case rct::RCTTypeCLSAG: + // bulletproof sig + CHECK_AND_ASSERT_MES(rvp.bulletproofs.size(), false, "sanity check bulletproofs length"); + CHECK_AND_ASSERT_MES(jrvp.HasMember("nbp"), false, "compare_tx_to_json_tx: rctsig_prunable missing nbp"); + CHECK_AND_ASSERT_MES(jrvp["nbp"].IsUint(), false, "compare_tx_to_json_tx: rctsig_prunable nbp not unsigned int"); + CHECK_AND_ASSERT_MES(jrvp["nbp"].GetUint() == rvp.bulletproofs.size(), false, "compare_tx_to_json_tx: rctsig_prunable nbp wrong value"); + CHECK_AND_ASSERT_MES(jrvp.HasMember("bp"), false, "compare_tx_to_json_tx: rctsig_prunable missing bp"); + CHECK_AND_ASSERT_MES(jrvp["bp"].IsArray(), false, "compare_tx_to_json_tx: rctsig_prunable bp not array"); + CHECK_AND_ASSERT_MES(jrvp["bp"].Size() == jrvp["nbp"].GetUint(), false, "compare_tx_to_json_tx: rctsig_prunable bp size not equal to nbp"); + for (size_t i = 0; i < jrvp["nbp"].GetUint(); ++i) + { + /* A, S, T1, T2, taux, mu, L[], R[], a, b, t */ + const rapidjson::Value &jbp = jrvp["bp"][i]; + const rct::Bulletproof &bp = rvp.bulletproofs[i]; + CHECK_AND_ASSERT_MES(jbp.IsObject(), false, "compare_tx_to_json_tx: bp entry not object"); + CHECK_AND_ASSERT_MES(jbp.HasMember("A") && jbp.HasMember("S") && jbp.HasMember("T1") && + jbp.HasMember("T2") && jbp.HasMember("taux") && jbp.HasMember("mu") && + jbp.HasMember("L") && jbp.HasMember("R") && jbp.HasMember("a") && + jbp.HasMember("b") && jbp.HasMember("t"), false, "compare_tx_to_json_tx: bp entry missing fields"); + CHECK_AND_ASSERT_MES(jbp["A"].IsString() && jbp["S"].IsString() && + jbp["T1"].IsString() && jbp["T2"].IsString() && jbp["taux"].IsString() && + jbp["mu"].IsString() && jbp["L"].IsArray() && jbp["R"].IsArray() && + jbp["a"].IsString() && jbp["b"].IsString() && jbp["t"].IsString(), false, + "compare_tx_to_json_tx: bp entry fields bad type"); + CHECK_AND_ASSERT_MES(jbp["A"].GetString() == pod_to_hex(bp.A), false, "compare_tx_to_json_tx: bp entry wrong A"); + CHECK_AND_ASSERT_MES(jbp["S"].GetString() == pod_to_hex(bp.S), false, "compare_tx_to_json_tx: bp entry wrong S"); + CHECK_AND_ASSERT_MES(jbp["T1"].GetString() == pod_to_hex(bp.T1), false, "compare_tx_to_json_tx: bp entry wrong T1"); + CHECK_AND_ASSERT_MES(jbp["T2"].GetString() == pod_to_hex(bp.T2), false, "compare_tx_to_json_tx: bp entry wrong T2"); + CHECK_AND_ASSERT_MES(jbp["taux"].GetString() == pod_to_hex(bp.taux), false, "compare_tx_to_json_tx: bp entry wrong taux"); + CHECK_AND_ASSERT_MES(jbp["mu"].GetString() == pod_to_hex(bp.mu), false, "compare_tx_to_json_tx: bp entry wrong mu"); + CHECK_AND_ASSERT_MES(jbp["a"].GetString() == pod_to_hex(bp.a), false, "compare_tx_to_json_tx: bp entry wrong a"); + CHECK_AND_ASSERT_MES(jbp["b"].GetString() == pod_to_hex(bp.b), false, "compare_tx_to_json_tx: bp entry wrong b"); + CHECK_AND_ASSERT_MES(jbp["t"].GetString() == pod_to_hex(bp.t), false, "compare_tx_to_json_tx: bp entry wrong t"); + CHECK_AND_ASSERT_MES(jbp["L"].Size() == bp.L.size(), false, "compare_tx_to_json_tx: bp entry L wrong size"); + for (size_t j = 0; j < bp.L.size(); ++j) + { + CHECK_AND_ASSERT_MES(jbp["L"][j].IsString(), false, "compare_tx_to_json_tx: bp entry L entry not string"); + CHECK_AND_ASSERT_MES(jbp["L"][j].GetString() == pod_to_hex(bp.L[j]), false, "compare_tx_to_json_tx: bp entry L entry wrong value"); + } + CHECK_AND_ASSERT_MES(jbp["R"].Size() == bp.R.size(), false, "compare_tx_to_json_tx: bp entry R wrong size"); + for (size_t j = 0; j < bp.R.size(); ++j) + { + CHECK_AND_ASSERT_MES(jbp["R"][j].IsString(), false, "compare_tx_to_json_tx: bp entry R entry not string"); + CHECK_AND_ASSERT_MES(jbp["R"][j].GetString() == pod_to_hex(bp.R[j]), false, "compare_tx_to_json_tx: bp entry R entry wrong value"); + } + } + break; + case rct::RCTTypeBulletproofPlus: + // bulletproof+ sig + CHECK_AND_ASSERT_MES(rvp.bulletproofs_plus.size(), false, "sanity check bulletproofs+ length"); + CHECK_AND_ASSERT_MES(jrvp.HasMember("nbp"), false, "compare_tx_to_json_tx: rctsig_prunable missing nbp"); + CHECK_AND_ASSERT_MES(jrvp["nbp"].IsUint(), false, "compare_tx_to_json_tx: rctsig_prunable nbp not unsigned int"); + CHECK_AND_ASSERT_MES(jrvp["nbp"].GetUint() == rvp.bulletproofs_plus.size(), false, "compare_tx_to_json_tx: rctsig_prunable nbp wrong value"); + CHECK_AND_ASSERT_MES(jrvp.HasMember("bpp"), false, "compare_tx_to_json_tx: rctsig_prunable missing bpp"); + CHECK_AND_ASSERT_MES(jrvp["bpp"].IsArray(), false, "compare_tx_to_json_tx: rctsig_prunable bpp not array"); + CHECK_AND_ASSERT_MES(jrvp["bpp"].Size() == jrvp["nbp"].GetUint(), false, "compare_tx_to_json_tx: rctsig_prunable bpp size not equal to nbp"); + for (size_t i = 0; i < jrvp["nbp"].GetUint(); ++i) + { + /* A, A1, B, r1, s1, d1, L[], R[] */ + const rapidjson::Value &jbpp = jrvp["bpp"][i]; + const rct::BulletproofPlus &bpp = rvp.bulletproofs_plus[i]; + CHECK_AND_ASSERT_MES(jbpp.IsObject(), false, "compare_tx_to_json_tx: bpp entry not object"); + CHECK_AND_ASSERT_MES(jbpp.HasMember("A") && jbpp.HasMember("A1") && jbpp.HasMember("B") && + jbpp.HasMember("r1") && jbpp.HasMember("s1") && jbpp.HasMember("d1") && + jbpp.HasMember("L") && jbpp.HasMember("R"), false, "compare_tx_to_json_tx: bpp entry missing fields"); + CHECK_AND_ASSERT_MES(jbpp["A"].IsString() && jbpp["A1"].IsString() && + jbpp["B"].IsString() && jbpp["r1"].IsString() && jbpp["s1"].IsString() && + jbpp["d1"].IsString() && jbpp["L"].IsArray() && jbpp["R"].IsArray(), false, + "compare_tx_to_json_tx: bpp entry fields bad type"); + CHECK_AND_ASSERT_MES(jbpp["A"].GetString() == pod_to_hex(bpp.A), false, "compare_tx_to_json_tx: bpp entry wrong A"); + CHECK_AND_ASSERT_MES(jbpp["A1"].GetString() == pod_to_hex(bpp.A1), false, "compare_tx_to_json_tx: bpp entry wrong S"); + CHECK_AND_ASSERT_MES(jbpp["B"].GetString() == pod_to_hex(bpp.B), false, "compare_tx_to_json_tx: bpp entry wrong T1"); + CHECK_AND_ASSERT_MES(jbpp["r1"].GetString() == pod_to_hex(bpp.r1), false, "compare_tx_to_json_tx: bpp entry wrong T2"); + CHECK_AND_ASSERT_MES(jbpp["s1"].GetString() == pod_to_hex(bpp.s1), false, "compare_tx_to_json_tx: bpp entry wrong taux"); + CHECK_AND_ASSERT_MES(jbpp["d1"].GetString() == pod_to_hex(bpp.d1), false, "compare_tx_to_json_tx: bpp entry wrong mu"); + CHECK_AND_ASSERT_MES(jbpp["L"].Size() == bpp.L.size(), false, "compare_tx_to_json_tx: bpp entry L wrong size"); + for (size_t j = 0; j < bpp.L.size(); ++j) + { + CHECK_AND_ASSERT_MES(jbpp["L"][j].IsString(), false, "compare_tx_to_json_tx: bpp entry L entry not string"); + CHECK_AND_ASSERT_MES(jbpp["L"][j].GetString() == pod_to_hex(bpp.L[j]), false, "compare_tx_to_json_tx: bpp entry L entry wrong value"); + } + CHECK_AND_ASSERT_MES(jbpp["R"].Size() == bpp.R.size(), false, "compare_tx_to_json_tx: bpp entry R wrong size"); + for (size_t j = 0; j < bpp.R.size(); ++j) + { + CHECK_AND_ASSERT_MES(jbpp["R"][j].IsString(), false, "compare_tx_to_json_tx: bpp entry R entry not string"); + CHECK_AND_ASSERT_MES(jbpp["R"][j].GetString() == pod_to_hex(bpp.R[j]), false, "compare_tx_to_json_tx: bpp entry R entry wrong value"); + } + } + break; + default: + MERROR("Unrecognized RCT Type"); + return false; + } + + // ring signatures + const bool is_full_rct = tx.rct_signatures.type == rct::RCTTypeFull; + const size_t num_mgs = is_full_rct ? 1 : num_inputs; + const size_t num_mg_cols = 1 + (is_full_rct ? num_inputs : 1); + switch (tx.rct_signatures.type) + { + case rct::RCTTypeFull: + case rct::RCTTypeSimple: + case rct::RCTTypeBulletproof: + case rct::RCTTypeBulletproof2: + // MLSAG sig + CHECK_AND_ASSERT_MES(rvp.MGs.size() == num_mgs, false, "sanity check tx has correct num MGs"); + CHECK_AND_ASSERT_MES(jrvp.HasMember("MGs"), false, "compare_tx_to_json_tx: rctsig_prunable missing MGs"); + CHECK_AND_ASSERT_MES(jrvp["MGs"].IsArray(), false, "compare_tx_to_json_tx: rctsig_prunable MGs not array"); + CHECK_AND_ASSERT_MES(jrvp["MGs"].Size() == num_mgs, false, "compare_tx_to_json_tx: rctsig_prunable MGs wrong size"); + for (size_t i = 0; i < num_mgs; ++i) + { + const rapidjson::Value &jmg = jrvp["MGs"][i]; + const rct::mgSig &mg = rvp.MGs[i]; + CHECK_AND_ASSERT_MES(jmg.IsObject(), false, "compare_tx_to_json_tx: rctsig_prunable MGs entry not object"); + CHECK_AND_ASSERT_MES(jmg.HasMember("ss") && jmg.HasMember("cc"), false, "compare_tx_to_json_tx: rctsig_prunable MGs entry missing fields"); + CHECK_AND_ASSERT_MES(jmg["cc"].IsString(), false, "compare_tx_to_json_tx: rctsig_prunable MGs cc not string"); + CHECK_AND_ASSERT_MES(jmg["cc"].GetString() == pod_to_hex(mg.cc), false, "compare_tx_to_json_tx: rctsig_prunable MGs cc wrong value"); + CHECK_AND_ASSERT_MES(jmg["ss"].IsArray(), false, "compare_tx_to_json_tx: rctsig_prunable MG ss not array"); + CHECK_AND_ASSERT_MES(jmg["ss"].Size() == ring_size, false, "compare_tx_to_json_tx: rctsig_prunable MG ss num rows not ring size"); + for (size_t j = 0; j < ring_size; ++j) + { + const rapidjson::Value &jrow = jmg["ss"][j]; + const rct::keyV &row = mg.ss[j]; + CHECK_AND_ASSERT_MES(jrow.IsArray(), false, "compare_tx_to_json_tx: rctsig_prunable MG ss row not array"); + CHECK_AND_ASSERT_MES(row.size() == num_mg_cols, false, "sanity check MG ss row size"); + CHECK_AND_ASSERT_MES(jrow.Size() == num_mg_cols, false, "compare_tx_to_json_tx: rctsig_prunable MG ss row wrong size"); + for (size_t k = 0; k < num_mg_cols; ++k) + { + CHECK_AND_ASSERT_MES(jrow[k].IsString(), false, "compare_tx_to_json_tx: rctsig_prunable MG ss scalar not string"); + CHECK_AND_ASSERT_MES(jrow[k].GetString() == pod_to_hex(row[k]), false, "compare_tx_to_json_tx: rctsig_prunable MG ss wrong scalar"); + } + } + } + break; + case rct::RCTTypeCLSAG: + case rct::RCTTypeBulletproofPlus: + // CLSAG sig + CHECK_AND_ASSERT_MES(rvp.CLSAGs.size() == num_inputs, false, "sanity check tx has correct num CLSAGs"); + CHECK_AND_ASSERT_MES(jrvp.HasMember("CLSAGs"), false, "compare_tx_to_json_tx: rctsig_prunable missing CLSAGs"); + CHECK_AND_ASSERT_MES(jrvp["CLSAGs"].IsArray(), false, "compare_tx_to_json_tx: rctsig_prunable CLSAGs not array"); + CHECK_AND_ASSERT_MES(jrvp["CLSAGs"].Size() == num_inputs, false, "compare_tx_to_json_tx: rctsig_prunable CLSAGs wrong size"); + for (size_t i = 0; i < num_inputs; ++i) + { + const rapidjson::Value &jclsag = jrvp["CLSAGs"][i]; + const rct::clsag &clsag = rvp.CLSAGs[i]; + CHECK_AND_ASSERT_MES(jclsag.IsObject(), false, "compare_tx_to_json_tx: rctsig_prunable CLSAG is not object"); + CHECK_AND_ASSERT_MES(jclsag.HasMember("s") && jclsag.HasMember("c1") && jclsag.HasMember("D"), + false, "compare_tx_to_json_tx: rctsig_prunable CLSAG missing fields"); + CHECK_AND_ASSERT_MES(jclsag["s"].IsArray() && jclsag["c1"].IsString() && jclsag["D"].IsString(), + false, "compare_tx_to_json_tx: rctsig_prunable CLSAG fields wrong type"); + CHECK_AND_ASSERT_MES(jclsag["c1"].GetString() == pod_to_hex(clsag.c1), + false, "compare_tx_to_json_tx: rctsig_prunable CLSAG wrong c1"); + CHECK_AND_ASSERT_MES(jclsag["D"].GetString() == pod_to_hex(clsag.D), + false, "compare_tx_to_json_tx: rctsig_prunable CLSAG wrong D"); + CHECK_AND_ASSERT_MES(jclsag["s"].Size() == ring_size, + false, "compare_tx_to_json_tx: rctsig_prunable CLSAG.s wrong size"); + CHECK_AND_ASSERT_MES(clsag.s.size() == ring_size, false, "sanity check CLSAG.s size"); + for (size_t j = 0; j < ring_size; ++j) + { + CHECK_AND_ASSERT_MES(jclsag["s"][j].IsString(), false, "compare_tx_to_json_tx: rctsig_prunable CLSAG c1 not string"); + CHECK_AND_ASSERT_MES(jclsag["s"][j].GetString() == pod_to_hex(clsag.s[j]), + false, "compare_tx_to_json_tx: rctsig_prunable CLSAG.s wrong key element"); + } + } + break; + default: + MERROR("Unrecognized RCT Type"); + return false; + } + } + } + + return true; + } + + bool jsonify_tx_from_file_and_parse_compare(const std::string &tx_fname) + { + const boost::filesystem::path tx_path = unit_test::data_dir / "txs" / tx_fname; + + std::string tx_blob; + CHECK_AND_ASSERT_THROW_MES(epee::file_io_utils::load_file_to_string(tx_path.string(), tx_blob), + "failed to load tx from file: " << tx_path.string()); + + cryptonote::transaction tx; + CHECK_AND_ASSERT_THROW_MES(cryptonote::parse_and_validate_tx_from_blob(tx_blob, tx), + "failed to parse tx from file: " << tx_path.string()); + + // Same JSONification used in /get_transactions RPC endpoint + const std::string tx_json{cryptonote::obj_to_json_str(tx)}; + + return compare_tx_to_json_tx(tx, tx_json); + } } // anonymous TEST(JsonSerialization, VectorBytes) @@ -247,3 +676,16 @@ TEST(JsonRpcSerialization, HandlerFromJson) cryptonote::rpc::GetHashesFast::Request request{}; EXPECT_THROW(request.fromJson(req_full.getMessage()), cryptonote::json::WRONG_TYPE); } + +TEST(JsonSerialization, jsonify_tx_from_file_and_parse_compare) +{ + EXPECT_TRUE(jsonify_tx_from_file_and_parse_compare("v1_coinbase_tx_bf4c0300.bin")); + EXPECT_TRUE(jsonify_tx_from_file_and_parse_compare("v1_tx_hf3_effcceb9.bin")); + EXPECT_TRUE(jsonify_tx_from_file_and_parse_compare("v2_coinbase_tx_7f88a52a.bin")); + EXPECT_TRUE(jsonify_tx_from_file_and_parse_compare("rct_full_tx_14056427.bin")); + EXPECT_TRUE(jsonify_tx_from_file_and_parse_compare("rct_simple_tx_c69861bf.bin")); + EXPECT_TRUE(jsonify_tx_from_file_and_parse_compare("rct_bp_tx_a685d68e.bin")); + EXPECT_TRUE(jsonify_tx_from_file_and_parse_compare("rct_bp_compact_tx_10312fd4.bin")); + EXPECT_TRUE(jsonify_tx_from_file_and_parse_compare("rct_clsag_tx_200c3215.bin")); + EXPECT_TRUE(jsonify_tx_from_file_and_parse_compare("bpp_tx_e89415.bin")); +}