From 887539203c708030fc23f6e5754711b3f187ce80 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Thu, 6 Aug 2020 14:19:29 +0200 Subject: [PATCH 01/36] Remove one DB implementation for tests as there is already one --- tests/unit_tests/hardfork.cpp | 147 +----------- tests/unit_tests/safex_commands.cpp | 322 +-------------------------- tests/unit_tests/safex_test_common.h | 149 +++++++++++++ 3 files changed, 152 insertions(+), 466 deletions(-) diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index b976119c9..26797d242 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -35,6 +35,7 @@ #include "blockchain_db/blockchain_db.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_basic/hardfork.h" +#include "safex_test_common.h" using namespace cryptonote; @@ -42,152 +43,6 @@ using namespace cryptonote; #define SECONDS_PER_YEAR 31557600 -class TestDB: public BlockchainDB { -public: - TestDB() {}; - virtual void open(const std::string& filename, const int db_flags = 0) { } - virtual void close() {} - virtual void sync() {} - virtual void safesyncmode(const bool onoff) {} - virtual void reset() {} - virtual std::vector get_filenames() const { return std::vector(); } - virtual std::string get_db_name() const { return std::string(); } - virtual bool lock() { return true; } - virtual void unlock() { } - virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) { return true; } - virtual void batch_stop() {} - virtual void batch_abort() {} - virtual void set_batch_transactions(bool) {} - virtual void block_txn_start(bool readonly=false) {} - virtual void block_txn_stop() {} - virtual void block_txn_abort() {} - virtual void drop_hard_fork_info() {} - virtual bool block_exists(const crypto::hash& h, uint64_t *height) const { return false; } - virtual blobdata get_block_blob_from_height(const uint64_t& height) const { return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); } - virtual blobdata get_block_blob(const crypto::hash& h) const { return blobdata(); } - virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const { return false; } - virtual uint64_t get_block_height(const crypto::hash& h) const { return 0; } - virtual block_header get_block_header(const crypto::hash& h) const { return block_header(); } - virtual uint64_t get_block_timestamp(const uint64_t& height) const { return 0; } - virtual uint64_t get_top_block_timestamp() const { return 0; } - virtual size_t get_block_size(const uint64_t& height) const { return 128; } - virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const { return 10; } - virtual difficulty_type get_block_difficulty(const uint64_t& height) const { return 0; } - virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const { return 10000000000; } - virtual uint64_t get_block_already_migrated_tokens(const uint64_t& height) const { return 10000000000; } - virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const { return crypto::hash(); } - virtual std::vector get_blocks_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector(); } - virtual std::vector get_hashes_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector(); } - virtual crypto::hash top_block_hash() const { return crypto::hash(); } - virtual block get_top_block() const { return block(); } - virtual uint64_t height() const { return blocks.size(); } - virtual bool tx_exists(const crypto::hash& h) const { return false; } - virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const { return false; } - virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const { return 0; } - virtual transaction get_tx(const crypto::hash& h) const { return transaction(); } - virtual bool get_tx(const crypto::hash& h, transaction &tx) const { return false; } - virtual uint64_t get_tx_count() const { return 0; } - virtual std::vector get_tx_list(const std::vector& hlist) const { return std::vector(); } - virtual uint64_t get_tx_block_height(const crypto::hash& h) const { return 0; } - virtual uint64_t get_num_outputs(const uint64_t& amount, const tx_out_type output_type) const { return 1; } - virtual uint64_t get_num_outputs(const tx_out_type output_type) const {return 1;} - virtual uint64_t get_indexing_base() const { return 0; } - virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const { return output_data_t(); } - virtual output_advanced_data_t get_output_advanced_data(const tx_out_type output_type, const uint64_t output_index) const { return output_advanced_data_t{}; } - virtual bool get_output_id(const tx_out_type output_type, const uint64_t output_index, uint64_t& output_id) const { return 0; } - virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const { return tx_out_index(); } - virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const { return tx_out_index(); } - virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices, const tx_out_type output_type) const {} - virtual void get_amount_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs, const tx_out_type output_type, bool allow_partial = false) const {} - virtual void get_advanced_output_key(const std::vector &output_indexes, std::vector &outputs, const tx_out_type output_type, bool allow_partial = false) const {} - virtual bool can_thread_bulk_indices() const { return false; } - virtual std::vector get_tx_output_indices(const crypto::hash& h) const { return std::vector(); } - virtual std::vector get_tx_amount_output_indices(const uint64_t tx_index) const { return std::vector(); } - virtual bool has_key_image(const crypto::key_image& img) const { return false; } - virtual void remove_block() { blocks.pop_back(); } - virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) {return 0;} - virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) {} - virtual void remove_unstake_token(const crypto::hash& tx_hash, const transaction& tx) {} - virtual uint64_t add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) {return 0;} - virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector& amount_output_indices) {} - virtual void add_spent_key(const crypto::key_image& k_image) {} - virtual void remove_spent_key(const crypto::key_image& k_image) {} - virtual void process_command_input(const cryptonote::txin_to_script &txin) {} - virtual uint64_t update_staked_token_sum_for_interval(const uint64_t interval_starting_block, const int64_t delta){return 0;} - virtual uint64_t update_staked_token_for_interval(const uint64_t interval, const uint64_t new_staked_tokens_in_interval) { return 0;} - virtual bool remove_staked_token_for_interval(const uint64_t interval){return true;}; - virtual uint64_t update_network_fee_sum_for_interval(const uint64_t interval_starting_block, const uint64_t collected_fee){return 0;} - virtual bool get_account_key(const safex::account_username &username, crypto::public_key &pkey) const { return true;} - virtual bool get_account_data(const safex::account_username &username, std::vector &data) const { return true;} - virtual bool get_offer(const crypto::hash offer_id, safex::safex_offer &offer) const { return true;} - virtual bool get_offer_seller(const crypto::hash offer_id, std::string &username) const { return true; }; - virtual bool get_offer_price(const crypto::hash offer_id, uint64_t &price) const { return true; }; - virtual bool get_offer_quantity(const crypto::hash offer_id, uint64_t &quantity) const { return true; }; - virtual bool get_offer_active_status(const crypto::hash offer_id, bool &active) const { return true; }; - virtual bool get_safex_accounts(std::vector> &accounts) const { return true; }; - virtual bool get_safex_offers(std::vector &offers) const { return true; }; - virtual bool get_safex_offer_height( crypto::hash &offer_id, uint64_t& height) const { return true; }; - virtual bool get_offer_stars_given(const crypto::hash offer_id, uint64_t &stars_received) const { return true; }; - virtual bool get_safex_feedbacks( std::vector &safex_feedbacks, const crypto::hash& offer_id) const { return true; }; - virtual bool get_safex_price_pegs( std::vector &safex_price_pegs, const std::string& currency) const { return true; }; - virtual bool get_safex_price_peg( const crypto::hash& price_peg_id,safex::safex_price_peg &safex_price_peg) const { return true; }; - - virtual bool get_table_sizes( std::vector &table_sizes) const { return true; }; - - - virtual bool for_all_key_images(std::function) const { return true; } - virtual bool for_blocks_range(const uint64_t&, const uint64_t&, std::function) const { return true; } - virtual bool for_all_transactions(std::function) const { return true; } - virtual bool for_all_outputs(std::function f, const tx_out_type output_type) const { return true; } - virtual bool for_all_outputs(uint64_t amount, const std::function &f, const tx_out_type output_type) const { return true; } - virtual bool for_all_advanced_outputs(std::function f, const tx_out_type output_type) const { return true;} - virtual bool is_read_only() const { return false; } - virtual std::map> get_output_histogram(const std::vector &amounts, bool unlocked, uint64_t recent_cutoff, const tx_out_type output_type) const { return std::map>(); } - - virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t& details) {} - virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& details) {} - virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const { return 0; } - virtual bool txpool_has_tx(const crypto::hash &txid) const { return false; } - virtual void remove_txpool_tx(const crypto::hash& txid) {} - virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const { return false; } - virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const { return false; } - virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const { return ""; } - virtual bool for_all_txpool_txes(std::function, bool include_blob = false, bool include_unrelayed_txes = false) const { return false; } - - virtual uint64_t get_current_staked_token_sum() const { return 0;} - virtual uint64_t get_staked_token_sum_for_interval(const uint64_t interval_starting_block) const override { return 0;}; - virtual uint64_t get_network_fee_sum_for_interval(const uint64_t interval) const override {return 0;} - virtual std::vector get_token_stake_expiry_outputs(const uint64_t block_height) const override {return std::vector{};} - virtual bool get_interval_interest_map(const uint64_t start_height, const uint64_t end_height, safex::map_interval_interest &map) const override {return true;} - virtual uint64_t calculate_staked_token_interest_for_output(const txin_to_script &txin, const uint64_t unlock_height) const override { return 0; } - - virtual void add_block( const block& blk - , const size_t& block_size - , const difficulty_type& cumulative_difficulty - , const uint64_t& coins_generated - , const uint64_t& tokens_migrated - , const crypto::hash& blk_hash - ) { - blocks.push_back(blk); - } - virtual block get_block_from_height(const uint64_t& height) const { - return blocks.at(height); - } - virtual void set_hard_fork_version(uint64_t height, uint8_t version) { - if (versions.size() <= height) - versions.resize(height+1); - versions[height] = version; - } - virtual uint8_t get_hard_fork_version(uint64_t height) const { - return versions.at(height); - } - virtual void check_hard_fork_info() {} - -private: - std::vector blocks; - std::deque versions; -}; - static cryptonote::block mkblock(uint8_t version, uint8_t vote) { cryptonote::block b; diff --git a/tests/unit_tests/safex_commands.cpp b/tests/unit_tests/safex_commands.cpp index 72dea63e1..f7d9d026a 100644 --- a/tests/unit_tests/safex_commands.cpp +++ b/tests/unit_tests/safex_commands.cpp @@ -36,329 +36,11 @@ #include "blockchain_db/blockchain_db.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_basic/hardfork.h" +#include "safex_test_common.h" using namespace safex; - -class TestBlockchainDB : public cryptonote::BlockchainDB -{ - public: - TestBlockchainDB() - {}; - - virtual void open(const std::string &filename, const int db_flags = 0) - {} - - virtual void close() - {} - - virtual void sync() - {} - - virtual void safesyncmode(const bool onoff) - {} - - virtual void reset() - {} - - virtual std::vector get_filenames() const - { return std::vector(); } - - virtual std::string get_db_name() const - { return std::string(); } - - virtual bool lock() - { return true; } - - virtual void unlock() - {} - - virtual bool batch_start(uint64_t batch_num_blocks = 0, uint64_t batch_bytes = 0) - { return true; } - - virtual void batch_stop() - {} - - virtual void batch_abort() - {} - - virtual void set_batch_transactions(bool) - {} - - virtual void block_txn_start(bool readonly = false) - {} - - virtual void block_txn_stop() - {} - - virtual void block_txn_abort() - {} - - virtual void drop_hard_fork_info() - {} - - virtual bool block_exists(const crypto::hash &h, uint64_t *height) const - { return false; } - - virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t &height) const - { return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); } - - virtual cryptonote::blobdata get_block_blob(const crypto::hash &h) const - { return cryptonote::blobdata(); } - - virtual bool get_tx_blob(const crypto::hash &h, cryptonote::blobdata &tx) const - { return false; } - - virtual uint64_t get_block_height(const crypto::hash &h) const - { return 0; } - - virtual cryptonote::block_header get_block_header(const crypto::hash &h) const - { return cryptonote::block_header(); } - - virtual uint64_t get_block_timestamp(const uint64_t &height) const - { return 0; } - - virtual uint64_t get_top_block_timestamp() const - { return 0; } - - virtual size_t get_block_size(const uint64_t &height) const - { return 128; } - - virtual cryptonote::difficulty_type get_block_cumulative_difficulty(const uint64_t &height) const - { return 10; } - - virtual cryptonote::difficulty_type get_block_difficulty(const uint64_t &height) const - { return 0; } - - virtual uint64_t get_block_already_generated_coins(const uint64_t &height) const - { return 10000000000; } - - virtual uint64_t get_block_already_migrated_tokens(const uint64_t &height) const - { return 10000000000; } - - virtual crypto::hash get_block_hash_from_height(const uint64_t &height) const - { return crypto::hash(); } - - virtual std::vector get_blocks_range(const uint64_t &h1, const uint64_t &h2) const - { return std::vector(); } - - virtual std::vector get_hashes_range(const uint64_t &h1, const uint64_t &h2) const - { return std::vector(); } - - virtual crypto::hash top_block_hash() const - { return crypto::hash(); } - - virtual cryptonote::block get_top_block() const - { return cryptonote::block(); } - - virtual uint64_t height() const - { return blocks.size(); } - - virtual bool tx_exists(const crypto::hash &h) const - { return false; } - - virtual bool tx_exists(const crypto::hash &h, uint64_t &tx_index) const - { return false; } - - virtual uint64_t get_tx_unlock_time(const crypto::hash &h) const - { return 0; } - - virtual cryptonote::transaction get_tx(const crypto::hash &h) const - { return cryptonote::transaction(); } - - virtual bool get_tx(const crypto::hash &h, cryptonote::transaction &tx) const - { return false; } - - virtual uint64_t get_tx_count() const - { return 0; } - - virtual std::vector get_tx_list(const std::vector &hlist) const - { return std::vector(); } - - virtual uint64_t get_tx_block_height(const crypto::hash &h) const - { return 0; } - - virtual uint64_t get_num_outputs(const uint64_t &amount, const cryptonote::tx_out_type output_type) const - { return 1; } - - virtual uint64_t get_num_outputs(const cryptonote::tx_out_type output_type) const {return 1;} - - virtual uint64_t get_indexing_base() const - { return 0; } - - virtual cryptonote::output_data_t get_output_key(const uint64_t &amount, const uint64_t &index, const cryptonote::tx_out_type output_type) const - { return cryptonote::output_data_t(); } - - virtual cryptonote::output_advanced_data_t get_output_advanced_data(const cryptonote::tx_out_type output_type, const uint64_t output_id) const {return cryptonote::output_advanced_data_t{};} - virtual bool get_output_id(const cryptonote::tx_out_type output_type, const uint64_t output_index, uint64_t& output_id) const { return 0; } - - virtual cryptonote::tx_out_index get_output_tx_and_index_from_global(const uint64_t &index) const - { return cryptonote::tx_out_index(); } - - virtual cryptonote::tx_out_index get_output_tx_and_index(const uint64_t &amount, const uint64_t &index, const cryptonote::tx_out_type output_type) const - { return cryptonote::tx_out_index(); } - - virtual void get_output_tx_and_index(const uint64_t &amount, const std::vector &offsets, std::vector &indices, const cryptonote::tx_out_type output_type) const - {} - - virtual void get_amount_output_key(const uint64_t &amount, const std::vector &offsets, - std::vector &outputs, - const cryptonote::tx_out_type output_type, bool allow_partial = false) const - {} - - virtual void get_advanced_output_key(const std::vector &output_indexes, std::vector &outputs, - const cryptonote::tx_out_type output_type, bool allow_partial = false) const - {} - - virtual bool can_thread_bulk_indices() const - { return false; } - - virtual std::vector get_tx_output_indices(const crypto::hash &h) const - { return std::vector(); } - - virtual std::vector get_tx_amount_output_indices(const uint64_t tx_index) const - { return std::vector(); } - - virtual bool has_key_image(const crypto::key_image &img) const - { return false; } - - virtual void remove_block() - { blocks.pop_back(); } - - virtual uint64_t add_transaction_data(const crypto::hash &blk_hash, const cryptonote::transaction &tx, const crypto::hash &tx_hash) - { return 0; } - - virtual void remove_transaction_data(const crypto::hash &tx_hash, const cryptonote::transaction &tx) - {} - - virtual void remove_unstake_token(const crypto::hash &tx_hash, const cryptonote::transaction &tx) - {} - - virtual uint64_t add_output(const crypto::hash &tx_hash, const cryptonote::tx_out &tx_output, const uint64_t &local_index, const uint64_t unlock_time, const rct::key *commitment) - { return 0; } - - virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector &amount_output_indices) - {} - - virtual void add_spent_key(const crypto::key_image &k_image) - {} - - virtual void remove_spent_key(const crypto::key_image &k_image) - {} - - virtual void process_command_input(const cryptonote::txin_to_script &txin) {} - - virtual uint64_t update_network_fee_sum_for_interval(const uint64_t interval_starting_block, const uint64_t collected_fee){return 0;} - virtual uint64_t update_staked_token_for_interval(const uint64_t interval, const uint64_t new_locked_tokens_in_interval) { return 0;} - virtual bool remove_staked_token_for_interval(const uint64_t interval){return true;}; - virtual bool for_all_key_images(std::function) const - { return true; } - - virtual bool for_blocks_range(const uint64_t &, const uint64_t &, std::function) const - { return true; } - - virtual bool for_all_transactions(std::function) const - { return true; } - - virtual bool for_all_outputs(std::function f, const cryptonote::tx_out_type output_type) const - { return true; } - - virtual bool for_all_outputs(uint64_t amount, const std::function &f, const cryptonote::tx_out_type output_type) const - { return true; } - - virtual bool for_all_advanced_outputs(std::function f, const cryptonote::tx_out_type output_type) const { return true;} - - virtual bool is_read_only() const - { return false; } - - virtual std::map> get_output_histogram(const std::vector &amounts, bool unlocked, uint64_t recent_cutoff, const cryptonote::tx_out_type output_type) const - { return std::map>(); } - - virtual void add_txpool_tx(const cryptonote::transaction &tx, const cryptonote::txpool_tx_meta_t &details) - {} - - virtual void update_txpool_tx(const crypto::hash &txid, const cryptonote::txpool_tx_meta_t &details) - {} - - virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const - { return 0; } - - virtual bool txpool_has_tx(const crypto::hash &txid) const - { return false; } - - virtual void remove_txpool_tx(const crypto::hash &txid) - {} - - virtual bool get_txpool_tx_meta(const crypto::hash &txid, cryptonote::txpool_tx_meta_t &meta) const - { return false; } - - virtual bool get_txpool_tx_blob(const crypto::hash &txid, cryptonote::blobdata &bd) const - { return false; } - - virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash &txid) const - { return ""; } - - virtual bool for_all_txpool_txes(std::function, bool include_blob = false, bool include_unrelayed_txes = false) const - { return false; } - - virtual uint64_t get_current_staked_token_sum() const override { return 0;} - virtual uint64_t get_staked_token_sum_for_interval(const uint64_t interval) const override { return 0;}; - virtual uint64_t get_network_fee_sum_for_interval(const uint64_t interval) const override {return 0;} - virtual std::vector get_token_stake_expiry_outputs(const uint64_t block_height) const override {return std::vector{};} - virtual bool get_interval_interest_map(const uint64_t start_height, const uint64_t end_height, safex::map_interval_interest &map) const override {return true;} - virtual uint64_t calculate_staked_token_interest_for_output(const cryptonote::txin_to_script &txin, const uint64_t unlock_height) const override { return 0; }; - virtual bool get_account_key(const safex::account_username &username, crypto::public_key &pkey) const { return true;} - virtual bool get_account_data(const safex::account_username &username, std::vector &data) const { return true;} - virtual bool get_offer(const crypto::hash offer_id, safex::safex_offer &offer) const { return true;} - virtual bool get_offer_seller(const crypto::hash offer_id, std::string &username) const { return true;} - virtual bool get_offer_price(const crypto::hash offer_id, uint64_t &price) const { return true; } - virtual bool get_offer_quantity(const crypto::hash offer_id, uint64_t &quantity) const { return true; } - virtual bool get_offer_active_status(const crypto::hash offer_id, bool &active) const { return true; } - - virtual bool get_safex_accounts(std::vector> &accounts) const { return true; }; - virtual bool get_safex_offers(std::vector &offers) const { return true; }; - virtual bool get_safex_offer_height( crypto::hash &offer_id, uint64_t& height) const { return true; }; - virtual bool get_offer_stars_given(const crypto::hash offer_id, uint64_t &stars_received) const { return true; }; - virtual bool get_safex_feedbacks( std::vector &safex_feedbacks, const crypto::hash& offer_id) const { return true; }; - virtual bool get_safex_price_pegs( std::vector &safex_price_pegs, const std::string& currency) const { return true; }; - virtual bool get_safex_price_peg( const crypto::hash& price_peg_id,safex::safex_price_peg &safex_price_peg) const { return true; }; - - virtual bool get_table_sizes( std::vector &table_sizes) const { return true; }; - - - virtual void add_block(const cryptonote::block &blk, const size_t &block_size, const cryptonote::difficulty_type &cumulative_difficulty, - const uint64_t &coins_generated, const uint64_t &tokens_migrated, const crypto::hash &blk_hash) - { - blocks.push_back(blk); - } - - virtual cryptonote::block get_block_from_height(const uint64_t &height) const - { - return blocks.at(height); - } - - virtual void set_hard_fork_version(uint64_t height, uint8_t version) - { - if (versions.size() <= height) - versions.resize(height + 1); - versions[height] = version; - } - - virtual uint8_t get_hard_fork_version(uint64_t height) const - { - return versions.at(height); - } - - virtual void check_hard_fork_info() - {} - - private: - std::vector blocks; - std::deque versions; -}; - - TEST(SafexCommandParsing, HandlesTokenLock) { @@ -449,7 +131,7 @@ namespace } protected: std::vector keys; - TestBlockchainDB db; + TestDB db; }; } diff --git a/tests/unit_tests/safex_test_common.h b/tests/unit_tests/safex_test_common.h index 04b62a212..d968195d0 100644 --- a/tests/unit_tests/safex_test_common.h +++ b/tests/unit_tests/safex_test_common.h @@ -14,6 +14,155 @@ #include "safex/safex_purchase.h" #include "safex/safex_feedback.h" +using namespace cryptonote; + +class TestDB: public BlockchainDB { +public: + TestDB() {}; + virtual void open(const std::string& filename, const int db_flags = 0) { } + virtual void close() {} + virtual void sync() {} + virtual void safesyncmode(const bool onoff) {} + virtual void reset() {} + virtual std::vector get_filenames() const { return std::vector(); } + virtual std::string get_db_name() const { return std::string(); } + virtual bool lock() { return true; } + virtual void unlock() { } + virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) { return true; } + virtual void batch_stop() {} + virtual void batch_abort() {} + virtual void set_batch_transactions(bool) {} + virtual void block_txn_start(bool readonly=false) {} + virtual void block_txn_stop() {} + virtual void block_txn_abort() {} + virtual void drop_hard_fork_info() {} + virtual bool block_exists(const crypto::hash& h, uint64_t *height) const { return false; } + virtual blobdata get_block_blob_from_height(const uint64_t& height) const { return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); } + virtual blobdata get_block_blob(const crypto::hash& h) const { return blobdata(); } + virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const { return false; } + virtual uint64_t get_block_height(const crypto::hash& h) const { return 0; } + virtual block_header get_block_header(const crypto::hash& h) const { return block_header(); } + virtual uint64_t get_block_timestamp(const uint64_t& height) const { return 0; } + virtual uint64_t get_top_block_timestamp() const { return 0; } + virtual size_t get_block_size(const uint64_t& height) const { return 128; } + virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const { return 10; } + virtual difficulty_type get_block_difficulty(const uint64_t& height) const { return 0; } + virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const { return 10000000000; } + virtual uint64_t get_block_already_migrated_tokens(const uint64_t& height) const { return 10000000000; } + virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const { return crypto::hash(); } + virtual std::vector get_blocks_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector(); } + virtual std::vector get_hashes_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector(); } + virtual crypto::hash top_block_hash() const { return crypto::hash(); } + virtual block get_top_block() const { return block(); } + virtual uint64_t height() const { return blocks.size(); } + virtual bool tx_exists(const crypto::hash& h) const { return false; } + virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const { return false; } + virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const { return 0; } + virtual transaction get_tx(const crypto::hash& h) const { return transaction(); } + virtual bool get_tx(const crypto::hash& h, transaction &tx) const { return false; } + virtual uint64_t get_tx_count() const { return 0; } + virtual std::vector get_tx_list(const std::vector& hlist) const { return std::vector(); } + virtual uint64_t get_tx_block_height(const crypto::hash& h) const { return 0; } + virtual uint64_t get_num_outputs(const uint64_t& amount, const tx_out_type output_type) const { return 1; } + virtual uint64_t get_num_outputs(const tx_out_type output_type) const {return 1;} + virtual uint64_t get_indexing_base() const { return 0; } + virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const { return output_data_t(); } + virtual output_advanced_data_t get_output_advanced_data(const tx_out_type output_type, const uint64_t output_index) const { return output_advanced_data_t{}; } + virtual bool get_output_id(const tx_out_type output_type, const uint64_t output_index, uint64_t& output_id) const { return 0; } + virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const { return tx_out_index(); } + virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const { return tx_out_index(); } + virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices, const tx_out_type output_type) const {} + virtual void get_amount_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs, const tx_out_type output_type, bool allow_partial = false) const {} + virtual void get_advanced_output_key(const std::vector &output_indexes, std::vector &outputs, const tx_out_type output_type, bool allow_partial = false) const {} + virtual bool can_thread_bulk_indices() const { return false; } + virtual std::vector get_tx_output_indices(const crypto::hash& h) const { return std::vector(); } + virtual std::vector get_tx_amount_output_indices(const uint64_t tx_index) const { return std::vector(); } + virtual bool has_key_image(const crypto::key_image& img) const { return false; } + virtual void remove_block() { blocks.pop_back(); } + virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) {return 0;} + virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) {} + virtual void remove_unstake_token(const crypto::hash& tx_hash, const transaction& tx) {} + virtual uint64_t add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) {return 0;} + virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector& amount_output_indices) {} + virtual void add_spent_key(const crypto::key_image& k_image) {} + virtual void remove_spent_key(const crypto::key_image& k_image) {} + virtual void process_command_input(const cryptonote::txin_to_script &txin) {} + virtual uint64_t update_staked_token_sum_for_interval(const uint64_t interval_starting_block, const int64_t delta){return 0;} + virtual uint64_t update_staked_token_for_interval(const uint64_t interval, const uint64_t new_staked_tokens_in_interval) { return 0;} + virtual bool remove_staked_token_for_interval(const uint64_t interval){return true;}; + virtual uint64_t update_network_fee_sum_for_interval(const uint64_t interval_starting_block, const uint64_t collected_fee){return 0;} + virtual bool get_account_key(const safex::account_username &username, crypto::public_key &pkey) const { return true;} + virtual bool get_account_data(const safex::account_username &username, std::vector &data) const { return true;} + virtual bool get_offer(const crypto::hash offer_id, safex::safex_offer &offer) const { return true;} + virtual bool get_offer_seller(const crypto::hash offer_id, std::string &username) const { return true; }; + virtual bool get_offer_price(const crypto::hash offer_id, uint64_t &price) const { return true; }; + virtual bool get_offer_quantity(const crypto::hash offer_id, uint64_t &quantity) const { return true; }; + virtual bool get_offer_active_status(const crypto::hash offer_id, bool &active) const { return true; }; + virtual bool get_safex_accounts(std::vector> &accounts) const { return true; }; + virtual bool get_safex_offers(std::vector &offers) const { return true; }; + virtual bool get_safex_offer_height( crypto::hash &offer_id, uint64_t& height) const { return true; }; + virtual bool get_offer_stars_given(const crypto::hash offer_id, uint64_t &stars_received) const { return true; }; + virtual bool get_safex_feedbacks( std::vector &safex_feedbacks, const crypto::hash& offer_id) const { return true; }; + virtual bool get_safex_price_pegs( std::vector &safex_price_pegs, const std::string& currency) const { return true; }; + virtual bool get_safex_price_peg( const crypto::hash& price_peg_id,safex::safex_price_peg &safex_price_peg) const { return true; }; + + virtual bool get_table_sizes( std::vector &table_sizes) const { return true; }; + + + virtual bool for_all_key_images(std::function) const { return true; } + virtual bool for_blocks_range(const uint64_t&, const uint64_t&, std::function) const { return true; } + virtual bool for_all_transactions(std::function) const { return true; } + virtual bool for_all_outputs(std::function f, const tx_out_type output_type) const { return true; } + virtual bool for_all_outputs(uint64_t amount, const std::function &f, const tx_out_type output_type) const { return true; } + virtual bool for_all_advanced_outputs(std::function f, const tx_out_type output_type) const { return true;} + virtual bool is_read_only() const { return false; } + virtual std::map> get_output_histogram(const std::vector &amounts, bool unlocked, uint64_t recent_cutoff, const tx_out_type output_type) const { return std::map>(); } + + virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t& details) {} + virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& details) {} + virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const { return 0; } + virtual bool txpool_has_tx(const crypto::hash &txid) const { return false; } + virtual void remove_txpool_tx(const crypto::hash& txid) {} + virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const { return false; } + virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const { return false; } + virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const { return ""; } + virtual bool for_all_txpool_txes(std::function, bool include_blob = false, bool include_unrelayed_txes = false) const { return false; } + + virtual uint64_t get_current_staked_token_sum() const { return 0;} + virtual uint64_t get_staked_token_sum_for_interval(const uint64_t interval_starting_block) const override { return 0;}; + virtual uint64_t get_network_fee_sum_for_interval(const uint64_t interval) const override {return 0;} + virtual std::vector get_token_stake_expiry_outputs(const uint64_t block_height) const override {return std::vector{};} + virtual bool get_interval_interest_map(const uint64_t start_height, const uint64_t end_height, safex::map_interval_interest &map) const override {return true;} + virtual uint64_t calculate_staked_token_interest_for_output(const txin_to_script &txin, const uint64_t unlock_height) const override { return 0; } + + virtual void add_block( const block& blk + , const size_t& block_size + , const difficulty_type& cumulative_difficulty + , const uint64_t& coins_generated + , const uint64_t& tokens_migrated + , const crypto::hash& blk_hash + ) { + blocks.push_back(blk); + } + virtual block get_block_from_height(const uint64_t& height) const { + return blocks.at(height); + } + virtual void set_hard_fork_version(uint64_t height, uint8_t version) { + if (versions.size() <= height) + versions.resize(height+1); + versions[height] = version; + } + virtual uint8_t get_hard_fork_version(uint64_t height) const { + return versions.at(height); + } + virtual void check_hard_fork_info() {} + +private: + std::vector blocks; + std::deque versions; +}; + + struct output_index { const cryptonote::txout_target_v out; From 8059a502a4cccc9e55ff6c3dde707ede4d44c37a Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 11 Aug 2020 15:41:30 +0200 Subject: [PATCH 02/36] Reorganize Safex unit tests --- tests/unit_tests/CMakeLists.txt | 16 +++++++++------- .../{ => safex_command}/safex_commands.cpp | 7 ++++++- .../unit_tests/{ => safex_db}/safex_account.cpp | 2 +- .../{ => safex_db}/safex_blockchain_fee.cpp | 2 +- tests/unit_tests/{ => safex_db}/safex_offer.cpp | 2 +- .../{ => safex_db}/safex_price_peg.cpp | 2 +- .../{ => safex_db}/safex_test_common.cpp | 2 +- .../{ => safex_db}/simple_purchase.cpp | 2 +- 8 files changed, 21 insertions(+), 14 deletions(-) rename tests/unit_tests/{ => safex_command}/safex_commands.cpp (99%) rename tests/unit_tests/{ => safex_db}/safex_account.cpp (99%) rename tests/unit_tests/{ => safex_db}/safex_blockchain_fee.cpp (99%) rename tests/unit_tests/{ => safex_db}/safex_offer.cpp (99%) rename tests/unit_tests/{ => safex_db}/safex_price_peg.cpp (99%) rename tests/unit_tests/{ => safex_db}/safex_test_common.cpp (99%) rename tests/unit_tests/{ => safex_db}/simple_purchase.cpp (99%) diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index cd28f1b94..8a9831510 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -70,14 +70,16 @@ set(unit_tests_sources ringct.cpp output_selection.cpp vercmp.cpp - safex_commands.cpp safex_blockchain_db.cpp - safex_test_common.cpp - safex_blockchain_fee.cpp - safex_account.cpp - safex_offer.cpp - simple_purchase.cpp - safex_price_peg.cpp + # Safex command tests + safex_command/safex_commands.cpp + # Safex db tests + safex_db/safex_test_common.cpp + safex_db/safex_blockchain_fee.cpp + safex_db/safex_account.cpp + safex_db/safex_offer.cpp + safex_db/simple_purchase.cpp + safex_db/safex_price_peg.cpp ) diff --git a/tests/unit_tests/safex_commands.cpp b/tests/unit_tests/safex_command/safex_commands.cpp similarity index 99% rename from tests/unit_tests/safex_commands.cpp rename to tests/unit_tests/safex_command/safex_commands.cpp index f7d9d026a..3d7aab500 100644 --- a/tests/unit_tests/safex_commands.cpp +++ b/tests/unit_tests/safex_command/safex_commands.cpp @@ -36,7 +36,7 @@ #include "blockchain_db/blockchain_db.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_basic/hardfork.h" -#include "safex_test_common.h" +#include "../safex_test_common.h" using namespace safex; @@ -268,6 +268,11 @@ TEST_F(SafexCommandExecution, TokenUnlockExecuteWrongType) } } +TEST_F(SafexCommandExecution, CreateSafexAccountExceptions) +{ + +} + //TEST_F(SafexCommandExecution, TokenUnlockExecute) //{ diff --git a/tests/unit_tests/safex_account.cpp b/tests/unit_tests/safex_db/safex_account.cpp similarity index 99% rename from tests/unit_tests/safex_account.cpp rename to tests/unit_tests/safex_db/safex_account.cpp index 3138edeca..4e28e2163 100644 --- a/tests/unit_tests/safex_account.cpp +++ b/tests/unit_tests/safex_db/safex_account.cpp @@ -40,7 +40,7 @@ #include "blockchain_db/lmdb/db_lmdb.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "safex/safex_account.h" -#include "safex_test_common.h" +#include "../safex_test_common.h" using namespace cryptonote; diff --git a/tests/unit_tests/safex_blockchain_fee.cpp b/tests/unit_tests/safex_db/safex_blockchain_fee.cpp similarity index 99% rename from tests/unit_tests/safex_blockchain_fee.cpp rename to tests/unit_tests/safex_db/safex_blockchain_fee.cpp index 32616196f..ffbc935f2 100644 --- a/tests/unit_tests/safex_blockchain_fee.cpp +++ b/tests/unit_tests/safex_db/safex_blockchain_fee.cpp @@ -42,7 +42,7 @@ #include "blockchain_db/lmdb/db_lmdb.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_core/cryptonote_tx_utils.h" -#include "safex_test_common.h" +#include "../safex_test_common.h" using namespace cryptonote; using epee::string_tools::pod_to_hex; diff --git a/tests/unit_tests/safex_offer.cpp b/tests/unit_tests/safex_db/safex_offer.cpp similarity index 99% rename from tests/unit_tests/safex_offer.cpp rename to tests/unit_tests/safex_db/safex_offer.cpp index 3603d29b8..db3bcb8b6 100644 --- a/tests/unit_tests/safex_offer.cpp +++ b/tests/unit_tests/safex_db/safex_offer.cpp @@ -41,7 +41,7 @@ #include "cryptonote_basic/cryptonote_format_utils.h" #include "safex/safex_account.h" #include "safex/safex_offer.h" -#include "safex_test_common.h" +#include "../safex_test_common.h" using namespace cryptonote; diff --git a/tests/unit_tests/safex_price_peg.cpp b/tests/unit_tests/safex_db/safex_price_peg.cpp similarity index 99% rename from tests/unit_tests/safex_price_peg.cpp rename to tests/unit_tests/safex_db/safex_price_peg.cpp index af50c4c9a..83ea287b2 100644 --- a/tests/unit_tests/safex_price_peg.cpp +++ b/tests/unit_tests/safex_db/safex_price_peg.cpp @@ -41,7 +41,7 @@ #include "cryptonote_basic/cryptonote_format_utils.h" #include "safex/safex_account.h" #include "safex/safex_price_peg.h" -#include "safex_test_common.h" +#include "../safex_test_common.h" using namespace cryptonote; diff --git a/tests/unit_tests/safex_test_common.cpp b/tests/unit_tests/safex_db/safex_test_common.cpp similarity index 99% rename from tests/unit_tests/safex_test_common.cpp rename to tests/unit_tests/safex_db/safex_test_common.cpp index 274850805..4e3951f45 100644 --- a/tests/unit_tests/safex_test_common.cpp +++ b/tests/unit_tests/safex_db/safex_test_common.cpp @@ -21,7 +21,7 @@ #include "safex/safex_offer.h" #include "safex/safex_purchase.h" -#include "safex_test_common.h" +#include "../safex_test_common.h" using namespace cryptonote; using epee::string_tools::pod_to_hex; diff --git a/tests/unit_tests/simple_purchase.cpp b/tests/unit_tests/safex_db/simple_purchase.cpp similarity index 99% rename from tests/unit_tests/simple_purchase.cpp rename to tests/unit_tests/safex_db/simple_purchase.cpp index 14b6938cb..98b6ecc81 100644 --- a/tests/unit_tests/simple_purchase.cpp +++ b/tests/unit_tests/safex_db/simple_purchase.cpp @@ -43,7 +43,7 @@ #include "safex/safex_offer.h" #include "safex/safex_purchase.h" #include "safex/safex_feedback.h" -#include "safex_test_common.h" +#include "../safex_test_common.h" using namespace cryptonote; From 526fd49eb8bfb84cc58475689a37d7e253f8efab Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Fri, 14 Aug 2020 13:14:37 +0200 Subject: [PATCH 03/36] Rename unit test for stake_unstake --- tests/unit_tests/CMakeLists.txt | 2 +- .../{safex_blockchain_fee.cpp => safex_stake_unstake.cpp} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/unit_tests/safex_db/{safex_blockchain_fee.cpp => safex_stake_unstake.cpp} (100%) diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 8a9831510..4cf6d6bbe 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -75,7 +75,7 @@ set(unit_tests_sources safex_command/safex_commands.cpp # Safex db tests safex_db/safex_test_common.cpp - safex_db/safex_blockchain_fee.cpp + safex_db/safex_stake_unstake.cpp safex_db/safex_account.cpp safex_db/safex_offer.cpp safex_db/simple_purchase.cpp diff --git a/tests/unit_tests/safex_db/safex_blockchain_fee.cpp b/tests/unit_tests/safex_db/safex_stake_unstake.cpp similarity index 100% rename from tests/unit_tests/safex_db/safex_blockchain_fee.cpp rename to tests/unit_tests/safex_db/safex_stake_unstake.cpp From dbce3caeb2fbc202f38dabe6a1feb058ed640678 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Fri, 14 Aug 2020 17:45:29 +0200 Subject: [PATCH 04/36] Move all safex command unit tests to safex_db --- tests/unit_tests/CMakeLists.txt | 2 - .../safex_command/safex_commands.cpp | 305 ------------------ .../safex_db/safex_stake_unstake.cpp | 247 ++++++++++++++ 3 files changed, 247 insertions(+), 307 deletions(-) delete mode 100644 tests/unit_tests/safex_command/safex_commands.cpp diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 4cf6d6bbe..043a8ad5d 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -71,8 +71,6 @@ set(unit_tests_sources output_selection.cpp vercmp.cpp safex_blockchain_db.cpp - # Safex command tests - safex_command/safex_commands.cpp # Safex db tests safex_db/safex_test_common.cpp safex_db/safex_stake_unstake.cpp diff --git a/tests/unit_tests/safex_command/safex_commands.cpp b/tests/unit_tests/safex_command/safex_commands.cpp deleted file mode 100644 index 3d7aab500..000000000 --- a/tests/unit_tests/safex_command/safex_commands.cpp +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (c) 2018, The Safex Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Parts of this file are originally copyright (c) 2017-2018 The Monero Project - -#include "gtest/gtest.h" -#include "safex/command.h" -#include -#include - -#include "blockchain_db/blockchain_db.h" -#include "cryptonote_basic/cryptonote_format_utils.h" -#include "cryptonote_basic/hardfork.h" -#include "../safex_test_common.h" - - -using namespace safex; - -TEST(SafexCommandParsing, HandlesTokenLock) -{ - - token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 2000}; - - //serialize - std::vector serialized_command; - safex_command_serializer::serialize_safex_object(command1, serialized_command); - - - - command_t command_type = safex_command_serializer::get_command_type(serialized_command); - ASSERT_EQ(command_type, command_t::token_stake) << "Token stake command type not properly parsed from binary blob"; - - //deserialize - std::unique_ptr command2 = safex_command_serializer::parse_safex_object(serialized_command, command_t::token_stake); - - ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; - ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; - ASSERT_EQ(command1.get_staked_token_amount(), dynamic_cast(command2.get())->get_staked_token_amount()) << "Original and deserialized command must have same locked amount"; - -} - -TEST(SafexCommandParsing, HandlesTokenCollect) -{ - - token_collect command1{SAFEX_COMMAND_PROTOCOL_VERSION, 2000}; - - //serialize - std::vector serialized_command; - safex_command_serializer::serialize_safex_object(command1, serialized_command); - - command_t command_type = safex_command_serializer::get_command_type(serialized_command); - ASSERT_EQ(command_type, command_t::token_collect) << "Token unlock command type not properly parsed from binary blob"; - - //deserialize - std::unique_ptr command2 = safex_command_serializer::parse_safex_object(serialized_command, command_t::token_collect); - - ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; - ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; - ASSERT_EQ(command1.get_staked_token_output_index(), dynamic_cast(command2.get())->get_staked_token_output_index()) << "Original and deserialized command must have same output index"; - -} - -TEST(SafexCommandParsing, HandlesCorruptedArrayOfBytes) -{ - - std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; - - //deserialize - EXPECT_THROW(safex_command_serializer::parse_safex_object(serialized_command, command_t::token_stake), safex::command_exception); - -} - - -TEST(SafexCommandCreation, HandlesUnknownProtocolVersion) -{ - - try - { - token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, 2000}; - FAIL() << "Should throw exception with message invalid command"; - } - catch (safex::command_exception &exception) - { - ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); - } - catch (...) - { - FAIL() << "Unexpected exception"; - } -} - - - -namespace -{ - - - class SafexCommandExecution : public ::testing::Test - { - public: - SafexCommandExecution() { - crypto::public_key pubKey; - epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); - keys.push_back(pubKey); - - } - protected: - std::vector keys; - TestDB db; - }; -} - -TEST_F(SafexCommandExecution, TokenLockExecute) -{ - - try - { - - - cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); - txinput.command_type = command_t::token_stake; - txinput.token_amount = 10000*SAFEX_TOKEN; - token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 10000*SAFEX_TOKEN}; - safex_command_serializer::serialize_safex_object(command1, txinput.script); - - std::unique_ptr command2 = safex_command_serializer::parse_safex_object(txinput.script, command_t::token_stake); - std::unique_ptr result{command2->execute(this->db, txinput)}; - - - - - std::cout << "Token amount: " << static_cast(result.get())->token_amount << " status:" << static_cast(result->status) - << " block number:" << static_cast(result.get())->block_number << std::endl; - } - catch (safex::command_exception &exception) - { - FAIL() << exception.what(); - } - catch (std::exception &exception) - { - FAIL() << "Exception happened " << exception.what(); - } - catch (...) - { - FAIL() << "Unexpected exception"; - } -} - - -TEST_F(SafexCommandExecution, TokenLockExceptions) -{ - - try - { - - cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); - txinput.token_amount = 8000; - txinput.command_type = command_t::token_stake; - token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 8000}; - safex_command_serializer::serialize_safex_object(command1, txinput.script); - - std::unique_ptr command2 = safex_command_serializer::parse_safex_object(txinput.script, command_t::token_stake); - - std::unique_ptr result{command2->execute(this->db, txinput)}; - FAIL() << "Should throw exception with minimum amount of tokens to lock"; - - } - catch (safex::command_exception &exception) - { - - } - catch (std::exception &exception) - { - FAIL() << "Exception happened " << exception.what(); - } - catch (...) - { - FAIL() << "Unexpected exception"; - } - - - try - { - - cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); - txinput.token_amount = 19000; - txinput.command_type = command_t::token_stake; - token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 11000}; - safex_command_serializer::serialize_safex_object(command1, txinput.script); - - std::unique_ptr command2 = safex_command_serializer::parse_safex_object(txinput.script, command_t::token_stake); - - std::unique_ptr result{command2->execute(this->db, txinput)}; - FAIL() << "Should throw exception with input amount differs from token stake command amount"; - } - catch (safex::command_exception &exception) - { - - } - catch (std::exception &exception) - { - FAIL() << "Exception happened " << exception.what(); - } - catch (...) - { - FAIL() << "Unexpected exception"; - } - - -} - - -TEST_F(SafexCommandExecution, TokenUnlockExecuteWrongType) -{ - - try - { - - cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); - txinput.token_amount = 10000; //unlock 10k tokens - txinput.command_type = command_t::token_unstake; - txinput.key_offsets.push_back(23); - uint64_t locked_token_output_index = 23; - token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; - safex_command_serializer::serialize_safex_object(command1, txinput.script); - - std::unique_ptr command2 = safex_command_serializer::parse_safex_object(txinput.script, command_t::token_stake); - std::unique_ptr result{command2->execute(db, txinput)}; - - } - catch (safex::command_exception &exception) - { - ASSERT_STREQ("Could not create command, wrong command type", std::string(exception.what()).c_str()); - - } - catch (std::exception &exception) - { - FAIL() << "Exception happened " << exception.what(); - } - catch (...) - { - FAIL() << "Unexpected exception"; - } -} - -TEST_F(SafexCommandExecution, CreateSafexAccountExceptions) -{ - -} - - -//TEST_F(SafexCommandExecution, TokenUnlockExecute) -//{ - -// try -// { - -// cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); -// txinput.token_amount = 120000; //unlock 120k tokens -// txinput.command_type = command_t::token_unstake; -// txinput.key_offsets.push_back(23); -// uint64_t locked_token_output_index = 23; -// token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; -// safex_command_serializer::serialize_safex_object(command1, txinput.script); - -// std::unique_ptr command2 = safex_command_serializer::parse_safex_object(txinput.script, command_t::token_unstake); -// std::unique_ptr rslt{command2->execute(this->db, txinput)}; -// token_unstake_result* result = static_cast(rslt.get()); - -// std::cout << "Token amount: " << result->token_amount << " valid:" << result->valid << " block number:" << result->block_number << " interest: " << result->interest << std::endl; -// } -// catch (std::exception &exception) -// { -// FAIL() << "Exception happened " << exception.what(); -// } -// catch (...) -// { -// FAIL() << "Unexpected exception"; -// } -//} diff --git a/tests/unit_tests/safex_db/safex_stake_unstake.cpp b/tests/unit_tests/safex_db/safex_stake_unstake.cpp index ffbc935f2..e0f8fe1a1 100644 --- a/tests/unit_tests/safex_db/safex_stake_unstake.cpp +++ b/tests/unit_tests/safex_db/safex_stake_unstake.cpp @@ -270,6 +270,199 @@ namespace #if 1 + TYPED_TEST(SafexBlockchainFeeTest, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::token_stake), safex::command_exception); + + } + + TYPED_TEST(SafexBlockchainFeeTest, HandlesUnknownProtocolVersion) + { + + try + { + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, 2000}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TYPED_TEST(SafexBlockchainFeeTest, HandlesCommandParsing) + { + + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 2000}; + + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::token_stake) << "Token stake command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::token_stake); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_staked_token_amount(), dynamic_cast(command2.get())->get_staked_token_amount()) << "Original and deserialized command must have same locked amount"; + + } + + + + TYPED_TEST(SafexBlockchainFeeTest, TokenLockExecute) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::token_stake; + txinput.token_amount = 10000*SAFEX_TOKEN; + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 10000*SAFEX_TOKEN}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + + + + + std::cout << "Token amount: " << static_cast(result.get())->token_amount << " status:" << static_cast(result->status) + << " block number:" << static_cast(result.get())->block_number << std::endl; + } + catch (safex::command_exception &exception) + { + FAIL() << exception.what(); + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexBlockchainFeeTest, TokenLockExceptions) + { + + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 8000; + txinput.command_type = safex::command_t::token_stake; + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 8000}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with minimum amount of tokens to lock"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 19000; + txinput.command_type = safex::command_t::token_stake; + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 11000}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with input amount differs from token stake command amount"; + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + + } + + + TYPED_TEST(SafexBlockchainFeeTest, TokenUnlockExecuteWrongType) + { + + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 10000; //unlock 10k tokens + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(23); + uint64_t locked_token_output_index = 23; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ("Could not create command, wrong command type", std::string(exception.what()).c_str()); + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + TYPED_TEST(SafexBlockchainFeeTest, RetrieveCollectedFee) { boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); @@ -361,6 +554,60 @@ namespace } +// TYPED_TEST(SafexBlockchainFeeTest, TokenUnlockExecute) +// { +// boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); +// std::string dirPath = tempPath.string(); + +// this->set_prefix(dirPath); + +// // make sure open does not throw +// ASSERT_NO_THROW(this->m_db->open(dirPath)); +// this->get_filenames(); +// this->init_hard_fork(); + +// for (int i = 0; i < NUMBER_OF_BLOCKS - 1; i++) +// { +// try +// { +// this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i]); +// } +// catch (std::exception &e) +// { +// std::cout << "Error: " << e.what() << std::endl; +// } +// } + +// try +// { + +// cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); +// txinput.token_amount = 120000; //unlock 120k tokens +// txinput.command_type = safex::command_t::token_unstake; +// txinput.key_offsets.push_back(23); +// uint64_t locked_token_output_index = 23; +// safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; +// safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + +// std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); +// std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; +// safex::token_unstake_result* result = static_cast(rslt.get()); + +// std::cout << "Token amount: " << result->token_amount << " valid:" << result->valid << " block number:" << result->block_number << " interest: " << result->interest << std::endl; +// } +// catch (std::exception &exception) +// { +// FAIL() << "Exception happened " << exception.what(); +// } +// catch (...) +// { +// FAIL() << "Unexpected exception"; +// } + +// ASSERT_NO_THROW(this->m_db->close()); + +// } + #endif From 83f3095bd4b58cac24aa4f4155bea727c486443c Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Fri, 14 Aug 2020 18:21:34 +0200 Subject: [PATCH 05/36] Speed up tests that doesn't need db --- .../safex_db/safex_stake_unstake.cpp | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/tests/unit_tests/safex_db/safex_stake_unstake.cpp b/tests/unit_tests/safex_db/safex_stake_unstake.cpp index e0f8fe1a1..6bf67c3a0 100644 --- a/tests/unit_tests/safex_db/safex_stake_unstake.cpp +++ b/tests/unit_tests/safex_db/safex_stake_unstake.cpp @@ -58,6 +58,19 @@ namespace "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; + class SafexStakeUnstakeCommand : public ::testing::Test + { + public: + SafexStakeUnstakeCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + + } + protected: + std::vector keys; + TestDB m_db; + }; template class SafexBlockchainFeeTest : public testing::Test @@ -270,7 +283,7 @@ namespace #if 1 - TYPED_TEST(SafexBlockchainFeeTest, HandlesCorruptedArrayOfBytes) + TEST_F(SafexStakeUnstakeCommand, HandlesCorruptedArrayOfBytes) { std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; @@ -280,7 +293,7 @@ namespace } - TYPED_TEST(SafexBlockchainFeeTest, HandlesUnknownProtocolVersion) + TEST_F(SafexStakeUnstakeCommand, HandlesUnknownProtocolVersion) { try @@ -298,7 +311,7 @@ namespace } } - TYPED_TEST(SafexBlockchainFeeTest, HandlesCommandParsing) + TEST_F(SafexStakeUnstakeCommand, HandlesCommandParsing) { safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 2000}; @@ -321,17 +334,8 @@ namespace - TYPED_TEST(SafexBlockchainFeeTest, TokenLockExecute) + TEST_F(SafexStakeUnstakeCommand, TokenLockExecute) { - boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); - std::string dirPath = tempPath.string(); - - this->set_prefix(dirPath); - - // make sure open does not throw - ASSERT_NO_THROW(this->m_db->open(dirPath)); - this->get_filenames(); - this->init_hard_fork(); try { @@ -342,7 +346,7 @@ namespace safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); - std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + std::unique_ptr result{command2->execute(this->m_db, txinput)}; @@ -363,11 +367,9 @@ namespace FAIL() << "Unexpected exception"; } - ASSERT_NO_THROW(this->m_db->close()); - } - TYPED_TEST(SafexBlockchainFeeTest, TokenLockExceptions) + TEST_F(SafexStakeUnstakeCommand, TokenLockExceptions) { try @@ -381,7 +383,7 @@ namespace std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); - std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + std::unique_ptr result{command2->execute(this->m_db, txinput)}; FAIL() << "Should throw exception with minimum amount of tokens to lock"; } @@ -410,7 +412,7 @@ namespace std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); - std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + std::unique_ptr result{command2->execute(this->m_db, txinput)}; FAIL() << "Should throw exception with input amount differs from token stake command amount"; } catch (safex::command_exception &exception) @@ -430,7 +432,7 @@ namespace } - TYPED_TEST(SafexBlockchainFeeTest, TokenUnlockExecuteWrongType) + TEST_F(SafexStakeUnstakeCommand, TokenUnlockExecuteWrongType) { try @@ -445,7 +447,7 @@ namespace safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); - std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + std::unique_ptr result{command2->execute(this->m_db, txinput)}; } catch (safex::command_exception &exception) From 60da40f47f1e8ca224b9f92593e713a8cde7005a Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Fri, 14 Aug 2020 19:52:01 +0200 Subject: [PATCH 06/36] Add additional error codes --- src/safex/command.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/safex/command.h b/src/safex/command.h index b25108940..2c137b159 100644 --- a/src/safex/command.h +++ b/src/safex/command.h @@ -40,16 +40,21 @@ namespace safex ok = 0, invalid = 1, error_wrong_input_params = 1, + // Safex stake token + error_stake_token_amount_not_matching = 2, + error_stake_token_not_whole_amount = 3, // Safex account error_account_data_too_big = 10, error_account_already_exists = 11, error_invalid_account_name = 12, error_account_non_existant = 13, + error_account_no_tokens = 14, // Safex purchase error_offer_non_existant = 20, error_purchase_out_of_stock = 21, error_purchase_not_enough_funds = 23, error_purchase_offer_not_active = 24, + error_purchase_quantity_zero = 25, // Safex offer error_offer_price_too_big = 30, error_offer_price_too_small = 31, @@ -66,7 +71,9 @@ namespace safex // Safex unstake token error_unstake_token_output_not_found = 60, error_unstake_token_minimum_period = 61, - error_unstake_token_network_fee_not_matching = 62 + error_unstake_token_network_fee_not_matching = 62, + error_unstake_token_offset_not_one = 63, + error_unstake_token_output_not_matching = 64 }; struct execution_result From bb64d13ba016f574057a0bce3979379d03efb7b4 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Fri, 14 Aug 2020 19:52:52 +0200 Subject: [PATCH 07/36] Use new error codes --- src/safex/command.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/safex/command.cpp b/src/safex/command.cpp index dd2981701..06aa4553f 100644 --- a/src/safex/command.cpp +++ b/src/safex/command.cpp @@ -43,9 +43,9 @@ namespace safex //per input execution, one input could be less than SAFEX_MINIMUM_TOKEN_STAKE_AMOUNT, all inputs must be SAFEX_MINIMUM_TOKEN_STAKE_AMOUNT if(!tools::is_whole_token_amount(this->get_staked_token_amount())) - result = execution_status::error_wrong_input_params; + result = execution_status::error_stake_token_not_whole_amount; if(!(txin.token_amount == this->get_staked_token_amount())) - result = execution_status::error_wrong_input_params; + result = execution_status::error_stake_token_amount_not_matching; return result; } @@ -77,10 +77,10 @@ namespace safex execution_status result = execution_status::ok; if(!(txin.key_offsets.size() == 1)) - result = execution_status::error_wrong_input_params; + result = execution_status::error_unstake_token_offset_not_one; if(!(txin.key_offsets[0] == this->get_staked_token_output_index())) - result = execution_status::error_wrong_input_params; + result = execution_status::error_unstake_token_output_not_matching; uint64_t staked_token_index = this->get_staked_token_output_index(); const cryptonote::output_advanced_data_t od = blokchainDB.get_output_advanced_data(cryptonote::tx_out_type::out_staked_token, staked_token_index); @@ -203,7 +203,7 @@ namespace safex return execution_status::error_purchase_out_of_stock; if(cmd->quantity==0) - return execution_status::error_wrong_input_params; + return execution_status::error_purchase_quantity_zero; uint64_t sfx_price = sfx_offer.min_sfx_price; @@ -251,7 +251,7 @@ namespace safex execution_status create_account::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) { if(txin.token_amount == 0) - return execution_status::error_wrong_input_params; + return execution_status::error_account_no_tokens; std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); From 31c14c34f511232cb172aa067a97d63a29165618 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Fri, 14 Aug 2020 19:53:19 +0200 Subject: [PATCH 08/36] Check validation of token stake commands --- tests/unit_tests/safex_db/safex_stake_unstake.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/unit_tests/safex_db/safex_stake_unstake.cpp b/tests/unit_tests/safex_db/safex_stake_unstake.cpp index 6bf67c3a0..72601e62c 100644 --- a/tests/unit_tests/safex_db/safex_stake_unstake.cpp +++ b/tests/unit_tests/safex_db/safex_stake_unstake.cpp @@ -348,9 +348,6 @@ namespace std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); std::unique_ptr result{command2->execute(this->m_db, txinput)}; - - - std::cout << "Token amount: " << static_cast(result.get())->token_amount << " status:" << static_cast(result->status) << " block number:" << static_cast(result.get())->block_number << std::endl; } @@ -372,6 +369,7 @@ namespace TEST_F(SafexStakeUnstakeCommand, TokenLockExceptions) { + // Token amount not whole try { @@ -383,8 +381,11 @@ namespace std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_stake_token_not_whole_amount); + std::unique_ptr result{command2->execute(this->m_db, txinput)}; - FAIL() << "Should throw exception with minimum amount of tokens to lock"; + FAIL() << "Should throw exception with token amount not whole"; } catch (safex::command_exception &exception) @@ -401,6 +402,7 @@ namespace } + // Token amount not matching try { @@ -412,6 +414,9 @@ namespace std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_stake_token_amount_not_matching); + std::unique_ptr result{command2->execute(this->m_db, txinput)}; FAIL() << "Should throw exception with input amount differs from token stake command amount"; } From dbfb59246841226d5569c63c5371f8c307006e70 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Mon, 17 Aug 2020 14:12:22 +0200 Subject: [PATCH 09/36] [token_stake] Use key_offset instead of get_staked_token_output_index() as the plan is to remove it at one point --- src/safex/command.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/safex/command.cpp b/src/safex/command.cpp index 06aa4553f..c2fb40a12 100644 --- a/src/safex/command.cpp +++ b/src/safex/command.cpp @@ -76,13 +76,10 @@ namespace safex execution_status result = execution_status::ok; - if(!(txin.key_offsets.size() == 1)) + if(txin.key_offsets.size() != 1) result = execution_status::error_unstake_token_offset_not_one; - if(!(txin.key_offsets[0] == this->get_staked_token_output_index())) - result = execution_status::error_unstake_token_output_not_matching; - - uint64_t staked_token_index = this->get_staked_token_output_index(); + uint64_t staked_token_index = txin.key_offsets[0]; const cryptonote::output_advanced_data_t od = blokchainDB.get_output_advanced_data(cryptonote::tx_out_type::out_staked_token, staked_token_index); From c6072ce29ec89450970f7245a63dfdbd2768b5f1 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Mon, 17 Aug 2020 14:13:45 +0200 Subject: [PATCH 10/36] [token_stake] Add unit test for unstake command checks --- .../safex_db/safex_stake_unstake.cpp | 292 ++++++++++++++---- 1 file changed, 236 insertions(+), 56 deletions(-) diff --git a/tests/unit_tests/safex_db/safex_stake_unstake.cpp b/tests/unit_tests/safex_db/safex_stake_unstake.cpp index 72601e62c..ed5aafeaa 100644 --- a/tests/unit_tests/safex_db/safex_stake_unstake.cpp +++ b/tests/unit_tests/safex_db/safex_stake_unstake.cpp @@ -63,9 +63,8 @@ namespace public: SafexStakeUnstakeCommand() { crypto::public_key pubKey; - epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); - keys.push_back(pubKey); - + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); } protected: std::vector keys; @@ -561,59 +560,240 @@ namespace } -// TYPED_TEST(SafexBlockchainFeeTest, TokenUnlockExecute) -// { -// boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); -// std::string dirPath = tempPath.string(); - -// this->set_prefix(dirPath); - -// // make sure open does not throw -// ASSERT_NO_THROW(this->m_db->open(dirPath)); -// this->get_filenames(); -// this->init_hard_fork(); - -// for (int i = 0; i < NUMBER_OF_BLOCKS - 1; i++) -// { -// try -// { -// this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i]); -// } -// catch (std::exception &e) -// { -// std::cout << "Error: " << e.what() << std::endl; -// } -// } - -// try -// { - -// cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); -// txinput.token_amount = 120000; //unlock 120k tokens -// txinput.command_type = safex::command_t::token_unstake; -// txinput.key_offsets.push_back(23); -// uint64_t locked_token_output_index = 23; -// safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; -// safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); - -// std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); -// std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; -// safex::token_unstake_result* result = static_cast(rslt.get()); - -// std::cout << "Token amount: " << result->token_amount << " valid:" << result->valid << " block number:" << result->block_number << " interest: " << result->interest << std::endl; -// } -// catch (std::exception &exception) -// { -// FAIL() << "Exception happened " << exception.what(); -// } -// catch (...) -// { -// FAIL() << "Unexpected exception"; -// } - -// ASSERT_NO_THROW(this->m_db->close()); - -// } + TYPED_TEST(SafexBlockchainFeeTest, TokenUnlockExecute) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS - 1; i++) + { + try + { + this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i]); + } + catch (std::exception &e) + { + std::cout << "Error: " << e.what() << std::endl; + } + } + + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 400 * SAFEX_TOKEN; //unlock 120k tokens + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(1); + uint64_t locked_token_output_index = 1; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; + safex::token_unstake_result* result = static_cast(rslt.get()); + + std::cout << "Token amount: " << result->token_amount << " valid:" << result->valid << " block number:" << result->block_number << " interest: " << result->interest << std::endl; + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexBlockchainFeeTest, TokenUnlockExceptions) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + uint64_t minimum_lock_block_height = 10 + safex::get_safex_minumum_token_lock_period(this->m_db->get_net_type()); + + for (int i = 0; i < minimum_lock_block_height; i++) + { + try + { + this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i]); + } + catch (std::exception &e) + { + std::cout << "Error: " << e.what() << std::endl; + } + } + + // Not enough time passed + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 400 * SAFEX_TOKEN; //unlock 400 tokens + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(1); + uint64_t locked_token_output_index = 0; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_unstake_token_minimum_period); + + std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with matching output not found"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + + try + { + this->m_db->add_block(this->m_blocks[minimum_lock_block_height], this->m_test_sizes[minimum_lock_block_height], + this->m_test_diffs[minimum_lock_block_height], this->m_test_coins[minimum_lock_block_height], + this->m_test_tokens[minimum_lock_block_height], this->m_txs[minimum_lock_block_height]); + } + catch (std::exception &e) + { + std::cout << "Error: " << e.what() << std::endl; + } + + + // Token amount offset more than one + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 400 * SAFEX_TOKEN; //unlock 400 tokens + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(1); + txinput.key_offsets.push_back(12); + uint64_t locked_token_output_index = 1; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_unstake_token_offset_not_one); + + std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with offsets size more than 1"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Interest too big + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 400 * SAFEX_TOKEN; //unlock 400 tokens + txinput.amount = 5000 * SAFEX_CASH_COIN; + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(1); + uint64_t locked_token_output_index = 0; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_unstake_token_network_fee_not_matching); + + std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with interest too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Output not found + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 100 * SAFEX_TOKEN; //unlock 400 tokens + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(1); + uint64_t locked_token_output_index = 0; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_unstake_token_output_not_found); + + std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with matching output not found"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } #endif From e88f083982b4bbe784744bfcd2aea8d9832fdad0 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Fri, 21 Aug 2020 17:21:29 +0200 Subject: [PATCH 11/36] [create_acount] Add another constructor for easier initialization of command --- src/safex/command.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/safex/command.h b/src/safex/command.h index 2c137b159..6b0a3b74c 100644 --- a/src/safex/command.h +++ b/src/safex/command.h @@ -799,6 +799,9 @@ struct create_price_peg_result : public execution_result create_account(const uint32_t _version, std::vector &_username, const crypto::public_key &_pkey, const std::vector &_account_data) : command(_version, command_t::create_account), username(_username), pkey{_pkey}, account_data{_account_data} {} + create_account(const uint32_t _version, const std::string &_username, const crypto::public_key &_pkey, const std::string &_account_data) : + command(_version, command_t::create_account), username(_username.begin(), _username.end()), pkey{_pkey}, account_data(_account_data.begin(), _account_data.end()) {} + create_account() : command(0, command_t::create_account), username{}, pkey{}, account_data{} {} std::string get_username() const { return std::string(std::begin(username), std::end(username)); } From 0bf367982fb843b17d413eebd4e9d4fef97f5000 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Fri, 21 Aug 2020 17:22:09 +0200 Subject: [PATCH 12/36] [unit_test] Return false for getting safex account to validate on TestDB --- tests/unit_tests/safex_test_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit_tests/safex_test_common.h b/tests/unit_tests/safex_test_common.h index d968195d0..df2054a72 100644 --- a/tests/unit_tests/safex_test_common.h +++ b/tests/unit_tests/safex_test_common.h @@ -92,7 +92,7 @@ class TestDB: public BlockchainDB { virtual bool remove_staked_token_for_interval(const uint64_t interval){return true;}; virtual uint64_t update_network_fee_sum_for_interval(const uint64_t interval_starting_block, const uint64_t collected_fee){return 0;} virtual bool get_account_key(const safex::account_username &username, crypto::public_key &pkey) const { return true;} - virtual bool get_account_data(const safex::account_username &username, std::vector &data) const { return true;} + virtual bool get_account_data(const safex::account_username &username, std::vector &data) const { return false;} virtual bool get_offer(const crypto::hash offer_id, safex::safex_offer &offer) const { return true;} virtual bool get_offer_seller(const crypto::hash offer_id, std::string &username) const { return true; }; virtual bool get_offer_price(const crypto::hash offer_id, uint64_t &price) const { return true; }; From c9885d40f79c96451c0165aae37d4703d012e189 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Fri, 21 Aug 2020 17:22:43 +0200 Subject: [PATCH 13/36] [safex_account][unit_test] Add unit tests for create safex account command --- tests/unit_tests/safex_db/safex_account.cpp | 287 ++++++++++++++++++++ 1 file changed, 287 insertions(+) diff --git a/tests/unit_tests/safex_db/safex_account.cpp b/tests/unit_tests/safex_db/safex_account.cpp index 4e28e2163..17deba773 100644 --- a/tests/unit_tests/safex_db/safex_account.cpp +++ b/tests/unit_tests/safex_db/safex_account.cpp @@ -58,6 +58,18 @@ namespace const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182"}; + class SafexAccountCommand : public ::testing::Test + { + public: + SafexAccountCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; template class SafexAccountTest : public testing::Test @@ -287,6 +299,281 @@ namespace } + TEST_F(SafexAccountCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_account), safex::command_exception); + + } + + TEST_F(SafexAccountCommand, HandlesUnknownProtocolVersion) + { + + std::string username = "test01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + try + { + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, username, safex_keys.get_keys().get_public_key(), description}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexAccountCommand, HandlesCommandParsing) + { + + std::string username = "test01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::create_account) << "Safex create account command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_account); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_username(), dynamic_cast(command2.get())->get_username()) << "Original and deserialized command must have same username"; + ASSERT_EQ(command1.get_account_key(), dynamic_cast(command2.get())->get_account_key()) << "Original and deserialized command must have same account key"; + ASSERT_EQ(command1.get_account_data(), dynamic_cast(command2.get())->get_account_data()) << "Original and deserialized command must have same description"; + + } + + TEST_F(SafexAccountCommand, CreateAccountExecute) + { + + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = "test_0-1"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + + } + catch (safex::command_exception &exception) + { + FAIL() << exception.what(); + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + } + + TEST_F(SafexAccountCommand, CreateAccountExceptions) + { + + // No tokens in the input + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 0; + std::string username = "test01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_account_no_tokens); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with token amount zero"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Invalid username + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = "Test01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_invalid_account_name); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with invalid account name"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Invalid username + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = "test/01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_invalid_account_name); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with invalid account name"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Username too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = "012345678901234567890123456789azb"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_account_data_too_big); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with username too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Account data too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = "test0"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = ""; + for(int i=0; i < SAFEX_ACCOUNT_DATA_MAX_SIZE + 1; i++) + description += "x"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_account_data_too_big); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with username too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + } TYPED_TEST(SafexAccountTest, CreateAccountCommand) { From 4e2efb89c949c57c7e315b4bae7451129ae435ba Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sat, 22 Aug 2020 13:43:10 +0200 Subject: [PATCH 14/36] [safex_account][unit_tests] Add unit test wgen account already exists --- tests/unit_tests/safex_db/safex_account.cpp | 59 +++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/tests/unit_tests/safex_db/safex_account.cpp b/tests/unit_tests/safex_db/safex_account.cpp index 17deba773..a9a918043 100644 --- a/tests/unit_tests/safex_db/safex_account.cpp +++ b/tests/unit_tests/safex_db/safex_account.cpp @@ -620,9 +620,6 @@ namespace ASSERT_NO_THROW(this->m_db->close()); } -#endif - -#if 1 TYPED_TEST(SafexAccountTest, EditAccount) { @@ -661,6 +658,62 @@ namespace ASSERT_TRUE(std::equal(this->m_safex_account3.account_data.begin(), this->m_safex_account3.account_data.end(), accdata03.begin())); + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexAccountTest, SafexAccountExceptions) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS2 - 1; i++) + { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex account exists + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = this->m_safex_account1.username; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_already_exists); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account already exists"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + ASSERT_NO_THROW(this->m_db->close()); } From 8b51d1b968fe800d03bddef6680fa55302f824fc Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sat, 22 Aug 2020 13:59:13 +0200 Subject: [PATCH 15/36] [token_stake][unit_tests] Refactor unit tests for token stake: * Separated cases for stake and unstake * Rename lock and unlock to stake and unstake --- .../safex_db/safex_stake_unstake.cpp | 175 ++++++++++++++---- 1 file changed, 135 insertions(+), 40 deletions(-) diff --git a/tests/unit_tests/safex_db/safex_stake_unstake.cpp b/tests/unit_tests/safex_db/safex_stake_unstake.cpp index ed5aafeaa..a8a871257 100644 --- a/tests/unit_tests/safex_db/safex_stake_unstake.cpp +++ b/tests/unit_tests/safex_db/safex_stake_unstake.cpp @@ -58,10 +58,23 @@ namespace "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; - class SafexStakeUnstakeCommand : public ::testing::Test + class SafexStakeCommand : public ::testing::Test { public: - SafexStakeUnstakeCommand() { + SafexStakeCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + class SafexUnstakeCommand : public ::testing::Test + { + public: + SafexUnstakeCommand() { crypto::public_key pubKey; epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); keys.push_back(pubKey); @@ -204,18 +217,18 @@ namespace } else if (i == 517) { - //token unlock transaction + //token unstake transaction tx_list.resize(tx_list.size() + 1); cryptonote::transaction &tx = tx_list.back(); - construct_token_unstake_transaction(m_txmap, m_blocks, tx, m_users_acc[1], m_users_acc[1], 100 * SAFEX_TOKEN, default_miner_fee, 0); //unlock 100 + construct_token_unstake_transaction(m_txmap, m_blocks, tx, m_users_acc[1], m_users_acc[1], 100 * SAFEX_TOKEN, default_miner_fee, 0); //unstake 100 m_txmap[get_transaction_hash(tx)] = tx; } else if (i == 520) { - //token unlock transaction + //token unstake transaction tx_list.resize(tx_list.size() + 1); cryptonote::transaction &tx = tx_list.back(); - construct_token_unstake_transaction(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[0], 400 * SAFEX_TOKEN, default_miner_fee, 0); //unlock 400 + construct_token_unstake_transaction(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[0], 400 * SAFEX_TOKEN, default_miner_fee, 0); //unstake 400 m_txmap[get_transaction_hash(tx)] = tx; } @@ -282,7 +295,7 @@ namespace #if 1 - TEST_F(SafexStakeUnstakeCommand, HandlesCorruptedArrayOfBytes) + TEST_F(SafexStakeCommand, HandlesCorruptedArrayOfBytes) { std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; @@ -292,7 +305,17 @@ namespace } - TEST_F(SafexStakeUnstakeCommand, HandlesUnknownProtocolVersion) + TEST_F(SafexUnstakeCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::token_unstake), safex::command_exception); + + } + + TEST_F(SafexStakeCommand, HandlesUnknownProtocolVersion) { try @@ -310,7 +333,25 @@ namespace } } - TEST_F(SafexStakeUnstakeCommand, HandlesCommandParsing) + TEST_F(SafexUnstakeCommand, HandlesUnknownProtocolVersion) + { + + try + { + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, 1}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexStakeCommand, HandlesCommandParsing) { safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 2000}; @@ -327,13 +368,34 @@ namespace ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; - ASSERT_EQ(command1.get_staked_token_amount(), dynamic_cast(command2.get())->get_staked_token_amount()) << "Original and deserialized command must have same locked amount"; + ASSERT_EQ(command1.get_staked_token_amount(), dynamic_cast(command2.get())->get_staked_token_amount()) << "Original and deserialized command must have same staked amount"; + + } + + TEST_F(SafexUnstakeCommand, HandlesCommandParsing) + { + + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 1}; + + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::token_unstake) << "Token stake command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::token_unstake); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_staked_token_output_index(), dynamic_cast(command2.get())->get_staked_token_output_index()) << "Original and deserialized command must have same staked index"; } - TEST_F(SafexStakeUnstakeCommand, TokenLockExecute) + TEST_F(SafexStakeCommand, TokenStakeExecute) { try @@ -365,7 +427,7 @@ namespace } - TEST_F(SafexStakeUnstakeCommand, TokenLockExceptions) + TEST_F(SafexStakeCommand, TokenStakeExceptions) { // Token amount not whole @@ -436,18 +498,51 @@ namespace } - TEST_F(SafexStakeUnstakeCommand, TokenUnlockExecuteWrongType) + TEST_F(SafexStakeCommand, TokenStakeExecuteWrongType) + { + + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 10000*SAFEX_TOKEN; //stake 10k tokens + txinput.command_type = safex::command_t::token_stake; + txinput.key_offsets.push_back(23); + uint64_t staked_token_output_index = 23; + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ("Could not create command, wrong command type", std::string(exception.what()).c_str()); + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexUnstakeCommand, TokenUnstakeExecuteWrongType) { try { cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); - txinput.token_amount = 10000; //unlock 10k tokens + txinput.token_amount = 10000; //unstake 10k tokens txinput.command_type = safex::command_t::token_unstake; txinput.key_offsets.push_back(23); - uint64_t locked_token_output_index = 23; - safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + uint64_t staked_token_output_index = 23; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); @@ -493,7 +588,7 @@ namespace } if (i == 517) { - //here, we have unlocked 100, check current db status + //here, we have unstaked 100, check current db status uint64_t number_of_staked_tokens51 = this->m_db->get_staked_token_sum_for_interval(51); uint64_t number_of_staked_tokens52 = this->m_db->get_staked_token_sum_for_interval(52); uint64_t number_of_staked_tokens52_cur = this->m_db->get_current_staked_token_sum(); @@ -502,7 +597,7 @@ namespace ASSERT_EQ(number_of_staked_tokens52, 700 * SAFEX_TOKEN); ASSERT_EQ(number_of_staked_tokens52_cur, 700 * SAFEX_TOKEN); } else if (i == 520) { - //here, we have unlocked 400, check current db status + //here, we have unstaked 400, check current db status uint64_t number_of_staked_tokens51 = this->m_db->get_staked_token_sum_for_interval(51); uint64_t number_of_staked_tokens52 = this->m_db->get_staked_token_sum_for_interval(52); uint64_t number_of_staked_tokens52_cur = this->m_db->get_current_staked_token_sum(); @@ -560,7 +655,7 @@ namespace } - TYPED_TEST(SafexBlockchainFeeTest, TokenUnlockExecute) + TYPED_TEST(SafexBlockchainFeeTest, TokenUnstakeExecute) { boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); std::string dirPath = tempPath.string(); @@ -588,11 +683,11 @@ namespace { cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); - txinput.token_amount = 400 * SAFEX_TOKEN; //unlock 120k tokens + txinput.token_amount = 400 * SAFEX_TOKEN; //unstake 120k tokens txinput.command_type = safex::command_t::token_unstake; txinput.key_offsets.push_back(1); - uint64_t locked_token_output_index = 1; - safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + uint64_t staked_token_output_index = 1; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); @@ -614,7 +709,7 @@ namespace } - TYPED_TEST(SafexBlockchainFeeTest, TokenUnlockExceptions) + TYPED_TEST(SafexBlockchainFeeTest, TokenUnstakeExceptions) { boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); std::string dirPath = tempPath.string(); @@ -626,9 +721,9 @@ namespace this->get_filenames(); this->init_hard_fork(); - uint64_t minimum_lock_block_height = 10 + safex::get_safex_minumum_token_lock_period(this->m_db->get_net_type()); + uint64_t minimum_stake_block_height = 10 + safex::get_safex_minumum_token_lock_period(this->m_db->get_net_type()); - for (int i = 0; i < minimum_lock_block_height; i++) + for (int i = 0; i < minimum_stake_block_height; i++) { try { @@ -645,11 +740,11 @@ namespace { cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); - txinput.token_amount = 400 * SAFEX_TOKEN; //unlock 400 tokens + txinput.token_amount = 400 * SAFEX_TOKEN; //unstake 400 tokens txinput.command_type = safex::command_t::token_unstake; txinput.key_offsets.push_back(1); - uint64_t locked_token_output_index = 0; - safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + uint64_t staked_token_output_index = 0; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); @@ -677,9 +772,9 @@ namespace try { - this->m_db->add_block(this->m_blocks[minimum_lock_block_height], this->m_test_sizes[minimum_lock_block_height], - this->m_test_diffs[minimum_lock_block_height], this->m_test_coins[minimum_lock_block_height], - this->m_test_tokens[minimum_lock_block_height], this->m_txs[minimum_lock_block_height]); + this->m_db->add_block(this->m_blocks[minimum_stake_block_height], this->m_test_sizes[minimum_stake_block_height], + this->m_test_diffs[minimum_stake_block_height], this->m_test_coins[minimum_stake_block_height], + this->m_test_tokens[minimum_stake_block_height], this->m_txs[minimum_stake_block_height]); } catch (std::exception &e) { @@ -692,12 +787,12 @@ namespace { cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); - txinput.token_amount = 400 * SAFEX_TOKEN; //unlock 400 tokens + txinput.token_amount = 400 * SAFEX_TOKEN; //unstake 400 tokens txinput.command_type = safex::command_t::token_unstake; txinput.key_offsets.push_back(1); txinput.key_offsets.push_back(12); - uint64_t locked_token_output_index = 1; - safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + uint64_t staked_token_output_index = 1; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); @@ -727,12 +822,12 @@ namespace { cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); - txinput.token_amount = 400 * SAFEX_TOKEN; //unlock 400 tokens + txinput.token_amount = 400 * SAFEX_TOKEN; //unstake 400 tokens txinput.amount = 5000 * SAFEX_CASH_COIN; txinput.command_type = safex::command_t::token_unstake; txinput.key_offsets.push_back(1); - uint64_t locked_token_output_index = 0; - safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + uint64_t staked_token_output_index = 0; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); @@ -762,11 +857,11 @@ namespace { cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); - txinput.token_amount = 100 * SAFEX_TOKEN; //unlock 400 tokens + txinput.token_amount = 100 * SAFEX_TOKEN; //unstake 400 tokens txinput.command_type = safex::command_t::token_unstake; txinput.key_offsets.push_back(1); - uint64_t locked_token_output_index = 0; - safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, locked_token_output_index}; + uint64_t staked_token_output_index = 0; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); From 2e4eea03f7da95ac1022861747e51d1bcba8b0b3 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sat, 22 Aug 2020 14:48:32 +0200 Subject: [PATCH 16/36] [eppe][boost] Include non-depricated header --- contrib/epee/include/math_helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/epee/include/math_helper.h b/contrib/epee/include/math_helper.h index ef839f609..4cda875da 100644 --- a/contrib/epee/include/math_helper.h +++ b/contrib/epee/include/math_helper.h @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include From 5790e32530d3e129a56429dda67fe5d99fb1fe98 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sat, 22 Aug 2020 14:49:27 +0200 Subject: [PATCH 17/36] [edit_account] Add constructor to make our life easier --- src/safex/command.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/safex/command.h b/src/safex/command.h index 6b0a3b74c..ce166953a 100644 --- a/src/safex/command.h +++ b/src/safex/command.h @@ -839,6 +839,10 @@ struct create_price_peg_result : public execution_result edit_account(const uint32_t _version, const std::vector _username, const std::vector _new_account_data) : command(_version, command_t::edit_account), username(_username), new_account_data{_new_account_data} {} + edit_account(const uint32_t _version, const std::string &_username, const std::string &_new_account_data) : + command(_version, command_t::edit_account), username(_username.begin(), _username.end()), new_account_data(_new_account_data.begin(), _new_account_data.end()) {} + + edit_account() : command(0, command_t::edit_account), username{}, new_account_data{} {} std::string get_username() const { return std::string(username.begin(), username.end()); } From 9366578fe83ed00378ee934336f16bf1b60891cf Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sat, 22 Aug 2020 14:50:12 +0200 Subject: [PATCH 18/36] [safex_account][unit_tests] Refactor safex account and split tests for create and edit account --- tests/unit_tests/safex_db/safex_account.cpp | 136 ++++++++++++++++++-- 1 file changed, 128 insertions(+), 8 deletions(-) diff --git a/tests/unit_tests/safex_db/safex_account.cpp b/tests/unit_tests/safex_db/safex_account.cpp index a9a918043..686133114 100644 --- a/tests/unit_tests/safex_db/safex_account.cpp +++ b/tests/unit_tests/safex_db/safex_account.cpp @@ -58,10 +58,23 @@ namespace const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182"}; - class SafexAccountCommand : public ::testing::Test + class SafexCreateAccountCommand : public ::testing::Test { public: - SafexAccountCommand() { + SafexCreateAccountCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + class SafexEditAccountCommand : public ::testing::Test + { + public: + SafexEditAccountCommand() { crypto::public_key pubKey; epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); keys.push_back(pubKey); @@ -299,7 +312,7 @@ namespace } - TEST_F(SafexAccountCommand, HandlesCorruptedArrayOfBytes) + TEST_F(SafexCreateAccountCommand, HandlesCorruptedArrayOfBytes) { std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; @@ -309,7 +322,17 @@ namespace } - TEST_F(SafexAccountCommand, HandlesUnknownProtocolVersion) + TEST_F(SafexEditAccountCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::edit_account), safex::command_exception); + + } + + TEST_F(SafexCreateAccountCommand, HandlesUnknownProtocolVersion) { std::string username = "test01"; @@ -331,7 +354,29 @@ namespace } } - TEST_F(SafexAccountCommand, HandlesCommandParsing) + TEST_F(SafexEditAccountCommand, HandlesUnknownProtocolVersion) + { + + std::string username = "test01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + try + { + safex::edit_account command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, username, description}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexCreateAccountCommand, HandlesCommandParsing) { std::string username = "test01"; @@ -359,7 +404,32 @@ namespace } - TEST_F(SafexAccountCommand, CreateAccountExecute) + TEST_F(SafexEditAccountCommand, HandlesCommandParsing) + { + + std::string username = "test01"; + std::string description = "Some newtest data inserted"; + + safex::edit_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, description}; + + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::edit_account) << "Safex edit account command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::edit_account); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_username(), dynamic_cast(command2.get())->get_username()) << "Original and deserialized command must have same username"; + ASSERT_EQ(command1.get_new_account_data(), dynamic_cast(command2.get())->get_new_account_data()) << "Original and deserialized command must have same description"; + + } + + TEST_F(SafexCreateAccountCommand, CreateAccountExecute) { try @@ -393,7 +463,7 @@ namespace } - TEST_F(SafexAccountCommand, CreateAccountExceptions) + TEST_F(SafexCreateAccountCommand, CreateAccountExceptions) { // No tokens in the input @@ -662,7 +732,7 @@ namespace } - TYPED_TEST(SafexAccountTest, SafexAccountExceptions) + TYPED_TEST(SafexAccountTest, CreateSafexAccountExceptions) { boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); std::string dirPath = tempPath.string(); @@ -717,6 +787,56 @@ namespace ASSERT_NO_THROW(this->m_db->close()); } + + TYPED_TEST(SafexAccountTest, EditSafexAccountExecute) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS2 - 1; i++) + { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = this->m_safex_account1.username; + std::string description = "Some test data inserted"; + safex::edit_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_account); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + + } + catch (safex::command_exception &exception) + { + FAIL() << exception.what(); + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } #endif } // anonymous namespace From 38d760e76dd150350b63974c830c81fe15b96ff8 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sat, 22 Aug 2020 14:57:42 +0200 Subject: [PATCH 19/36] [safex_account][unit_tests] Add edit account exceptions unit tests --- tests/unit_tests/safex_db/safex_account.cpp | 89 +++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/tests/unit_tests/safex_db/safex_account.cpp b/tests/unit_tests/safex_db/safex_account.cpp index 686133114..7fde5d276 100644 --- a/tests/unit_tests/safex_db/safex_account.cpp +++ b/tests/unit_tests/safex_db/safex_account.cpp @@ -837,6 +837,95 @@ namespace ASSERT_NO_THROW(this->m_db->close()); } + + TYPED_TEST(SafexAccountTest, EditSafexAccountExceptions) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS2 - 1; i++) + { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex username not existant + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = "not_here"; + std::string description = "Some test data inserted"; + safex::edit_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_account); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account already exists"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex account data too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = this->m_safex_account1.username; + std::string description = ""; + for(int i=0; i < SAFEX_ACCOUNT_DATA_MAX_SIZE + 1; i++) + description += "x"; + safex::edit_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_account); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account already exists"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } #endif } // anonymous namespace From a3af1119a6176c475100de95a6c529e856180a14 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sat, 22 Aug 2020 15:15:14 +0200 Subject: [PATCH 20/36] [boost] Move from deprecated endian API --- external/boost/archive/portable_binary_archive.hpp | 2 +- external/boost/archive/portable_binary_iarchive.hpp | 6 +++--- external/boost/archive/portable_binary_oarchive.hpp | 4 ++-- tests/unit_tests/epee_utils.cpp | 3 ++- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/external/boost/archive/portable_binary_archive.hpp b/external/boost/archive/portable_binary_archive.hpp index e940c5b9e..7ae01a225 100644 --- a/external/boost/archive/portable_binary_archive.hpp +++ b/external/boost/archive/portable_binary_archive.hpp @@ -22,7 +22,7 @@ #endif #include -#include +#include #include diff --git a/external/boost/archive/portable_binary_iarchive.hpp b/external/boost/archive/portable_binary_iarchive.hpp index 7792b530d..bd19599f3 100644 --- a/external/boost/archive/portable_binary_iarchive.hpp +++ b/external/boost/archive/portable_binary_iarchive.hpp @@ -226,7 +226,7 @@ class portable_binary_iarchive : #include #include -#include +#include #include #include @@ -252,12 +252,12 @@ portable_binary_iarchive::load_impl(boost::intmax_t & l, char maxsize){ ); char * cptr = reinterpret_cast(& l); - #ifdef BOOST_BIG_ENDIAN + #if BOOST_ENDIAN_BIG_BYTE cptr += (sizeof(boost::intmax_t) - size); #endif this->primitive_base_t::load_binary(cptr, size); - #ifdef BOOST_BIG_ENDIAN + #if BOOST_ENDIAN_BIG_BYTE if(m_flags & endian_little) #else if(m_flags & endian_big) diff --git a/external/boost/archive/portable_binary_oarchive.hpp b/external/boost/archive/portable_binary_oarchive.hpp index e2dcb9456..783c7f7c9 100644 --- a/external/boost/archive/portable_binary_oarchive.hpp +++ b/external/boost/archive/portable_binary_oarchive.hpp @@ -221,7 +221,7 @@ class portable_binary_oarchive : // See http://www.boost.org for updates, documentation, and revision history. #include -#include +#include namespace boost { namespace archive { @@ -258,7 +258,7 @@ portable_binary_oarchive::save_impl( else ll = l; char * cptr = reinterpret_cast(& ll); - #ifdef BOOST_BIG_ENDIAN + #if BOOST_ENDIAN_BIG_BYTE cptr += (sizeof(boost::intmax_t) - size); if(m_flags & endian_little) reverse_bytes(size, cptr); diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp index fe911d6a0..8336f0ace 100644 --- a/tests/unit_tests/epee_utils.cpp +++ b/tests/unit_tests/epee_utils.cpp @@ -29,6 +29,7 @@ // Parts of this file are originally copyright (c) 2014-2018 The Monero Project #include +#include #include #include #include @@ -134,7 +135,7 @@ namespace EXPECT_FALSE( lhs >= rhs ); \ EXPECT_TRUE( rhs >= lhs ) - #ifdef BOOST_LITTLE_ENDIAN + #if BOOST_ENDIAN_LITTLE_BYTE #define CHECK_LESS_ENDIAN(lhs, rhs) CHECK_LESS( rhs , lhs ) #else #define CHECK_LESS_ENDIAN(lhs, rhs) CHECK_LESS( lhs , rhs ) From af05aec0a0339c7e8ea2e2482d323c99cb46f0cf Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Mon, 24 Aug 2020 17:57:32 +0200 Subject: [PATCH 21/36] [safex_offer][unit_tests] Create basic unit tests for Safex offer command poarsing --- tests/unit_tests/safex_db/safex_offer.cpp | 84 +++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/tests/unit_tests/safex_db/safex_offer.cpp b/tests/unit_tests/safex_db/safex_offer.cpp index db3bcb8b6..a56cbdceb 100644 --- a/tests/unit_tests/safex_db/safex_offer.cpp +++ b/tests/unit_tests/safex_db/safex_offer.cpp @@ -61,6 +61,19 @@ namespace "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182"}; + class SafexCreateOfferCommand : public ::testing::Test + { + public: + SafexCreateOfferCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + template class SafexOfferTest : public testing::Test { @@ -279,6 +292,77 @@ namespace #if 1 + TEST_F(SafexCreateOfferCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_offer), safex::command_exception); + + } + + TEST_F(SafexCreateOfferCommand, HandlesUnknownProtocolVersion) + { + + safex::create_offer_data offer_data{}; + try + { + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, offer_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexCreateOfferCommand, HandlesCommandParsing) + { + + cryptonote::account_base acc_base; + acc_base.generate(); + + safex::safex_account_key_handler m_safex_account_keys; + m_safex_account_keys.generate(); + + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + "username",acc_base.get_keys().m_view_secret_key, + acc_base.get_keys().m_account_address); + + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::create_offer) << "Safex create offer command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_offer); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_offerid(), dynamic_cast(command2.get())->get_offerid()) << "Original and deserialized command must have same offer ID"; + ASSERT_EQ(command1.get_price_peg_id(), dynamic_cast(command2.get())->get_price_peg_id()) << "Original and deserialized command must have same price peg ID"; + ASSERT_EQ(command1.get_seller(), dynamic_cast(command2.get())->get_seller()) << "Original and deserialized command must have same seller"; + ASSERT_EQ(command1.get_title(), dynamic_cast(command2.get())->get_title()) << "Original and deserialized command must have same title"; + ASSERT_EQ(command1.get_price(), dynamic_cast(command2.get())->get_price()) << "Original and deserialized command must have same price"; + ASSERT_EQ(command1.get_min_sfx_price(), dynamic_cast(command2.get())->get_min_sfx_price()) << "Original and deserialized command must have same minimal Safex price"; + ASSERT_EQ(command1.get_active(), dynamic_cast(command2.get())->get_active()) << "Original and deserialized command must have same active status"; + ASSERT_EQ(command1.get_price_peg_used(), dynamic_cast(command2.get())->get_price_peg_used()) << "Original and deserialized command must have same price peg used field"; + ASSERT_EQ(command1.get_description(), dynamic_cast(command2.get())->get_description()) << "Original and deserialized command must have same description"; + ASSERT_EQ(command1.get_seller_address(), dynamic_cast(command2.get())->get_seller_address()) << "Original and deserialized command must have same seller address"; + ASSERT_EQ(command1.get_seller_private_view_key(), dynamic_cast(command2.get())->get_seller_private_view_key()) << "Original and deserialized command must have same sellers private key"; + + } + TYPED_TEST(SafexOfferTest, CreateOfferCommand) { boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); std::string dirPath = tempPath.string(); From fb89f555e1c8edd06d6f09ce70cef04a56abd378 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 25 Aug 2020 12:33:38 +0200 Subject: [PATCH 22/36] [safex_offer] Improve logic for create offer checks * We must be sure that min_sfx_price is less than price if no price peg is used * Only min_sfx_price must be checked for min and max price allowed --- src/safex/command.cpp | 8 ++++++-- src/safex/command.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/safex/command.cpp b/src/safex/command.cpp index c2fb40a12..7aa0bc841 100644 --- a/src/safex/command.cpp +++ b/src/safex/command.cpp @@ -349,8 +349,12 @@ namespace safex result = execution_status::error_offer_price_too_small; } - if(cmd->get_price() > MONEY_SUPPLY) { - result = execution_status::error_offer_price_too_big; + if(cmd->get_min_sfx_price() > MONEY_SUPPLY){ + result = execution_status::error_offer_price_too_big; + } + + if(!cmd->get_price_peg_used() && cmd->get_min_sfx_price() > cmd->get_price()){ + result = execution_status::error_offer_price_mismatch; } if (cmd->get_title().size() > SAFEX_OFFER_NAME_MAX_SIZE) diff --git a/src/safex/command.h b/src/safex/command.h index ce166953a..4a839903f 100644 --- a/src/safex/command.h +++ b/src/safex/command.h @@ -60,6 +60,7 @@ namespace safex error_offer_price_too_small = 31, error_offer_data_too_big = 32, error_offer_price_peg_not_existant = 33, + error_offer_price_mismatch = 34, // Safex feedback error_feedback_invalid_rating = 40, error_feedback_data_too_big = 41, From f6f1afe62b6ee8ce2fd3eb3f62a630d6eab13fce Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 25 Aug 2020 12:37:20 +0200 Subject: [PATCH 23/36] [safex_offer][unit_tests] Add create Safex offer exception tests --- tests/unit_tests/safex_db/safex_offer.cpp | 298 ++++++++++++++++++++++ 1 file changed, 298 insertions(+) diff --git a/tests/unit_tests/safex_db/safex_offer.cpp b/tests/unit_tests/safex_db/safex_offer.cpp index a56cbdceb..177387d95 100644 --- a/tests/unit_tests/safex_db/safex_offer.cpp +++ b/tests/unit_tests/safex_db/safex_offer.cpp @@ -465,6 +465,304 @@ namespace ASSERT_NO_THROW(this->m_db->close()); } + + TYPED_TEST(SafexOfferTest, CreateOfferExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex account doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + "usernamenothere",this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price too small + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.min_sfx_price = SAFEX_OFFER_MINIMUM_PRICE - 1; + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_too_small); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer min price too small"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.min_sfx_price = MONEY_SUPPLY + 1; + sfx_offer.price = sfx_offer.min_sfx_price; + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer min price too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price mismatch + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.min_sfx_price = sfx_offer.price + 1; + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_mismatch); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price mismatch"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer title too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.title = ""; + for(int i = 0; i<=SAFEX_OFFER_NAME_MAX_SIZE+1; i++) + sfx_offer.title+='x'; + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer title too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer description too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.description.clear(); + for(int i = 0; i<=SAFEX_OFFER_DATA_MAX_SIZE+1; i++) + sfx_offer.description.push_back('x'); + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer description too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price peg doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.set_price_peg(sfx_offer.offer_id,100,100); + + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_peg_not_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } #endif } // anonymous namespace From b301daa034589577863352a120179dbb28903a88 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 25 Aug 2020 13:03:00 +0200 Subject: [PATCH 24/36] [safex_offer][unit_tests] Create initial unit tests for edit offer command --- tests/unit_tests/safex_db/safex_offer.cpp | 83 +++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/tests/unit_tests/safex_db/safex_offer.cpp b/tests/unit_tests/safex_db/safex_offer.cpp index 177387d95..dc521fc68 100644 --- a/tests/unit_tests/safex_db/safex_offer.cpp +++ b/tests/unit_tests/safex_db/safex_offer.cpp @@ -74,6 +74,19 @@ namespace TestDB m_db; }; + class SafexEditOfferCommand : public ::testing::Test + { + public: + SafexEditOfferCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + template class SafexOfferTest : public testing::Test { @@ -302,6 +315,16 @@ namespace } + TEST_F(SafexEditOfferCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::edit_offer), safex::command_exception); + + } + TEST_F(SafexCreateOfferCommand, HandlesUnknownProtocolVersion) { @@ -321,6 +344,25 @@ namespace } } + TEST_F(SafexEditOfferCommand, HandlesUnknownProtocolVersion) + { + + safex::edit_offer_data offer_data{}; + try + { + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, offer_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + TEST_F(SafexCreateOfferCommand, HandlesCommandParsing) { @@ -355,6 +397,7 @@ namespace ASSERT_EQ(command1.get_title(), dynamic_cast(command2.get())->get_title()) << "Original and deserialized command must have same title"; ASSERT_EQ(command1.get_price(), dynamic_cast(command2.get())->get_price()) << "Original and deserialized command must have same price"; ASSERT_EQ(command1.get_min_sfx_price(), dynamic_cast(command2.get())->get_min_sfx_price()) << "Original and deserialized command must have same minimal Safex price"; + ASSERT_EQ(command1.get_quantity(), dynamic_cast(command2.get())->get_quantity()) << "Original and deserialized command must have same quantity"; ASSERT_EQ(command1.get_active(), dynamic_cast(command2.get())->get_active()) << "Original and deserialized command must have same active status"; ASSERT_EQ(command1.get_price_peg_used(), dynamic_cast(command2.get())->get_price_peg_used()) << "Original and deserialized command must have same price peg used field"; ASSERT_EQ(command1.get_description(), dynamic_cast(command2.get())->get_description()) << "Original and deserialized command must have same description"; @@ -363,6 +406,46 @@ namespace } + TEST_F(SafexEditOfferCommand, HandlesCommandParsing) + { + + cryptonote::account_base acc_base; + acc_base.generate(); + + safex::safex_account_key_handler m_safex_account_keys; + m_safex_account_keys.generate(); + + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + "username",acc_base.get_keys().m_view_secret_key, + acc_base.get_keys().m_account_address); + + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::edit_offer) << "Safex edit offer command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::edit_offer); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_offerid(), dynamic_cast(command2.get())->get_offerid()) << "Original and deserialized command must have same offer ID"; + ASSERT_EQ(command1.get_price_peg_id(), dynamic_cast(command2.get())->get_price_peg_id()) << "Original and deserialized command must have same price peg ID"; + ASSERT_EQ(command1.get_seller(), dynamic_cast(command2.get())->get_seller()) << "Original and deserialized command must have same seller"; + ASSERT_EQ(command1.get_title(), dynamic_cast(command2.get())->get_title()) << "Original and deserialized command must have same title"; + ASSERT_EQ(command1.get_price(), dynamic_cast(command2.get())->get_price()) << "Original and deserialized command must have same price"; + ASSERT_EQ(command1.get_min_sfx_price(), dynamic_cast(command2.get())->get_min_sfx_price()) << "Original and deserialized command must have same minimal Safex price"; + ASSERT_EQ(command1.get_quantity(), dynamic_cast(command2.get())->get_quantity()) << "Original and deserialized command must have same quantity"; + ASSERT_EQ(command1.get_active(), dynamic_cast(command2.get())->get_active()) << "Original and deserialized command must have same active status"; + ASSERT_EQ(command1.get_price_peg_used(), dynamic_cast(command2.get())->get_price_peg_used()) << "Original and deserialized command must have same price peg used field"; + ASSERT_EQ(command1.get_description(), dynamic_cast(command2.get())->get_description()) << "Original and deserialized command must have same description"; + } + TYPED_TEST(SafexOfferTest, CreateOfferCommand) { boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); std::string dirPath = tempPath.string(); From dba9275e170fc384be0507f72444e01c4e74620d Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 25 Aug 2020 16:43:41 +0200 Subject: [PATCH 25/36] [safex_offer] Add more check for offer creation * Dont't allow offers with ID already in the DB * Dont't allow creation of the offer with status inactive or quantity 0 --- src/safex/command.cpp | 9 +++++++++ src/safex/command.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/safex/command.cpp b/src/safex/command.cpp index 7aa0bc841..a0e64ef9c 100644 --- a/src/safex/command.cpp +++ b/src/safex/command.cpp @@ -345,6 +345,15 @@ namespace safex result = execution_status::error_account_non_existant; } + safex::safex_offer sfx_offer{}; + if (blokchainDB.get_offer(cmd->get_offerid(),sfx_offer)) { + return execution_status::error_offer_already_exists; + } + + if(cmd->get_active() == false || cmd->get_quantity() == 0) { + return execution_status::error_wrong_input_params; + } + if(cmd->get_min_sfx_price() < SAFEX_OFFER_MINIMUM_PRICE){ result = execution_status::error_offer_price_too_small; } diff --git a/src/safex/command.h b/src/safex/command.h index 4a839903f..e0caee482 100644 --- a/src/safex/command.h +++ b/src/safex/command.h @@ -61,6 +61,7 @@ namespace safex error_offer_data_too_big = 32, error_offer_price_peg_not_existant = 33, error_offer_price_mismatch = 34, + error_offer_already_exists = 35, // Safex feedback error_feedback_invalid_rating = 40, error_feedback_data_too_big = 41, From d40b7ece86126f45f7c487adfeae59fc8ca448b1 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 25 Aug 2020 19:04:56 +0200 Subject: [PATCH 26/36] [safex_offer][unit_tests] Added tests for duplicate offerID, and invalid active status or quantity 0 --- tests/unit_tests/safex_db/safex_offer.cpp | 114 ++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/tests/unit_tests/safex_db/safex_offer.cpp b/tests/unit_tests/safex_db/safex_offer.cpp index dc521fc68..e583b9360 100644 --- a/tests/unit_tests/safex_db/safex_offer.cpp +++ b/tests/unit_tests/safex_db/safex_offer.cpp @@ -843,6 +843,120 @@ namespace FAIL() << "Unexpected exception"; } + // Safex offer already exists + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + + safex::create_offer_data offer_data{this->m_safex_offer[0]}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_already_exists); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer quantity zero + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.quantity = 0; + + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_wrong_input_params); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer inactive + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.active = false; + + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_wrong_input_params); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } ASSERT_NO_THROW(this->m_db->close()); } From 58ba73363940e8d6ec7c1d6a9cf258e390298f36 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 25 Aug 2020 19:57:58 +0200 Subject: [PATCH 27/36] [safex_command][refactor] Return error in comand validation as soon as it is found --- src/safex/command.cpp | 100 ++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 57 deletions(-) diff --git a/src/safex/command.cpp b/src/safex/command.cpp index a0e64ef9c..6da3dd60a 100644 --- a/src/safex/command.cpp +++ b/src/safex/command.cpp @@ -39,15 +39,14 @@ namespace safex execution_status token_stake::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) { - execution_status result = execution_status::ok; //per input execution, one input could be less than SAFEX_MINIMUM_TOKEN_STAKE_AMOUNT, all inputs must be SAFEX_MINIMUM_TOKEN_STAKE_AMOUNT if(!tools::is_whole_token_amount(this->get_staked_token_amount())) - result = execution_status::error_stake_token_not_whole_amount; + return execution_status::error_stake_token_not_whole_amount; if(!(txin.token_amount == this->get_staked_token_amount())) - result = execution_status::error_stake_token_amount_not_matching; + return execution_status::error_stake_token_amount_not_matching; - return result; + return execution_status::ok; } token_unstake_result* token_unstake::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) @@ -74,10 +73,8 @@ namespace safex execution_status token_unstake::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) { - execution_status result = execution_status::ok; - if(txin.key_offsets.size() != 1) - result = execution_status::error_unstake_token_offset_not_one; + return execution_status::error_unstake_token_offset_not_one; uint64_t staked_token_index = txin.key_offsets[0]; const cryptonote::output_advanced_data_t od = blokchainDB.get_output_advanced_data(cryptonote::tx_out_type::out_staked_token, staked_token_index); @@ -94,14 +91,14 @@ namespace safex uint64_t expected_interest = blokchainDB.calculate_staked_token_interest_for_output(txin, blokchainDB.height()); if(txin.amount > expected_interest) - result = execution_status::error_unstake_token_network_fee_not_matching; + return execution_status::error_unstake_token_network_fee_not_matching; if(!output_found) - result = execution_status::error_unstake_token_output_not_found; + return execution_status::error_unstake_token_output_not_found; if(od.height + get_safex_minumum_token_lock_period(blokchainDB.get_net_type()) > blokchainDB.height()) - result = execution_status::error_unstake_token_minimum_period; + return execution_status::error_unstake_token_minimum_period; - return result; + return execution_status::ok; } @@ -128,13 +125,12 @@ namespace safex { //TODO: GRKI Do not allow token_collect for now - execution_status result = execution_status::invalid; //todo Get data about locked token output from database using its index //todo check if db output amount is same as txin amount //todo check if minimum amount of time is fulfilled - return result; + return execution_status::invalid; } @@ -155,14 +151,12 @@ namespace safex execution_status donate_fee::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) { - execution_status result = execution_status::ok; - if(!(txin.amount > 0)) return execution_status::error_wrong_input_params; if(txin.token_amount != 0) return execution_status::error_wrong_input_params; - return result; + return execution_status::ok; }; simple_purchase_result* simple_purchase::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) @@ -186,8 +180,6 @@ namespace safex { std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); - execution_status result = execution_status::ok; - safex::safex_offer sfx_offer{}; if (!blokchainDB.get_offer(cmd->offer_id,sfx_offer)) { return execution_status::error_offer_non_existant; @@ -229,7 +221,7 @@ namespace safex if(txin.token_amount != 0) return execution_status::error_wrong_input_params; - return result; + return execution_status::ok; }; create_account_result* create_account::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) @@ -292,19 +284,18 @@ namespace safex execution_status edit_account::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) { - execution_status result = execution_status::ok; std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); for (auto ch: cmd->get_username()) { if (!(std::islower(ch) || std::isdigit(ch)) && ch!='_' && ch!='-') { - result = execution_status::error_invalid_account_name; + return execution_status::error_invalid_account_name; } } std::vector dummy{}; if (!blokchainDB.get_account_data(cmd->get_username(), dummy)) { - result = execution_status::error_account_non_existant; + return execution_status::error_account_non_existant; } if (cmd->get_username().length() > SAFEX_ACCOUNT_USERNAME_MAX_SIZE) @@ -317,7 +308,7 @@ namespace safex return execution_status::error_account_data_too_big; } - return result; + return execution_status::ok; }; @@ -337,12 +328,11 @@ namespace safex execution_status create_offer::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) { - execution_status result = execution_status::ok; std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); std::vector dummy{}; if (!blokchainDB.get_account_data(cmd->get_seller(), dummy)) { - result = execution_status::error_account_non_existant; + return execution_status::error_account_non_existant; } safex::safex_offer sfx_offer{}; @@ -355,35 +345,35 @@ namespace safex } if(cmd->get_min_sfx_price() < SAFEX_OFFER_MINIMUM_PRICE){ - result = execution_status::error_offer_price_too_small; + return execution_status::error_offer_price_too_small; } if(cmd->get_min_sfx_price() > MONEY_SUPPLY){ - result = execution_status::error_offer_price_too_big; + return execution_status::error_offer_price_too_big; } if(!cmd->get_price_peg_used() && cmd->get_min_sfx_price() > cmd->get_price()){ - result = execution_status::error_offer_price_mismatch; + return execution_status::error_offer_price_mismatch; } if (cmd->get_title().size() > SAFEX_OFFER_NAME_MAX_SIZE) { MERROR("Offer title is bigger than max allowed " + std::to_string(SAFEX_OFFER_NAME_MAX_SIZE)); - result = execution_status::error_offer_data_too_big; + return execution_status::error_offer_data_too_big; } if (cmd->get_description().size() > SAFEX_OFFER_DATA_MAX_SIZE) { MERROR("Offer data is bigger than max allowed " + std::to_string(SAFEX_OFFER_DATA_MAX_SIZE)); - result = execution_status::error_offer_data_too_big; + return execution_status::error_offer_data_too_big; } safex::safex_price_peg sfx_price_peg{}; if(cmd->get_price_peg_used() && !blokchainDB.get_safex_price_peg(cmd->get_price_peg_id(),sfx_price_peg)){ - result = execution_status::error_offer_price_peg_not_existant; + return execution_status::error_offer_price_peg_not_existant; } - return result; + return execution_status::ok; }; edit_offer_result* edit_offer::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) @@ -401,44 +391,43 @@ namespace safex execution_status edit_offer::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) { - execution_status result = execution_status::ok; std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); std::vector dummy{}; if (!blokchainDB.get_account_data(cmd->get_seller(), dummy)) { - result = execution_status::error_account_non_existant; + return execution_status::error_account_non_existant; } if(cmd->get_min_sfx_price() < SAFEX_OFFER_MINIMUM_PRICE){ - result = execution_status::error_offer_price_too_small; + return execution_status::error_offer_price_too_small; } if(cmd->get_price() > MONEY_SUPPLY) { - result = execution_status::error_offer_price_too_big; + return execution_status::error_offer_price_too_big; } if (cmd->get_title().size() > SAFEX_OFFER_NAME_MAX_SIZE) { MERROR("Offer title is bigger than max allowed " + std::to_string(SAFEX_OFFER_NAME_MAX_SIZE)); - result = execution_status::error_offer_data_too_big; + return execution_status::error_offer_data_too_big; } if (cmd->get_description().size() > SAFEX_OFFER_DATA_MAX_SIZE) { MERROR("Offer data is bigger than max allowed " + std::to_string(SAFEX_OFFER_DATA_MAX_SIZE)); - result = execution_status::error_offer_data_too_big; + return execution_status::error_offer_data_too_big; } safex::safex_price_peg sfx_price_peg{}; if(cmd->get_price_peg_used() && !blokchainDB.get_safex_price_peg(cmd->get_price_peg_id(),sfx_price_peg)){ - result = execution_status::error_offer_price_peg_not_existant; + return execution_status::error_offer_price_peg_not_existant; } safex::safex_offer sfx_dummy{}; if (!blokchainDB.get_offer(cmd->get_offerid(), sfx_dummy)) { - result = execution_status::error_offer_non_existant; + return execution_status::error_offer_non_existant; } - return result; + return execution_status::ok; }; create_feedback_result* create_feedback::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) @@ -456,23 +445,22 @@ namespace safex execution_status create_feedback::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) { - execution_status result = execution_status::ok; std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); safex::safex_offer sfx_dummy{}; if (!blokchainDB.get_offer(cmd->get_offerid(), sfx_dummy)) { - result = execution_status::error_offer_non_existant; + return execution_status::error_offer_non_existant; } uint64_t rating_given = cmd->get_stars_given(); if(rating_given > 3 ) - result = execution_status::error_feedback_invalid_rating; + return execution_status::error_feedback_invalid_rating; if(cmd->get_comment().size() > SAFEX_FEEDBACK_DATA_MAX_SIZE) - result = execution_status::error_feedback_data_too_big; + return execution_status::error_feedback_data_too_big; - return result; + return execution_status::ok; }; create_price_peg_result* create_price_peg::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) @@ -491,37 +479,36 @@ namespace safex execution_status create_price_peg::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) { - execution_status result = execution_status::ok; std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); if (cmd->get_title().size() > SAFEX_PRICE_PEG_NAME_MAX_SIZE) { - result = execution_status::error_price_peg_data_too_big; + return execution_status::error_price_peg_data_too_big; } if (cmd->get_currency().size() > SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE) { - result = execution_status::error_price_peg_bad_currency_format; + return execution_status::error_price_peg_bad_currency_format; } for (auto ch: cmd->get_currency()) { if (!std::isupper(ch)) { - result = execution_status::error_price_peg_bad_currency_format; + return execution_status::error_price_peg_bad_currency_format; } } if(cmd->get_rate() == 0) { - result = execution_status::error_price_peg_rate_zero; + return execution_status::error_price_peg_rate_zero; } //check price peg data size if (cmd->get_description().size() > SAFEX_PRICE_PEG_DATA_MAX_SIZE) { - result = execution_status::error_price_peg_data_too_big; + return execution_status::error_price_peg_data_too_big; } - return result; + return execution_status::ok; }; update_price_peg_result* update_price_peg::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) @@ -540,21 +527,20 @@ namespace safex execution_status update_price_peg::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) { - execution_status result = execution_status::ok; std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); if(cmd->get_rate() == 0) { - result = execution_status::error_price_peg_rate_zero; + return execution_status::error_price_peg_rate_zero; } safex::safex_price_peg sfx_dummy{}; if (!blokchainDB.get_safex_price_peg(cmd->get_price_peg_id(), sfx_dummy)) { - result = execution_status::error_price_peg_not_existant; + return execution_status::error_price_peg_not_existant; } - return result; + return execution_status::ok; }; bool validate_safex_command(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) From 496bb2d1a9dc9b04bee825581e4024edd6686091 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 25 Aug 2020 20:29:58 +0200 Subject: [PATCH 28/36] [safex_offer] Add checks for price when edit offer command is validated --- src/safex/command.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/safex/command.cpp b/src/safex/command.cpp index 6da3dd60a..5e330c2c1 100644 --- a/src/safex/command.cpp +++ b/src/safex/command.cpp @@ -402,8 +402,12 @@ namespace safex return execution_status::error_offer_price_too_small; } - if(cmd->get_price() > MONEY_SUPPLY) { - return execution_status::error_offer_price_too_big; + if(cmd->get_min_sfx_price() > MONEY_SUPPLY){ + return execution_status::error_offer_price_too_big; + } + + if(!cmd->get_price_peg_used() && cmd->get_min_sfx_price() > cmd->get_price()){ + return execution_status::error_offer_price_mismatch; } if (cmd->get_title().size() > SAFEX_OFFER_NAME_MAX_SIZE) From e344fd5b525be608d52acc239c691f1fb3e5f3dd Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 25 Aug 2020 20:32:48 +0200 Subject: [PATCH 29/36] [safex_offer][unit_tests] Add exceptions for edit offer tests --- tests/unit_tests/safex_db/safex_offer.cpp | 414 +++++++++++++++++++++- 1 file changed, 413 insertions(+), 1 deletion(-) diff --git a/tests/unit_tests/safex_db/safex_offer.cpp b/tests/unit_tests/safex_db/safex_offer.cpp index e583b9360..36b96b4d8 100644 --- a/tests/unit_tests/safex_db/safex_offer.cpp +++ b/tests/unit_tests/safex_db/safex_offer.cpp @@ -812,7 +812,7 @@ namespace this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, this->m_users_acc[0].get_keys().m_account_address); - sfx_offer.set_price_peg(sfx_offer.offer_id,100,100); + sfx_offer.set_price_peg(sfx_offer.offer_id,100,100*COIN); safex::create_offer_data offer_data{sfx_offer}; @@ -960,6 +960,418 @@ namespace ASSERT_NO_THROW(this->m_db->close()); } + + TYPED_TEST(SafexOfferTest, EditOfferExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex account doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + "usernamenothere",this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price too small + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.min_sfx_price = SAFEX_OFFER_MINIMUM_PRICE - 1; + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_too_small); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer min price too small"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.min_sfx_price = MONEY_SUPPLY + 1; + sfx_offer.price = sfx_offer.min_sfx_price; + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer min price too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price mismatch + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.min_sfx_price = sfx_offer.price + 1; + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_mismatch); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price mismatch"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer title too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.title = ""; + for(int i = 0; i<=SAFEX_OFFER_NAME_MAX_SIZE+1; i++) + sfx_offer.title+='x'; + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer title too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer description too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.description.clear(); + for(int i = 0; i<=SAFEX_OFFER_DATA_MAX_SIZE+1; i++) + sfx_offer.description.push_back('x'); + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer description too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price peg doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.set_price_peg(sfx_offer.offer_id,100,100*COIN); + + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_peg_not_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + + safex::edit_offer_data offer_data{this->m_safex_offer[0]}; + offer_data.offer_id.data[0] +=1; + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer quantity zero + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.quantity = 0; + + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_wrong_input_params); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer inactive + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.active = false; + + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_wrong_input_params); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + ASSERT_NO_THROW(this->m_db->close()); + + } #endif } // anonymous namespace From 8204e5c1d383917cb98d57b596193787ec40b518 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 25 Aug 2020 21:02:59 +0200 Subject: [PATCH 30/36] [unit_tests] Fix for unit tests to pass --- tests/unit_tests/safex_db/safex_stake_unstake.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit_tests/safex_db/safex_stake_unstake.cpp b/tests/unit_tests/safex_db/safex_stake_unstake.cpp index a8a871257..19fbb86e8 100644 --- a/tests/unit_tests/safex_db/safex_stake_unstake.cpp +++ b/tests/unit_tests/safex_db/safex_stake_unstake.cpp @@ -468,9 +468,9 @@ namespace { cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); - txinput.token_amount = 19000; + txinput.token_amount = 19000*SAFEX_TOKEN; txinput.command_type = safex::command_t::token_stake; - safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 11000}; + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 11000*SAFEX_TOKEN}; safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); From 9bec5b5daba990ea11f169318877057eaf9d8167 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Thu, 27 Aug 2020 11:19:51 +0200 Subject: [PATCH 31/36] [price_peg][unit_tests] Add basic unit tests for price peg creation and update --- tests/unit_tests/safex_db/safex_price_peg.cpp | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/tests/unit_tests/safex_db/safex_price_peg.cpp b/tests/unit_tests/safex_db/safex_price_peg.cpp index 83ea287b2..156f18b0d 100644 --- a/tests/unit_tests/safex_db/safex_price_peg.cpp +++ b/tests/unit_tests/safex_db/safex_price_peg.cpp @@ -60,6 +60,31 @@ namespace const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182"}; + class SafexCreatePricePegCommand : public ::testing::Test + { + public: + SafexCreatePricePegCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + class SafexUpdatePricePegCommand : public ::testing::Test + { + public: + SafexUpdatePricePegCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; template class SafexPricePegTest : public testing::Test @@ -248,6 +273,130 @@ namespace #if 1 + TEST_F(SafexCreatePricePegCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_price_peg), safex::command_exception); + + } + + TEST_F(SafexUpdatePricePegCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::update_price_peg), safex::command_exception); + + } + + TEST_F(SafexCreatePricePegCommand, HandlesUnknownProtocolVersion) + { + + safex::create_price_peg_data price_peg_data{}; + try + { + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, price_peg_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexUpdatePricePegCommand, HandlesUnknownProtocolVersion) + { + + safex::update_price_peg_data price_peg_data{}; + try + { + safex::update_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, price_peg_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexCreatePricePegCommand, HandlesCommandParsing) + { + + cryptonote::account_base acc_base; + acc_base.generate(); + + safex::safex_account_key_handler m_safex_account_keys; + m_safex_account_keys.generate(); + + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", "username","USD","Some description", 1828); + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::create_price_peg) << "Safex create price peg command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_price_peg); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_price_peg_id(), dynamic_cast(command2.get())->get_price_peg_id()) << "Original and deserialized command must have same price peg ID"; + ASSERT_EQ(command1.get_creator(), dynamic_cast(command2.get())->get_creator()) << "Original and deserialized command must have same creator"; + ASSERT_EQ(command1.get_title(), dynamic_cast(command2.get())->get_title()) << "Original and deserialized command must have same title"; + ASSERT_EQ(command1.get_description(), dynamic_cast(command2.get())->get_description()) << "Original and deserialized command must have same description"; + ASSERT_EQ(command1.get_currency(), dynamic_cast(command2.get())->get_currency()) << "Original and deserialized command must have same currency"; + ASSERT_EQ(command1.get_rate(), dynamic_cast(command2.get())->get_rate()) << "Original and deserialized command must have same rate"; + + } + + TEST_F(SafexUpdatePricePegCommand, HandlesCommandParsing) + { + + cryptonote::account_base acc_base; + acc_base.generate(); + + safex::safex_account_key_handler m_safex_account_keys; + m_safex_account_keys.generate(); + + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", "username","USD","Some description", 1828); + + safex::update_price_peg_data price_peg_data{sfx_price_peg}; + + safex::update_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::update_price_peg) << "Safex create price peg command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::update_price_peg); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_price_peg_id(), dynamic_cast(command2.get())->get_price_peg_id()) << "Original and deserialized command must have same price peg ID"; + ASSERT_EQ(command1.get_rate(), dynamic_cast(command2.get())->get_rate()) << "Original and deserialized command must have same rate"; + + } + TYPED_TEST(SafexPricePegTest, CreatePricePegCommand) { boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); std::string dirPath = tempPath.string(); From 3d5aec0492c1353b9510be1859958468ab3a2f61 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Thu, 27 Aug 2020 15:00:14 +0200 Subject: [PATCH 32/36] [safex_command][price_peg] Don't allow command verification if username is not in the DB or price peg ID already exists --- src/safex/command.cpp | 13 ++++++++++++- src/safex/command.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/safex/command.cpp b/src/safex/command.cpp index 5e330c2c1..c0dfcd932 100644 --- a/src/safex/command.cpp +++ b/src/safex/command.cpp @@ -485,6 +485,17 @@ namespace safex std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); + std::vector dummy{}; + if (!blokchainDB.get_account_data(cmd->get_creator(), dummy)) { + return execution_status::error_account_non_existant; + } + + safex::safex_price_peg dummy_price_peg{}; + if(blokchainDB.get_safex_price_peg(cmd->get_price_peg_id(),dummy_price_peg)) + { + return execution_status::error_price_peg_already_exists; + } + if (cmd->get_title().size() > SAFEX_PRICE_PEG_NAME_MAX_SIZE) { return execution_status::error_price_peg_data_too_big; @@ -492,7 +503,7 @@ namespace safex if (cmd->get_currency().size() > SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE) { - return execution_status::error_price_peg_bad_currency_format; + return execution_status::error_price_peg_data_too_big; } for (auto ch: cmd->get_currency()) { diff --git a/src/safex/command.h b/src/safex/command.h index e0caee482..2edde29b6 100644 --- a/src/safex/command.h +++ b/src/safex/command.h @@ -70,6 +70,7 @@ namespace safex error_price_peg_data_too_big = 52, error_price_peg_not_existant = 53, error_price_peg_rate_zero = 54, + error_price_peg_already_exists = 55, // Safex unstake token error_unstake_token_output_not_found = 60, error_unstake_token_minimum_period = 61, From c92454781127aeaa534aef16309dafc347879b18 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Thu, 27 Aug 2020 15:01:06 +0200 Subject: [PATCH 33/36] [price_peg][unit_tests] Add exception unit tests for price peg create and update --- tests/unit_tests/safex_db/safex_price_peg.cpp | 383 ++++++++++++++++++ 1 file changed, 383 insertions(+) diff --git a/tests/unit_tests/safex_db/safex_price_peg.cpp b/tests/unit_tests/safex_db/safex_price_peg.cpp index 156f18b0d..98683e109 100644 --- a/tests/unit_tests/safex_db/safex_price_peg.cpp +++ b/tests/unit_tests/safex_db/safex_price_peg.cpp @@ -463,6 +463,389 @@ namespace ASSERT_NO_THROW(this->m_db->close()); } + + TYPED_TEST(SafexPricePegTest, CreatePricePegExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex account doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", "username","USD","Some description", 1828); + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg ID already exists + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + + safex::create_price_peg_data price_peg_data{this->m_safex_price_pegs[0]}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_already_exists); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg ID already in the DB"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg name too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"USD","Some description", 1828); + + sfx_price_peg.title = ""; + for (int i=0; i < SAFEX_PRICE_PEG_NAME_MAX_SIZE + 2 ; i++) { + sfx_price_peg.title += "x"; + } + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg title too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg curreny name too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"USD","Some description", 1828); + + sfx_price_peg.currency = ""; + for (int i=0; i < SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE + 2 ; i++) { + sfx_price_peg.currency += "x"; + } + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg currency name too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg description too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"USD","Some description", 1828); + + sfx_price_peg.description.clear(); + for (int i=0; i < SAFEX_PRICE_PEG_DATA_MAX_SIZE + 2 ; i++) { + sfx_price_peg.description.push_back('x'); + } + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg currency description too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg curreny name invalid + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"US-D","Some description", 1828); + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_bad_currency_format); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg currency name invalid"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg rate zero + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"USD","Some description", 1828); + + sfx_price_peg.rate = 0; + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_rate_zero); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg rate is zero"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexPricePegTest, UpdatePricePegExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex price peg doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::update_price_peg; + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", "username","USD","Some description", 1828); + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::update_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_not_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg already exists"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg rate zero + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::update_price_peg; + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"USD","Some description", 1828); + + sfx_price_peg.rate = 0; + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::update_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_rate_zero); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg rate zero"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + #endif } // anonymous namespace From 10f7655dfdd1d1e163659561b4b2b07ec0134ab4 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Thu, 27 Aug 2020 17:24:02 +0200 Subject: [PATCH 34/36] [safex_purchase][unit_tests] Add additional unit tests for safex purchase --- tests/unit_tests/safex_db/simple_purchase.cpp | 288 +++++++++++++++++- 1 file changed, 286 insertions(+), 2 deletions(-) diff --git a/tests/unit_tests/safex_db/simple_purchase.cpp b/tests/unit_tests/safex_db/simple_purchase.cpp index 98b6ecc81..e07b1df34 100644 --- a/tests/unit_tests/safex_db/simple_purchase.cpp +++ b/tests/unit_tests/safex_db/simple_purchase.cpp @@ -62,6 +62,18 @@ namespace const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182"}; + class SafexPurchaseCommand : public ::testing::Test + { + public: + SafexPurchaseCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; template class SimplePurchaseTest : public testing::Test @@ -114,8 +126,9 @@ namespace std::string new_str_desc{"Now without worms!!"}; std::vector new_desc{new_str_desc.begin(),new_str_desc.end()}; - m_edited_safex_offer = m_safex_offer[0]; + m_edited_safex_offer = m_safex_offer[1]; m_edited_safex_offer.description = new_desc; + m_edited_safex_offer.active = false; for (int i = 0; i < NUMBER_OF_BLOCKS; i++) @@ -191,8 +204,13 @@ namespace { tx_list.resize(tx_list.size() + 1); cryptonote::transaction &tx = tx_list.back(); \ - construct_create_purchase_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_purchase,m_users_acc[1].get_keys().m_account_address); + construct_edit_offer_transaction(m_txmap, m_blocks, tx, m_users_acc[1], default_miner_fee, 0, m_safex_account2.pkey, m_edited_safex_offer, m_safex_account2_keys.get_keys()); m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_create_purchase_transaction(m_txmap, m_blocks, tx2, m_users_acc[0], default_miner_fee, 0, m_safex_purchase,m_users_acc[1].get_keys().m_account_address); + m_txmap[get_transaction_hash(tx2)] = tx2; } else if (i == 25) { @@ -282,6 +300,64 @@ namespace #if 1 + TEST_F(SafexPurchaseCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::simple_purchase), safex::command_exception); + + } + + TEST_F(SafexPurchaseCommand, HandlesUnknownProtocolVersion) + { + + safex::create_purchase_data purchase_data{}; + try + { + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, purchase_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexPurchaseCommand, HandlesCommandParsing) + { + + crypto::hash offer_id; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(1, 100, offer_id, false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::simple_purchase) << "Safex purchase command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::simple_purchase); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_offerid(), dynamic_cast(command2.get())->get_offerid()) << "Original and deserialized command must have same offer ID"; + ASSERT_EQ(command1.get_quantity(), dynamic_cast(command2.get())->get_quantity()) << "Original and deserialized command must have same quantity"; + ASSERT_EQ(command1.get_price(), dynamic_cast(command2.get())->get_price()) << "Original and deserialized command must have same price"; + ASSERT_EQ(command1.get_shipping(), dynamic_cast(command2.get())->get_shipping()) << "Original and deserialized command must have same shipping"; + + } + TYPED_TEST(SimplePurchaseTest, CreatePurchaseCommand) { boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); std::string dirPath = tempPath.string(); @@ -363,6 +439,214 @@ namespace ASSERT_NO_THROW(this->m_db->close()); } + + TYPED_TEST(SimplePurchaseTest, CreatePurchaseExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS2; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex offer doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::simple_purchase; + + crypto::hash offer_id{}; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(1, 100, offer_id, false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::simple_purchase); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer isn't active + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::simple_purchase; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(1, 100, this->m_edited_safex_offer.offer_id, false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::simple_purchase); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_purchase_offer_not_active); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer isn't active"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer doesn't have enough in stock + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::simple_purchase; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(this->m_safex_offer[0].quantity + 1, 100, this->m_safex_offer[0].offer_id, false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::simple_purchase); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_purchase_out_of_stock); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer doesn't have enough"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex purchase quantity cannot be zero + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::simple_purchase; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(0, 100, this->m_safex_offer[0].offer_id, false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::simple_purchase); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_purchase_quantity_zero); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex purchase quantity is zero"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex purchase not enough funds registred + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::simple_purchase; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(1, this->m_safex_offer[0].price-1, this->m_safex_offer[0].offer_id, false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::simple_purchase); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_purchase_not_enough_funds); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex purchase given not enough funds"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + #endif } // anonymous namespace From c6e24258015bff9b82292ae5b901152c926b6548 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Fri, 28 Aug 2020 13:04:19 +0200 Subject: [PATCH 35/36] [safex_feedback][unit_tests] Add basic unit tests for create feedback command --- tests/unit_tests/safex_db/simple_purchase.cpp | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/unit_tests/safex_db/simple_purchase.cpp b/tests/unit_tests/safex_db/simple_purchase.cpp index e07b1df34..750c5f614 100644 --- a/tests/unit_tests/safex_db/simple_purchase.cpp +++ b/tests/unit_tests/safex_db/simple_purchase.cpp @@ -75,6 +75,19 @@ namespace TestDB m_db; }; + class SafexFeedbackCommand : public ::testing::Test + { + public: + SafexFeedbackCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + template class SimplePurchaseTest : public testing::Test { @@ -310,6 +323,16 @@ namespace } + TEST_F(SafexFeedbackCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_feedback), safex::command_exception); + + } + TEST_F(SafexPurchaseCommand, HandlesUnknownProtocolVersion) { @@ -329,6 +352,25 @@ namespace } } + TEST_F(SafexFeedbackCommand, HandlesUnknownProtocolVersion) + { + + safex::create_feedback_data feedback_data{}; + try + { + safex::create_feedback command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, feedback_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + TEST_F(SafexPurchaseCommand, HandlesCommandParsing) { @@ -358,6 +400,34 @@ namespace } + TEST_F(SafexFeedbackCommand, HandlesCommandParsing) + { + + crypto::hash offer_id; + + safex::safex_feedback sfx_feedback = safex::safex_feedback(1, "100", offer_id); + + safex::create_feedback_data feedback_data{sfx_feedback}; + + safex::create_feedback command1{SAFEX_COMMAND_PROTOCOL_VERSION , feedback_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::create_feedback) << "Safex feedback command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_feedback); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_offerid(), dynamic_cast(command2.get())->get_offerid()) << "Original and deserialized command must have same offer ID"; + ASSERT_EQ(command1.get_stars_given(), dynamic_cast(command2.get())->get_stars_given()) << "Original and deserialized command must have same rating"; + ASSERT_EQ(command1.get_comment(), dynamic_cast(command2.get())->get_comment()) << "Original and deserialized command must have same comment"; + + } + TYPED_TEST(SimplePurchaseTest, CreatePurchaseCommand) { boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); std::string dirPath = tempPath.string(); From 3054aad1b1bf7ac997dc78fe55d4d026ba45c998 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Fri, 28 Aug 2020 13:16:53 +0200 Subject: [PATCH 36/36] [safex_feedback][unit_tests] Add create feedback command exception tests --- tests/unit_tests/safex_db/simple_purchase.cpp | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/tests/unit_tests/safex_db/simple_purchase.cpp b/tests/unit_tests/safex_db/simple_purchase.cpp index 750c5f614..f28cfd65f 100644 --- a/tests/unit_tests/safex_db/simple_purchase.cpp +++ b/tests/unit_tests/safex_db/simple_purchase.cpp @@ -717,6 +717,142 @@ namespace } + TYPED_TEST(SimplePurchaseTest, CreateFeedbackExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS2; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex offer doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_feedback; + + crypto::hash offer_id{}; + + safex::safex_feedback sfx_feedback = safex::safex_feedback(1, "100", offer_id); + + safex::create_feedback_data feedback_data{sfx_feedback}; + + safex::create_feedback command1{SAFEX_COMMAND_PROTOCOL_VERSION , feedback_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_feedback); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Given rating is higher than valid + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_feedback; + + safex::safex_feedback sfx_feedback = safex::safex_feedback(4, "100", this->m_edited_safex_offer.offer_id); + + safex::create_feedback_data feedback_data{sfx_feedback}; + + safex::create_feedback command1{SAFEX_COMMAND_PROTOCOL_VERSION , feedback_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_feedback); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_feedback_invalid_rating); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex feedback ratign higher than valid"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex feedback comment is too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_feedback; + + safex::safex_feedback sfx_feedback = safex::safex_feedback(3, "100", this->m_edited_safex_offer.offer_id); + + sfx_feedback.comment = ""; + for(int i=0; i command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_feedback); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_feedback_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex feedback comment is too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + #endif } // anonymous namespace