Merge pull request #4308
9907ea06
cryptonote: sort tx_extra fields (moneromooo-monero)
This commit is contained in:
commit
1c91963dcd
|
@ -47,7 +47,6 @@
|
||||||
#include "crypto/crypto.h"
|
#include "crypto/crypto.h"
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
#include "misc_language.h"
|
#include "misc_language.h"
|
||||||
#include "tx_extra.h"
|
|
||||||
#include "ringct/rctTypes.h"
|
#include "ringct/rctTypes.h"
|
||||||
#include "device/device.hpp"
|
#include "device/device.hpp"
|
||||||
|
|
||||||
|
|
|
@ -445,6 +445,91 @@ namespace cryptonote
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
template<typename T>
|
||||||
|
static bool pick(binary_archive<true> &ar, std::vector<tx_extra_field> &fields, uint8_t tag)
|
||||||
|
{
|
||||||
|
std::vector<tx_extra_field>::iterator it;
|
||||||
|
while ((it = std::find_if(fields.begin(), fields.end(), [](const tx_extra_field &f) { return f.type() == typeid(T); })) != fields.end())
|
||||||
|
{
|
||||||
|
bool r = ::do_serialize(ar, tag);
|
||||||
|
CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra field");
|
||||||
|
r = ::do_serialize(ar, boost::get<T>(*it));
|
||||||
|
CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra field");
|
||||||
|
fields.erase(it);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
bool sort_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<uint8_t> &sorted_tx_extra, bool allow_partial)
|
||||||
|
{
|
||||||
|
std::vector<tx_extra_field> tx_extra_fields;
|
||||||
|
|
||||||
|
if(tx_extra.empty())
|
||||||
|
{
|
||||||
|
sorted_tx_extra.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size());
|
||||||
|
std::istringstream iss(extra_str);
|
||||||
|
binary_archive<false> ar(iss);
|
||||||
|
|
||||||
|
bool eof = false;
|
||||||
|
size_t processed = 0;
|
||||||
|
while (!eof)
|
||||||
|
{
|
||||||
|
tx_extra_field field;
|
||||||
|
bool r = ::do_serialize(ar, field);
|
||||||
|
if (!r)
|
||||||
|
{
|
||||||
|
MWARNING("failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
|
||||||
|
if (!allow_partial)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tx_extra_fields.push_back(field);
|
||||||
|
processed = iss.tellg();
|
||||||
|
|
||||||
|
std::ios_base::iostate state = iss.rdstate();
|
||||||
|
eof = (EOF == iss.peek());
|
||||||
|
iss.clear(state);
|
||||||
|
}
|
||||||
|
if (!::serialization::check_stream_state(ar))
|
||||||
|
{
|
||||||
|
MWARNING("failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
|
||||||
|
if (!allow_partial)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MTRACE("Sorted " << processed << "/" << tx_extra.size());
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
binary_archive<true> nar(oss);
|
||||||
|
|
||||||
|
// sort by:
|
||||||
|
if (!pick<tx_extra_pub_key>(nar, tx_extra_fields, TX_EXTRA_TAG_PUBKEY)) return false;
|
||||||
|
if (!pick<tx_extra_additional_pub_keys>(nar, tx_extra_fields, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS)) return false;
|
||||||
|
if (!pick<tx_extra_nonce>(nar, tx_extra_fields, TX_EXTRA_NONCE)) return false;
|
||||||
|
if (!pick<tx_extra_merge_mining_tag>(nar, tx_extra_fields, TX_EXTRA_MERGE_MINING_TAG)) return false;
|
||||||
|
if (!pick<tx_extra_mysterious_minergate>(nar, tx_extra_fields, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG)) return false;
|
||||||
|
if (!pick<tx_extra_padding>(nar, tx_extra_fields, TX_EXTRA_TAG_PADDING)) return false;
|
||||||
|
|
||||||
|
// if not empty, someone added a new type and did not add a case above
|
||||||
|
if (!tx_extra_fields.empty())
|
||||||
|
{
|
||||||
|
MERROR("tx_extra_fields not empty after sorting, someone forgot to add a case above");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string oss_str = oss.str();
|
||||||
|
if (allow_partial && processed < tx_extra.size())
|
||||||
|
{
|
||||||
|
MDEBUG("Appending unparsed data");
|
||||||
|
oss_str += std::string((const char*)tx_extra.data() + processed, tx_extra.size() - processed);
|
||||||
|
}
|
||||||
|
sorted_tx_extra = std::vector<uint8_t>(oss_str.begin(), oss_str.end());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------
|
||||||
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index)
|
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index)
|
||||||
{
|
{
|
||||||
std::vector<tx_extra_field> tx_extra_fields;
|
std::vector<tx_extra_field> tx_extra_fields;
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "blobdatatype.h"
|
#include "blobdatatype.h"
|
||||||
#include "cryptonote_basic_impl.h"
|
#include "cryptonote_basic_impl.h"
|
||||||
|
#include "tx_extra.h"
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "subaddress_index.h"
|
#include "subaddress_index.h"
|
||||||
#include "include_base_utils.h"
|
#include "include_base_utils.h"
|
||||||
|
@ -65,6 +66,7 @@ namespace cryptonote
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields);
|
bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields);
|
||||||
|
bool sort_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<uint8_t> &sorted_tx_extra, bool allow_partial = false);
|
||||||
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index = 0);
|
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index = 0);
|
||||||
crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx, size_t pk_index = 0);
|
crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx, size_t pk_index = 0);
|
||||||
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx, size_t pk_index = 0);
|
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx, size_t pk_index = 0);
|
||||||
|
|
|
@ -38,6 +38,7 @@ using namespace epee;
|
||||||
#include "cryptonote_tx_utils.h"
|
#include "cryptonote_tx_utils.h"
|
||||||
#include "cryptonote_config.h"
|
#include "cryptonote_config.h"
|
||||||
#include "cryptonote_basic/miner.h"
|
#include "cryptonote_basic/miner.h"
|
||||||
|
#include "cryptonote_basic/tx_extra.h"
|
||||||
#include "crypto/crypto.h"
|
#include "crypto/crypto.h"
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
#include "ringct/rctSigs.h"
|
#include "ringct/rctSigs.h"
|
||||||
|
@ -84,6 +85,8 @@ namespace cryptonote
|
||||||
if(!extra_nonce.empty())
|
if(!extra_nonce.empty())
|
||||||
if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
|
if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
|
||||||
return false;
|
return false;
|
||||||
|
if (!sort_tx_extra(tx.extra, tx.extra))
|
||||||
|
return false;
|
||||||
|
|
||||||
txin_gen in;
|
txin_gen in;
|
||||||
in.height = height;
|
in.height = height;
|
||||||
|
@ -434,6 +437,9 @@ namespace cryptonote
|
||||||
add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys);
|
add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!sort_tx_extra(tx.extra, tx.extra))
|
||||||
|
return false;
|
||||||
|
|
||||||
//check money
|
//check money
|
||||||
if(summary_outs_money > summary_inputs_money )
|
if(summary_outs_money > summary_inputs_money )
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
#include "cryptonote_basic/cryptonote_basic.h"
|
||||||
|
#include "cryptonote_basic/tx_extra.h"
|
||||||
#include "cryptonote_core/cryptonote_tx_utils.h"
|
#include "cryptonote_core/cryptonote_tx_utils.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -203,3 +205,85 @@ TEST(validate_parse_amount_case, validate_parse_amount)
|
||||||
r = cryptonote::parse_amount(res, "1 00.00 00");
|
r = cryptonote::parse_amount(res, "1 00.00 00");
|
||||||
ASSERT_FALSE(r);
|
ASSERT_FALSE(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(sort_tx_extra, empty)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> extra, sorted;
|
||||||
|
ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted));
|
||||||
|
ASSERT_EQ(extra, sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sort_tx_extra, pubkey)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> sorted;
|
||||||
|
const uint8_t extra_arr[] = {1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
|
||||||
|
80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230};
|
||||||
|
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
|
||||||
|
ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted));
|
||||||
|
ASSERT_EQ(extra, sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sort_tx_extra, two_pubkeys)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> sorted;
|
||||||
|
const uint8_t extra_arr[] = {1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
|
||||||
|
80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230,
|
||||||
|
1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
|
||||||
|
80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230};
|
||||||
|
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
|
||||||
|
ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted));
|
||||||
|
ASSERT_EQ(extra, sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sort_tx_extra, keep_order)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> sorted;
|
||||||
|
const uint8_t extra_arr[] = {1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
|
||||||
|
80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230,
|
||||||
|
2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
|
||||||
|
ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted));
|
||||||
|
ASSERT_EQ(extra, sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sort_tx_extra, switch_order)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> sorted;
|
||||||
|
const uint8_t extra_arr[] = {2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
|
||||||
|
80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230};
|
||||||
|
const uint8_t expected_arr[] = {1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
|
||||||
|
80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230,
|
||||||
|
2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
|
||||||
|
ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted));
|
||||||
|
std::vector<uint8_t> expected(&expected_arr[0], &expected_arr[0] + sizeof(expected_arr));
|
||||||
|
ASSERT_EQ(expected, sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sort_tx_extra, invalid)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> sorted;
|
||||||
|
const uint8_t extra_arr[] = {1};
|
||||||
|
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
|
||||||
|
ASSERT_FALSE(cryptonote::sort_tx_extra(extra, sorted));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sort_tx_extra, invalid_suffix_strict)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> sorted;
|
||||||
|
const uint8_t extra_arr[] = {2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||||
|
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
|
||||||
|
ASSERT_FALSE(cryptonote::sort_tx_extra(extra, sorted));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sort_tx_extra, invalid_suffix_partial)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> sorted;
|
||||||
|
const uint8_t extra_arr[] = {2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||||
|
const uint8_t expected_arr[] = {2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||||
|
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
|
||||||
|
ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted, true));
|
||||||
|
std::vector<uint8_t> expected(&expected_arr[0], &expected_arr[0] + sizeof(expected_arr));
|
||||||
|
ASSERT_EQ(sorted, expected);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue