aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/daemon/command_parser_executor.cpp19
-rw-r--r--src/daemon/command_server.cpp2
-rw-r--r--src/daemon/rpc_command_executor.cpp42
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/rpc/message.cpp53
-rw-r--r--src/simplewallet/simplewallet.cpp36
-rw-r--r--src/wallet/api/wallet.cpp22
-rw-r--r--src/wallet/wallet2.cpp13
-rw-r--r--src/wallet/wallet2.h4
-rw-r--r--src/wallet/wallet_errors.h35
10 files changed, 170 insertions, 58 deletions
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index c85e5edb5..5307b2472 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -187,9 +187,24 @@ bool t_command_parser_executor::print_block(const std::vector<std::string>& args
bool t_command_parser_executor::print_transaction(const std::vector<std::string>& args)
{
+ bool include_hex = false;
+ bool include_json = false;
+
+ // Assumes that optional flags come after mandatory argument <transaction_hash>
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "+hex")
+ include_hex = true;
+ else if (args[i] == "+json")
+ include_json = true;
+ else
+ {
+ std::cout << "unexpected argument: " << args[i] << std::endl;
+ return true;
+ }
+ }
if (args.empty())
{
- std::cout << "expected: print_tx <transaction hash>" << std::endl;
+ std::cout << "expected: print_tx <transaction_hash> [+hex] [+json]" << std::endl;
return true;
}
@@ -197,7 +212,7 @@ bool t_command_parser_executor::print_transaction(const std::vector<std::string>
crypto::hash tx_hash;
if (parse_hash256(str_hash, tx_hash))
{
- m_executor.print_transaction(tx_hash);
+ m_executor.print_transaction(tx_hash, include_hex, include_json);
}
return true;
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 3f1543857..b134aee61 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -91,7 +91,7 @@ t_command_server::t_command_server(
m_command_lookup.set_handler(
"print_tx"
, std::bind(&t_command_parser_executor::print_transaction, &m_parser, p::_1)
- , "Print transaction, print_tx <transaction_hash>"
+ , "Print transaction, print_tx <transaction_hash> [+hex] [+json]"
);
m_command_lookup.set_handler(
"is_key_image_spent"
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 867c523c9..2c11dcb31 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -693,7 +693,9 @@ bool t_rpc_command_executor::print_block_by_height(uint64_t height) {
return true;
}
-bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) {
+bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash,
+ bool include_hex,
+ bool include_json) {
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req;
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res;
@@ -728,30 +730,34 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) {
tools::success_msg_writer() << "Found in blockchain at height " << res.txs.front().block_height;
}
- // first as hex
const std::string &as_hex = (1 == res.txs.size()) ? res.txs.front().as_hex : res.txs_as_hex.front();
- tools::success_msg_writer() << as_hex;
+ // Print raw hex if requested
+ if (include_hex)
+ tools::success_msg_writer() << as_hex << std::endl;
- // then as json
- crypto::hash tx_hash, tx_prefix_hash;
- cryptonote::transaction tx;
- cryptonote::blobdata blob;
- if (!string_tools::parse_hexstr_to_binbuff(as_hex, blob))
- {
- tools::fail_msg_writer() << "Failed to parse tx";
- }
- else if (!cryptonote::parse_and_validate_tx_from_blob(blob, tx, tx_hash, tx_prefix_hash))
+ // Print json if requested
+ if (include_json)
{
- tools::fail_msg_writer() << "Failed to parse tx blob";
- }
- else
- {
- tools::success_msg_writer() << cryptonote::obj_to_json_str(tx) << std::endl;
+ crypto::hash tx_hash, tx_prefix_hash;
+ cryptonote::transaction tx;
+ cryptonote::blobdata blob;
+ if (!string_tools::parse_hexstr_to_binbuff(as_hex, blob))
+ {
+ tools::fail_msg_writer() << "Failed to parse tx to get json format";
+ }
+ else if (!cryptonote::parse_and_validate_tx_from_blob(blob, tx, tx_hash, tx_prefix_hash))
+ {
+ tools::fail_msg_writer() << "Failed to parse tx blob to get json format";
+ }
+ else
+ {
+ tools::success_msg_writer() << cryptonote::obj_to_json_str(tx) << std::endl;
+ }
}
}
else
{
- tools::fail_msg_writer() << "transaction wasn't found: " << transaction_hash << std::endl;
+ tools::fail_msg_writer() << "Transaction wasn't found: " << transaction_hash << std::endl;
}
return true;
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index c9d0ac671..efe1ae56a 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -95,7 +95,7 @@ public:
bool print_block_by_height(uint64_t height);
- bool print_transaction(crypto::hash transaction_hash);
+ bool print_transaction(crypto::hash transaction_hash, bool include_hex, bool include_json);
bool is_key_image_spent(const crypto::key_image &ki);
diff --git a/src/rpc/message.cpp b/src/rpc/message.cpp
index 086820180..d6da124d1 100644
--- a/src/rpc/message.cpp
+++ b/src/rpc/message.cpp
@@ -45,6 +45,15 @@ const char* Message::STATUS_FAILED = "Failed";
const char* Message::STATUS_BAD_REQUEST = "Invalid request type";
const char* Message::STATUS_BAD_JSON = "Malformed json";
+namespace
+{
+constexpr const char error_field[] = "error";
+constexpr const char id_field[] = "id";
+constexpr const char method_field[] = "method";
+constexpr const char params_field[] = "params";
+constexpr const char result_field[] = "result";
+}
+
rapidjson::Value Message::toJson(rapidjson::Document& doc) const
{
rapidjson::Value val(rapidjson::kObjectType);
@@ -70,8 +79,8 @@ FullMessage::FullMessage(const std::string& request, Message* message)
{
doc.SetObject();
- doc.AddMember("method", rapidjson::StringRef(request.c_str()), doc.GetAllocator());
- doc.AddMember("params", message->toJson(doc), doc.GetAllocator());
+ doc.AddMember(method_field, rapidjson::StringRef(request.c_str()), doc.GetAllocator());
+ doc.AddMember(params_field, message->toJson(doc), doc.GetAllocator());
// required by JSON-RPC 2.0 spec
doc.AddMember("jsonrpc", rapidjson::Value("2.0"), doc.GetAllocator());
@@ -86,7 +95,7 @@ FullMessage::FullMessage(Message* message)
if (message->status == Message::STATUS_OK)
{
- doc.AddMember("response", message->toJson(doc), doc.GetAllocator());
+ doc.AddMember(result_field, message->toJson(doc), doc.GetAllocator());
}
else
{
@@ -111,14 +120,14 @@ FullMessage::FullMessage(const std::string& json_string, bool request)
if (request)
{
- OBJECT_HAS_MEMBER_OR_THROW(doc, "method")
- OBJECT_HAS_MEMBER_OR_THROW(doc, "params")
+ OBJECT_HAS_MEMBER_OR_THROW(doc, method_field)
+ OBJECT_HAS_MEMBER_OR_THROW(doc, params_field)
}
else
{
- if (!doc.HasMember("response") && !doc.HasMember("error"))
+ if (!doc.HasMember(result_field) && !doc.HasMember(error_field))
{
- throw cryptonote::json::MISSING_KEY("error/response");
+ throw cryptonote::json::MISSING_KEY("error/result");
}
}
}
@@ -126,9 +135,9 @@ FullMessage::FullMessage(const std::string& json_string, bool request)
std::string FullMessage::getJson()
{
- if (!doc.HasMember("id"))
+ if (!doc.HasMember(id_field))
{
- doc.AddMember("id", rapidjson::Value("unused"), doc.GetAllocator());
+ doc.AddMember(id_field, rapidjson::Value("unused"), doc.GetAllocator());
}
rapidjson::StringBuffer buf;
@@ -142,24 +151,24 @@ std::string FullMessage::getJson()
std::string FullMessage::getRequestType() const
{
- OBJECT_HAS_MEMBER_OR_THROW(doc, "method")
- return doc["method"].GetString();
+ OBJECT_HAS_MEMBER_OR_THROW(doc, method_field)
+ return doc[method_field].GetString();
}
rapidjson::Value& FullMessage::getMessage()
{
- if (doc.HasMember("params"))
+ if (doc.HasMember(params_field))
{
- return doc["params"];
+ return doc[params_field];
}
- else if (doc.HasMember("response"))
+ else if (doc.HasMember(result_field))
{
- return doc["response"];
+ return doc[result_field];
}
//else
- OBJECT_HAS_MEMBER_OR_THROW(doc, "error")
- return doc["error"];
+ OBJECT_HAS_MEMBER_OR_THROW(doc, error_field)
+ return doc[error_field];
}
@@ -172,20 +181,20 @@ rapidjson::Value FullMessage::getMessageCopy()
rapidjson::Value& FullMessage::getID()
{
- OBJECT_HAS_MEMBER_OR_THROW(doc, "id")
- return doc["id"];
+ OBJECT_HAS_MEMBER_OR_THROW(doc, id_field)
+ return doc[id_field];
}
void FullMessage::setID(rapidjson::Value& id)
{
- auto itr = doc.FindMember("id");
+ auto itr = doc.FindMember(id_field);
if (itr != doc.MemberEnd())
{
itr->value = id;
}
else
{
- doc.AddMember("id", id, doc.GetAllocator());
+ doc.AddMember(id_field, id, doc.GetAllocator());
}
}
@@ -193,7 +202,7 @@ cryptonote::rpc::error FullMessage::getError()
{
cryptonote::rpc::error err;
err.use = false;
- if (doc.HasMember("error"))
+ if (doc.HasMember(error_field))
{
GET_FROM_JSON_OBJECT(doc, err, error);
err.use = true;
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index aac9c69f0..85e2c8cf1 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -2825,13 +2825,20 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
{
fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
- catch (const tools::error::not_enough_money& e)
+ catch (const tools::error::not_enough_unlocked_money& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") %
print_money(e.available()) %
print_money(e.tx_amount()));
fail_msg_writer() << tr("Not enough money in unlocked balance");
}
+ catch (const tools::error::not_enough_money& e)
+ {
+ LOG_PRINT_L0(boost::format("not enough money to transfer, overall balance only %s, sent amount %s") %
+ print_money(e.available()) %
+ print_money(e.tx_amount()));
+ fail_msg_writer() << tr("Not enough money in overall balance");
+ }
catch (const tools::error::tx_not_possible& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") %
@@ -2997,13 +3004,20 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
{
fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
- catch (const tools::error::not_enough_money& e)
+ catch (const tools::error::not_enough_unlocked_money& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") %
print_money(e.available()) %
print_money(e.tx_amount()));
fail_msg_writer() << tr("Not enough money in unlocked balance");
}
+ catch (const tools::error::not_enough_money& e)
+ {
+ LOG_PRINT_L0(boost::format("not enough money to transfer, overall balance only %s, sent amount %s") %
+ print_money(e.available()) %
+ print_money(e.tx_amount()));
+ fail_msg_writer() << tr("Not enough money in overall balance");
+ }
catch (const tools::error::tx_not_possible& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") %
@@ -3281,13 +3295,20 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
{
fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
- catch (const tools::error::not_enough_money& e)
+ catch (const tools::error::not_enough_unlocked_money& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") %
print_money(e.available()) %
print_money(e.tx_amount()));
fail_msg_writer() << tr("Not enough money in unlocked balance");
}
+ catch (const tools::error::not_enough_money& e)
+ {
+ LOG_PRINT_L0(boost::format("not enough money to transfer, overall balance only %s, sent amount %s") %
+ print_money(e.available()) %
+ print_money(e.tx_amount()));
+ fail_msg_writer() << tr("Not enough money in overall balance");
+ }
catch (const tools::error::tx_not_possible& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") %
@@ -3631,13 +3652,20 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_)
{
fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
- catch (const tools::error::not_enough_money& e)
+ catch (const tools::error::not_enough_unlocked_money& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") %
print_money(e.available()) %
print_money(e.tx_amount()));
fail_msg_writer() << tr("Not enough money in unlocked balance");
}
+ catch (const tools::error::not_enough_money& e)
+ {
+ LOG_PRINT_L0(boost::format("not enough money to transfer, overall balance only %s, sent amount %s") %
+ print_money(e.available()) %
+ print_money(e.tx_amount()));
+ fail_msg_writer() << tr("Not enough money in overall balance");
+ }
catch (const tools::error::tx_not_possible& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") %
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 8f7befc8c..8e747d16b 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1146,7 +1146,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
m_errorString = (boost::format(tr("failed to get random outputs to mix: %s")) % e.what()).str();
m_status = Status_Error;
- } catch (const tools::error::not_enough_money& e) {
+ } catch (const tools::error::not_enough_unlocked_money& e) {
m_status = Status_Error;
std::ostringstream writer;
@@ -1155,6 +1155,15 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
print_money(e.tx_amount());
m_errorString = writer.str();
+ } catch (const tools::error::not_enough_money& e) {
+ m_status = Status_Error;
+ std::ostringstream writer;
+
+ writer << boost::format(tr("not enough money to transfer, overall balance only %s, sent amount %s")) %
+ print_money(e.available()) %
+ print_money(e.tx_amount());
+ m_errorString = writer.str();
+
} catch (const tools::error::tx_not_possible& e) {
m_status = Status_Error;
std::ostringstream writer;
@@ -1240,7 +1249,7 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
m_errorString = tr("failed to get random outputs to mix");
m_status = Status_Error;
- } catch (const tools::error::not_enough_money& e) {
+ } catch (const tools::error::not_enough_unlocked_money& e) {
m_status = Status_Error;
std::ostringstream writer;
@@ -1249,6 +1258,15 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
print_money(e.tx_amount());
m_errorString = writer.str();
+ } catch (const tools::error::not_enough_money& e) {
+ m_status = Status_Error;
+ std::ostringstream writer;
+
+ writer << boost::format(tr("not enough money to transfer, overall balance only %s, sent amount %s")) %
+ print_money(e.available()) %
+ print_money(e.tx_amount());
+ m_errorString = writer.str();
+
} catch (const tools::error::tx_not_possible& e) {
m_status = Status_Error;
std::ostringstream writer;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 22afac7b7..adbe267eb 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -4441,7 +4441,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
}
LOG_PRINT_L2("wanted " << print_money(needed_money) << ", found " << print_money(found_money) << ", fee " << print_money(fee));
- THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
+ THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee);
uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major;
for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i)
@@ -4598,7 +4598,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
}
LOG_PRINT_L2("wanted " << print_money(needed_money) << ", found " << print_money(found_money) << ", fee " << print_money(fee));
- THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
+ THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee);
uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major;
for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i)
@@ -5475,6 +5475,15 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
}
+ // early out if we know we can't make it anyway
+ // we could also check for being within FEE_PER_KB, but if the fee calculation
+ // ever changes, this might be missed, so let this go through
+ // first check overall balance is enough, then unlocked one, so we throw distinct exceptions
+ THROW_WALLET_EXCEPTION_IF(needed_money > balance(), error::not_enough_money,
+ unlocked_balance(), needed_money, 0);
+ THROW_WALLET_EXCEPTION_IF(needed_money > unlocked_balance(), error::not_enough_unlocked_money,
+ unlocked_balance(), needed_money, 0);
+
// shuffle & sort output indices
{
std::random_device rd;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 746255fa9..9178d18ad 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -1264,10 +1264,10 @@ namespace tools
}
// randomly select inputs for transaction
- // throw if requested send amount is greater than amount available to send
+ // throw if requested send amount is greater than (unlocked) amount available to send
std::list<size_t> selected_transfers;
uint64_t found_money = select_transfers(needed_money, unused_transfers_indices, selected_transfers, trusted_daemon);
- THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
+ THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee);
uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major;
for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i)
diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h
index d1f4a796d..9d66f125e 100644
--- a/src/wallet/wallet_errors.h
+++ b/src/wallet/wallet_errors.h
@@ -68,6 +68,7 @@ namespace tools
// get_tx_pool_error
// transfer_error *
// get_random_outs_general_error
+ // not_enough_unlocked_money
// not_enough_money
// tx_not_possible
// not_enough_outs_to_mix
@@ -356,11 +357,37 @@ namespace tools
//----------------------------------------------------------------------------------------------------
typedef failed_rpc_request<transfer_error, get_random_outs_error_message_index> get_random_outs_error;
//----------------------------------------------------------------------------------------------------
+ struct not_enough_unlocked_money : public transfer_error
+ {
+ explicit not_enough_unlocked_money(std::string&& loc, uint64_t available, uint64_t tx_amount, uint64_t fee)
+ : transfer_error(std::move(loc), "not enough unlocked money")
+ , m_available(available)
+ , m_tx_amount(tx_amount)
+ {
+ }
+
+ uint64_t available() const { return m_available; }
+ uint64_t tx_amount() const { return m_tx_amount; }
+
+ std::string to_string() const
+ {
+ std::ostringstream ss;
+ ss << transfer_error::to_string() <<
+ ", available = " << cryptonote::print_money(m_available) <<
+ ", tx_amount = " << cryptonote::print_money(m_tx_amount);
+ return ss.str();
+ }
+
+ private:
+ uint64_t m_available;
+ uint64_t m_tx_amount;
+ };
+ //----------------------------------------------------------------------------------------------------
struct not_enough_money : public transfer_error
{
- explicit not_enough_money(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee)
+ explicit not_enough_money(std::string&& loc, uint64_t available, uint64_t tx_amount, uint64_t fee)
: transfer_error(std::move(loc), "not enough money")
- , m_available(availbable)
+ , m_available(available)
, m_tx_amount(tx_amount)
{
}
@@ -384,9 +411,9 @@ namespace tools
//----------------------------------------------------------------------------------------------------
struct tx_not_possible : public transfer_error
{
- explicit tx_not_possible(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee)
+ explicit tx_not_possible(std::string&& loc, uint64_t available, uint64_t tx_amount, uint64_t fee)
: transfer_error(std::move(loc), "tx not possible")
- , m_available(availbable)
+ , m_available(available)
, m_tx_amount(tx_amount)
, m_fee(fee)
{