You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
742 lines
20 KiB
742 lines
20 KiB
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <boost/iterator/filter_iterator.hpp>
|
|
|
|
#include "../src/UniversalIdentifier.hpp"
|
|
|
|
#include "mocks.h"
|
|
#include "JsonTx.h"
|
|
|
|
#define ADD_MOCKS(mcore) \
|
|
EXPECT_CALL(mcore, get_output_tx_and_index(_, _, _)) \
|
|
.WillRepeatedly( \
|
|
Invoke(&*jtx, &JsonTx::get_output_tx_and_index)); \
|
|
\
|
|
EXPECT_CALL(mcore, get_tx(_, _)) \
|
|
.WillRepeatedly( \
|
|
Invoke(&*jtx, &JsonTx::get_tx)); \
|
|
\
|
|
EXPECT_CALL(mcore, get_output_key(_, _, _)) \
|
|
.WillRepeatedly( \
|
|
Invoke(&*jtx, &JsonTx::get_output_key));\
|
|
\
|
|
EXPECT_CALL(mcore, get_num_outputs(_)) \
|
|
.WillRepeatedly(Return(1e10));
|
|
|
|
namespace
|
|
{
|
|
|
|
using namespace xmreg;
|
|
|
|
|
|
// equality operators for outputs
|
|
|
|
inline bool
|
|
operator==(const Output::info& lhs, const JsonTx::output& rhs)
|
|
{
|
|
return lhs.amount == rhs.amount
|
|
&& lhs.pub_key == rhs.pub_key
|
|
&& lhs.idx_in_tx == rhs.index;
|
|
}
|
|
|
|
inline bool
|
|
operator!=(const Output::info& lhs, const JsonTx::output& rhs)
|
|
{
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
inline bool
|
|
operator==(const vector<Output::info>& lhs, const vector<JsonTx::output>& rhs)
|
|
{
|
|
if (lhs.size() != rhs.size())
|
|
return false;
|
|
|
|
for (size_t i = 0; i < lhs.size(); i++)
|
|
{
|
|
if (lhs[i] != rhs[i])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
// equality operators for inputs
|
|
|
|
|
|
inline bool
|
|
operator==(const Input::info& lhs, const JsonTx::input& rhs)
|
|
{
|
|
return lhs.amount == rhs.amount
|
|
&& lhs.out_pub_key == rhs.out_pub_key
|
|
&& lhs.key_img == rhs.key_img;
|
|
}
|
|
|
|
inline bool
|
|
operator!=(const Input::info& lhs, const JsonTx::input& rhs)
|
|
{
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
inline bool
|
|
operator==(const vector<Input::info>& lhs,
|
|
const vector<JsonTx::input>& rhs)
|
|
{
|
|
if (lhs.size() != rhs.size())
|
|
return false;
|
|
|
|
for (size_t i = 0; i < lhs.size(); i++)
|
|
{
|
|
if (lhs[i] != rhs[i])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
inline bool
|
|
operator==(const Input::info& lhs, const Input::info& rhs)
|
|
{
|
|
return lhs.amount == rhs.amount
|
|
&& lhs.out_pub_key == rhs.out_pub_key
|
|
&& lhs.key_img == rhs.key_img;
|
|
}
|
|
|
|
inline bool
|
|
operator!=(const Input::info& lhs, const Input::info& rhs)
|
|
{
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
inline bool
|
|
operator==(const vector<Input::info>& lhs,
|
|
const vector<Input::info>& rhs)
|
|
{
|
|
if (lhs.size() != rhs.size())
|
|
return false;
|
|
|
|
for (size_t i = 0; i < lhs.size(); i++)
|
|
{
|
|
if (lhs[i] != rhs[i])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
class DifferentJsonTxs :
|
|
public ::testing::TestWithParam<string>
|
|
{
|
|
|
|
};
|
|
|
|
class ModularIdentifierTest : public DifferentJsonTxs
|
|
{};
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
DifferentJsonTxs, ModularIdentifierTest,
|
|
::testing::Values(
|
|
"ddff95211b53c194a16c2b8f37ae44b643b8bd46b4cb402af961ecabeb8417b2"s,
|
|
"f3c84fe925292ec5b4dc383d306d934214f4819611566051bca904d1cf4efceb"s,
|
|
"d7dcb2daa64b5718dad71778112d48ad62f4d5f54337037c420cb76efdd8a21c"s,
|
|
"61f756a299efd17442eed5437fa03cbda6b01f341907845f8880bf30319fa01c"s,
|
|
"ae8f3ad29a40e02dff6a3267c769f08c0af3dc8858683c90ce3ef90212cb7e4b"s,
|
|
"140807b970e52b7c633d7ca0ba5be603922aa7a2a1213bdd16d3c1a531402bf6"s,
|
|
"a7a4e3bdb305b97c43034440b0bc5125c23b24d0730189261151c0aa3f2a05fc"s,
|
|
"c06df274acc273fbce0666b2c8846ac6925a1931fb61e3020b7cc5410d4646b1"s,
|
|
"d89f32f1434b6a668cbbc5c55cb1c0c64e41fccb89f6b1eef210fefdacbdd89f"s,
|
|
"bd461b938c3c8c8e4d9909852221d5c37350ade05e99ef836d6ccb628f6a5a0e"s,
|
|
"f81ecd0381c0b89f23cffe86a799e924af7b5843c663e8c07db98a14e913585e"s,
|
|
"386ac4fbf7d3d2ab6fd4f2d9c2e97d00527ca2867e33cd7aedb1fd05a4b791ec"s,
|
|
"e658966b256ca30c85848751ff986e3ba7c7cfdadeb46ee1a845a042b3da90db"s
|
|
));
|
|
|
|
TEST_P(ModularIdentifierTest, OutputsRingCT)
|
|
{
|
|
string tx_hash_str = GetParam();
|
|
|
|
auto jtx = construct_jsontx(tx_hash_str);
|
|
|
|
ASSERT_TRUE(jtx);
|
|
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<Output>(&jtx->sender.address,
|
|
&jtx->sender.viewkey));
|
|
|
|
identifier.identify();
|
|
|
|
ASSERT_EQ(identifier.get<0>()->get().size(),
|
|
jtx->sender.outputs.size());
|
|
|
|
ASSERT_TRUE(identifier.get<0>()->get() == jtx->sender.outputs);
|
|
|
|
ASSERT_EQ(identifier.get<0>()->get_total(),
|
|
jtx->sender.change);
|
|
}
|
|
|
|
|
|
TEST_P(ModularIdentifierTest, OutputsRingCTCoinbaseTx)
|
|
{
|
|
string tx_hash_str = GetParam();
|
|
|
|
auto jtx = construct_jsontx(tx_hash_str);
|
|
|
|
ASSERT_TRUE(jtx);
|
|
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<Output>(&jtx->recipients.at(0).address,
|
|
&jtx->recipients.at(0).viewkey));
|
|
|
|
identifier.identify();
|
|
|
|
ASSERT_TRUE(identifier.get<0>()->get()
|
|
== jtx->recipients.at(0).outputs);
|
|
|
|
ASSERT_EQ(identifier.get<0>()->get_total(),
|
|
jtx->recipients.at(0).amount);
|
|
}
|
|
|
|
TEST_P(ModularIdentifierTest, MultiOutputsRingCT)
|
|
{
|
|
string tx_hash_str = GetParam();
|
|
|
|
auto jtx = construct_jsontx(tx_hash_str);
|
|
|
|
ASSERT_TRUE(jtx);
|
|
|
|
for (auto const& jrecipient: jtx->recipients)
|
|
{
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<Output>(&jrecipient.address,
|
|
&jrecipient.viewkey));
|
|
|
|
identifier.identify();
|
|
|
|
EXPECT_TRUE(identifier.get<0>()->get()
|
|
== jrecipient.outputs);
|
|
}
|
|
}
|
|
|
|
|
|
TEST_P(ModularIdentifierTest, LegacyPaymentID)
|
|
{
|
|
string tx_hash_str = GetParam();
|
|
|
|
auto jtx = construct_jsontx(tx_hash_str);
|
|
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<LegacyPaymentID>());
|
|
|
|
identifier.identify();
|
|
|
|
auto pid = identifier.get<0>()->get();
|
|
|
|
//cout << pod_to_hex(jtx->payment_id) << '\n';
|
|
|
|
if (jtx->payment_id == crypto::null_hash)
|
|
{
|
|
EXPECT_FALSE(pid);
|
|
}
|
|
else
|
|
{
|
|
EXPECT_TRUE(pid);
|
|
EXPECT_TRUE(*pid == jtx->payment_id);
|
|
}
|
|
}
|
|
|
|
|
|
TEST_P(ModularIdentifierTest, IntegratedPaymentID)
|
|
{
|
|
string tx_hash_str = GetParam();
|
|
|
|
auto jtx = construct_jsontx(tx_hash_str);
|
|
|
|
ASSERT_TRUE(jtx);
|
|
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<IntegratedPaymentID>(
|
|
&jtx->recipients[0].address,
|
|
&jtx->recipients[0].viewkey));
|
|
|
|
identifier.identify();
|
|
|
|
auto pid = identifier.get<0>()->get();
|
|
|
|
if (jtx->payment_id8 == crypto::null_hash8)
|
|
{
|
|
EXPECT_FALSE(pid);
|
|
}
|
|
else
|
|
{
|
|
EXPECT_TRUE(pid);
|
|
EXPECT_TRUE(*pid == jtx->payment_id8e);
|
|
}
|
|
}
|
|
|
|
TEST_P(ModularIdentifierTest, InputWithKnownOutputs)
|
|
{
|
|
string tx_hash_str = GetParam();
|
|
|
|
auto jtx = construct_jsontx(tx_hash_str);
|
|
|
|
ASSERT_TRUE(jtx);
|
|
|
|
// make vector of known outputs
|
|
|
|
Input::known_outputs_t known_outputs;
|
|
uint64_t expected_total {};
|
|
|
|
// first add real public keys
|
|
for (auto&& input: jtx->sender.inputs)
|
|
{
|
|
known_outputs.insert({input.out_pub_key, input.amount});
|
|
expected_total += input.amount;
|
|
}
|
|
|
|
|
|
// now add some random ones
|
|
|
|
for (size_t i = 0; i < 20; ++i)
|
|
{
|
|
auto rand_pk = crypto::rand<public_key>();
|
|
known_outputs.insert({rand_pk, 4353534534}); // some amount
|
|
}
|
|
|
|
MockMicroCore mcore;
|
|
|
|
ADD_MOCKS(mcore);
|
|
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<Input>(
|
|
&jtx->sender.address,
|
|
&jtx->sender.viewkey,
|
|
&known_outputs,
|
|
&mcore));
|
|
|
|
|
|
identifier.identify();
|
|
|
|
ASSERT_TRUE(identifier.get<0>()->get()
|
|
== jtx->sender.inputs);
|
|
|
|
ASSERT_EQ(identifier.get<0>()->get_total(),
|
|
expected_total);
|
|
}
|
|
|
|
// in some rare cases, different txs have same output
|
|
// public keys, but different amounts. so known_output map
|
|
// is of type of unordered_mulitimap to allow for such a
|
|
// situation
|
|
//TEST_P(ModularIdentifierTest, InputWithKnownMultipleOutputs)
|
|
//{
|
|
//string tx_hash_str = GetParam();
|
|
|
|
//auto jtx = construct_jsontx(tx_hash_str);
|
|
|
|
//ASSERT_TRUE(jtx);
|
|
|
|
//// make vector of known outputs
|
|
|
|
//Input::known_outputs_t known_outputs;
|
|
//uint64_t expected_total {};
|
|
|
|
//// first add real public keys
|
|
//for (auto&& input: jtx->sender.inputs)
|
|
//{
|
|
//known_outputs.insert({input.out_pub_key, input.amount});
|
|
|
|
//// insert duplicate output with different amount
|
|
//known_outputs.insert({input.out_pub_key, input.amount*2});
|
|
|
|
//expected_total += input.amount;
|
|
//}
|
|
|
|
//// now add some random ones
|
|
|
|
//for (size_t i = 0; i < 20; ++i)
|
|
//{
|
|
//auto rand_pk = crypto::rand<public_key>();
|
|
//known_outputs.insert({rand_pk, 4353534534}); // some amount
|
|
//}
|
|
|
|
//MockMicroCore mcore;
|
|
|
|
//ADD_MOCKS(mcore);
|
|
|
|
//auto identifier = make_identifier(jtx->tx,
|
|
//make_unique<Input>(
|
|
//&jtx->sender.address,
|
|
//&jtx->sender.viewkey,
|
|
//&known_outputs,
|
|
//&mcore));
|
|
|
|
|
|
//identifier.identify();
|
|
|
|
//// we just expect to get two return vector of inputs
|
|
//// twice the size of the actual inputs due to there being
|
|
//// double outputs
|
|
|
|
//ASSERT_EQ(identifier.get<0>()->get().size(),
|
|
//jtx->sender.inputs.size()*2);
|
|
|
|
//// since second dupicate of each outputs has double
|
|
//// amount, the expected total is 3 times greater
|
|
//// than real amount
|
|
//ASSERT_EQ(identifier.get<0>()->get_total(),
|
|
//expected_total*3);
|
|
//}
|
|
|
|
TEST_P(ModularIdentifierTest, GuessInputRingCT)
|
|
{
|
|
string tx_hash_str = GetParam();
|
|
|
|
auto jtx = construct_jsontx(tx_hash_str);
|
|
|
|
ASSERT_TRUE(jtx);
|
|
|
|
MockMicroCore mcore;
|
|
|
|
ADD_MOCKS(mcore);
|
|
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<GuessInput>(
|
|
&jtx->sender.address,
|
|
&jtx->sender.viewkey,
|
|
&mcore));
|
|
|
|
identifier.identify();
|
|
|
|
auto const& found_inputs = identifier.get<0>()->get();
|
|
|
|
EXPECT_GE(found_inputs.size(),
|
|
jtx->sender.inputs.size());
|
|
|
|
if (!jtx->sender.inputs.empty())
|
|
{
|
|
// to check whether GuessIdentifier is correct
|
|
// we check weath all outputs and key images are present
|
|
// in its found_inputs
|
|
//
|
|
|
|
for (auto const& input: jtx->sender.inputs)
|
|
{
|
|
|
|
// make lambda that will check wether
|
|
// current input's public key matches a
|
|
// given one
|
|
//
|
|
// to do this, first we find all public
|
|
// output keys in found_inputs vector
|
|
// that GuessInput populated
|
|
|
|
using input_elem_type
|
|
= std::remove_reference_t<decltype(found_inputs)>::value_type;
|
|
|
|
vector<input_elem_type const*>
|
|
matched_public_keys;
|
|
|
|
for (auto const& fin: found_inputs)
|
|
{
|
|
if (input.out_pub_key == fin.out_pub_key)
|
|
matched_public_keys.push_back(&fin);
|
|
}
|
|
|
|
if (matched_public_keys.empty())
|
|
FAIL() << "matched_public_keys is empty";
|
|
|
|
// second, if we found something, check
|
|
// if matched_public_keys contains
|
|
// key image from senders.input
|
|
|
|
bool match_found {false};
|
|
|
|
for (auto const matched_pk: matched_public_keys)
|
|
if (input.key_img == matched_pk->key_img)
|
|
{
|
|
match_found = true;
|
|
SUCCEED();
|
|
}
|
|
|
|
if (!match_found)
|
|
FAIL() << "No maching key image found";
|
|
|
|
} //for (auto const& input: jtx->sender.inputs)
|
|
|
|
} // if (!jtx->sender.inputs.empty())
|
|
|
|
}
|
|
|
|
TEST_P(ModularIdentifierTest, RealInputRingCT)
|
|
{
|
|
string tx_hash_str = GetParam();
|
|
|
|
auto jtx = construct_jsontx(tx_hash_str);
|
|
|
|
ASSERT_TRUE(jtx);
|
|
|
|
MockMicroCore mcore;
|
|
|
|
ADD_MOCKS(mcore);
|
|
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<RealInput>(
|
|
&jtx->sender.address,
|
|
&jtx->sender.viewkey,
|
|
&jtx->sender.spendkey,
|
|
&mcore));
|
|
|
|
identifier.identify();
|
|
|
|
// for (auto const& input_info: identifier.get<0>()->get())
|
|
// cout << input_info << endl;
|
|
|
|
EXPECT_TRUE(identifier.get<0>()->get()
|
|
== jtx->sender.inputs);
|
|
}
|
|
|
|
|
|
TEST(Subaddresses, RegularTwoOutputTxToSubaddress)
|
|
{
|
|
// this tx has funds for one subaddress. so we try to identify the outputs
|
|
// and the subaddress using primary address of the recipient
|
|
auto jtx = construct_jsontx("024dc13cb11d411682f04d41b52931849527d530e4cb198a63526c13da31a413");
|
|
|
|
ASSERT_TRUE(jtx);
|
|
|
|
// recipeint primary address and viewkey
|
|
string const raddress {"56heRv2ANffW1Py2kBkJDy8xnWqZsSrgjLygwjua2xc8Wbksead1NK1ehaYpjQhymGK4S8NPL9eLuJ16CuEJDag8Hq3RbPV"};
|
|
string const rviewkey {"b45e6f38b2cd1c667459527decb438cdeadf9c64d93c8bccf40a9bf98943dc09"};
|
|
|
|
auto racc = make_primaryaccount(raddress, rviewkey);
|
|
|
|
// make sure we have primary address
|
|
ASSERT_FALSE(racc->is_subaddress());
|
|
|
|
racc->populate_subaddress_indices();
|
|
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<Output>(racc.get()));
|
|
|
|
identifier.identify();
|
|
|
|
EXPECT_EQ(identifier.get<0>()->get().size(),
|
|
jtx->recipients.at(0).outputs.size());
|
|
|
|
EXPECT_TRUE(identifier.get<0>()->get()
|
|
== jtx->recipients.at(0).outputs);
|
|
|
|
auto const& output_info
|
|
= identifier.get<0>()->get().at(0);
|
|
|
|
EXPECT_TRUE(output_info.has_subaddress_index());
|
|
|
|
subaddress_index expected_idx {0, 6};
|
|
|
|
EXPECT_EQ(output_info.subaddr_idx, expected_idx);
|
|
}
|
|
|
|
TEST(Subaddresses, MultiOutputTxToSubaddress)
|
|
{
|
|
// this tx has funds for few subaddress of the same primary account.
|
|
// so we try to identify the outputs
|
|
// and the subaddresses indices using primary address of the recipient
|
|
auto jtx = construct_jsontx("f81ecd0381c0b89f23cffe86a799e924af7b5843c663e8c07db98a14e913585e");
|
|
|
|
ASSERT_TRUE(jtx);
|
|
|
|
// recipeint primary address and viewkey
|
|
string const raddress {"56heRv2ANffW1Py2kBkJDy8xnWqZsSrgjLygwjua2xc8Wbksead1NK1ehaYpjQhymGK4S8NPL9eLuJ16CuEJDag8Hq3RbPV"};
|
|
string const rviewkey {"b45e6f38b2cd1c667459527decb438cdeadf9c64d93c8bccf40a9bf98943dc09"};
|
|
|
|
auto racc = make_primaryaccount(raddress, rviewkey);
|
|
|
|
// make sure we have primary address
|
|
ASSERT_FALSE(racc->is_subaddress());
|
|
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<Output>(racc.get()));
|
|
|
|
identifier.identify();
|
|
|
|
auto const& outputs_found
|
|
= identifier.get<Output>()->get();
|
|
|
|
auto total_outputs = calc_total_xmr(outputs_found);
|
|
|
|
uint64_t expected_total {0};
|
|
|
|
set<pair<string, string>> output_indices;
|
|
|
|
for (auto&& out: outputs_found)
|
|
{
|
|
stringstream ss;
|
|
|
|
ss << out.subaddr_idx;
|
|
|
|
output_indices.insert({pod_to_hex(out.pub_key),
|
|
ss.str()});
|
|
|
|
}
|
|
|
|
set<pair<string, string>> expected_indices;
|
|
|
|
for (auto const& jrecipient: jtx->recipients)
|
|
{
|
|
auto identifier_rec = make_identifier(jtx->tx,
|
|
make_unique<Output>(&jrecipient.address,
|
|
&jrecipient.viewkey));
|
|
|
|
identifier_rec.identify();
|
|
|
|
auto const& output_rec
|
|
= identifier_rec.get<Output>()->get();
|
|
|
|
expected_total += calc_total_xmr(output_rec);
|
|
|
|
|
|
for (auto&& out: output_rec)
|
|
{
|
|
stringstream ss;
|
|
|
|
ss << *jrecipient.subaddr_idx;
|
|
|
|
expected_indices.insert({pod_to_hex(out.pub_key),
|
|
ss.str()});
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(total_outputs, expected_total);
|
|
|
|
vector<decltype(output_indices)::value_type> result;
|
|
|
|
std::set_symmetric_difference(output_indices.begin(),
|
|
output_indices.end(),
|
|
expected_indices.begin(),
|
|
expected_indices.end(),
|
|
std::back_inserter(result));
|
|
|
|
EXPECT_TRUE(result.empty());
|
|
|
|
// check if expansion of subbaddress list worked
|
|
EXPECT_EQ(racc->get_next_subbaddress_acc_id(),
|
|
PrimaryAccount::SUBADDRESS_LOOKAHEAD_MAJOR + 49);
|
|
|
|
EXPECT_EQ(racc->get_subaddress_map().size(), 10'000 + 49*200);
|
|
}
|
|
|
|
|
|
TEST(Subaddresses, GuessInputFromSubaddress)
|
|
{
|
|
auto jtx = construct_jsontx("386ac4fbf7d3d2ab6fd4f2d9c2e97d00527ca2867e33cd7aedb1fd05a4b791ec");
|
|
|
|
ASSERT_TRUE(jtx);
|
|
|
|
MockMicroCore mcore;
|
|
ADD_MOCKS(mcore);
|
|
|
|
|
|
// sender primary address and viewkey
|
|
string const sender_addr = jtx->sender.address_str();
|
|
string const sender_viewkey = pod_to_hex(jtx->sender.viewkey);
|
|
string const sender_spendkey = pod_to_hex(jtx->sender.spendkey);
|
|
|
|
auto sender = make_primaryaccount(sender_addr,
|
|
sender_viewkey,
|
|
sender_spendkey);
|
|
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<GuessInput>(sender.get(), &mcore),
|
|
make_unique<RealInput>(sender.get(), &mcore));
|
|
|
|
identifier.identify();
|
|
|
|
auto const& found_inputs = identifier.get<GuessInput>()->get();
|
|
auto const& expected_inputs = identifier.get<RealInput>()->get();
|
|
|
|
EXPECT_EQ(found_inputs.size(), expected_inputs.size());
|
|
|
|
EXPECT_TRUE(found_inputs == expected_inputs);
|
|
|
|
|
|
// now lets check recipient outputs
|
|
|
|
// recipeint primary address and viewkey
|
|
string const raddress {"55ZbQdMnZHPFS8pmrhHN5jMpgJwnnTXpTDmmM5wkrBBx4xD6aEnpZq7dPkeDeWs67TV9HunDQtT3qF2UGYWzGGxq3zYWCBE"};
|
|
string const rviewkey {"c8a4d62e3c86de907bd84463f194505ab07fc231b3da753342d93fccb5d39203"};
|
|
|
|
|
|
auto acc = make_account(raddress, rviewkey);
|
|
|
|
ASSERT_TRUE(acc->type() == Account::PRIMARY);
|
|
|
|
auto primary_account = dynamic_cast<PrimaryAccount*>(acc.get());
|
|
|
|
ASSERT_TRUE(primary_account);
|
|
|
|
primary_account->populate_subaddress_indices();
|
|
|
|
auto ridentifier = make_identifier(jtx->tx,
|
|
make_unique<Output>(primary_account));
|
|
|
|
ridentifier.identify();
|
|
|
|
auto const& outputs_found
|
|
= ridentifier.get<Output>()->get();
|
|
|
|
cout << outputs_found << endl;
|
|
|
|
EXPECT_EQ(outputs_found.size(), 3);
|
|
|
|
auto total_outputs = calc_total_xmr(outputs_found);
|
|
|
|
EXPECT_EQ(total_outputs, 8000000000000);
|
|
|
|
vector<subaddress_index> expected_indices {{0, 1}, {0, 2}, {0, 3}};
|
|
|
|
for (size_t i {0}; i < outputs_found.size(); ++i)
|
|
{
|
|
EXPECT_EQ(outputs_found[i].subaddr_idx,
|
|
expected_indices[i]);
|
|
}
|
|
|
|
EXPECT_EQ(primary_account->get_next_subbaddress_acc_id(),
|
|
PrimaryAccount::SUBADDRESS_LOOKAHEAD_MAJOR);
|
|
}
|
|
|
|
TEST(Subaddresses, RealInputsToSubaddress)
|
|
{
|
|
auto jtx = construct_jsontx("e658966b256ca30c85848751ff986e3ba7c7cfdadeb46ee1a845a042b3da90db");
|
|
|
|
ASSERT_TRUE(jtx);
|
|
|
|
MockMicroCore mcore;
|
|
ADD_MOCKS(mcore);
|
|
|
|
// sender primary address and viewkey
|
|
string const sender_addr = jtx->sender.address_str();
|
|
string const sender_viewkey = pod_to_hex(jtx->sender.viewkey);
|
|
string const sender_spendkey = pod_to_hex(jtx->sender.spendkey);
|
|
|
|
auto sender = make_primaryaccount(sender_addr,
|
|
sender_viewkey,
|
|
sender_spendkey);
|
|
|
|
auto identifier = make_identifier(jtx->tx,
|
|
make_unique<GuessInput>(sender.get(), &mcore),
|
|
make_unique<RealInput>(sender.get(), &mcore));
|
|
|
|
identifier.identify();
|
|
|
|
auto const& found_inputs = identifier.get<GuessInput>()->get();
|
|
auto const& expected_inputs = identifier.get<RealInput>()->get();
|
|
|
|
EXPECT_EQ(found_inputs.size(), expected_inputs.size());
|
|
|
|
EXPECT_TRUE(found_inputs == expected_inputs);
|
|
}
|
|
|
|
}
|