aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--tests/README.md117
-rw-r--r--tests/unit_tests/crypto.cpp28
12 files changed, 315 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)
{
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 000000000..48a6c41a7
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,117 @@
+# Running all tests
+
+To run all tests, run:
+
+```
+cd /path/to/monero
+make [-jn] debug-test # where n is number of compiler processes
+```
+
+To test a release build, replace `debug-test` with `release-test` in the previous command.
+
+# Core tests
+
+Core tests take longer than any other Monero tests, due to the high amount of computational work involved in validating core components.
+
+Tests are located in `tests/core_tests/`, and follow a straightforward naming convention. Most cases cover core functionality (`block_reward.cpp`, `chaingen.cpp`, `rct.cpp`, etc.), while some cover basic security tests (`double_spend.cpp` & `integer_overflow.cpp`).
+
+To run only Monero's core tests (after building):
+
+```
+cd build/debug/tests/core
+ctest
+```
+
+To run the same tests on a release build, replace `debug` with `release`.
+
+
+# Crypto Tests
+
+Crypto tests are located under the `tests/crypto` directory.
+
+- `crypto-tests.h` contains test harness headers
+- `main.cpp` implements the driver for the crypto tests
+
+Tests correspond to components under `src/crypto/`. A quick comparison reveals the pattern, and new tests should continue the naming convention.
+
+To run only Monero's crypto tests (after building):
+
+```
+cd build/debug/tests/crypto
+ctest
+```
+
+To run the same tests on a release build, replace `debug` with `release`.
+
+# Daemon tests
+
+[TODO]
+
+# Functional tests
+
+[TODO]
+
+# Fuzz tests
+
+Fuzz tests are written using American Fuzzy Lop (AFL), and located under the `tests/fuzz` directory.
+
+An additional helper utility is provided `contrib/fuzz_testing/fuzz.sh`. AFL must be installed, and some additional setup may be necessary for the script to run properly.
+
+# Hash tests
+
+Hash tests exist under `tests/hash`, and include a set of target hashes in text files.
+
+To run only Monero's hash tests (after building):
+
+```
+cd build/debug/tests/hash
+ctest
+```
+
+To run the same tests on a release build, replace `debug` with `release`.
+
+# Libwallet API tests
+
+[TODO]
+
+# Net Load tests
+
+[TODO]
+
+# Performance tests
+
+Performance tests are located in `tests/performance_tests`, and test features for performance metrics on the host machine.
+
+To run only Monero's performance tests (after building):
+
+```
+cd build/debug/tests/performance_tests
+./performance_tests
+```
+
+If the `performance_tests` binary does not exist, try running `make` in the `build/debug/tests/performance_tests` directory.
+
+To run the same tests on a release build, replace `debug` with `release`.
+
+# Unit tests
+
+Unit tests are defined under the `tests/unit_tests` directory. Independent components are tested individually to ensure they work properly on their own.
+
+To run only Monero's unit tests (after building):
+
+```
+cd build/debug/tests/unit_tests
+ctest
+```
+
+To run the same tests on a release build, replace `debug` with `release`.
+
+# Writing new tests
+
+## Test hygiene
+
+When writing new tests, please implement all functions in `.cpp` or `.c` files, and only put function headers in `.h` files. This will help keep the fairly complex test suites somewhat sane going forward.
+
+## Writing fuzz tests
+
+[TODO]
diff --git a/tests/unit_tests/crypto.cpp b/tests/unit_tests/crypto.cpp
index 3a8e787ec..51e26c2bb 100644
--- a/tests/unit_tests/crypto.cpp
+++ b/tests/unit_tests/crypto.cpp
@@ -47,6 +47,14 @@ namespace
"8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"
"6c7251d54154cfa92c173a0dd39c1f948b655970153799af2aeadc9ff1add0ea";
+ static std::uint8_t md[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
template<typename T>
bool is_formatted()
{
@@ -61,6 +69,26 @@ namespace
out << "BEGIN" << value << "END";
return out.str() == "BEGIN<" + std::string{expected, sizeof(T) * 2} + ">END";
}
+
+ bool keccak_harness()
+ {
+ size_t inlen = sizeof(source);
+ int mdlen = (int)sizeof(md);
+ int ret = keccak(source, inlen, md, mdlen);
+
+ if (md[0] != 0x00)
+ {
+ return true;
+ }
+ else if (!ret)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
}
TEST(Crypto, Ostream)