diff --git a/.gitignore b/.gitignore index 5cdb0935..c4d159d2 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ witness_node_data_dir programs/witness_node/object_database/* object_database/* + +*.pyc +*.pyo diff --git a/README.md b/README.md index 7e06a971..fd8ed41b 100644 --- a/README.md +++ b/README.md @@ -118,15 +118,38 @@ API 0 is accessible using regular JSON-RPC: $ curl --data '{"jsonrpc": "2.0", "method": "get_accounts", "params": [["1.2.0"]], "id": 1}' http://127.0.0.1:8090/rpc -You can use the login API to obtain `network`, `database` and `history` API's. Here is an example of how to call `add_node` from the `network` API: +Accessing restricted API's +-------------------------- + +You can restrict API's to particular users by specifying an `apiaccess` file in `config.ini`. Here is an example `apiaccess` file which allows +user `bytemaster` with password `supersecret` to access four different API's: + + { + "permission_map" : + [ + [ + "bytemaster", + { + "password_hash_b64" : "9e9GF7ooXVb9k4BoSfNIPTelXeGOZ5DrgOYMj94elaY=", + "password_salt_b64" : "INDdM6iCi/8=", + "allowed_apis" : ["database_api", "network_broadcast_api", "history_api", "network_node_api"] + } + ] + ] + } + +Passwords are stored in `base64` as as salted `sha256` hashes. A simple Python script, `saltpass.py` is avaliable to obtain hash and salt values from a password. +A single asterisk `"*"` may be specified as username or password hash to accept any value. + +With the above configuration, here is an example of how to call `add_node` from the `network_node` API: {"id":1, "method":"call", "params":[1,"login",["bytemaster", "supersecret"]]} - {"id":2, "method":"call", "params":[1,"network",[]]} + {"id":2, "method":"call", "params":[1,"network_node",[]]} {"id":3, "method":"call", "params":[2,"add_node",["127.0.0.1:9090"]]} -Note, the call to `network` is necessary to obtain the correct API identifier for the network API. It is not guaranteed that the network API identifier will always be `2`. +Note, the call to `network_node` is necessary to obtain the correct API identifier for the network API. It is not guaranteed that the network API identifier will always be `2`. -Since the `network` API requires login, it is only accessible over the websocket RPC. Our `doxygen` documentation contains the most up-to-date information +Since the `network_node` API requires login, it is only accessible over the websocket RPC. Our `doxygen` documentation contains the most up-to-date information about API's for the [witness node](https://bitshares.github.io/doxygen/namespacegraphene_1_1app.html) and the [wallet](https://bitshares.github.io/doxygen/classgraphene_1_1wallet_1_1wallet__api.html). If you want information which is not available from an API, it might be available @@ -166,7 +189,15 @@ Questions - Is there a way to generate help with parameter names and method descriptions? Yes. Documentation of the code base, including APIs, can be generated using Doxygen. Simply run `doxygen` in this directory. - We are thinking of integrating Doxygen's XML output format to provide a better `help` command to the CLI wallet. + + If both Doxygen and perl are available in your build environment, the CLI wallet's `help` and `gethelp` + commands will display help generated from the doxygen documentation. + + If your CLI wallet's `help` command displays descriptions without parameter names like + `signed_transaction transfer(string, string, string, string, string, bool)` + it means CMake was unable to find Doxygen or perl during configuration. If found, the + output should look like this: + `signed_transaction transfer(string from, string to, string amount, string asset_symbol, string memo, bool broadcast)` - Is there a way to allow external program to drive `cli_wallet` via websocket, JSONRPC, or HTTP? diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index bde65975..958eb2dc 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -16,6 +16,7 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include #include #include #include @@ -350,21 +351,53 @@ namespace graphene { namespace app { bool login_api::login(const string& user, const string& password) { - auto db_api = std::make_shared(std::ref(*_app.chain_database())); - auto net_api = std::make_shared(std::ref(_app)); - auto hist_api = std::make_shared(_app); - _database_api = db_api; - _network_api = net_api; - _history_api = hist_api; + optional< api_access_info > acc = _app.get_api_access_info( user ); + if( !acc.valid() ) + return false; + if( acc->password_hash_b64 != "*" ) + { + std::string password_salt = fc::base64_decode( acc->password_salt_b64 ); + std::string acc_password_hash = fc::base64_decode( acc->password_hash_b64 ); + + fc::sha256 hash_obj = fc::sha256::hash( password + password_salt ); + if( hash_obj.data_size() != acc_password_hash.length() ) + return false; + if( memcmp( hash_obj.data(), acc_password_hash.c_str(), hash_obj.data_size() ) != 0 ) + return false; + } + + for( const std::string& api_name : acc->allowed_apis ) + enable_api( api_name ); return true; } - network_api::network_api(application& a):_app(a) + void login_api::enable_api( const std::string& api_name ) + { + if( api_name == "database_api" ) + { + _database_api = std::make_shared< database_api >( std::ref( *_app.chain_database() ) ); + } + else if( api_name == "network_broadcast_api" ) + { + _network_broadcast_api = std::make_shared< network_broadcast_api >( std::ref( _app ) ); + } + else if( api_name == "history_api" ) + { + _history_api = std::make_shared< history_api >( _app ); + } + else if( api_name == "network_node_api" ) + { + _network_node_api = std::make_shared< network_node_api >( std::ref(_app) ); + } + return; + } + + network_broadcast_api::network_broadcast_api(application& a):_app(a) { _applied_block_connection = _app.chain_database()->applied_block.connect([this](const signed_block& b){ on_applied_block(b); }); } - void network_api::on_applied_block( const signed_block& b ) + void network_broadcast_api::on_applied_block( const signed_block& b ) { if( _callbacks.size() ) { @@ -382,18 +415,14 @@ namespace graphene { namespace app { } } - void network_api::add_node(const fc::ip::endpoint& ep) - { - _app.p2p_node()->add_node(ep); - } - - void network_api::broadcast_transaction(const signed_transaction& trx) + void network_broadcast_api::broadcast_transaction(const signed_transaction& trx) { trx.validate(); _app.chain_database()->push_transaction(trx); _app.p2p_node()->broadcast_transaction(trx); } - void network_api::broadcast_transaction_with_callback( confirmation_callback cb, const signed_transaction& trx) + + void network_broadcast_api::broadcast_transaction_with_callback( confirmation_callback cb, const signed_transaction& trx) { trx.validate(); _callbacks[trx.id()] = cb; @@ -401,16 +430,30 @@ namespace graphene { namespace app { _app.p2p_node()->broadcast_transaction(trx); } + network_node_api::network_node_api( application& a ) : _app( a ) + { + } - std::vector network_api::get_connected_peers() const + void network_node_api::add_node(const fc::ip::endpoint& ep) + { + _app.p2p_node()->add_node(ep); + } + + std::vector network_node_api::get_connected_peers() const { return _app.p2p_node()->get_connected_peers(); } - fc::api login_api::network()const + fc::api login_api::network_broadcast()const { - FC_ASSERT(_network_api); - return *_network_api; + FC_ASSERT(_network_broadcast_api); + return *_network_broadcast_api; + } + + fc::api login_api::network_node()const + { + FC_ASSERT(_network_node_api); + return *_network_node_api; } fc::api login_api::database()const diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 463f5138..b5288b4c 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -15,9 +15,10 @@ * 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. */ +#include +#include #include #include -#include #include @@ -62,6 +63,9 @@ namespace detail { genesis_state_type initial_state; initial_state.initial_parameters.current_fees = fee_schedule::get_default();//->set_all_fees(GRAPHENE_BLOCKCHAIN_PRECISION); initial_state.initial_active_witnesses = 10; + initial_state.initial_timestamp = time_point_sec(time_point::now().sec_since_epoch() / + initial_state.initial_parameters.block_interval * + initial_state.initial_parameters.block_interval); for( int i = 0; i < initial_state.initial_active_witnesses; ++i ) { auto name = "init"+fc::to_string(i); @@ -181,12 +185,14 @@ namespace detail { bool clean = !fc::exists(_data_dir / "blockchain/dblock"); fc::create_directories(_data_dir / "blockchain/dblock"); - genesis_state_type initial_state; - if( _options->count("genesis-json") ) - initial_state = fc::json::from_file(_options->at("genesis-json").as()) - .as(); - else - initial_state = create_example_genesis(); + auto initial_state = [&] { + ilog("Initializing database..."); + if( _options->count("genesis-json") ) + return fc::json::from_file(_options->at("genesis-json").as()) + .as(); + else + return create_example_genesis(); + }; if( _options->count("resync-blockchain") ) _chain_db->wipe(_data_dir / "blockchain", true); @@ -194,12 +200,29 @@ namespace detail { if( _options->count("replay-blockchain") ) { ilog("Replaying blockchain on user request."); - _chain_db->reindex(_data_dir/"blockchain", initial_state); + _chain_db->reindex(_data_dir/"blockchain", initial_state()); } else if( clean ) _chain_db->open(_data_dir / "blockchain", initial_state); else { wlog("Detected unclean shutdown. Replaying blockchain..."); - _chain_db->reindex(_data_dir / "blockchain", initial_state); + _chain_db->reindex(_data_dir / "blockchain", initial_state()); + } + + if( _options->count("apiaccess") ) + _apiaccess = fc::json::from_file( _options->at("apiaccess").as() ) + .as(); + else + { + // TODO: Remove this generous default access policy + // when the UI logs in properly + _apiaccess = api_access(); + api_access_info wild_access; + wild_access.password_hash_b64 = "*"; + wild_access.password_salt_b64 = "*"; + wild_access.allowed_apis.push_back( "database_api" ); + wild_access.allowed_apis.push_back( "network_broadcast_api" ); + wild_access.allowed_apis.push_back( "history_api" ); + _apiaccess.permission_map["*"] = wild_access; } reset_p2p_node(_data_dir); @@ -207,10 +230,23 @@ namespace detail { reset_websocket_tls_server(); } FC_CAPTURE_AND_RETHROW() } + optional< api_access_info > get_api_access_info(const string& username)const + { + optional< api_access_info > result; + auto it = _apiaccess.permission_map.find(username); + if( it == _apiaccess.permission_map.end() ) + { + it = _apiaccess.permission_map.find("*"); + if( it == _apiaccess.permission_map.end() ) + return result; + } + return it->second; + } + /** * If delegate has the item, the network has no need to fetch it. */ - virtual bool has_item( const net::item_id& id ) override + virtual bool has_item(const net::item_id& id) override { try { @@ -230,7 +266,7 @@ namespace detail { * * @throws exception if error validating the item, otherwise the item is safe to broadcast on. */ - virtual bool handle_block( const graphene::net::block_message& blk_msg, bool sync_mode ) override + virtual bool handle_block(const graphene::net::block_message& blk_msg, bool sync_mode) override { try { ilog("Got block #${n} from network", ("n", blk_msg.block.block_num())); try { @@ -241,7 +277,7 @@ namespace detail { } } FC_CAPTURE_AND_RETHROW( (blk_msg)(sync_mode) ) } - virtual bool handle_transaction( const graphene::net::trx_message& trx_msg, bool sync_mode ) override + virtual bool handle_transaction(const graphene::net::trx_message& trx_msg, bool sync_mode) override { try { ilog("Got transaction from network"); _chain_db->push_transaction( trx_msg.trx ); @@ -296,18 +332,18 @@ namespace detail { /** * Given the hash of the requested data, fetch the body. */ - virtual message get_item( const item_id& id ) override + virtual message get_item(const item_id& id) override { try { ilog("Request for item ${id}", ("id", id)); if( id.item_type == graphene::net::block_message_type ) { - auto opt_block = _chain_db->fetch_block_by_id( id.item_hash ); + auto opt_block = _chain_db->fetch_block_by_id(id.item_hash); if( !opt_block ) elog("Couldn't find block ${id} -- corresponding ID in our chain is ${id2}", ("id", id.item_hash)("id2", _chain_db->get_block_id_for_num(block_header::num_from_id(id.item_hash)))); FC_ASSERT( opt_block.valid() ); ilog("Serving up block #${num}", ("num", opt_block->block_num())); - return block_message( std::move(*opt_block) ); + return block_message(std::move(*opt_block)); } return trx_message( _chain_db->get_recent_transaction( id.item_hash ) ); } FC_CAPTURE_AND_RETHROW( (id) ) } @@ -332,18 +368,18 @@ namespace detail { * &c. * the last item in the list will be the hash of the most recent block on our preferred chain */ - virtual std::vector get_blockchain_synopsis( uint32_t item_type, - const graphene::net::item_hash_t& reference_point, - uint32_t number_of_blocks_after_reference_point ) override + virtual std::vector get_blockchain_synopsis(uint32_t item_type, + const graphene::net::item_hash_t& reference_point, + uint32_t number_of_blocks_after_reference_point) override { try { std::vector result; result.reserve(30); auto head_block_num = _chain_db->head_block_num(); - result.push_back( _chain_db->head_block_id() ); + result.push_back(_chain_db->head_block_id()); auto current = 1; while( current < head_block_num ) { - result.push_back( _chain_db->get_block_id_for_num( head_block_num - current ) ); + result.push_back(_chain_db->get_block_id_for_num(head_block_num - current)); current = current*2; } std::reverse( result.begin(), result.end() ); @@ -358,7 +394,7 @@ namespace detail { * @param item_count the number of items known to the node that haven't been sent to handle_item() yet. * After `item_count` more calls to handle_item(), the node will be in sync */ - virtual void sync_status( uint32_t item_type, uint32_t item_count ) override + virtual void sync_status(uint32_t item_type, uint32_t item_count) override { // any status reports to GUI go here } @@ -366,7 +402,7 @@ namespace detail { /** * Call any time the number of connected peers changes. */ - virtual void connection_count_changed( uint32_t c ) override + virtual void connection_count_changed(uint32_t c) override { // any status reports to GUI go here } @@ -412,6 +448,7 @@ namespace detail { fc::path _data_dir; const bpo::variables_map* _options = nullptr; + api_access _apiaccess; std::shared_ptr _chain_db; std::shared_ptr _p2p_network; @@ -451,6 +488,7 @@ void application::set_program_options(boost::program_options::options_descriptio ("server-pem,p", bpo::value()->implicit_value("server.pem"), "The TLS certificate file for this server") ("server-pem-password,P", bpo::value()->implicit_value(""), "Password for this certificate") ("genesis-json", bpo::value(), "File to read Genesis State from") + ("apiaccess", bpo::value(), "JSON file specifying API permissions") ; command_line_options.add(configuration_file_options); command_line_options.add_options() @@ -521,6 +559,11 @@ void application::set_block_production(bool producing_blocks) my->_is_block_producer = producing_blocks; } +optional< api_access_info > application::get_api_access_info( const string& username )const +{ + return my->get_api_access_info( username ); +} + void graphene::app::application::add_plugin(const string& name, std::shared_ptr p) { my->_plugins[name] = p; diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index 1c86caba..b3f471c2 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -28,7 +28,6 @@ #include #include - #include #include @@ -44,7 +43,7 @@ namespace graphene { namespace app { * * This API exposes accessors on the database which query state tracked by a blockchain validating node. This API is * read-only; all modifications to the database must be performed via transactions. Transactions are broadcast via - * the @ref network_api. + * the @ref network_broadcast_api. */ class database_api { @@ -331,14 +330,12 @@ namespace graphene { namespace app { }; /** - * @brief The network_api class implements the RPC API for the network - * - * This API has methods to query the network status, connect to new peers, and send transactions. + * @brief The network_broadcast_api class allows broadcasting of transactions. */ - class network_api + class network_broadcast_api { public: - network_api(application& a); + network_broadcast_api(application& a); struct transaction_confirmation { @@ -366,15 +363,13 @@ namespace graphene { namespace app { void broadcast_transaction_with_callback( confirmation_callback cb, const signed_transaction& trx); /** - * @brief add_node Connect to a new peer - * @param ep The IP/Port of the peer to connect to + * @brief Not reflected, thus not accessible to API clients. + * + * This function is registered to receive the applied_block + * signal from the chain database when a block is received. + * It then dispatches callbacks to clients who have requested + * to be notified when a particular txid is included in a block. */ - void add_node(const fc::ip::endpoint& ep); - /** - * @brief Get status of all current connections to peers - */ - std::vector get_connected_peers() const; - void on_applied_block( const signed_block& b ); private: boost::signals2::scoped_connection _applied_block_connection; @@ -382,6 +377,35 @@ namespace graphene { namespace app { application& _app; }; + /** + * @brief The network_node_api class allows maintenance of p2p connections. + */ + class network_node_api + { + public: + network_node_api(application& a); + + /** + * @brief add_node Connect to a new peer + * @param ep The IP/Port of the peer to connect to + */ + void add_node(const fc::ip::endpoint& ep); + + /** + * @brief Get status of all current connections to peers + * @brief Not reflected, thus not accessible to API clients. + * + * This function is registered to receive the applied_block + * signal from the chain database when a block is received. + * It then dispatches callbacks to clients who have requested + * to be notified when a particular txid is included in a block. + */ + std::vector get_connected_peers() const; + + private: + application& _app; + }; + /** * @brief The login_api class implements the bottom layer of the RPC API * @@ -403,23 +427,29 @@ namespace graphene { namespace app { * has sucessfully authenticated. */ bool login(const string& user, const string& password); - /// @brief Retrieve the network API - fc::api network()const; + /// @brief Retrieve the network broadcast API + fc::api network_broadcast()const; /// @brief Retrieve the database API fc::api database()const; /// @brief Retrieve the history API fc::api history()const; + /// @brief Retrieve the network node API + fc::api network_node()const; private: + /// @brief Called to enable an API, not reflected. + void enable_api( const string& api_name ); + application& _app; optional< fc::api > _database_api; - optional< fc::api > _network_api; + optional< fc::api > _network_broadcast_api; + optional< fc::api > _network_node_api; optional< fc::api > _history_api; }; }} // graphene::app -FC_REFLECT( graphene::app::network_api::transaction_confirmation, +FC_REFLECT( graphene::app::network_broadcast_api::transaction_confirmation, (id)(block_num)(trx_num)(trx) ) FC_API(graphene::app::database_api, @@ -460,13 +490,23 @@ FC_API(graphene::app::database_api, (get_margin_positions) (get_balance_objects) ) -FC_API(graphene::app::history_api, (get_account_history)(get_market_history)(get_market_history_buckets)) -FC_API(graphene::app::network_api, (broadcast_transaction)(broadcast_transaction_with_callback) - /* (add_node)(get_connected_peers) */ - ) +FC_API(graphene::app::history_api, + (get_account_history) + (get_market_history) + (get_market_history_buckets) + ) +FC_API(graphene::app::network_broadcast_api, + (broadcast_transaction) + (broadcast_transaction_with_callback) + ) +FC_API(graphene::app::network_node_api, + (add_node) + (get_connected_peers) + ) FC_API(graphene::app::login_api, (login) - (network) + (network_broadcast) (database) (history) + (network_node) ) diff --git a/libraries/app/include/graphene/app/api_access.hpp b/libraries/app/include/graphene/app/api_access.hpp new file mode 100644 index 00000000..b6f4e2f3 --- /dev/null +++ b/libraries/app/include/graphene/app/api_access.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, Cryptonomex, Inc. + * All rights reserved. + * + * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and + * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification, + * are permitted until September 8, 2015, provided that the following conditions are met: + * + * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes. + * + * 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. + */ +#pragma once + +#include + +#include +#include +#include + +namespace graphene { namespace app { + +struct api_access_info +{ + std::string password_hash_b64; + std::string password_salt_b64; + std::vector< std::string > allowed_apis; +}; + +struct api_access +{ + std::map< std::string, api_access_info > permission_map; +}; + +} } // graphene::app + +FC_REFLECT( graphene::app::api_access_info, + (password_hash_b64) + (password_salt_b64) + (allowed_apis) + ) + +FC_REFLECT( graphene::app::api_access, + (permission_map) + ) diff --git a/libraries/app/include/graphene/app/application.hpp b/libraries/app/include/graphene/app/application.hpp index f7ee1450..4eccc980 100644 --- a/libraries/app/include/graphene/app/application.hpp +++ b/libraries/app/include/graphene/app/application.hpp @@ -17,6 +17,7 @@ */ #pragma once +#include #include #include @@ -74,6 +75,7 @@ namespace graphene { namespace app { std::shared_ptr chain_database()const; void set_block_production(bool producing_blocks); + fc::optional< api_access_info > get_api_access_info( const string& username )const; private: void add_plugin( const string& name, std::shared_ptr p ); diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index b296be92..a99a3951 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -393,6 +394,8 @@ void_result asset_settle_evaluator::do_evaluate(const asset_settle_evaluator::op FC_ASSERT(asset_to_settle->can_force_settle() || bitasset.has_settlement() ); if( bitasset.is_prediction_market ) FC_ASSERT( bitasset.has_settlement(), "global settlement must occur before force settling a prediction market" ); + else if( bitasset.current_feed.settlement_price.is_null() ) + FC_THROW_EXCEPTION(insufficient_feeds, "Cannot force settle with no price feed."); FC_ASSERT(d.get_balance(d.get(op.account), *asset_to_settle) >= op.amount); return void_result(); diff --git a/libraries/chain/balance_evaluator.cpp b/libraries/chain/balance_evaluator.cpp index 1a5dee52..d69003f5 100644 --- a/libraries/chain/balance_evaluator.cpp +++ b/libraries/chain/balance_evaluator.cpp @@ -7,27 +7,38 @@ void_result balance_claim_evaluator::do_evaluate(const balance_claim_operation& database& d = db(); balance = &op.balance_to_claim(d); - FC_ASSERT(op.balance_owner_key == balance->owner || + GRAPHENE_ASSERT( + op.balance_owner_key == balance->owner || pts_address(op.balance_owner_key, false, 56) == balance->owner || pts_address(op.balance_owner_key, true, 56) == balance->owner || pts_address(op.balance_owner_key, false, 0) == balance->owner || pts_address(op.balance_owner_key, true, 0) == balance->owner, - "balance_owner_key does not match balance's owner"); + balance_claim_owner_mismatch, + "Balance owner key was specified as '${op}' but balance's actual owner is '${bal}'", + ("op", op.balance_owner_key) + ("bal", balance->owner) + ); if( !(d.get_node_properties().skip_flags & (database::skip_authority_check | database::skip_transaction_signatures)) ) FC_ASSERT(op.total_claimed.asset_id == balance->asset_type()); - if( balance->is_vesting_balance() ) { - if( !balance->vesting_policy->is_withdraw_allowed({balance->balance, - d.head_block_time(), - op.total_claimed}) ) - FC_THROW_EXCEPTION(invalid_claim_amount, - "Attempted to claim ${c} from a vesting balance with ${a} available", - ("c", op.total_claimed)("a", balance->available(d.head_block_time()))); - if( d.head_block_time() - balance->last_claim_date < fc::days(1) ) - FC_THROW_EXCEPTION(balance_claimed_too_often, - "Genesis vesting balances may not be claimed more than once per day."); + if( balance->is_vesting_balance() ) + { + GRAPHENE_ASSERT( + balance->vesting_policy->is_withdraw_allowed( + { balance->balance, + d.head_block_time(), + op.total_claimed } ), + balance_claim_invalid_claim_amount, + "Attempted to claim ${c} from a vesting balance with ${a} available", + ("c", op.total_claimed)("a", balance->available(d.head_block_time())) + ); + GRAPHENE_ASSERT( + d.head_block_time() - balance->last_claim_date >= fc::days(1), + balance_claim_claimed_too_often, + "Genesis vesting balances may not be claimed more than once per day." + ); return {}; } diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 448f3229..5a67ac26 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -193,6 +193,9 @@ void database::initialize_indexes() void database::init_genesis(const genesis_state_type& genesis_state) { try { + FC_ASSERT( genesis_state.initial_timestamp != time_point_sec(), "Must initialize genesis timestamp." ); + FC_ASSERT( genesis_state.initial_timestamp.sec_since_epoch() % GRAPHENE_DEFAULT_BLOCK_INTERVAL == 0, + "Genesis timestamp must be divisible by GRAPHENE_DEFAULT_BLOCK_INTERVAL." ); FC_ASSERT(genesis_state.initial_witness_candidates.size() > 0, "Cannot start a chain with zero witnesses."); FC_ASSERT(genesis_state.initial_active_witnesses <= genesis_state.initial_witness_candidates.size(), @@ -300,8 +303,8 @@ void database::init_genesis(const genesis_state_type& genesis_state) p.parameters.current_fees->zero_all_fees(); }); - create( [&](dynamic_global_property_object& p) { - p.time = fc::time_point_sec(GRAPHENE_GENESIS_TIMESTAMP); + create([&](dynamic_global_property_object& p) { + p.time = genesis_state.initial_timestamp; p.witness_budget = 0; }); create([&](block_summary_object&) {}); @@ -313,13 +316,16 @@ void database::init_genesis(const genesis_state_type& genesis_state) cop.name = account.name; cop.registrar = GRAPHENE_TEMP_ACCOUNT; cop.owner = authority(1, account.owner_key, 1); - if( account.owner_key != account.active_key ) + if( account.active_key == public_key_type() ) { - cop.active = authority(1, account.owner_key, 1); - } else { cop.active = cop.owner; + cop.options.memo_key = account.owner_key; + } + else + { + cop.active = authority(1, account.active_key, 1); + cop.options.memo_key = account.active_key; } - cop.options.memo_key = account.owner_key; account_id_type account_id(apply_operation(genesis_eval_state, cop).get()); if( account.is_lifetime_member ) @@ -457,31 +463,45 @@ void database::init_genesis(const genesis_state_type& genesis_state) adjust_balance(GRAPHENE_COMMITTEE_ACCOUNT, -get_balance(GRAPHENE_COMMITTEE_ACCOUNT,{})); } - // Create initial witnesses and delegates + // Create initial witnesses std::for_each(genesis_state.initial_witness_candidates.begin(), genesis_state.initial_witness_candidates.end(), [&](const genesis_state_type::initial_witness_type& witness) { witness_create_operation op; + op.witness_account = get_account_id(witness.owner_name); op.block_signing_key = witness.block_signing_key; op.initial_secret = secret_hash_type::hash( secret_hash_type() ); - op.witness_account = get_account_id(witness.owner_name); apply_operation(genesis_eval_state, op); }); + + // Create initial committee members std::for_each(genesis_state.initial_committee_candidates.begin(), genesis_state.initial_committee_candidates.end(), [&](const genesis_state_type::initial_committee_member_type& member) { delegate_create_operation op; op.delegate_account = get_account_id(member.owner_name); - apply_operation(genesis_eval_state, op).get(); + apply_operation(genesis_eval_state, op); + }); + + // Create initial workers + std::for_each(genesis_state.initial_worker_candidates.begin(), genesis_state.initial_worker_candidates.end(), + [&](const genesis_state_type::initial_worker_type& worker) + { + worker_create_operation op; + op.owner = get_account_id(worker.owner_name); + op.work_begin_date = genesis_state.initial_timestamp; + op.work_end_date = time_point_sec::maximum(); + op.daily_pay = worker.daily_pay; + op.name = "Genesis-Worker-" + worker.owner_name; + op.initializer = vesting_balance_worker_initializer{uint16_t(0)}; + + apply_operation(genesis_eval_state, std::move(op)); }); // Set active witnesses modify(get_global_properties(), [&](global_property_object& p) { - auto idx = get_index_type().indices(); - for( auto itr = idx.begin(); - itr != idx.end() && p.active_witnesses.size() < genesis_state.initial_active_witnesses; - ++itr ) + for( int i = 0; i < genesis_state.initial_active_witnesses; ++i ) { - p.active_witnesses.insert(itr->id); - p.witness_accounts.insert(itr->witness_account); + p.active_witnesses.insert(i); + p.witness_accounts.insert(get(witness_id_type(i)).witness_account); } }); diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index bc9ce537..eb429e36 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -44,7 +44,11 @@ vector> database::sort [](const ObjectType& o) { return std::cref(o); }); std::partial_sort(refs.begin(), refs.begin() + count, refs.end(), [this](const ObjectType& a, const ObjectType& b)->bool { - return _vote_tally_buffer[a.vote_id] > _vote_tally_buffer[b.vote_id]; + share_type oa_vote = _vote_tally_buffer[a.vote_id]; + share_type ob_vote = _vote_tally_buffer[b.vote_id]; + if( oa_vote != ob_vote ) + return oa_vote > ob_vote; + return a.vote_id < b.vote_id; }); refs.resize(count, refs.front()); @@ -127,9 +131,10 @@ void database::update_active_witnesses() share_type stake_target = _total_voting_stake / 2; share_type stake_tally = _witness_count_histogram_buffer[0]; size_t witness_count = 0; - while( (witness_count < _witness_count_histogram_buffer.size() - 1) - && (stake_tally <= stake_target) ) - stake_tally += _witness_count_histogram_buffer[++witness_count]; + if( stake_target > 0 ) + while( (witness_count < _witness_count_histogram_buffer.size() - 1) + && (stake_tally <= stake_target) ) + stake_tally += _witness_count_histogram_buffer[++witness_count]; auto wits = sort_votable_objects(std::max(witness_count*2+1, (size_t)GRAPHENE_MIN_WITNESS_COUNT)); const global_property_object& gpo = get_global_properties(); @@ -192,9 +197,10 @@ void database::update_active_delegates() uint64_t stake_target = _total_voting_stake / 2; uint64_t stake_tally = _committee_count_histogram_buffer[0]; size_t delegate_count = 0; - while( (delegate_count < _committee_count_histogram_buffer.size() - 1) - && (stake_tally <= stake_target) ) - stake_tally += _committee_count_histogram_buffer[++delegate_count]; + if( stake_target > 0 ) + while( (delegate_count < _committee_count_histogram_buffer.size() - 1) + && (stake_tally <= stake_target) ) + stake_tally += _committee_count_histogram_buffer[++delegate_count]; auto delegates = sort_votable_objects(std::max(delegate_count*2+1, (size_t)GRAPHENE_MIN_DELEGATE_COUNT)); @@ -396,7 +402,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g uint32_t offset = id.instance(); // if they somehow managed to specify an illegal offset, ignore it. if( offset < d._vote_tally_buffer.size() ) - d._vote_tally_buffer[ offset ] += voting_stake; + d._vote_tally_buffer[offset] += voting_stake; } if( opinion_account.options.num_witness <= props.parameters.maximum_witness_count ) @@ -409,7 +415,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g // in particular, this takes care of the case where a // member was voting for a high number, then the // parameter was lowered. - d._witness_count_histogram_buffer[ offset ] += voting_stake; + d._witness_count_histogram_buffer[offset] += voting_stake; } if( opinion_account.options.num_committee <= props.parameters.maximum_committee_count ) { @@ -419,7 +425,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g // are turned into votes for maximum_committee_count. // // same rationale as for witnesses - d._committee_count_histogram_buffer[ offset ] += voting_stake; + d._committee_count_histogram_buffer[offset] += voting_stake; } d._total_voting_stake += voting_stake; diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index e77ccc2f..597fa3dc 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -21,6 +21,8 @@ #include #include +#include + namespace graphene { namespace chain { database::database() @@ -34,31 +36,10 @@ database::~database(){ _pending_block_session->commit(); } -void database::open( const fc::path& data_dir, const genesis_state_type& initial_allocation ) -{ try { - object_database::open( data_dir ); - - _block_id_to_block.open(data_dir / "database" / "block_num_to_block"); - - if( !find(global_property_id_type()) ) - { -// ilog( "Init Genesis State" ); - init_genesis(initial_allocation); - } - - _pending_block.previous = head_block_id(); - _pending_block.timestamp = head_block_time(); - - auto last_block= _block_id_to_block.last(); - if( last_block.valid() ) - _fork_db.start_block( *last_block ); - -} FC_CAPTURE_AND_RETHROW( (data_dir) ) } - void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation) { try { wipe(data_dir, false); - open(data_dir, initial_allocation); + open(data_dir, [&initial_allocation]{return initial_allocation;}); auto start = fc::time_point::now(); auto last_block = _block_id_to_block.last(); @@ -70,13 +51,13 @@ void database::reindex(fc::path data_dir, const genesis_state_type& initial_allo //_undo_db.disable(); for( uint32_t i = 1; i <= last_block_num; ++i ) { - apply_block( *_block_id_to_block.fetch_by_number(i), skip_delegate_signature | + apply_block(*_block_id_to_block.fetch_by_number(i), skip_delegate_signature | skip_transaction_signatures | skip_undo_block | skip_undo_transaction | skip_transaction_dupe_check | skip_tapos_check | - skip_authority_check ); + skip_authority_check); } //_undo_db.enable(); auto end = fc::time_point::now(); diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index a6d82bf6..98ce95dd 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -23,9 +23,6 @@ namespace graphene { namespace chain { -static_assert((GRAPHENE_GENESIS_TIMESTAMP % GRAPHENE_DEFAULT_BLOCK_INTERVAL) == 0, - "GRAPHENE_GENESIS_TIMESTAMP must be aligned to a block interval."); - pair database::get_scheduled_witness(uint32_t slot_num)const { if( slot_num == 0 ) diff --git a/libraries/chain/evaluator.cpp b/libraries/chain/evaluator.cpp index c34a49cb..05b3cd0a 100644 --- a/libraries/chain/evaluator.cpp +++ b/libraries/chain/evaluator.cpp @@ -17,7 +17,9 @@ */ #include #include +#include #include + #include #include #include @@ -88,14 +90,24 @@ database& generic_evaluator::db()const { return trx_state->db(); } operation_get_required_authorities( op, active_auths, owner_auths, other_auths ); for( auto id : active_auths ) - FC_ASSERT(verify_authority(id(db()), authority::active) || - verify_authority(id(db()), authority::owner), "", ("id", id)); + GRAPHENE_ASSERT( + verify_authority(id(db()), authority::active) || + verify_authority(id(db()), authority::owner), + tx_missing_active_auth, + "missing required active authority ${id}", ("id", id)); for( auto id : owner_auths ) - FC_ASSERT(verify_authority(id(db()), authority::owner), "", ("id", id)); + GRAPHENE_ASSERT( + verify_authority(id(db()), authority::owner), + tx_missing_owner_auth, + "missing required owner authority ${id}", ("id", id)); for( const auto& auth : other_auths ) - FC_ASSERT(trx_state->check_authority(auth), "invalid authority", ("auth",auth)("sigs",trx_state->_sigs)); + GRAPHENE_ASSERT( + trx_state->check_authority(auth), + tx_missing_other_auth, + "missing required authority ${auth}", + ("auth",auth)("sigs",trx_state->_sigs)); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/chain/include/graphene/chain/account_object.hpp b/libraries/chain/include/graphene/chain/account_object.hpp index d625dac3..f176fbc8 100644 --- a/libraries/chain/include/graphene/chain/account_object.hpp +++ b/libraries/chain/include/graphene/chain/account_object.hpp @@ -236,7 +236,7 @@ namespace graphene { namespace chain { /** * @brief This secondary index will allow a reverse lookup of all accounts that a particular key or account - * is an potential signing authority. + * is an potential signing authority. */ class account_member_index : public secondary_index { diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 6e56ecbf..aaa40b18 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -86,7 +86,7 @@ #define GRAPHENE_DEFAULT_MAX_WITNESSES (1001) // SHOULD BE ODD #define GRAPHENE_DEFAULT_MAX_COMMITTEE (1001) // SHOULD BE ODD #define GRAPHENE_DEFAULT_MAX_PROPOSAL_LIFETIME_SEC (60*60*24*7*4) // Four weeks -#define GRAPHENE_DEFAULT_GENESIS_PROPOSAL_REVIEW_PERIOD_SEC (60*60*24*7*2) // Two weeks +#define GRAPHENE_DEFAULT_COMMITTEE_PROPOSAL_REVIEW_PERIOD_SEC (60*60*24*7*2) // Two weeks #define GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE (20*GRAPHENE_1_PERCENT) #define GRAPHENE_DEFAULT_LIFETIME_REFERRER_PERCENT_OF_FEE (30*GRAPHENE_1_PERCENT) #define GRAPHENE_DEFAULT_MAX_BULK_DISCOUNT_PERCENT (50*GRAPHENE_1_PERCENT) @@ -100,7 +100,6 @@ #define GRAPHENE_DEFAULT_FEE_LIQUIDATION_THRESHOLD GRAPHENE_BLOCKCHAIN_PRECISION * 100; #define GRAPHENE_DEFAULT_ACCOUNTS_PER_FEE_SCALE 1000 #define GRAPHENE_DEFAULT_ACCOUNT_FEE_SCALE_BITSHIFTS 4 -#define GRAPHENE_GENESIS_TIMESTAMP (1431700000) /// Should be divisible by GRAPHENE_DEFAULT_BLOCK_INTERVAL #define GRAPHENE_MAX_WORKER_NAME_LENGTH 63 @@ -139,7 +138,7 @@ * Reserved Account IDs with special meaning */ ///@{ -/// Represents the current committee members, two-week review period (GRAPHENE_DEFAULT_GENESIS_PROPOSAL_REVIEW_PERIOD_SEC) +/// Represents the current committee members, two-week review period #define GRAPHENE_COMMITTEE_ACCOUNT (graphene::chain::account_id_type(0)) /// Represents the current witnesses #define GRAPHENE_WITNESS_ACCOUNT (graphene::chain::account_id_type(1)) diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 4919bb0d..1efc7eee 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -69,7 +69,7 @@ namespace graphene { namespace chain { * @class database * @brief tracks the blockchain state in an extensible manner */ - class database : public object_database + class database : public db::object_database { public: //////////////////// db_management.cpp //////////////////// @@ -93,7 +93,19 @@ namespace graphene { namespace chain { skip_assert_evaluation = 0x400 ///< used while reindexing }; - void open(const fc::path& data_dir, const genesis_state_type& initial_allocation = genesis_state_type()); + /** + * @brief Open a database, creating a new one if necessary + * + * Opens a database in the specified directory. If no initialized database is found, genesis_loader is called + * and its return value is used as the genesis state when initializing the new database + * + * genesis_loader will not be called if an existing database is found. + * + * @param data_dir Path to open or create database in + * @param genesis_loader A callable object which returns the genesis state to initialize new databases on + */ + template + void open(const fc::path& data_dir, F&& genesis_loader); /** * @brief Rebuild object graph from block history and open detabase * @@ -477,4 +489,24 @@ namespace graphene { namespace chain { (void)l; } } + + template + void database::open(const fc::path& data_dir, F&& genesis_loader) + { try { + object_database::open(data_dir); + + _block_id_to_block.open(data_dir / "database" / "block_num_to_block"); + + if( !find(global_property_id_type()) ) + init_genesis(genesis_loader()); + + _pending_block.previous = head_block_id(); + _pending_block.timestamp = head_block_time(); + + auto last_block= _block_id_to_block.last(); + if( last_block.valid() ) + _fork_db.start_block( *last_block ); + + } FC_CAPTURE_AND_RETHROW( (data_dir) ) } + } } diff --git a/libraries/chain/include/graphene/chain/exceptions.hpp b/libraries/chain/include/graphene/chain/exceptions.hpp index f06ecb02..19ef93df 100644 --- a/libraries/chain/include/graphene/chain/exceptions.hpp +++ b/libraries/chain/include/graphene/chain/exceptions.hpp @@ -18,12 +18,121 @@ #pragma once #include +#include + +#define GRAPHENE_ASSERT( expr, exc_type, ... ) \ + if( !(expr) ) \ + { \ + FC_THROW_EXCEPTION( exc_type, __VA_ARGS__ ); \ + } + +#define GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( op_name ) \ + FC_DECLARE_DERIVED_EXCEPTION( \ + op_name ## _validate_exception, \ + graphene::chain::operation_validate_exception, \ + 3040000 + 100 * operation::tag< op_name ## _operation >::value, \ + #op_name "_operation validation exception" \ + ) \ + FC_DECLARE_DERIVED_EXCEPTION( \ + op_name ## _evaluate_exception, \ + graphene::chain::operation_evaluate_exception, \ + 3050000 + 100 * operation::tag< op_name ## _operation >::value, \ + #op_name "_operation evaluation exception" \ + ) + +#define GRAPHENE_DECLARE_OP_VALIDATE_EXCEPTION( exc_name, op_name, seqnum, msg ) \ + FC_DECLARE_DERIVED_EXCEPTION( \ + op_name ## _ ## exc_name, \ + graphene::chain::op_name ## _validate_exception, \ + 3040000 + 100 * operation::tag< op_name ## _operation >::value \ + + seqnum, \ + msg \ + ) + +#define GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( exc_name, op_name, seqnum, msg ) \ + FC_DECLARE_DERIVED_EXCEPTION( \ + op_name ## _ ## exc_name, \ + graphene::chain::op_name ## _evaluate_exception, \ + 3050000 + 100 * operation::tag< op_name ## _operation >::value \ + + seqnum, \ + msg \ + ) namespace graphene { namespace chain { - // registered in chain_database.cpp - FC_DECLARE_EXCEPTION( chain_exception, 30000, "Blockchain Exception" ) - FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, graphene::chain::chain_exception, 30001, "invalid pts address" ) + FC_DECLARE_EXCEPTION( chain_exception, 3000000, "blockchain exception" ) + FC_DECLARE_DERIVED_EXCEPTION( database_query_exception, graphene::chain::chain_exception, 3010000, "database query exception" ) + FC_DECLARE_DERIVED_EXCEPTION( block_validate_exception, graphene::chain::chain_exception, 3020000, "block validation exception" ) + FC_DECLARE_DERIVED_EXCEPTION( transaction_exception, graphene::chain::chain_exception, 3030000, "transaction validation exception" ) + FC_DECLARE_DERIVED_EXCEPTION( operation_validate_exception, graphene::chain::chain_exception, 3040000, "operation validation exception" ) + FC_DECLARE_DERIVED_EXCEPTION( operation_evaluate_exception, graphene::chain::chain_exception, 3050000, "operation evaluation exception" ) + FC_DECLARE_DERIVED_EXCEPTION( utility_exception, graphene::chain::chain_exception, 3060000, "utility method exception" ) + + FC_DECLARE_DERIVED_EXCEPTION( tx_missing_active_auth, graphene::chain::transaction_exception, 3030001, "missing required active authority" ) + FC_DECLARE_DERIVED_EXCEPTION( tx_missing_owner_auth, graphene::chain::transaction_exception, 3030002, "missing required owner authority" ) + FC_DECLARE_DERIVED_EXCEPTION( tx_missing_other_auth, graphene::chain::transaction_exception, 3030003, "missing required other authority" ) + //FC_DECLARE_DERIVED_EXCEPTION( tx_irrelevant_authority, graphene::chain::transaction_exception, 3030004, "irrelevant authority" ) + + FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, graphene::chain::utility_exception, 3060001, "invalid pts address" ) + FC_DECLARE_DERIVED_EXCEPTION( insufficient_feeds, graphene::chain::chain_exception, 37006, "insufficient feeds" ) + + GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( transfer ); + + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( from_account_not_whitelisted, transfer, 1, "owner mismatch" ) + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( to_account_not_whitelisted, transfer, 2, "owner mismatch" ) + + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( limit_order_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( limit_order_cancel ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( call_order_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( account_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( account_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( account_whitelist ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( account_upgrade ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( account_transfer ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_update_bitasset ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_update_feed_producers ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_issue ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_reserve ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_fund_fee_pool ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_settle ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_global_settle ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( asset_publish_feed ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( delegate_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( witness_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( witness_withdraw_pay ); + + GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( proposal_create ); + + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( review_period_required, proposal_create, 1, "review_period required" ) + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( review_period_insufficient, proposal_create, 2, "review_period insufficient" ) + + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( proposal_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( proposal_delete ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( withdraw_permission_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( withdraw_permission_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( withdraw_permission_claim ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( withdraw_permission_delete ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( fill_order ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( global_parameters_update ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( vesting_balance_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( vesting_balance_withdraw ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( worker_create ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( custom ); + //GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( assert ); + + GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( balance_claim ); + + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( claimed_too_often, balance_claim, 1, "balance claimed too often" ) + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( invalid_claim_amount, balance_claim, 2, "invalid claim amount" ) + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( owner_mismatch, balance_claim, 3, "owner mismatch" ) + + GRAPHENE_DECLARE_OP_BASE_EXCEPTIONS( override_transfer ); + + GRAPHENE_DECLARE_OP_EVALUATE_EXCEPTION( not_permitted, override_transfer, 1, "not permitted" ) + + /* FC_DECLARE_DERIVED_EXCEPTION( addition_overflow, graphene::chain::chain_exception, 30002, "addition overflow" ) FC_DECLARE_DERIVED_EXCEPTION( subtraction_overflow, graphene::chain::chain_exception, 30003, "subtraction overflow" ) FC_DECLARE_DERIVED_EXCEPTION( asset_type_mismatch, graphene::chain::chain_exception, 30004, "asset/price mismatch" ) @@ -63,8 +172,6 @@ namespace graphene { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( expired_transaction, graphene::chain::evaluation_error, 31010, "expired transaction" ) FC_DECLARE_DERIVED_EXCEPTION( invalid_transaction_expiration, graphene::chain::evaluation_error, 31011, "invalid transaction expiration" ) FC_DECLARE_DERIVED_EXCEPTION( oversized_transaction, graphene::chain::evaluation_error, 31012, "transaction exceeded the maximum transaction size" ) - FC_DECLARE_DERIVED_EXCEPTION( balance_claimed_too_often, graphene::chain::evaluation_error, 31013, "balance claimed too often" ) - FC_DECLARE_DERIVED_EXCEPTION( invalid_claim_amount, graphene::chain::evaluation_error, 31013, "invalid claim amount" ) FC_DECLARE_DERIVED_EXCEPTION( invalid_account_name, graphene::chain::evaluation_error, 32001, "invalid account name" ) FC_DECLARE_DERIVED_EXCEPTION( unknown_account_id, graphene::chain::evaluation_error, 32002, "unknown account id" ) @@ -111,5 +218,6 @@ namespace graphene { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( price_multiplication_overflow, graphene::chain::evaluation_error, 38001, "price multiplication overflow" ) FC_DECLARE_DERIVED_EXCEPTION( price_multiplication_underflow, graphene::chain::evaluation_error, 38002, "price multiplication underflow" ) FC_DECLARE_DERIVED_EXCEPTION( price_multiplication_undefined, graphene::chain::evaluation_error, 38003, "price multiplication undefined product 0*inf" ) + */ } } // graphene::chain diff --git a/libraries/chain/include/graphene/chain/genesis_state.hpp b/libraries/chain/include/graphene/chain/genesis_state.hpp index 00ac6e56..c256c589 100644 --- a/libraries/chain/include/graphene/chain/genesis_state.hpp +++ b/libraries/chain/include/graphene/chain/genesis_state.hpp @@ -23,7 +23,7 @@ struct genesis_state_type { string name; public_key_type owner_key; public_key_type active_key; - bool is_lifetime_member; + bool is_lifetime_member = false; }; struct initial_asset_type { string symbol; @@ -79,36 +79,51 @@ struct genesis_state_type { /// Must correspond to one of the initial accounts string owner_name; }; + struct initial_worker_type { + /// Must correspond to one of the initial accounts + string owner_name; + share_type daily_pay; + }; - chain_parameters initial_parameters; - vector initial_accounts; - vector initial_assets; - vector initial_balances; - vector initial_vesting_balances; - int initial_active_witnesses = GRAPHENE_DEFAULT_NUM_WITNESSES; - vector initial_witness_candidates; - // These are only candidates; the chain will have no active committee members at genesis - vector initial_committee_candidates; + time_point_sec initial_timestamp; + chain_parameters initial_parameters; + vector initial_accounts; + vector initial_assets; + vector initial_balances; + vector initial_vesting_balances; + int initial_active_witnesses = GRAPHENE_DEFAULT_NUM_WITNESSES; + vector initial_witness_candidates; + vector initial_committee_candidates; + vector initial_worker_candidates; }; } } // namespace graphene::chain FC_REFLECT(graphene::chain::genesis_state_type::initial_account_type, (name)(owner_key)(active_key)(is_lifetime_member)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_balance_type, - (owner)(asset_symbol)(amount)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_vesting_balance_type, - (owner)(asset_symbol)(amount)(begin_timestamp)(vesting_duration_seconds)(begin_balance)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_witness_type, (owner_name)(block_signing_key)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_committee_member_type, (owner_name)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type::initial_bitasset_options::initial_collateral_position, - (collateral)(debt)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type::initial_bitasset_options, - (feed_lifetime_sec)(minimum_feeds)(force_settlement_delay_sec)(force_settlement_offset_percent) - (maximum_force_settlement_volume)(backing_asset_symbol)(maintenance_collateral_ratio)(collateral_records)) + FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type, (symbol)(description)(precision)(issuer_name)(max_supply)(market_fee_percent) (issuer_permissions)(flags)(bitasset_options)(initial_accumulated_fees)) +FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type::initial_bitasset_options, + (feed_lifetime_sec)(minimum_feeds)(force_settlement_delay_sec)(force_settlement_offset_percent) + (maximum_force_settlement_volume)(backing_asset_symbol)(maintenance_collateral_ratio)(collateral_records)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type::initial_bitasset_options::initial_collateral_position, + (collateral)(debt)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_balance_type, + (owner)(asset_symbol)(amount)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_vesting_balance_type, + (owner)(asset_symbol)(amount)(begin_timestamp)(vesting_duration_seconds)(begin_balance)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_witness_type, (owner_name)(block_signing_key)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_committee_member_type, (owner_name)) + +FC_REFLECT(graphene::chain::genesis_state_type::initial_worker_type, (owner_name)(daily_pay)) + FC_REFLECT(graphene::chain::genesis_state_type, - (initial_parameters)(initial_accounts)(initial_assets)(initial_balances) + (initial_timestamp)(initial_parameters)(initial_accounts)(initial_assets)(initial_balances) (initial_vesting_balances)(initial_active_witnesses)(initial_witness_candidates) - (initial_committee_candidates)) + (initial_committee_candidates)(initial_worker_candidates)) diff --git a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp index ff202a2d..e9d3436f 100644 --- a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp +++ b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp @@ -36,7 +36,7 @@ namespace graphene { namespace chain { smart_ref current_fees; ///< current schedule of fees uint8_t block_interval = GRAPHENE_DEFAULT_BLOCK_INTERVAL; ///< interval in seconds between blocks uint32_t maintenance_interval = GRAPHENE_DEFAULT_MAINTENANCE_INTERVAL; ///< interval in sections between blockchain maintenance events - uint32_t genesis_proposal_review_period = GRAPHENE_DEFAULT_GENESIS_PROPOSAL_REVIEW_PERIOD_SEC; ///< minimum time in seconds that a proposed transaction requiring genesis authority may not be signed, prior to expiration + uint32_t committee_proposal_review_period = GRAPHENE_DEFAULT_COMMITTEE_PROPOSAL_REVIEW_PERIOD_SEC; ///< minimum time in seconds that a proposed transaction requiring genesis authority may not be signed, prior to expiration uint32_t maximum_transaction_size = GRAPHENE_DEFAULT_MAX_TRANSACTION_SIZE; ///< maximum allowable size in bytes for a transaction uint32_t maximum_block_size = GRAPHENE_DEFAULT_MAX_BLOCK_SIZE; ///< maximum allowable size in bytes for a block uint32_t maximum_undo_history = GRAPHENE_DEFAULT_MAX_UNDO_HISTORY; ///< maximum number of undo states to keep in RAM @@ -87,7 +87,7 @@ namespace graphene { namespace chain { "Block size limit is too low" ); FC_ASSERT( maximum_time_until_expiration > block_interval, "Maximum transaction expiration time must be greater than a block interval" ); - FC_ASSERT( maximum_proposal_lifetime - genesis_proposal_review_period > block_interval, + FC_ASSERT( maximum_proposal_lifetime - committee_proposal_review_period > block_interval, "Genesis proposal review period must be less than the maximum proposal lifetime" ); } }; @@ -98,7 +98,7 @@ FC_REFLECT( graphene::chain::chain_parameters, (current_fees) (block_interval) (maintenance_interval) - (genesis_proposal_review_period) + (committee_proposal_review_period) (maximum_transaction_size) (maximum_block_size) (maximum_undo_history) diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index 3c903f03..1c613933 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -38,6 +38,7 @@ #include #include #include +#include namespace graphene { namespace chain { using namespace graphene::db; @@ -316,7 +317,6 @@ namespace graphene { namespace chain { return std::to_string(type()) + ":" + std::to_string(instance()); } }; - struct public_key_type { struct binary_key @@ -325,9 +325,7 @@ namespace graphene { namespace chain { uint32_t check; fc::ecc::public_key_data data; }; - fc::ecc::public_key_data key_data; - public_key_type(); public_key_type( const fc::ecc::public_key_data& data ); public_key_type( const fc::ecc::public_key& pubkey ); @@ -338,12 +336,12 @@ namespace graphene { namespace chain { friend bool operator == ( const public_key_type& p1, const fc::ecc::public_key& p2); friend bool operator == ( const public_key_type& p1, const public_key_type& p2); friend bool operator != ( const public_key_type& p1, const public_key_type& p2); - // TODO: This is temporary for testing bool is_valid_v1( const std::string& base58str ); }; + } } // graphene::chain namespace fc @@ -399,7 +397,6 @@ FC_REFLECT_ENUM( graphene::chain::impl_object_type, FC_REFLECT_ENUM( graphene::chain::meta_info_object_type, (meta_account_object_type)(meta_asset_object_type) ) - FC_REFLECT_TYPENAME( graphene::chain::share_type ) FC_REFLECT_TYPENAME( graphene::chain::account_id_type ) diff --git a/libraries/chain/include/graphene/chain/protocol/worker.hpp b/libraries/chain/include/graphene/chain/protocol/worker.hpp index 968a8dc7..8f4e0465 100644 --- a/libraries/chain/include/graphene/chain/protocol/worker.hpp +++ b/libraries/chain/include/graphene/chain/protocol/worker.hpp @@ -30,6 +30,7 @@ namespace graphene { namespace chain { struct vesting_balance_worker_initializer { + vesting_balance_worker_initializer(uint16_t days=0):pay_vesting_period_days(days){} uint16_t pay_vesting_period_days = 0; }; diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index 22f1b76b..2867e866 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -17,6 +17,7 @@ */ #include #include +#include #include namespace graphene { namespace chain { @@ -117,8 +118,8 @@ void_result call_order_update_evaluator::do_evaluate(const call_order_update_ope if( _bitasset_data->is_prediction_market ) FC_ASSERT( o.delta_collateral.amount == o.delta_debt.amount ); - else - FC_ASSERT( !_bitasset_data->current_feed.settlement_price.is_null() ); + else if( _bitasset_data->current_feed.settlement_price.is_null() ) + FC_THROW_EXCEPTION(insufficient_feeds, "Cannot borrow asset with no price feed."); if( o.delta_debt.amount < 0 ) { diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index 6e1c8150..1bc684af 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -45,8 +46,21 @@ void_result proposal_create_evaluator::do_evaluate(const proposal_create_operati FC_ASSERT( other.size() == 0 ); // TODO: what about other??? if( auths.find(account_id_type()) != auths.end() ) - FC_ASSERT( o.review_period_seconds - && *o.review_period_seconds >= global_parameters.genesis_proposal_review_period ); + { + GRAPHENE_ASSERT( + o.review_period_seconds.valid(), + proposal_create_review_period_required, + "Review period not given, but at least ${min} required", + ("min", global_parameters.committee_proposal_review_period) + ); + GRAPHENE_ASSERT( + *o.review_period_seconds >= global_parameters.committee_proposal_review_period, + proposal_create_review_period_insufficient, + "Review period of ${t} required, but at least ${min} required", + ("t", *o.review_period_seconds) + ("min", global_parameters.committee_proposal_review_period) + ); + } } for( const op_wrapper& op : o.proposed_ops ) diff --git a/libraries/chain/protocol/proposal.cpp b/libraries/chain/protocol/proposal.cpp index cbfc5362..6f866929 100644 --- a/libraries/chain/protocol/proposal.cpp +++ b/libraries/chain/protocol/proposal.cpp @@ -8,7 +8,7 @@ proposal_create_operation proposal_create_operation::genesis_proposal(const chai { proposal_create_operation op; op.expiration_time = head_block_time + global_params.maximum_proposal_lifetime; - op.review_period_seconds = global_params.genesis_proposal_review_period; + op.review_period_seconds = global_params.committee_proposal_review_period; return op; } diff --git a/libraries/chain/transfer_evaluator.cpp b/libraries/chain/transfer_evaluator.cpp index d2ef09fb..66e5724b 100644 --- a/libraries/chain/transfer_evaluator.cpp +++ b/libraries/chain/transfer_evaluator.cpp @@ -17,6 +17,7 @@ */ #include #include +#include namespace graphene { namespace chain { void_result transfer_evaluator::do_evaluate( const transfer_operation& op ) @@ -30,8 +31,20 @@ void_result transfer_evaluator::do_evaluate( const transfer_operation& op ) if( asset_type.options.flags & white_list ) { - FC_ASSERT( to_account.is_authorized_asset( asset_type ) ); - FC_ASSERT( from_account.is_authorized_asset( asset_type ) ); + GRAPHENE_ASSERT( + from_account.is_authorized_asset( asset_type ), + transfer_from_account_not_whitelisted, + "'from' account ${from} is not whitelisted for asset ${asset}", + ("from",op.from) + ("asset",op.amount.asset_id) + ); + GRAPHENE_ASSERT( + to_account.is_authorized_asset( asset_type ), + transfer_to_account_not_whitelisted, + "'to' account ${to} is not whitelisted for asset ${asset}", + ("to",op.to) + ("asset",op.amount.asset_id) + ); } if( fee_asset_type.options.flags & white_list ) @@ -60,7 +73,12 @@ void_result override_transfer_evaluator::do_evaluate( const override_transfer_op database& d = db(); const asset_object& asset_type = op.amount.asset_id(d); - FC_ASSERT( asset_type.can_override() ); + GRAPHENE_ASSERT( + asset_type.can_override(), + override_transfer_not_permitted, + "override_transfer not permitted for asset ${asset}", + ("asset", op.amount.asset_id) + ); FC_ASSERT( asset_type.issuer == op.issuer ); const account_object& from_account = op.from(d); diff --git a/libraries/chain/withdraw_permission_evaluator.cpp b/libraries/chain/withdraw_permission_evaluator.cpp index 086ec368..d7a33c7f 100644 --- a/libraries/chain/withdraw_permission_evaluator.cpp +++ b/libraries/chain/withdraw_permission_evaluator.cpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace graphene { namespace chain { diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 2d98dc2c..cffeaeff 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -301,7 +301,7 @@ public: : self(s), _remote_api(rapi), _remote_db(rapi->database()), - _remote_net(rapi->network()), + _remote_net_broadcast(rapi->network_broadcast()), _remote_hist(rapi->history()) { _remote_db->subscribe_to_objects( [=]( const fc::variant& obj ) @@ -741,7 +741,7 @@ public: } if( broadcast ) - _remote_net->broadcast_transaction( tx ); + _remote_net_broadcast->broadcast_transaction( tx ); return tx; } FC_CAPTURE_AND_RETHROW( (name)(owner)(active)(registrar_account)(referrer_account)(referrer_percent)(broadcast) ) } @@ -868,7 +868,7 @@ public: if( save_wallet ) save_wallet_file(); if( broadcast ) - _remote_net->broadcast_transaction( tx ); + _remote_net_broadcast->broadcast_transaction( tx ); return tx; } FC_CAPTURE_AND_RETHROW( (account_name)(registrar_account)(referrer_account)(broadcast) ) } @@ -1451,7 +1451,7 @@ public: } if( broadcast ) - _remote_net->broadcast_transaction( tx ); + _remote_net_broadcast->broadcast_transaction( tx ); return tx; } @@ -1696,7 +1696,7 @@ public: fc::api _remote_api; fc::api _remote_db; - fc::api _remote_net; + fc::api _remote_net_broadcast; fc::api _remote_hist; #ifdef __unix__ @@ -2441,7 +2441,7 @@ signed_transaction wallet_api::import_balance( string name_or_id, const vector(boost::sort(tx.signatures))); if( broadcast ) - my->_remote_net->broadcast_transaction(tx); + my->_remote_net_broadcast->broadcast_transaction(tx); return tx; } FC_CAPTURE_AND_RETHROW( (name_or_id) ) } diff --git a/programs/js_operation_serializer/main.cpp b/programs/js_operation_serializer/main.cpp index dfa7eb56..5fb2a114 100644 --- a/programs/js_operation_serializer/main.cpp +++ b/programs/js_operation_serializer/main.cpp @@ -365,7 +365,7 @@ int main( int argc, char** argv ) detail_ns::js_name>::name("key_data"); detail_ns::js_name::name("operation_result"); detail_ns::js_name::name("header_extension"); - detail_ns::js_name::name("parameter_extension"); + detail_ns::js_name::name("worker_initializer"); detail_ns::js_name>::name("vesting_policy_initializer"); detail_ns::serializer::init(); detail_ns::serializer::init(); diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index aad45e91..99387f31 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -119,7 +119,7 @@ int main(int argc, char** argv) { node.startup_plugins(); fc::promise::ptr exit_promise = new fc::promise("UNIX Signal Handler"); -#ifdef __unix__ +#if defined __APPLE__ || defined __unix__ fc::set_signal_handler([&exit_promise](int signal) { exit_promise->set_value(signal); }, SIGINT); diff --git a/programs/witness_node/saltpass.py b/programs/witness_node/saltpass.py new file mode 100755 index 00000000..6562fc23 --- /dev/null +++ b/programs/witness_node/saltpass.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +import base64 +import getpass +import hashlib +import json +import os + +pw = getpass.getpass("enter your password: ") +pw_bytes = pw.encode("utf-8") +salt_bytes = os.urandom(8) +salt_b64 = base64.b64encode( salt_bytes ) +pw_hash = hashlib.sha256( pw_bytes + salt_bytes ).digest() +pw_hash_b64 = base64.b64encode( pw_hash ) + +print(json.dumps( +{ + "password_hash_b64" : pw_hash_b64.decode("ascii"), + "password_salt_b64" : salt_b64.decode("ascii"), +}, +sort_keys=True, +indent=3, separators=(',', ' : ') +)) diff --git a/testnet-shared-accounts.txt b/testnet-shared-accounts.txt new file mode 100644 index 00000000..c3777468 --- /dev/null +++ b/testnet-shared-accounts.txt @@ -0,0 +1,50 @@ + "name": "dummy0", + "owner_key": "BTS6qkMe8pHmQ4zUetLV1bbVKoQJYTNb1fSUbkQzuzpscYhonWpgk", + "active_key": "BTS6qkMe8pHmQ4zUetLV1bbVKoQJYTNb1fSUbkQzuzpscYhonWpgk", + "is_lifetime_member": true + },{ + "name": "dummy1", + "owner_key": "BTS7wXsTzBBR2QEetjrgxcSmN7Kuzey3RAzQWNNHwbPQsKYxkP6fp", + "active_key": "BTS7wXsTzBBR2QEetjrgxcSmN7Kuzey3RAzQWNNHwbPQsKYxkP6fp", + "is_lifetime_member": true + },{ + "name": "dummy2", + "owner_key": "BTS7rzifzfJxS8RWhev9aU8HDYoJi1EGwJRHG9B2fJKxnZAiF2Rsh", + "active_key": "BTS7rzifzfJxS8RWhev9aU8HDYoJi1EGwJRHG9B2fJKxnZAiF2Rsh", + "is_lifetime_member": true + },{ + "name": "dummy3", + "owner_key": "BTS6QZdcwFEFMtHsfW27YBGTv9KLaLTvgx5wgGrPHeUxDTrYEQJ2d", + "active_key": "BTS6QZdcwFEFMtHsfW27YBGTv9KLaLTvgx5wgGrPHeUxDTrYEQJ2d", + "is_lifetime_member": true + },{ + "name": "dummy4", + "owner_key": "BTS7q5MqhSP2a6CRTWaJk77ZcGdpnv14JbT4cVzbXaoAsWJoCxFJG", + "active_key": "BTS7q5MqhSP2a6CRTWaJk77ZcGdpnv14JbT4cVzbXaoAsWJoCxFJG", + "is_lifetime_member": true + },{ + "name": "dummy5", + "owner_key": "BTS5sRXxgDCnteHLUS623xtxJM5WKKVygwDMzEso6LigwxvprJqBA", + "active_key": "BTS5sRXxgDCnteHLUS623xtxJM5WKKVygwDMzEso6LigwxvprJqBA", + "is_lifetime_member": true + },{ + "name": "dummy6", + "owner_key": "BTS5V4HEQJbVbMjUWASeknQ42NT3NP9bZaygt83XMuvy6v4QMJuSP", + "active_key": "BTS5V4HEQJbVbMjUWASeknQ42NT3NP9bZaygt83XMuvy6v4QMJuSP", + "is_lifetime_member": true + },{ + "name": "dummy7", + "owner_key": "BTS86ukuPAufzKouerZf1dCxjVSmxQPA5kLwvnYEjn9GRqi5qXBop", + "active_key": "BTS86ukuPAufzKouerZf1dCxjVSmxQPA5kLwvnYEjn9GRqi5qXBop", + "is_lifetime_member": true + },{ + "name": "dummy8", + "owner_key": "BTS7Sdg3kQuz2pPT8mA8Yr3mkBe7zr6293mnBmoR36z9xxtRdiMmJ", + "active_key": "BTS7Sdg3kQuz2pPT8mA8Yr3mkBe7zr6293mnBmoR36z9xxtRdiMmJ", + "is_lifetime_member": true + },{ + "name": "dummy9", + "owner_key": "BTS5WCj1mMiiqEE4QRs7xhaFfSaiFroejUp3GuZE9wvfue9nxhPPn", + "active_key": "BTS5WCj1mMiiqEE4QRs7xhaFfSaiFroejUp3GuZE9wvfue9nxhPPn", + "is_lifetime_member": true + },{ diff --git a/testnet-shared-balances.txt b/testnet-shared-balances.txt new file mode 100644 index 00000000..dc9061fa --- /dev/null +++ b/testnet-shared-balances.txt @@ -0,0 +1,41 @@ + "initial_balances": [{ + "owner": "BTSHYhQcrjVg5kBzCoeeD38eQdncCC5pBgee", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTSPgQZg5929ht1NBdEvsGKqoQ7buRu3nKf4", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTSC9zrLXSAPUQaVmQPk1S9dMqSzT7jPqYU7", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTS93aQPtbbkXwaSjtHaREsNVcCvbfHo93aZ", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTS6RM4UfsYFPDuhbmgkvDS9ip8Kvqundvyk", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTSNVkZXdqWWSzqHVxvfetMe347is6kEkC4K", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTS5GHzWZ64Luoajqsz6JGjTKVMgWYkGV9SQ", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTSDCVRFez92bW9doRLjnFCKLJnpM58mgmMb", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTS5CCdX3JYLBptYMuCjbsezqGYzN9vG9JCu", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ + "owner": "BTSEQ3yQdr3EMDL2eRqGiceMCpoanaW16Puw", + "asset_symbol": "CORE", + "amount": 100000000000 + },{ diff --git a/testnet-shared-private-keys.txt b/testnet-shared-private-keys.txt new file mode 100644 index 00000000..e2a8d7dd --- /dev/null +++ b/testnet-shared-private-keys.txt @@ -0,0 +1,10 @@ +5KCNDLVGqvX8p3GcMFun9sMe6XbMvycVTm4bGrkB5aZGWCbAAtr +5HvFQ1bcAWk8H1A2qXj1AqSNp93GUAb6b2w5TVfLb1jWL6yNF3f +5JSxv2kgaBSm9nGseRNhLhgEKTBmoKJ5CkgLbbk5RW4RBCNsLJC +5K5E2TQtrodDFzsqPq3oVFi9rVX15AN8sLE3iTHfVsX1b49y49J +5HxC3fwN7VDZXKVkbbX3SzCczh18Fetx8TXBfJ3z3ovDUSPKvVd +5KSr4w978PDanQDYtftarcfJVvGe4wedYb1sYbdH6HNpi15heRa +5Kan4si6qWvDVpZuqug4c6KQH4zkvDhwspaGQiFKYniJv6qji6t +5KcZri5DDsMcDp1DjNeMkZSijkWurPoAoR7gBKTnnetNQ9CpXoJ +5K5TRZyEhC6GPgi57t5FhiSMRGVTHEbwXngbBEtCA41gM8LPFhF +5KXVG4oP4Vj3RawRpta79UFAg7pWp17FGf4DnrKfkr69ELytDMv diff --git a/tests/app/main.cpp b/tests/app/main.cpp index fa923e87..6febbfd7 100644 --- a/tests/app/main.cpp +++ b/tests/app/main.cpp @@ -40,7 +40,8 @@ BOOST_AUTO_TEST_CASE( two_node_network ) fc::temp_directory app2_dir; fc::temp_file genesis_json; - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + // TODO: Time should be read from the blockchain + fc::time_point_sec now( 1431700000 ); graphene::app::application app1; app1.register_plugin(); diff --git a/tests/benchmarks/genesis_allocation.cpp b/tests/benchmarks/genesis_allocation.cpp index 476360ed..fc842719 100644 --- a/tests/benchmarks/genesis_allocation.cpp +++ b/tests/benchmarks/genesis_allocation.cpp @@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE( genesis_and_persistence_bench ) { database db; - db.open(data_dir.path(), genesis_state); + db.open(data_dir.path(), [&]{return genesis_state;}); for( int i = 11; i < account_count + 11; ++i) BOOST_CHECK(db.get_balance(account_id_type(i), asset_id_type()).amount == GRAPHENE_MAX_SHARE_SUPPLY / account_count); @@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE( genesis_and_persistence_bench ) database db; fc::time_point start_time = fc::time_point::now(); - db.open(data_dir.path()); + db.open(data_dir.path(), [&]{return genesis_state;}); ilog("Opened database in ${t} milliseconds.", ("t", (fc::time_point::now() - start_time).count() / 1000)); for( int i = 11; i < account_count + 11; ++i) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 522feb32..cc6063cd 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -48,6 +48,16 @@ database_fixture::database_fixture() : app(), db( *app.chain_database() ) { try { + int argc = boost::unit_test::framework::master_test_suite().argc; + char** argv = boost::unit_test::framework::master_test_suite().argv; + for( int i=1; i(); auto mhplugin = app.register_plugin(); delegate_pub_key = delegate_priv_key.get_public_key(); @@ -60,6 +70,8 @@ database_fixture::database_fixture() mhplugin->plugin_set_app(&app); mhplugin->plugin_initialize(options); + genesis_state.initial_timestamp = time_point_sec( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); + genesis_state.initial_active_witnesses = 10; for( int i = 0; i < genesis_state.initial_active_witnesses; ++i ) { @@ -274,7 +286,7 @@ void database_fixture::open_database() { if( !data_dir ) { data_dir = fc::temp_directory(); - db.open(data_dir->path(), genesis_state); + db.open(data_dir->path(), [this]{return genesis_state;}); } } diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 5e2a74b9..50582315 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -21,8 +21,12 @@ #include #include +#include + using namespace graphene::db; +#define GRAPHENE_TESTING_GENESIS_TIMESTAMP (1431700000) + #define PUSH_TX \ graphene::chain::test::_push_transaction @@ -37,13 +41,6 @@ using namespace graphene::db; op.validate(); \ op.field = temp; \ } -#define REQUIRE_OP_VALIDATION_FAILURE( op, field, value ) \ -{ \ - const auto temp = op.field; \ - op.field = value; \ - BOOST_REQUIRE_THROW( op.validate(), fc::exception ); \ - op.field = temp; \ -} #define REQUIRE_OP_EVALUATION_SUCCESS( op, field, value ) \ { \ const auto temp = op.field; \ @@ -52,17 +49,65 @@ using namespace graphene::db; op.field = temp; \ db.push_transaction( trx, ~0 ); \ } -///Shortcut to require an exception when processing a transaction with an operation containing an expected bad value -/// Uses require insteach of check, because these transactions are expected to fail. If they don't, subsequent tests -/// may spuriously succeed or fail due to unexpected database state. -#define REQUIRE_THROW_WITH_VALUE(op, field, value) \ + +#define GRAPHENE_REQUIRE_THROW( expr, exc_type ) \ +{ \ + std::string req_throw_info = fc::json::to_string( \ + fc::mutable_variant_object() \ + ("source_file", __FILE__) \ + ("source_lineno", __LINE__) \ + ("expr", #expr) \ + ("exc_type", #exc_type) \ + ); \ + if( fc::enable_record_assert_trip ) \ + std::cout << "GRAPHENE_REQUIRE_THROW begin " \ + << req_throw_info << std::endl; \ + BOOST_REQUIRE_THROW( expr, exc_type ); \ + if( fc::enable_record_assert_trip ) \ + std::cout << "GRAPHENE_REQUIRE_THROW end " \ + << req_throw_info << std::endl; \ +} + +#define GRAPHENE_CHECK_THROW( expr, exc_type ) \ +{ \ + std::string req_throw_info = fc::json::to_string( \ + fc::mutable_variant_object() \ + ("source_file", __FILE__) \ + ("source_lineno", __LINE__) \ + ("expr", #expr) \ + ("exc_type", #exc_type) \ + ); \ + if( fc::enable_record_assert_trip ) \ + std::cout << "GRAPHENE_CHECK_THROW begin " \ + << req_throw_info << std::endl; \ + BOOST_CHECK_THROW( expr, exc_type ); \ + if( fc::enable_record_assert_trip ) \ + std::cout << "GRAPHENE_CHECK_THROW end " \ + << req_throw_info << std::endl; \ +} + +#define REQUIRE_OP_VALIDATION_FAILURE_2( op, field, value, exc_type ) \ +{ \ + const auto temp = op.field; \ + op.field = value; \ + GRAPHENE_REQUIRE_THROW( op.validate(), exc_type ); \ + op.field = temp; \ +} +#define REQUIRE_OP_VALIDATION_FAILURE( op, field, value ) \ + REQUIRE_OP_VALIDATION_FAILURE_2( op, field, value, fc::exception ) + +#define REQUIRE_THROW_WITH_VALUE_2(op, field, value, exc_type) \ { \ auto bak = op.field; \ op.field = value; \ trx.operations.back() = op; \ op.field = bak; \ - BOOST_REQUIRE_THROW(db.push_transaction(trx, ~0), fc::exception); \ + GRAPHENE_REQUIRE_THROW(db.push_transaction(trx, ~0), exc_type); \ } + +#define REQUIRE_THROW_WITH_VALUE( op, field, value ) \ + REQUIRE_THROW_WITH_VALUE_2( op, field, value, fc::exception ) + ///This simply resets v back to its default-constructed value. Requires v to have a working assingment operator and /// default constructor. #define RESET(v) v = decltype(v)() @@ -71,7 +116,7 @@ using namespace graphene::db; #define INVOKE(test) ((struct test*)this)->test_method(); trx.clear() #define PREP_ACTOR(name) \ - fc::ecc::private_key name ## _private_key = generate_private_key(BOOST_PP_STRINGIZE(name)); + fc::ecc::private_key name ## _private_key = generate_private_key(BOOST_PP_STRINGIZE(name)); #define ACTOR(name) \ PREP_ACTOR(name) \ @@ -102,8 +147,6 @@ struct database_fixture { fc::ecc::private_key delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); public_key_type delegate_pub_key; - fc::time_point_sec genesis_time = fc::time_point_sec( GRAPHENE_GENESIS_TIMESTAMP ); - fc::time_point_sec now = fc::time_point_sec( GRAPHENE_GENESIS_TIMESTAMP ); optional data_dir; bool skip_key_index_test = false; uint32_t anon_acct_count; @@ -146,10 +189,20 @@ struct database_fixture { ); void force_global_settle(const asset_object& what, const price& p); + void force_settle(account_id_type who, asset what) + { force_settle(who(db), what); } void force_settle(const account_object& who, asset what); + void update_feed_producers(asset_id_type mia, flat_set producers) + { update_feed_producers(mia(db), producers); } void update_feed_producers(const asset_object& mia, flat_set producers); + void publish_feed(asset_id_type mia, account_id_type by, const price_feed& f) + { publish_feed(mia(db), by(db), f); } void publish_feed(const asset_object& mia, const account_object& by, const price_feed& f); + void borrow(account_id_type who, asset what, asset collateral) + { borrow(who(db), what, collateral); } void borrow(const account_object& who, asset what, asset collateral); + void cover(account_id_type who, asset what, asset collateral_freed) + { cover(who(db), what, collateral_freed); } void cover(const account_object& who, asset what, asset collateral_freed); const asset_object& get_asset( const string& symbol )const; @@ -163,7 +216,7 @@ struct database_fixture { uint16_t market_fee_percent = 100 /*1%*/, uint16_t flags = charge_market_fee); const asset_object& create_user_issued_asset( const string& name ); - const asset_object& create_user_issued_asset( const string& name, + const asset_object& create_user_issued_asset( const string& name, const account_object& issuer, uint16_t flags ); void issue_uia( const account_object& recipient, asset amount ); diff --git a/tests/intense/block_tests.cpp b/tests/intense/block_tests.cpp index ffe2d67d..4065961a 100644 --- a/tests/intense/block_tests.cpp +++ b/tests/intense/block_tests.cpp @@ -22,10 +22,11 @@ #include #include -#include +#include #include #include #include +#include #include @@ -71,7 +72,7 @@ BOOST_FIXTURE_TEST_CASE( update_account_keys, database_fixture ) generate_block( skip_flags ); db.modify(db.get_global_properties(), [](global_property_object& p) { - p.parameters.genesis_proposal_review_period = fc::hours(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::hours(1).to_seconds(); }); transaction tx; @@ -206,7 +207,7 @@ BOOST_FIXTURE_TEST_CASE( update_account_keys, database_fixture ) trx.sign( *owner_privkey[i] ); if( i < int(create_op.owner.weight_threshold-1) ) { - BOOST_REQUIRE_THROW(db.push_transaction(trx), fc::exception); + GRAPHENE_REQUIRE_THROW(db.push_transaction(trx), fc::exception); } else { @@ -401,4 +402,91 @@ BOOST_FIXTURE_TEST_CASE( generic_scheduler_mc_test, database_fixture ) } } +BOOST_FIXTURE_TEST_CASE( tapos_rollover, database_fixture ) +{ + try + { + ACTORS((alice)(bob)); + const auto& core = asset_id_type()(db); + + BOOST_TEST_MESSAGE( "Give Alice some money" ); + transfer(genesis_account, alice_id, asset(10000)); + generate_block(); + + BOOST_TEST_MESSAGE( "Generate up to block 0xFF00" ); + generate_blocks( 0xFF00 ); + signed_transaction xfer_tx; + + BOOST_TEST_MESSAGE( "Transfer money at/about 0xFF00" ); + transfer_operation xfer_op; + xfer_op.from = alice_id; + xfer_op.to = bob_id; + xfer_op.amount = asset(1000); + + xfer_tx.operations.push_back( xfer_op ); + xfer_tx.set_expiration( db.head_block_id(), 0x1000 ); + sign( xfer_tx, alice_private_key ); + PUSH_TX( db, xfer_tx, 0 ); + generate_block(); + + BOOST_TEST_MESSAGE( "Sign new tx's" ); + xfer_tx.set_expiration( db.head_block_id(), 0x1000 ); + xfer_tx.signatures.clear(); + sign( xfer_tx, alice_private_key ); + + BOOST_TEST_MESSAGE( "Generate up to block 0x10010" ); + generate_blocks( 0x110 ); + + BOOST_TEST_MESSAGE( "Transfer at/about block 0x10010 using reference block at/about 0xFF00" ); + PUSH_TX( db, xfer_tx, 0 ); + generate_block(); + } + catch (fc::exception& e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_FIXTURE_TEST_CASE(bulk_discount, database_fixture) +{ try { + ACTOR(nathan); + // Give nathan ALLLLLL the money! + transfer(GRAPHENE_COMMITTEE_ACCOUNT, nathan_id, db.get_balance(GRAPHENE_COMMITTEE_ACCOUNT, asset_id_type())); + enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); + upgrade_to_lifetime_member(nathan_id); + share_type new_fees; + while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN ) + { + transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); + new_fees += transfer_operation().calculate_fee(db.current_fee_schedule()); + } + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); + auto old_cashback = nathan_id(db).cashback_balance(db).balance; + + transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); + + BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value, + old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 8); + + new_fees = 0; + while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX ) + { + transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); + new_fees += transfer_operation().calculate_fee(db.current_fee_schedule()); + } + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); + old_cashback = nathan_id(db).cashback_balance(db).balance; + + transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + + BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value, + old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 9); +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/performance/performance_tests.cpp b/tests/performance/performance_tests.cpp index 49f2c051..d137949f 100644 --- a/tests/performance/performance_tests.cpp +++ b/tests/performance/performance_tests.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include diff --git a/tests/tests/authority_tests.cpp b/tests/tests/authority_tests.cpp index 1922a945..c6fdab5b 100644 --- a/tests/tests/authority_tests.cpp +++ b/tests/tests/authority_tests.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -80,7 +81,7 @@ BOOST_AUTO_TEST_CASE( any_two_of_three ) transfer_operation op = {asset(), nathan.id, account_id_type(), core.amount(500)}; trx.operations.push_back(op); sign(trx, nathan_key1); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); sign(trx, nathan_key2); PUSH_TX( db, trx, database::skip_transaction_dupe_check ); BOOST_CHECK_EQUAL(get_balance(nathan, core), old_balance - 500); @@ -100,7 +101,7 @@ BOOST_AUTO_TEST_CASE( any_two_of_three ) trx.signatures.clear(); //sign(trx, fc::ecc::private_key::generate()); sign(trx,nathan_key3); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_CHECK_EQUAL(get_balance(nathan, core), old_balance - 1500); } catch (fc::exception& e) { edump((e.to_detail_string())); @@ -135,16 +136,16 @@ BOOST_AUTO_TEST_CASE( recursive_accounts ) BOOST_TEST_MESSAGE( "Attempting to transfer with no signatures, should fail" ); transfer_operation op = {asset(), child.id, account_id_type(), core.amount(500)}; trx.operations.push_back(op); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_TEST_MESSAGE( "Attempting to transfer with parent1 signature, should fail" ); sign(trx,parent1_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); trx.signatures.clear(); BOOST_TEST_MESSAGE( "Attempting to transfer with parent2 signature, should fail" ); sign(trx,parent2_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_TEST_MESSAGE( "Attempting to transfer with parent1 and parent2 signature, should succeed" ); sign(trx,parent1_key); @@ -172,14 +173,14 @@ BOOST_AUTO_TEST_CASE( recursive_accounts ) op = {asset(),child.id, account_id_type(), core.amount(500)}; trx.operations.push_back(op); BOOST_TEST_MESSAGE( "Attempting transfer with no signatures, should fail" ); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_TEST_MESSAGE( "Attempting transfer just parent1, should fail" ); sign(trx, parent1_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); trx.signatures.clear(); BOOST_TEST_MESSAGE( "Attempting transfer just parent2, should fail" ); sign(trx, parent2_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_TEST_MESSAGE( "Attempting transfer both parents, should succeed" ); sign(trx, parent1_key); @@ -216,7 +217,7 @@ BOOST_AUTO_TEST_CASE( recursive_accounts ) trx.operations.push_back(op); sign(trx, parent1_key); sign(trx, parent2_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); trx.signatures.clear(); trx.sign( parent2_key ); trx.sign( grandparent_key ); @@ -244,7 +245,7 @@ BOOST_AUTO_TEST_CASE( recursive_accounts ) sign(trx, grandparent_key); sign(trx, delegate_priv_key); //Fails due to recursion depth. - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); BOOST_TEST_MESSAGE( "verify child key can override recursion checks" ); trx.signatures.clear(); sign(trx, child_key); @@ -268,7 +269,7 @@ BOOST_AUTO_TEST_CASE( recursive_accounts ) trx.operations.push_back(op); sign(trx, parent2_key); //Fails due to recursion depth. - BOOST_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, database::skip_transaction_dupe_check ), fc::exception); } catch (fc::exception& e) { edump((e.to_detail_string())); throw; @@ -331,11 +332,11 @@ BOOST_AUTO_TEST_CASE( proposed_single_account ) trx.operations = {proposal_update_operation{account_id_type(), asset(), proposal.id,{nathan.id},flat_set{},flat_set{},flat_set{},flat_set{},flat_set{}}}; trx.sign( genesis_key ); //Genesis may not add nathan's approval. - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); trx.operations = {proposal_update_operation{account_id_type(), asset(), proposal.id,{account_id_type()},flat_set{},flat_set{},flat_set{},flat_set{},flat_set{}}}; trx.sign( genesis_key ); //Genesis has no stake in the transaction. - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); trx.signatures.clear(); trx.operations = {proposal_update_operation{nathan.id, asset(), proposal.id,{nathan.id},flat_set{},flat_set{},flat_set{},flat_set{},flat_set{}}}; @@ -366,31 +367,31 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) // Signatures are for suckers. db.modify(db.get_global_properties(), [](global_property_object& p) { // Turn the review period WAY down, so it doesn't take long to produce blocks to that point in simulated time. - p.parameters.genesis_proposal_review_period = fc::days(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::days(1).to_seconds(); }); BOOST_TEST_MESSAGE( "transfering 100000 CORE to nathan, signing with genesis key" ); trx.operations.push_back(transfer_operation({asset(), account_id_type(), nathan.id, asset(100000)})); sign(trx, genesis_key); - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); auto sign = [&] { trx.signatures.clear(); trx.sign(nathan_key); }; proposal_create_operation pop; pop.proposed_ops.push_back({trx.operations.front()}); - pop.expiration_time = db.head_block_time() + global_params.genesis_proposal_review_period*2; + pop.expiration_time = db.head_block_time() + global_params.committee_proposal_review_period*2; pop.fee_paying_account = nathan.id; trx.operations = {pop}; sign(); // The review period isn't set yet. Make sure it throws. - BOOST_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); - pop.review_period_seconds = global_params.genesis_proposal_review_period / 2; + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), proposal_create_review_period_required ); + pop.review_period_seconds = global_params.committee_proposal_review_period / 2; trx.operations.back() = pop; sign(); // The review period is too short. Make sure it throws. - BOOST_REQUIRE_THROW( PUSH_TX( db, trx ), fc::exception ); - pop.review_period_seconds = global_params.genesis_proposal_review_period; + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx ), proposal_create_review_period_insufficient ); + pop.review_period_seconds = global_params.committee_proposal_review_period; trx.operations.back() = pop; sign(); proposal_object prop = db.get(PUSH_TX( db, trx ).operation_results.front().get()); @@ -405,7 +406,7 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) generate_block(); BOOST_REQUIRE(db.find_object(prop.id)); BOOST_CHECK_EQUAL(get_balance(nathan, asset_id_type()(db)), 0); - + BOOST_TEST_MESSAGE( "Checking that the proposal is not authorized to execute" ); BOOST_REQUIRE(!db.get(prop.id).is_authorized_to_execute(db)); trx.operations.clear(); @@ -435,7 +436,7 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) trx.operations.back() = uop; trx.sign( genesis_key); // Should throw because the transaction is now in review. - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); generate_blocks(prop.expiration_time); BOOST_CHECK_EQUAL(get_balance(nathan, asset_id_type()(db)), 100000); @@ -456,7 +457,7 @@ BOOST_FIXTURE_TEST_CASE( fired_delegates, database_fixture ) db.modify(db.get_global_properties(), [](global_property_object& p) { // Turn the review period WAY down, so it doesn't take long to produce blocks to that point in simulated time. - p.parameters.genesis_proposal_review_period = fc::days(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::days(1).to_seconds(); }); for( int i = 0; i < 15; ++i ) @@ -590,7 +591,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_two_accounts, database_fixture ) uop.active_approvals_to_add = {dan.get_id()}; trx.operations.push_back(uop); trx.sign(nathan_key); - BOOST_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception); trx.sign(dan_key); PUSH_TX( db, trx ); @@ -840,7 +841,7 @@ BOOST_FIXTURE_TEST_CASE( max_authority_membership, database_fixture ) generate_block(); db.modify(db.get_global_properties(), [](global_property_object& p) { - p.parameters.genesis_proposal_review_period = fc::hours(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::hours(1).to_seconds(); }); transaction tx; @@ -911,7 +912,7 @@ BOOST_FIXTURE_TEST_CASE( max_authority_membership, database_fixture ) if( num_keys > max_authority_membership ) { - BOOST_REQUIRE_THROW(PUSH_TX( db, tx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, tx, ~0 ), fc::exception); } else { @@ -976,7 +977,7 @@ BOOST_FIXTURE_TEST_CASE( bogus_signature, database_fixture ) trx.operations.push_back( xfer_op ); BOOST_TEST_MESSAGE( "Invalidating Alices Signature" ); // Alice's signature is now invalid - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception ); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception ); // Re-sign, now OK (sig is replaced) BOOST_TEST_MESSAGE( "Resign with Alice's Signature" ); trx.signatures.clear(); @@ -988,7 +989,7 @@ BOOST_FIXTURE_TEST_CASE( bogus_signature, database_fixture ) trx.sign( alice_key ); trx.sign( charlie_key ); // Signed by third-party Charlie (irrelevant key, not in authority) - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception ); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception ); } FC_LOG_AND_RETHROW() } @@ -1029,7 +1030,7 @@ BOOST_FIXTURE_TEST_CASE( voting_account, database_fixture ) trx.operations.push_back(op); trx.sign(vikram_private_key); // Fails because num_committee is larger than the cardinality of committee members being voted for - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); op.new_options->num_committee = 3; trx.operations = {op}; trx.signatures.clear(); diff --git a/tests/tests/basic_tests.cpp b/tests/tests/basic_tests.cpp index 56f4cf96..727a0690 100644 --- a/tests/tests/basic_tests.cpp +++ b/tests/tests/basic_tests.cpp @@ -330,7 +330,7 @@ BOOST_AUTO_TEST_CASE( data_fees ) BOOST_AUTO_TEST_CASE( exceptions ) { - BOOST_CHECK_THROW(FC_THROW_EXCEPTION(invalid_claim_amount, "Etc"), invalid_claim_amount); + GRAPHENE_CHECK_THROW(FC_THROW_EXCEPTION(balance_claim_invalid_claim_amount, "Etc"), balance_claim_invalid_claim_amount); } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 1293aacd..279cbbc0 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -36,6 +36,9 @@ using namespace graphene::chain; genesis_state_type make_genesis() { genesis_state_type genesis_state; + + genesis_state.initial_timestamp = time_point_sec( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); + auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key"))); genesis_state.initial_active_witnesses = 10; for( int i = 0; i < genesis_state.initial_active_witnesses; ++i ) @@ -117,7 +120,7 @@ BOOST_AUTO_TEST_CASE( block_database_test ) BOOST_AUTO_TEST_CASE( generate_empty_blocks ) { try { - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); fc::temp_directory data_dir; signed_block b; @@ -126,7 +129,7 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks ) auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); { database db; - db.open(data_dir.path(), make_genesis() ); + db.open(data_dir.path(), make_genesis ); b = db.generate_block(now, db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); for( uint32_t i = 1; i < 200; ++i ) @@ -134,25 +137,25 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks ) BOOST_CHECK( db.head_block_id() == b.id() ); witness_id_type prev_witness = b.witness; now += db.block_interval(); - witness_id_type cur_witness = db.get_scheduled_witness( 1 ).first; + witness_id_type cur_witness = db.get_scheduled_witness(1).first; BOOST_CHECK( cur_witness != prev_witness ); - b = db.generate_block( now, cur_witness, delegate_priv_key, database::skip_nothing ); + b = db.generate_block(now, cur_witness, delegate_priv_key, database::skip_nothing); BOOST_CHECK( b.witness == cur_witness ); } db.close(); } { database db; - db.open(data_dir.path() ); + db.open(data_dir.path(), []{return genesis_state_type();}); BOOST_CHECK_EQUAL( db.head_block_num(), 200 ); for( uint32_t i = 0; i < 200; ++i ) { BOOST_CHECK( db.head_block_id() == b.id() ); witness_id_type prev_witness = b.witness; now += db.block_interval(); - witness_id_type cur_witness = db.get_scheduled_witness( 1 ).first; + witness_id_type cur_witness = db.get_scheduled_witness(1).first; BOOST_CHECK( cur_witness != prev_witness ); - b = db.generate_block( now, cur_witness, delegate_priv_key, database::skip_nothing ); + b = db.generate_block(now, cur_witness, delegate_priv_key, database::skip_nothing); } BOOST_CHECK_EQUAL( db.head_block_num(), 400 ); } @@ -168,8 +171,8 @@ BOOST_AUTO_TEST_CASE( undo_block ) fc::temp_directory data_dir; { database db; - db.open(data_dir.path(), make_genesis() ); - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + db.open(data_dir.path(), make_genesis); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); for( uint32_t i = 0; i < 5; ++i ) @@ -205,12 +208,12 @@ BOOST_AUTO_TEST_CASE( fork_blocks ) try { fc::temp_directory data_dir1; fc::temp_directory data_dir2; - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); database db1; - db1.open(data_dir1.path(), make_genesis()); + db1.open(data_dir1.path(), make_genesis); database db2; - db2.open(data_dir2.path(), make_genesis()); + db2.open(data_dir2.path(), make_genesis); auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); for( uint32_t i = 0; i < 10; ++i ) @@ -251,7 +254,7 @@ BOOST_AUTO_TEST_CASE( fork_blocks ) b.transactions.back().operations.emplace_back(transfer_operation()); b.sign(delegate_priv_key); BOOST_CHECK_EQUAL(b.block_num(), 14); - BOOST_CHECK_THROW(PUSH_BLOCK( db1, b ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_BLOCK( db1, b ), fc::exception); } BOOST_CHECK_EQUAL(db1.head_block_num(), 13); BOOST_CHECK_EQUAL(db1.head_block_id().str(), db1_tip); @@ -269,11 +272,11 @@ BOOST_AUTO_TEST_CASE( fork_blocks ) BOOST_AUTO_TEST_CASE( undo_pending ) { try { - fc::time_point_sec now(GRAPHENE_GENESIS_TIMESTAMP); + fc::time_point_sec now(GRAPHENE_TESTING_GENESIS_TIMESTAMP); fc::temp_directory data_dir; { database db; - db.open(data_dir.path(), make_genesis()); + db.open(data_dir.path(), make_genesis); auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); public_key_type delegate_pub_key = delegate_priv_key.get_public_key(); @@ -331,10 +334,10 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create ) dir2; database db1, db2; - db1.open(dir1.path(), make_genesis()); - db2.open(dir2.path(), make_genesis()); + db1.open(dir1.path(), make_genesis); + db2.open(dir2.path(), make_genesis); - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); public_key_type delegate_pub_key = delegate_priv_key.get_public_key(); const graphene::db::index& account_idx = db1.get_index(protocol_ids, account_object_type); @@ -355,7 +358,7 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create ) BOOST_CHECK(nathan_id(db1).name == "nathan"); - now = fc::time_point_sec( GRAPHENE_GENESIS_TIMESTAMP ); + now = fc::time_point_sec( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); now += db2.block_interval(); b = db2.generate_block(now, db2.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); db1.push_block(b); @@ -364,7 +367,7 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create ) b = db2.generate_block(now, db2.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); db1.push_block(b); - BOOST_CHECK_THROW(nathan_id(db1), fc::exception); + GRAPHENE_CHECK_THROW(nathan_id(db1), fc::exception); PUSH_TX( db2, trx ); @@ -384,13 +387,13 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create ) BOOST_AUTO_TEST_CASE( duplicate_transactions ) { try { - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); fc::temp_directory dir1, dir2; database db1, db2; - db1.open(dir1.path(), make_genesis()); - db2.open(dir2.path(), make_genesis()); + db1.open(dir1.path(), make_genesis); + db2.open(dir2.path(), make_genesis); auto skip_sigs = database::skip_transaction_signatures | database::skip_authority_check; @@ -414,14 +417,14 @@ BOOST_AUTO_TEST_CASE( duplicate_transactions ) trx.sign( delegate_priv_key ); PUSH_TX( db1, trx, skip_sigs ); - BOOST_CHECK_THROW(PUSH_TX( db1, trx, skip_sigs ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db1, trx, skip_sigs ), fc::exception); now += db1.block_interval(); auto b = db1.generate_block( now, db1.get_scheduled_witness( 1 ).first, delegate_priv_key, skip_sigs ); PUSH_BLOCK( db2, b, skip_sigs ); - BOOST_CHECK_THROW(PUSH_TX( db1, trx, skip_sigs ), fc::exception); - BOOST_CHECK_THROW(PUSH_TX( db2, trx, skip_sigs ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db1, trx, skip_sigs ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db2, trx, skip_sigs ), fc::exception); BOOST_CHECK_EQUAL(db1.get_balance(nathan_id, asset_id_type()).amount.value, 500); BOOST_CHECK_EQUAL(db2.get_balance(nathan_id, asset_id_type()).amount.value, 500); } catch (fc::exception& e) { @@ -433,13 +436,13 @@ BOOST_AUTO_TEST_CASE( duplicate_transactions ) BOOST_AUTO_TEST_CASE( tapos ) { try { - fc::time_point_sec now( GRAPHENE_GENESIS_TIMESTAMP ); + fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); fc::temp_directory dir1, dir2; database db1, db2; - db1.open(dir1.path(), make_genesis()); - db2.open(dir2.path(), make_genesis()); + db1.open(dir1.path(), make_genesis); + db2.open(dir2.path(), make_genesis); const account_object& init1 = *db1.get_index_type().indices().get().find("init1"); @@ -448,7 +451,7 @@ BOOST_AUTO_TEST_CASE( tapos ) const graphene::db::index& account_idx = db1.get_index(protocol_ids, account_object_type); now += db1.block_interval(); - auto b = db1.generate_block( now, db1.get_scheduled_witness( 1 ).first, delegate_priv_key, database::skip_nothing ); + auto b = db1.generate_block(now, db1.get_scheduled_witness( 1 ).first, delegate_priv_key, database::skip_nothing); signed_transaction trx; //This transaction must be in the next block after its reference, or it is invalid. @@ -464,16 +467,12 @@ BOOST_AUTO_TEST_CASE( tapos ) db1.push_transaction(trx); now += db1.block_interval(); b = db1.generate_block(now, db1.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); - /* - now += db1.block_interval(); - b = db1.generate_block(now, db1.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); - */ trx.clear(); trx.operations.push_back(transfer_operation({asset(), account_id_type(), nathan_id, asset(50)})); trx.sign(delegate_priv_key); //relative_expiration is 1, but ref block is 2 blocks old, so this should fail. - BOOST_REQUIRE_THROW(PUSH_TX( db1, trx, database::skip_transaction_signatures | database::skip_authority_check ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db1, trx, database::skip_transaction_signatures | database::skip_authority_check ), fc::exception); trx.set_expiration(db1.head_block_id(), 2); trx.signatures.clear(); trx.sign(delegate_priv_key); @@ -598,17 +597,17 @@ BOOST_FIXTURE_TEST_CASE( double_sign_check, database_fixture ) trx.validate(); BOOST_TEST_MESSAGE( "Verify that not-signing causes an exception" ); - BOOST_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); + GRAPHENE_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); BOOST_TEST_MESSAGE( "Verify that double-signing causes an exception" ); trx.sign(bob_private_key); trx.sign(bob_private_key); - BOOST_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); + GRAPHENE_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); BOOST_TEST_MESSAGE( "Verify that signing with an extra, unused key fails" ); trx.signatures.pop_back(); trx.sign(generate_private_key("bogus")); - BOOST_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); + GRAPHENE_REQUIRE_THROW( db.push_transaction(trx, 0), fc::exception ); BOOST_TEST_MESSAGE( "Verify that signing once with the proper key passes" ); trx.signatures.pop_back(); @@ -622,7 +621,7 @@ BOOST_FIXTURE_TEST_CASE( change_block_interval, database_fixture ) generate_block(); db.modify(db.get_global_properties(), [](global_property_object& p) { - p.parameters.genesis_proposal_review_period = fc::hours(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::hours(1).to_seconds(); }); { @@ -773,7 +772,7 @@ BOOST_FIXTURE_TEST_CASE( unimp_force_settlement, database_fixture ) trx.operations.push_back(sop); trx.sign(key_id_type(),private_key); //Trx has expired by now. Make sure it throws. - BOOST_CHECK_THROW(settle_id = PUSH_TX( db, trx ).operation_results.front().get(), fc::exception); + GRAPHENE_CHECK_THROW(settle_id = PUSH_TX( db, trx ).operation_results.front().get(), fc::exception); trx.set_expiration(db.head_block_time() + fc::minutes(1)); trx.sign(key_id_type(),private_key); settle_id = PUSH_TX( db, trx ).operation_results.front().get(); @@ -823,13 +822,13 @@ BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture ) // Sam is the creator of accounts private_key_type genesis_key = delegate_priv_key; private_key_type sam_key = generate_private_key("sam"); - account_object sam_account_object = create_account( "sam", sam_key ); + account_object sam_account_object = create_account("sam", sam_key); //Get a sane head block time generate_block( skip_flags ); db.modify(db.get_global_properties(), [](global_property_object& p) { - p.parameters.genesis_proposal_review_period = fc::hours(1).to_seconds(); + p.parameters.committee_proposal_review_period = fc::hours(1).to_seconds(); }); transaction tx; @@ -839,18 +838,16 @@ BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture ) // transfer from genesis account to Sam account transfer(genesis_account_object, sam_account_object, core.amount(100000)); - generate_block( skip_flags ); + generate_block(skip_flags); - create_account( "alice" ); - generate_block( skip_flags ); - create_account( "bob" ); - generate_block( skip_flags ); + create_account("alice"); + generate_block(skip_flags); + create_account("bob"); + generate_block(skip_flags); db.pop_block(); db.pop_block(); - } - catch( const fc::exception& e ) - { + } catch(const fc::exception& e) { edump( (e.to_detail_string()) ); throw; } @@ -882,73 +879,4 @@ BOOST_FIXTURE_TEST_CASE( witness_scheduler_missed_blocks, database_fixture ) }); } FC_LOG_AND_RETHROW() } -BOOST_FIXTURE_TEST_CASE( account_create_fee_scaling, database_fixture ) -{ try { - auto accounts_per_scale = db.get_global_properties().parameters.accounts_per_fee_scale; - enable_fees(1); - - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 1); - for( int i = db.get_dynamic_global_properties().accounts_registered_this_interval; i < accounts_per_scale; ++i ) - create_account("shill" + fc::to_string(i)); - generate_block(); - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 16); - for( int i = 0; i < accounts_per_scale; ++i ) - create_account("moreshills" + fc::to_string(i)); - generate_block(); - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 256); - for( int i = 0; i < accounts_per_scale; ++i ) - create_account("moarshills" + fc::to_string(i)); - generate_block(); - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 4096); - - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 1); -} FC_LOG_AND_RETHROW() } - -BOOST_FIXTURE_TEST_CASE( tapos_rollover, database_fixture ) -{ - try - { - ACTORS((alice)(bob)); - const auto& core = asset_id_type()(db); - - BOOST_TEST_MESSAGE( "Give Alice some money" ); - transfer(genesis_account, alice_id, asset(10000)); - generate_block(); - - BOOST_TEST_MESSAGE( "Generate up to block 0xFF00" ); - generate_blocks( 0xFF00 ); - signed_transaction xfer_tx; - - BOOST_TEST_MESSAGE( "Transfer money at/about 0xFF00" ); - transfer_operation xfer_op; - xfer_op.from = alice_id; - xfer_op.to = bob_id; - xfer_op.amount = asset(1000); - - xfer_tx.operations.push_back( xfer_op ); - xfer_tx.set_expiration( db.head_block_id(), 0x1000 ); - sign( xfer_tx, alice_private_key ); - PUSH_TX( db, xfer_tx, 0 ); - generate_block(); - - BOOST_TEST_MESSAGE( "Sign new tx's" ); - xfer_tx.set_expiration( db.head_block_id(), 0x1000 ); - xfer_tx.signatures.clear(); - sign( xfer_tx, alice_private_key ); - - BOOST_TEST_MESSAGE( "Generate up to block 0x10010" ); - generate_blocks( 0x110 ); - - BOOST_TEST_MESSAGE( "Transfer at/about block 0x10010 using reference block at/about 0xFF00" ); - PUSH_TX( db, xfer_tx, 0 ); - generate_block(); - } - catch (fc::exception& e) - { - edump((e.to_detail_string())); - throw; - } -} - BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/fee_tests.cpp b/tests/tests/fee_tests.cpp index b330aaf9..e25a850b 100644 --- a/tests/tests/fee_tests.cpp +++ b/tests/tests/fee_tests.cpp @@ -130,45 +130,4 @@ BOOST_AUTO_TEST_CASE( cashback_test ) BOOST_CHECK_EQUAL(stud_id(db).cashback_balance(db).balance.amount.value, 25750); } FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(bulk_discount) -{ try { - ACTOR(nathan); - // Give nathan ALLLLLL the money! - transfer(GRAPHENE_COMMITTEE_ACCOUNT, nathan_id, db.get_balance(GRAPHENE_COMMITTEE_ACCOUNT, asset_id_type())); - enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); - upgrade_to_lifetime_member(nathan_id); - share_type new_fees; - while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN ) - { - transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); - new_fees += transfer_operation().calculate_fee(db.current_fee_schedule()); - } - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); - auto old_cashback = nathan_id(db).cashback_balance(db).balance; - - transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); - - BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value, - old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 8); - - new_fees = 0; - while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX ) - { - transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); - new_fees += transfer_operation().calculate_fee(db.current_fee_schedule()); - } - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - enable_fees(GRAPHENE_BLOCKCHAIN_PRECISION*10); - old_cashback = nathan_id(db).cashback_balance(db).balance; - - transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1)); - generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - - BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value, - old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 9); -} FC_LOG_AND_RETHROW() } - BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index e61d0f89..04d35ef0 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE( call_order_update_test ) BOOST_REQUIRE_EQUAL( get_balance( dan, core ), 10000000 - 10000 + 5000 ); BOOST_TEST_MESSAGE( "verifying that attempting to cover the full amount without claiming the collateral fails" ); - BOOST_REQUIRE_THROW( cover( dan, bitusd.amount(2500), core.amount(0) ), fc::exception ); + GRAPHENE_REQUIRE_THROW( cover( dan, bitusd.amount(2500), core.amount(0) ), fc::exception ); cover( dan, bitusd.amount(2500), core.amount(5000)); @@ -127,14 +127,14 @@ BOOST_AUTO_TEST_CASE( call_order_update_test ) BOOST_REQUIRE_EQUAL( get_balance( dan, core ), 10000000 - 20000 ); BOOST_TEST_MESSAGE( "increasing debt without increasing collateral again" ); - BOOST_REQUIRE_THROW( borrow( dan, bitusd.amount(80000), asset(0)), fc::exception ); + GRAPHENE_REQUIRE_THROW( borrow( dan, bitusd.amount(80000), asset(0)), fc::exception ); BOOST_TEST_MESSAGE( "attempting to claim all collateral without paying off debt" ); - BOOST_REQUIRE_THROW( cover( dan, bitusd.amount(0), asset(20000)), fc::exception ); + GRAPHENE_REQUIRE_THROW( cover( dan, bitusd.amount(0), asset(20000)), fc::exception ); BOOST_TEST_MESSAGE( "attempting reduce collateral without paying off any debt" ); cover( dan, bitusd.amount(0), asset(1000)); BOOST_TEST_MESSAGE( "attempting change call price to be below minimum for debt/collateral ratio" ); - BOOST_REQUIRE_THROW( cover( dan, bitusd.amount(0), asset(0)), fc::exception ); + GRAPHENE_REQUIRE_THROW( cover( dan, bitusd.amount(0), asset(0)), fc::exception ); } catch (fc::exception& e) { edump((e.to_detail_string())); @@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE( black_swan ) force_settle(borrower, bitusd.amount(100)); BOOST_TEST_MESSAGE( "Verify that we cannot borrow after black swan" ); - BOOST_REQUIRE_THROW( borrow(borrower, bitusd.amount(1000), asset(2000)), fc::exception ); + GRAPHENE_REQUIRE_THROW( borrow(borrower, bitusd.amount(1000), asset(2000)), fc::exception ); } catch( const fc::exception& e) { edump((e.to_detail_string())); throw; @@ -275,22 +275,22 @@ BOOST_AUTO_TEST_CASE( prediction_market ) transfer(genesis_account, nathan_id, asset(init_balance)); BOOST_TEST_MESSAGE( "Require throw for mismatch collateral amounts" ); - BOOST_REQUIRE_THROW( borrow( dan, pmark.amount(1000), asset(2000) ), fc::exception ); + GRAPHENE_REQUIRE_THROW( borrow( dan, pmark.amount(1000), asset(2000) ), fc::exception ); BOOST_TEST_MESSAGE( "Open position with equal collateral" ); borrow( dan, pmark.amount(1000), asset(1000) ); BOOST_TEST_MESSAGE( "Cover position with unequal asset should fail." ); - BOOST_REQUIRE_THROW( cover( dan, pmark.amount(500), asset(1000) ), fc::exception ); + GRAPHENE_REQUIRE_THROW( cover( dan, pmark.amount(500), asset(1000) ), fc::exception ); BOOST_TEST_MESSAGE( "Cover half of position with equal ammounts" ); cover( dan, pmark.amount(500), asset(500) ); BOOST_TEST_MESSAGE( "Verify that forced settlment fails before global settlement" ); - BOOST_REQUIRE_THROW( force_settle( dan, pmark.amount(100) ), fc::exception ); + GRAPHENE_REQUIRE_THROW( force_settle( dan, pmark.amount(100) ), fc::exception ); BOOST_TEST_MESSAGE( "Shouldn't be allowed to force settle at more than 1 collateral per debt" ); - BOOST_REQUIRE_THROW( force_global_settle( pmark, pmark.amount(100) / core.amount(105) ), fc::exception ); + GRAPHENE_REQUIRE_THROW( force_global_settle( pmark, pmark.amount(100) / core.amount(105) ), fc::exception ); force_global_settle( pmark, pmark.amount(100) / core.amount(95) ); @@ -328,7 +328,7 @@ BOOST_AUTO_TEST_CASE( create_account_test ) op.owner.add_authority(account_id_type(9999999999), 10); trx.operations.back() = op; op.owner = auth_bak; - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); op.owner = auth_bak; trx.operations.back() = op; @@ -487,7 +487,7 @@ BOOST_AUTO_TEST_CASE( create_mia ) BOOST_CHECK(bitusd.symbol == "BITUSD"); BOOST_CHECK(bitusd.bitasset_data(db).options.short_backing_asset == asset_id_type()); BOOST_CHECK(bitusd.dynamic_asset_data_id(db).current_supply == 0); - BOOST_REQUIRE_THROW( create_bitasset("BITUSD"), fc::exception); + GRAPHENE_REQUIRE_THROW( create_bitasset("BITUSD"), fc::exception); } catch ( const fc::exception& e ) { elog( "${e}", ("e", e.to_detail_string() ) ); throw; @@ -574,7 +574,7 @@ BOOST_AUTO_TEST_CASE( create_uia ) BOOST_CHECK(test_asset.options.max_supply == 100000000); BOOST_CHECK(!test_asset.bitasset_data_id.valid()); BOOST_CHECK(test_asset.options.market_fee_percent == GRAPHENE_MAX_MARKET_FEE_PERCENT/100); - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); const asset_dynamic_data_object& test_asset_dynamic_data = test_asset.dynamic_asset_data_id(db); BOOST_CHECK(test_asset_dynamic_data.current_supply == 0); @@ -649,7 +649,7 @@ BOOST_AUTO_TEST_CASE( update_uia ) trx.operations.back() = op; PUSH_TX( db, trx, ~0 ); op.issuer = account_id_type(); - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); op.new_issuer.reset(); } catch(fc::exception& e) { edump((e.to_detail_string())); @@ -1078,7 +1078,7 @@ BOOST_AUTO_TEST_CASE( limit_order_fill_or_kill ) trx.operations.clear(); trx.operations.push_back(op); - BOOST_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); op.fill_or_kill = false; trx.operations.back() = op; PUSH_TX( db, trx, ~0 ); @@ -1088,7 +1088,7 @@ BOOST_AUTO_TEST_CASE( limit_order_fill_or_kill ) BOOST_AUTO_TEST_CASE( fill_order ) { try { fill_order_operation o; - BOOST_CHECK_THROW(o.validate(), fc::exception); + GRAPHENE_CHECK_THROW(o.validate(), fc::exception); o.calculate_fee(db.current_fee_schedule()); } FC_LOG_AND_RETHROW() } diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index f1cf9dab..9d25826f 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -42,8 +42,6 @@ BOOST_FIXTURE_TEST_SUITE( operation_tests, database_fixture ) BOOST_AUTO_TEST_CASE( withdraw_permission_create ) { try { - //ACTORS((nathan)(dan)) - //idump((nathan)(dan)); auto nathan_private_key = generate_private_key("nathan"); auto dan_private_key = generate_private_key("dan"); account_id_type nathan_id = create_account("nathan", nathan_private_key.get_public_key()).id; @@ -110,7 +108,7 @@ BOOST_AUTO_TEST_CASE( withdraw_permission_test ) op.amount_to_withdraw = asset(1); trx.operations.push_back(op); //Throws because we haven't entered the first withdrawal period yet. - BOOST_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx ), fc::exception); //Get to the actual withdrawal period generate_blocks(permit(db).period_start_time); @@ -167,7 +165,7 @@ BOOST_AUTO_TEST_CASE( withdraw_permission_test ) trx.operations.push_back(op); trx.sign(dan_private_key); //Throws because nathan doesn't have the money - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); op.amount_to_withdraw = asset(1); trx.clear(); trx.operations = {op}; @@ -202,7 +200,7 @@ BOOST_AUTO_TEST_CASE( withdraw_permission_test ) trx.operations.push_back(op); trx.sign(dan_private_key); //Throws because the permission has expired - BOOST_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx ), fc::exception); } } FC_LOG_AND_RETHROW() } @@ -370,7 +368,7 @@ BOOST_AUTO_TEST_CASE( mia_feeds ) op.publisher = nathan_id; trx.operations.back() = op; - BOOST_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); } } FC_LOG_AND_RETHROW() } @@ -895,7 +893,7 @@ BOOST_AUTO_TEST_CASE( unimp_force_settlement_unavailable ) sop.amount = asset(50, bit_usd); trx.operations = {sop}; //Force settlement is disabled; check that it fails - BOOST_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_CHECK_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); { //Enable force settlement asset_update_operation op; @@ -969,7 +967,7 @@ BOOST_AUTO_TEST_CASE( assert_op_test ) op.predicates.back() = fc::raw::pack(predicate(pred::account_name_eq_lit{ nathan_id, "dan" })); trx.operations.back() = op; trx.sign(nathan_private_key); - BOOST_CHECK_THROW( PUSH_TX( db, trx ), fc::exception ); + GRAPHENE_CHECK_THROW( PUSH_TX( db, trx ), fc::exception ); } FC_LOG_AND_RETHROW() } @@ -1003,7 +1001,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) genesis_state.initial_accounts.emplace_back("n", n_key.get_public_key()); - db.open(td.path(), genesis_state); + db.open(td.path(), [this]{return genesis_state;}); const balance_object& balance = balance_id_type()(db); BOOST_CHECK_EQUAL(balance.balance.amount.value, 1); BOOST_CHECK_EQUAL(balance_id_type(1)(db).balance.amount.value, 1); @@ -1016,7 +1014,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.operations = {op}; trx.sign(n_key); // Fail because I'm claiming from an address which hasn't signed - BOOST_CHECK_THROW(db.push_transaction(trx), fc::exception); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), fc::exception); trx.clear(); op.balance_to_claim = balance_id_type(); op.balance_owner_key = n_key.get_public_key(); @@ -1031,6 +1029,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) auto slot = db.get_slot_at_time(starting_time); db.generate_block(starting_time, db.get_scheduled_witness(slot).first, delegate_priv_key, database::skip_nothing); + trx.set_expiration(db.head_block_id()); const balance_object& vesting_balance_1 = balance_id_type(2)(db); const balance_object& vesting_balance_2 = balance_id_type(3)(db); @@ -1045,12 +1044,11 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) op.total_claimed = asset(1); op.balance_owner_key = v1_key.get_public_key(); trx.clear(); - trx.set_expiration(db.head_block_id()); trx.operations = {op}; trx.sign(n_key); trx.sign(v1_key); // Attempting to claim 1 from a balance with 0 available - BOOST_CHECK_THROW(db.push_transaction(trx), invalid_claim_amount); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claim_invalid_claim_amount); op.balance_to_claim = vesting_balance_2.id; op.total_claimed.amount = 151; @@ -1060,7 +1058,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.sign(n_key); trx.sign(v2_key); // Attempting to claim 151 from a balance with 150 available - BOOST_CHECK_THROW(db.push_transaction(trx), invalid_claim_amount); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claim_invalid_claim_amount); op.balance_to_claim = vesting_balance_2.id; op.total_claimed.amount = 100; @@ -1070,33 +1068,58 @@ BOOST_AUTO_TEST_CASE( balance_object_test ) trx.sign(n_key); trx.sign(v2_key); db.push_transaction(trx); - BOOST_CHECK_EQUAL(db.get_balance(op.deposit_to_account, asset_id_type()).amount.value, 101); + BOOST_CHECK_EQUAL(vesting_balance_2.balance.amount.value, 300); + op.total_claimed.amount = 10; trx.operations = {op}; trx.signatures.clear(); trx.sign(n_key); trx.sign(v2_key); // Attempting to claim twice within a day - BOOST_CHECK_THROW(db.push_transaction(trx), balance_claimed_too_often); + GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claim_claimed_too_often); -// TODO: test withdrawing entire vesting_balance_1 balance, remainder of vesting_balance_2 balance -// slot = db.get_slot_at_time(vesting_balance_1.vesting_policy->begin_timestamp + 60); -// db.generate_block(starting_time, db.get_scheduled_witness(slot).first, delegate_priv_key, database::skip_nothing); + db.generate_block(db.get_slot_time(1), db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); + slot = db.get_slot_at_time(vesting_balance_1.vesting_policy->begin_timestamp + 60); + db.generate_block(db.get_slot_time(slot), db.get_scheduled_witness(slot).first, delegate_priv_key, database::skip_nothing); + trx.set_expiration(db.head_block_id()); -// op.balance_to_claim = vesting_balance_1.id; -// op.total_claimed.amount = 500; -// op.balance_owner_key = v1_key.get_public_key(); -// trx.operations = {op}; -// trx.signatures.clear(); -// trx.sign(n_key); -// trx.sign(v2_key); -// db.push_transaction(trx); -// BOOST_CHECK(db.find_object(op.balance_to_claim) == nullptr); + op.balance_to_claim = vesting_balance_1.id; + op.total_claimed.amount = 500; + op.balance_owner_key = v1_key.get_public_key(); + trx.operations = {op}; + trx.signatures.clear(); + trx.sign(n_key); + trx.sign(v1_key); + db.push_transaction(trx); + BOOST_CHECK(db.find_object(op.balance_to_claim) == nullptr); + BOOST_CHECK_EQUAL(db.get_balance(op.deposit_to_account, asset_id_type()).amount.value, 601); + + op.balance_to_claim = vesting_balance_2.id; + op.balance_owner_key = v2_key.get_public_key(); + op.total_claimed.amount = 10; + trx.operations = {op}; + trx.signatures.clear(); + trx.sign(n_key); + trx.sign(v2_key); + // Attempting to claim twice within a day + GRAPHENE_CHECK_THROW(db.push_transaction(trx), balance_claim_claimed_too_often); + + db.generate_block(db.get_slot_time(1), db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing); + slot = db.get_slot_at_time(db.head_block_time() + fc::days(1)); + db.generate_block(db.get_slot_time(slot), db.get_scheduled_witness(slot).first, delegate_priv_key, database::skip_nothing); + trx.set_expiration(db.head_block_id()); + + op.total_claimed = vesting_balance_2.balance; + trx.operations = {op}; + trx.signatures.clear(); + trx.sign(n_key); + trx.sign(v2_key); + db.push_transaction(trx); + BOOST_CHECK(db.find_object(op.balance_to_claim) == nullptr); + BOOST_CHECK_EQUAL(db.get_balance(op.deposit_to_account, asset_id_type()).amount.value, 901); } FC_LOG_AND_RETHROW() } // TODO: Write linear VBO tests BOOST_AUTO_TEST_SUITE_END() - - diff --git a/tests/tests/uia_tests.cpp b/tests/tests/uia_tests.cpp index 72d4df30..7dfb9c6e 100644 --- a/tests/tests/uia_tests.cpp +++ b/tests/tests/uia_tests.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -84,10 +85,10 @@ BOOST_AUTO_TEST_CASE( override_transfer_test ) trx.operations.push_back(otrans); BOOST_TEST_MESSAGE( "Require throwing without signature" ); - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), tx_missing_active_auth ); BOOST_TEST_MESSAGE( "Require throwing with dan's signature" ); trx.sign( dan_private_key ); - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), tx_missing_active_auth ); BOOST_TEST_MESSAGE( "Pass with issuer's signature" ); trx.signatures.clear(); trx.sign( sam_private_key ); @@ -112,14 +113,14 @@ BOOST_AUTO_TEST_CASE( override_transfer_test2 ) trx.operations.push_back(otrans); BOOST_TEST_MESSAGE( "Require throwing without signature" ); - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); BOOST_TEST_MESSAGE( "Require throwing with dan's signature" ); trx.sign( dan_private_key ); - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception); BOOST_TEST_MESSAGE( "Fail because overide_authority flag is not set" ); trx.signatures.clear(); trx.sign( sam_private_key ); - BOOST_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception ); + GRAPHENE_REQUIRE_THROW( PUSH_TX( db, trx, 0 ), fc::exception ); BOOST_REQUIRE_EQUAL( get_balance( dan, advanced ), 1000 ); BOOST_REQUIRE_EQUAL( get_balance( eric, advanced ), 0 ); @@ -137,7 +138,7 @@ BOOST_AUTO_TEST_CASE( issue_whitelist_uia ) asset_issue_operation op({asset(), advanced.issuer, advanced.amount(1000), nathan.id}); trx.operations.emplace_back(op); //Fail because nathan is not whitelisted. - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); account_whitelist_operation wop({asset(), account_id_type(), nathan.id, account_whitelist_operation::white_listed}); @@ -168,7 +169,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) transfer_operation op({advanced.amount(0), nathan.id, dan.id, advanced.amount(100)}); trx.operations.push_back(op); //Fail because dan is not whitelisted. - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), transfer_to_account_not_whitelisted ); account_whitelist_operation wop({asset(), account_id_type(), dan.id, account_whitelist_operation::white_listed}); trx.operations.back() = wop; @@ -187,14 +188,14 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) op.amount = advanced.amount(50); trx.operations.back() = op; //Fail because nathan is blacklisted - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), transfer_from_account_not_whitelisted ); trx.operations = {asset_reserve_operation{asset(), nathan.id, advanced.amount(10)}}; //Fail because nathan is blacklisted - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); std::swap(op.from, op.to); trx.operations.back() = op; //Fail because nathan is blacklisted - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); { asset_update_operation op; @@ -221,7 +222,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) trx.operations.back() = op; //Fail because nathan is blacklisted BOOST_CHECK(!nathan.is_authorized_asset(advanced)); - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); //Remove nathan from genesis' whitelist, add him to dan's. This should not authorize him to hold ADVANCED. wop.authorizing_account = account_id_type(); @@ -238,7 +239,7 @@ BOOST_AUTO_TEST_CASE( transfer_whitelist_uia ) trx.operations.back() = op; //Fail because nathan is not whitelisted BOOST_CHECK(!nathan.is_authorized_asset(advanced)); - BOOST_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); + GRAPHENE_REQUIRE_THROW(PUSH_TX( db, trx, ~0 ), fc::exception); trx.operations = {asset_reserve_operation{asset(), dan.id, advanced.amount(10)}}; PUSH_TX(db, trx, ~0);