Merge commit '459beb5' into MergeUpstream2

This commit is contained in:
Doyle 2020-04-20 17:25:53 +10:00
commit e7e622e08b
9 changed files with 195 additions and 83 deletions

View file

@ -32,6 +32,9 @@
#include <boost/utility/string_ref.hpp>
#include "misc_log_ex.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "serialization"
namespace epee
{
namespace misc_utils
@ -63,6 +66,26 @@ namespace misc_utils
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static const constexpr unsigned char isx[256] =
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
inline bool isspace(char c)
{
return lut[(uint8_t)c] & 8;
@ -163,6 +186,42 @@ namespace misc_utils
val.push_back('\\');break;
case '/': //Slash character
val.push_back('/');break;
case 'u': //Unicode code point
if (buf_end - it < 4)
{
ASSERT_MES_AND_THROW("Invalid Unicode escape sequence");
}
else
{
uint32_t dst = 0;
for (int i = 0; i < 4; ++i)
{
const unsigned char tmp = isx[(int)*++it];
CHECK_AND_ASSERT_THROW_MES(tmp != 0xff, "Bad Unicode encoding");
dst = dst << 4 | tmp;
}
// encode as UTF-8
if (dst <= 0x7f)
{
val.push_back(dst);
}
else if (dst <= 0x7ff)
{
val.push_back(0xc0 | (dst >> 6));
val.push_back(0x80 | (dst & 0x3f));
}
else if (dst <= 0xffff)
{
val.push_back(0xe0 | (dst >> 12));
val.push_back(0x80 | ((dst >> 6) & 0x3f));
val.push_back(0x80 | (dst & 0x3f));
}
else
{
ASSERT_MES_AND_THROW("Unicode code point is out or range");
}
}
break;
default:
val.push_back(*it);
LOG_PRINT_L0("Unknown escape sequence :\"\\" << *it << "\"");

View file

@ -59,26 +59,6 @@
#pragma comment (lib, "Rpcrt4.lib")
#endif
static const constexpr unsigned char isx[256] =
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
namespace epee
{
namespace string_tools
@ -99,10 +79,10 @@ namespace string_tools
for(size_t i = 0; i < s.size(); i += 2)
{
int tmp = *src++;
tmp = isx[tmp];
tmp = epee::misc_utils::parse::isx[tmp];
if (tmp == 0xff) return false;
int t2 = *src++;
t2 = isx[t2];
t2 = epee::misc_utils::parse::isx[t2];
if (t2 == 0xff) return false;
*dst++ = (tmp << 4) | t2;
}

View file

@ -1439,8 +1439,7 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat
// - unconfirmed_transfer_details;
// - confirmed_transfer_details)
PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional<uint64_t> amount, uint32_t /*mixin_count*/,
uint32_t priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<string> &dst_addr, const string &payment_id, optional<std::vector<uint64_t>> amount, uint32_t priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
clearStatus();
@ -1452,83 +1451,84 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
do {
if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), dst_addr)) {
// TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982
setStatusError(tr("Invalid destination address"));
std::vector<uint8_t> extra;
std::string extra_nonce;
vector<cryptonote::tx_destination_entry> dsts;
if (!amount && dst_addr.size() > 1) {
setStatusError(tr("Sending all requires one destination address"));
break;
}
std::vector<uint8_t> extra;
// if dst_addr is not an integrated address, parse payment_id
if (!info.has_payment_id && !payment_id.empty()) {
// copy-pasted from simplewallet.cpp:2212
if (amount && (dst_addr.size() != (*amount).size())) {
setStatusError(tr("Destinations and amounts are unequal"));
break;
}
if (!payment_id.empty()) {
crypto::hash payment_id_long;
bool r = tools::wallet2::parse_long_payment_id(payment_id, payment_id_long);
if (r) {
std::string extra_nonce;
if (tools::wallet2::parse_long_payment_id(payment_id, payment_id_long)) {
cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_long);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
} else {
r = tools::wallet2::parse_short_payment_id(payment_id, info.payment_id);
if (r) {
std::string extra_nonce;
set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
setStatusError(tr("payment id has invalid format, expected 64 character hex string: ") + payment_id);
break;
}
}
bool error = false;
for (size_t i = 0; i < dst_addr.size() && !error; i++) {
if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), dst_addr[i])) {
// TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982
setStatusError(tr("Invalid destination address"));
error = true;
break;
}
if (info.has_payment_id) {
if (!extra_nonce.empty()) {
setStatusError(tr("a single transaction cannot use more than one payment id"));
error = true;
break;
}
set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
}
if (!r) {
setStatusError(tr("payment id has invalid format, expected 16 or 64 character hex string: ") + payment_id);
break;
}
}
else if (info.has_payment_id) {
std::string extra_nonce;
set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
bool r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
if (!r) {
setStatusError(tr("Failed to add short payment id: ") + epee::string_tools::pod_to_hex(info.payment_id));
break;
}
}
//std::vector<tools::wallet2::pending_tx> ptx_vector;
try {
if (amount) {
vector<cryptonote::tx_destination_entry> dsts;
cryptonote::tx_destination_entry de;
de.original = dst_addr;
de.original = dst_addr[i];
de.addr = info.address;
de.amount = *amount;
de.amount = (*amount)[i];
de.is_subaddress = info.is_subaddress;
de.is_integrated = info.has_payment_id;
dsts.push_back(de);
boost::optional<uint8_t> hf_version = m_wallet->get_hard_fork_version();
if (!hf_version)
{
setStatusError(tools::ERR_MSG_NETWORK_VERSION_QUERY_FAILED);
return transaction;
}
loki_construct_tx_params tx_params = tools::wallet2::construct_params(*hf_version, txtype::standard, priority);
transaction->m_pending_tx = m_wallet->create_transactions_2(
dsts, CRYPTONOTE_DEFAULT_TX_MIXIN, 0 /* unlock_time */,
priority, extra, subaddr_account, subaddr_indices, tx_params);
} else {
// for the GUI, sweep_all (i.e. amount set as "(all)") will always sweep all the funds in all the addresses
if (subaddr_indices.empty())
{
if (subaddr_indices.empty()) {
for (uint32_t index = 0; index < m_wallet->get_num_subaddresses(subaddr_account); ++index)
subaddr_indices.insert(index);
}
transaction->m_pending_tx = m_wallet->create_transactions_all(
0, info.address, info.is_subaddress, 1, CRYPTONOTE_DEFAULT_TX_MIXIN, 0 /* unlock_time */,
priority, extra, subaddr_account, subaddr_indices);
}
}
if (error) {
break;
}
if (!extra_nonce.empty() && !add_extra_nonce_to_tx_extra(extra, extra_nonce)) {
setStatusError(tr("failed to set up payment id, though it was decoded correctly"));
break;
}
try {
boost::optional<uint8_t> hf_version = m_wallet->get_hard_fork_version();
if (!hf_version)
{
setStatusError(tools::ERR_MSG_NETWORK_VERSION_QUERY_FAILED);
return transaction;
}
loki_construct_tx_params tx_params = tools::wallet2::construct_params(*hf_version, txtype::standard, priority);
if (amount) {
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, CRYPTONOTE_DEFAULT_TX_MIXIN, 0 /* unlock_time */,
priority,
extra, subaddr_account, subaddr_indices, tx_params);
} else {
transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, CRYPTONOTE_DEFAULT_TX_MIXIN, 0 /* unlock_time */,
priority,
extra, subaddr_account, subaddr_indices, tx_params);
}
pendingTxPostProcess(transaction);
if (multisig().isMultisig) {
@ -1605,6 +1605,13 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
return transaction;
}
PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional<uint64_t> amount,
uint32_t priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
return createTransactionMultDest(std::vector<string> {dst_addr}, payment_id, amount ? (std::vector<uint64_t> {*amount}) : (optional<std::vector<uint64_t>>()), mixin_count, priority, subaddr_account, subaddr_indices);
}
PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
{

View file

@ -151,8 +151,13 @@ public:
bool hasMultisigPartialKeyImages() const override;
PendingTransaction* restoreMultisigTransaction(const std::string& signData) override;
PendingTransaction * createTransactionMultDest(const std::vector<std::string> &dst_addr, const std::string &payment_id,
optional<std::vector<uint64_t>> amount,
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {}) override;
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
optional<uint64_t> amount, uint32_t mixin_count,
optional<uint64_t> amount,
uint32_t priority = 0,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {}) override;

