diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/daemon/command_parser_executor.cpp | 19 | ||||
-rw-r--r-- | src/daemon/command_server.cpp | 2 | ||||
-rw-r--r-- | src/daemon/rpc_command_executor.cpp | 42 | ||||
-rw-r--r-- | src/daemon/rpc_command_executor.h | 2 | ||||
-rw-r--r-- | src/rpc/message.cpp | 53 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 36 | ||||
-rw-r--r-- | src/wallet/api/wallet.cpp | 22 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 13 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 4 | ||||
-rw-r--r-- | src/wallet/wallet_errors.h | 35 |
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) { |