Electroneum
json_serialization.cpp
Go to the documentation of this file.
1 
2 #include <boost/optional/optional.hpp>
3 #include <boost/range/adaptor/indexed.hpp>
4 #include <gtest/gtest.h>
5 #include <rapidjson/document.h>
6 #include <vector>
7 
8 #include "crypto/hash.h"
14 
15 
16 namespace
17 {
19  make_miner_transaction(cryptonote::account_public_address const& to)
20  {
22  if (!cryptonote::construct_miner_tx(0, 0, 5000, 500, 500, to, tx))
23  throw std::runtime_error{"transaction construction error"};
24 
25  crypto::hash id{0};
27  throw std::runtime_error{"could not get transaction hash"};
28 
29  return tx;
30  }
31 
33  make_transaction(
34  cryptonote::account_keys const& from,
35  std::vector<cryptonote::transaction> const& sources,
36  std::vector<cryptonote::account_public_address> const& destinations,
37  bool rct,
38  bool bulletproof)
39  {
40  std::uint64_t source_amount = 0;
41  std::vector<cryptonote::tx_source_entry> actual_sources;
42  for (auto const& source : sources)
43  {
44  std::vector<cryptonote::tx_extra_field> extra_fields;
45  if (!cryptonote::parse_tx_extra(source.extra, extra_fields))
46  throw std::runtime_error{"invalid transaction"};
47 
48  cryptonote::tx_extra_pub_key key_field{};
49  if (!cryptonote::find_tx_extra_field_by_type(extra_fields, key_field))
50  throw std::runtime_error{"invalid transaction"};
51 
52  for (auto const& input : boost::adaptors::index(source.vout))
53  {
54  source_amount += input.value().amount;
55  auto const& key = boost::get<cryptonote::txout_to_key>(input.value().target);
56 
57  actual_sources.push_back(
58  {{}, 0, key_field.pub_key, {}, std::size_t(input.index()), input.value().amount, rct, rct::identity()}
59  );
60 
61  for (unsigned ring = 0; ring < 10; ++ring)
62  actual_sources.back().push_output(input.index(), key.key, input.value().amount);
63  }
64  }
65 
66  std::vector<cryptonote::tx_destination_entry> to;
67  for (auto const& destination : destinations)
68  to.push_back({(source_amount / destinations.size()), destination, false});
69 
71 
72  crypto::secret_key tx_key{};
73  std::vector<crypto::secret_key> extra_keys{};
74 
75  std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
76  subaddresses[from.m_account_address.m_spend_public_key] = {0,0};
77 
78  if (!cryptonote::construct_tx_and_get_tx_key(from, subaddresses, actual_sources, to, boost::none, {}, tx, 0, tx_key, extra_keys, rct, { bulletproof ? rct::RangeProofBulletproof : rct::RangeProofBorromean, bulletproof ? 2 : 0 }))
79  throw std::runtime_error{"transaction construction error"};
80 
81  return tx;
82  }
83 } // anonymous
84 
85 TEST(JsonSerialization, MinerTransaction)
86 {
88  acct.generate();
89  const auto miner_tx = make_miner_transaction(acct.get_keys().m_account_address);
90 
91  crypto::hash tx_hash{};
93 
95  cryptonote::json::toJsonValue(doc, miner_tx, doc);
96 
97  cryptonote::transaction miner_tx_copy;
98  cryptonote::json::fromJsonValue(doc, miner_tx_copy);
99 
100  crypto::hash tx_copy_hash{};
101  ASSERT_TRUE(cryptonote::get_transaction_hash(miner_tx_copy, tx_copy_hash));
102  EXPECT_EQ(tx_hash, tx_copy_hash);
103 
104  cryptonote::blobdata tx_bytes{};
105  cryptonote::blobdata tx_copy_bytes{};
106 
108  ASSERT_TRUE(cryptonote::t_serializable_object_to_blob(miner_tx_copy, tx_copy_bytes));
109 
110  EXPECT_EQ(tx_bytes, tx_copy_bytes);
111 }
112 
113 TEST(JsonSerialization, RegularTransaction)
114 {
116  acct1.generate();
117 
119  acct2.generate();
120 
121  const auto miner_tx = make_miner_transaction(acct1.get_keys().m_account_address);
122  const auto tx = make_transaction(
123  acct1.get_keys(), {miner_tx}, {acct2.get_keys().m_account_address}, false, false
124  );
125 
126  crypto::hash tx_hash{};
128 
130  cryptonote::json::toJsonValue(doc, tx, doc);
131 
132  cryptonote::transaction tx_copy;
133  cryptonote::json::fromJsonValue(doc, tx_copy);
134 
135  crypto::hash tx_copy_hash{};
136  ASSERT_TRUE(cryptonote::get_transaction_hash(tx_copy, tx_copy_hash));
137  EXPECT_EQ(tx_hash, tx_copy_hash);
138 
139  cryptonote::blobdata tx_bytes{};
140  cryptonote::blobdata tx_copy_bytes{};
141 
144 
145  EXPECT_EQ(tx_bytes, tx_copy_bytes);
146 }
147 
148 TEST(JsonSerialization, RingctTransaction)
149 {
151  acct1.generate();
152 
154  acct2.generate();
155 
156  const auto miner_tx = make_miner_transaction(acct1.get_keys().m_account_address);
157  const auto tx = make_transaction(
158  acct1.get_keys(), {miner_tx}, {acct2.get_keys().m_account_address}, true, false
159  );
160 
161  crypto::hash tx_hash{};
163 
165  cryptonote::json::toJsonValue(doc, tx, doc);
166 
167  cryptonote::transaction tx_copy;
168  cryptonote::json::fromJsonValue(doc, tx_copy);
169 
170  crypto::hash tx_copy_hash{};
171  ASSERT_TRUE(cryptonote::get_transaction_hash(tx_copy, tx_copy_hash));
172  EXPECT_EQ(tx_hash, tx_copy_hash);
173 
174  cryptonote::blobdata tx_bytes{};
175  cryptonote::blobdata tx_copy_bytes{};
176 
179 
180  EXPECT_EQ(tx_bytes, tx_copy_bytes);
181 }
182 
183 TEST(JsonSerialization, BulletproofTransaction)
184 {
186  acct1.generate();
187 
189  acct2.generate();
190 
191  const auto miner_tx = make_miner_transaction(acct1.get_keys().m_account_address);
192  const auto tx = make_transaction(
193  acct1.get_keys(), {miner_tx}, {acct2.get_keys().m_account_address}, true, true
194  );
195 
196  crypto::hash tx_hash{};
198 
200  cryptonote::json::toJsonValue(doc, tx, doc);
201 
202  cryptonote::transaction tx_copy;
203  cryptonote::json::fromJsonValue(doc, tx_copy);
204 
205  crypto::hash tx_copy_hash{};
206  ASSERT_TRUE(cryptonote::get_transaction_hash(tx_copy, tx_copy_hash));
207  EXPECT_EQ(tx_hash, tx_copy_hash);
208 
209  cryptonote::blobdata tx_bytes{};
210  cryptonote::blobdata tx_copy_bytes{};
211 
214 
215  EXPECT_EQ(tx_bytes, tx_copy_bytes);
216 }
217 
bool parse_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< tx_extra_field > &tx_extra_fields)
const CharType(& source)[N]
Definition: pointer.h:1147
const char * key
Definition: hmac_keccak.cpp:39
bool find_tx_extra_field_by_type(const std::vector< tx_extra_field > &tx_extra_fields, T &field, size_t index=0)
crypto::secret_key generate(const crypto::secret_key &recovery_key=crypto::secret_key(), bool recover=false, bool two_random=false)
Definition: account.cpp:158
const account_keys & get_keys() const
Definition: account.cpp:264
return true
unsigned __int64 uint64_t
Definition: stdint.h:136
GenericDocument< UTF8<> > Document
GenericDocument with UTF8 encoding.
Definition: document.h:2512
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
#define false
Definition: stdbool.h:38
std::string blobdata
Definition: blobdatatype.h:39
void toJsonValue(rapidjson::Document &doc, const std::string &i, rapidjson::Value &val)
account_public_address m_account_address
Definition: account.h:43
void fromJsonValue(const rapidjson::Value &val, std::string &str)
key identity()
Definition: rctOps.h:73
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865
crypto::hash get_transaction_hash(const transaction &t)
POD_CLASS hash
Definition: hash.h:50
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction &tx, const blobdata &extra_nonce, size_t max_outs, uint8_t hard_fork_version, network_type nettype)
TEST(JsonSerialization, MinerTransaction)
bool construct_tx_and_get_tx_key(const account_keys &sender_account_keys, const std::unordered_map< crypto::public_key, subaddress_index > &subaddresses, std::vector< tx_source_entry > &sources, std::vector< tx_destination_entry > &destinations, const boost::optional< cryptonote::account_public_address > &change_addr, const std::vector< uint8_t > &extra, transaction &tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector< crypto::secret_key > &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, rct::multisig_out *msout, const uint32_t account_major_offset, const cryptonote::network_type nettype)
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922