View file

@ -808,6 +808,26 @@ struct Wallet
* @return PendingTransaction
*/
virtual PendingTransaction* restoreMultisigTransaction(const std::string& signData) = 0;
/*!
* \brief createTransactionMultDest creates transaction with multiple destinations. if dst_addr is an integrated address, payment_id is ignored
* \param dst_addr vector of destination address as string
* \param payment_id optional payment_id, can be empty string
* \param amount vector of amounts
* \param mixin_count mixin count. if 0 passed, wallet will use default value
* \param subaddr_account subaddress account from which the input funds are taken
* \param subaddr_indices set of subaddress indices to use for transfer or sweeping. if set empty, all are chosen when sweeping, and one or more are automatically chosen when transferring. after execution, returns the set of actually used indices
* \param priority
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
* after object returned
*/
virtual PendingTransaction * createTransactionMultDest(const std::vector<std::string> &dst_addr, const std::string &payment_id,
optional<std::vector<uint64_t>> amount, uint32_t mixin_count,
PendingTransaction::Priority = PendingTransaction::Priority_Low,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {}) = 0;
/*!
* \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored
* \param dst_addr destination address as string

View file

@ -78,6 +78,12 @@ class BlockchainTest():
except: ok = True
assert ok
res = daemon.get_fee_estimate()
assert res.fee == 234562
assert res.quantization_mask == 10000
res = daemon.get_fee_estimate(10)
assert res.fee <= 234562
# generate blocks
res_generateblocks = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', blocks)
@ -229,6 +235,12 @@ class BlockchainTest():
assert res.histogram[i].unlocked_instances == 0
assert res.histogram[i].recent_instances == 0
res = daemon.get_fee_estimate()
assert res.fee == 234560
assert res.quantization_mask == 10000
res = daemon.get_fee_estimate(10)
assert res.fee <= 234560
def _test_alt_chains(self):
print('Testing alt chains')
daemon = Daemon()

View file

@ -198,8 +198,9 @@ class WalletAddressTest():
try: wallet.close_wallet()
except: pass
languages = res.languages
for language in languages:
print('Creating ' + str(language) + ' wallet')
languages_local = res.languages_local
for language in languages + languages_local:
print('Creating ' + language.encode('utf8') + ' wallet')
wallet.create_wallet(filename = '', language = language)
res = wallet.query_key('mnemonic')
wallet.close_wallet()

View file

@ -946,3 +946,20 @@ TEST(parsing, number)
epee::misc_utils::parse::match_number(i, s.end(), val);
ASSERT_EQ(val, "+9.34e+03");
}
TEST(parsing, unicode)
{
std::string bs;
std::string s;
std::string::const_iterator si;
s = "\"\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, "");
s = "\"\\u0000\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, std::string(1, '\0'));
s = "\"\\u0020\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, " ");
s = "\"\\u1\""; si = s.begin(); ASSERT_FALSE(epee::misc_utils::parse::match_string(si, s.end(), bs));
s = "\"\\u12\""; si = s.begin(); ASSERT_FALSE(epee::misc_utils::parse::match_string(si, s.end(), bs));
s = "\"\\u123\""; si = s.begin(); ASSERT_FALSE(epee::misc_utils::parse::match_string(si, s.end(), bs));
s = "\"\\u1234\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, "");
s = "\"foo\\u1234bar\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, "fooሴbar");
s = "\"\\u3042\\u307e\\u3084\\u304b\\u3059\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, "あまやかす");
}

View file

@ -333,3 +333,14 @@ class Daemon(object):
'id': '0'
}
return self.rpc.send_json_rpc_request(get_alternate_chains)
def get_fee_estimate(self, grace_blocks = 0):
get_fee_estimate = {
'method': 'get_fee_estimate',
'params': {
'grace_blocks': grace_blocks,
},
'jsonrpc': '2.0',
'id': '0'
}
return self.rpc.send_json_rpc_request(get_fee_estimate)