diff --git a/libraries/chain/chain_controller.cpp b/libraries/chain/chain_controller.cpp index ad0091d5922d16b4d940cf87d173b4a89ad9c5ba..79899fa18031d935a82ea0708c8d073b17b0cd88 100644 --- a/libraries/chain/chain_controller.cpp +++ b/libraries/chain/chain_controller.cpp @@ -639,11 +639,20 @@ void chain_controller::apply_message( apply_context& context ) } FC_CAPTURE_AND_RETHROW((context.msg)) } - void chain_controller::_apply_transaction(const SignedTransaction& trx) { try { validate_transaction(trx); + auto getAuthority = [&db=_db](const types::AccountPermission& permission) { + auto key = boost::make_tuple(permission.account, permission.permission); + return db.get(key).auth; + }; +#warning TODO: Use a real chain_id here (where is this stored? Do we still need it?) + auto checker = MakeAuthorityChecker(std::move(getAuthority), trx.get_signature_keys(chain_id_type{})); + + for (const auto& requiredAuthority : trx.authorizations) + EOS_ASSERT(checker.satisfied(requiredAuthority), tx_missing_auth, "Transaction is not authorized."); + for (const auto& message : trx.messages) { process_message(message); } diff --git a/libraries/chain/include/eos/chain/account_object.hpp b/libraries/chain/include/eos/chain/account_object.hpp index 13b5aebcce41cbcd24745ee9a739cc524b8135ff..80877fa92ff12b2206985496a15422f33b4a3d04 100644 --- a/libraries/chain/include/eos/chain/account_object.hpp +++ b/libraries/chain/include/eos/chain/account_object.hpp @@ -29,33 +29,6 @@ namespace eos { namespace chain { - struct shared_authority { - shared_authority( chainbase::allocator alloc ) - :accounts(alloc),keys(alloc) - {} - - shared_authority& operator=(const Authority& a) { - threshold = a.threshold; - accounts = decltype(accounts)(a.accounts.begin(), a.accounts.end(), accounts.get_allocator()); - keys = decltype(keys)(a.keys.begin(), a.keys.end(), keys.get_allocator()); - return *this; - } - shared_authority& operator=(Authority&& a) { - threshold = a.threshold; - accounts.reserve(a.accounts.size()); - for (auto& p : a.accounts) - accounts.emplace_back(std::move(p)); - keys.reserve(a.keys.size()); - for (auto& p : a.keys) - keys.emplace_back(std::move(p)); - return *this; - } - - UInt32 threshold = 0; - shared_vector accounts; - shared_vector keys; - }; - class account_object : public chainbase::object { OBJECT_CTOR(account_object,(code)) @@ -78,52 +51,10 @@ namespace eos { namespace chain { > >; - class permission_object : public chainbase::object { - OBJECT_CTOR(permission_object, (auth) ) - - id_type id; - AccountName owner; ///< the account this permission belongs to - id_type parent; ///< parent permission - PermissionName name; ///< human-readable name for the permission - shared_authority auth; ///< authority required to execute this permission - }; - - struct by_parent; - struct by_owner; - using permission_index = chainbase::shared_multi_index_container< - permission_object, - indexed_by< - ordered_unique, member>, - ordered_unique, - composite_key, - member - > - >, - ordered_unique, - composite_key, - member, - member - > - >, - ordered_unique, - composite_key, - member - > - > - > - >; - } } // eos::chain CHAINBASE_SET_INDEX_TYPE(eos::chain::account_object, eos::chain::account_index) -CHAINBASE_SET_INDEX_TYPE(eos::chain::permission_object, eos::chain::permission_index) -FC_REFLECT(chainbase::oid, (_id)) FC_REFLECT(chainbase::oid, (_id)) -FC_REFLECT(eos::chain::shared_authority, (threshold)(accounts)(keys)) FC_REFLECT(eos::chain::account_object, (id)(name)(vm_type)(vm_version)(code_version)(code)(creation_date)) -FC_REFLECT(eos::chain::permission_object, (id)(owner)(parent)(name)(auth)) diff --git a/libraries/chain/include/eos/chain/action_objects.hpp b/libraries/chain/include/eos/chain/action_objects.hpp index 9c1abdbbecd73cbc7f492bda4d200cf6d8e0ef97..d32bd09178af0160e1cf47653e7e08320b174b5e 100644 --- a/libraries/chain/include/eos/chain/action_objects.hpp +++ b/libraries/chain/include/eos/chain/action_objects.hpp @@ -23,7 +23,7 @@ */ #pragma once #include -#include +#include #include "multi_index_includes.hpp" @@ -57,7 +57,7 @@ namespace eos { namespace chain { OBJECT_CTOR(action_permission_object) id_type id; - account_id_type owner; ///< the account whose permission we seek + AccountName owner; ///< the account whose permission we seek permission_object::id_type scope_permission; ///< the scope permission defined by the contract for the action permission_object::id_type owner_permission; ///< the owner permission that is required }; @@ -69,7 +69,7 @@ namespace eos { namespace chain { ordered_unique, member>, ordered_unique, composite_key< action_permission_object, - member, + member, member > > diff --git a/libraries/chain/include/eos/chain/authority.hpp b/libraries/chain/include/eos/chain/authority.hpp index 06f5f90ec507fb9455376bf107ea4ec555498baa..6cbc7fe649cf2e0214c4227c0980d5b3c9955a91 100644 --- a/libraries/chain/include/eos/chain/authority.hpp +++ b/libraries/chain/include/eos/chain/authority.hpp @@ -2,26 +2,101 @@ #include #include -namespace eos { - inline bool operator < ( const types::AccountPermission& a, const types::AccountPermission& b ) { - return std::tie( a.account, a.permission ) < std::tie( b.account, b.permission ); +namespace eos { namespace chain { +struct shared_authority { + shared_authority( chainbase::allocator alloc ) + :accounts(alloc),keys(alloc) + {} + + shared_authority& operator=(const Authority& a) { + threshold = a.threshold; + accounts = decltype(accounts)(a.accounts.begin(), a.accounts.end(), accounts.get_allocator()); + keys = decltype(keys)(a.keys.begin(), a.keys.end(), keys.get_allocator()); + return *this; + } + shared_authority& operator=(Authority&& a) { + threshold = a.threshold; + accounts.reserve(a.accounts.size()); + for (auto& p : a.accounts) + accounts.emplace_back(std::move(p)); + keys.reserve(a.keys.size()); + for (auto& p : a.keys) + keys.emplace_back(std::move(p)); + return *this; } - /** - * Makes sure all keys are unique and sorted and all account permissions are unique and sorted - */ - inline bool validate( types::Authority& auth ) { - const types::KeyPermissionWeight* prev = nullptr; - for( const auto& k : auth.keys ) { - if( !prev ) prev = &k; - else if( prev->key < k.key ) return false; - } - const types::AccountPermissionWeight* pa = nullptr; - for( const auto& a : auth.accounts ) { - if( !pa ) pa = &a; - else if( pa->permission < a.permission ) return false; - } - return true; + UInt32 threshold = 0; + shared_vector accounts; + shared_vector keys; +}; + +/** + * @brief This class determines whether a set of signing keys are sufficient to satisfy an authority or not + * + * To determine whether an authority is satisfied or not, we first determine which keys have approved of a message, and + * then determine whether that list of keys is sufficient to satisfy the authority. This class takes a list of keys and + * provides the @ref satisfied method to determine whether that list of keys satisfies a provided authority. + * + * @tparam F A callable which takes a single argument of type @ref AccountPermission and returns the corresponding + * authority + */ +template +class AuthorityChecker { + F PermissionToAuthority; + const flat_set& signingKeys; + +public: + AuthorityChecker(F PermissionToAuthority, const flat_set& signingKeys) + : PermissionToAuthority(PermissionToAuthority), signingKeys(signingKeys) {} + + bool satisfied(const types::AccountPermission& permission) const { + return satisfied(PermissionToAuthority(permission)); + } + template + bool satisfied(const AuthorityType& authority) const { + UInt32 weight = 0; + for (const auto& kpw : authority.keys) + if (signingKeys.count(kpw.key)) { + weight += kpw.weight; + if (weight >= authority.threshold) + return true; + } + for (const auto& apw : authority.accounts) +#warning TODO: Recursion limit? + if (satisfied(apw.permission)) { + weight += apw.weight; + if (weight >= authority.threshold) + return true; + } + return false; } +}; + +inline bool operator < ( const types::AccountPermission& a, const types::AccountPermission& b ) { + return std::tie( a.account, a.permission ) < std::tie( b.account, b.permission ); } +template +AuthorityChecker MakeAuthorityChecker(F&& pta, const flat_set& signingKeys) { + return AuthorityChecker(std::forward(pta), signingKeys); +} + +/** + * Makes sure all keys are unique and sorted and all account permissions are unique and sorted + */ +inline bool validate( types::Authority& auth ) { + const types::KeyPermissionWeight* prev = nullptr; + for( const auto& k : auth.keys ) { + if( !prev ) prev = &k; + else if( prev->key < k.key ) return false; + } + const types::AccountPermissionWeight* pa = nullptr; + for( const auto& a : auth.accounts ) { + if( !pa ) pa = &a; + else if( pa->permission < a.permission ) return false; + } + return true; +} + +} } // namespace eos::chain +FC_REFLECT(eos::chain::shared_authority, (threshold)(accounts)(keys)) diff --git a/libraries/chain/include/eos/chain/exceptions.hpp b/libraries/chain/include/eos/chain/exceptions.hpp index 70f4770499e1f0f27829e0a7f8e6d131ce1e8424..22e341d1308427537d565eac2e90a75d53f57490 100644 --- a/libraries/chain/include/eos/chain/exceptions.hpp +++ b/libraries/chain/include/eos/chain/exceptions.hpp @@ -42,9 +42,7 @@ namespace eos { namespace chain { FC_DECLARE_DERIVED_EXCEPTION( black_swan_exception, eos::chain::chain_exception, 3100000, "black swan" ) FC_DECLARE_DERIVED_EXCEPTION( unknown_block_exception, eos::chain::chain_exception, 3110000, "unknown block" ) - FC_DECLARE_DERIVED_EXCEPTION( tx_missing_active_auth, eos::chain::transaction_exception, 3030001, "missing required active authority" ) - FC_DECLARE_DERIVED_EXCEPTION( tx_missing_owner_auth, eos::chain::transaction_exception, 3030002, "missing required owner authority" ) - FC_DECLARE_DERIVED_EXCEPTION( tx_missing_other_auth, eos::chain::transaction_exception, 3030003, "missing required other authority" ) + FC_DECLARE_DERIVED_EXCEPTION( tx_missing_auth, eos::chain::transaction_exception, 3030001, "missing required authority" ) FC_DECLARE_DERIVED_EXCEPTION( tx_irrelevant_sig, eos::chain::transaction_exception, 3030004, "irrelevant signature included" ) FC_DECLARE_DERIVED_EXCEPTION( tx_duplicate_sig, eos::chain::transaction_exception, 3030005, "duplicate signature included" ) FC_DECLARE_DERIVED_EXCEPTION( invalid_committee_approval, eos::chain::transaction_exception, 3030006, "committee account cannot directly approve transaction" ) diff --git a/libraries/chain/include/eos/chain/permission_object.hpp b/libraries/chain/include/eos/chain/permission_object.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fda72bbc0a170e0b50dc51655ec6955357dc9143 --- /dev/null +++ b/libraries/chain/include/eos/chain/permission_object.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017, Respective Authors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once +#include + +#include "multi_index_includes.hpp" + +namespace eos { namespace chain { + class permission_object : public chainbase::object { + OBJECT_CTOR(permission_object, (auth) ) + + id_type id; + AccountName owner; ///< the account this permission belongs to + id_type parent; ///< parent permission + PermissionName name; ///< human-readable name for the permission + shared_authority auth; ///< authority required to execute this permission + }; + + struct by_parent; + struct by_owner; + struct by_name; + using permission_index = chainbase::shared_multi_index_container< + permission_object, + indexed_by< + ordered_unique, member>, + ordered_unique, + composite_key, + member + > + >, + ordered_unique, + composite_key, + member + > + >, + ordered_unique, + composite_key, + member + > + > + > + >; + +} } // eos::chain + +CHAINBASE_SET_INDEX_TYPE(eos::chain::permission_object, eos::chain::permission_index) + +FC_REFLECT(chainbase::oid, (_id)) +FC_REFLECT(eos::chain::permission_object, (id)(owner)(parent)(name)(auth)) diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index 001d901aa2a5a3b942bb7c484c99af4623b77028..94b202229a46f7a2706a26469aaaa2f00cb74969 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -27,6 +27,8 @@ #include #include +#include + namespace eos { namespace chain { digest_type SignedTransaction::digest()const { @@ -50,16 +52,12 @@ eos::chain::transaction_id_type SignedTransaction::id() const { } const signature_type& eos::chain::SignedTransaction::sign(const private_key_type& key, const chain_id_type& chain_id) { - digest_type h = sig_digest( chain_id ); - signatures.push_back(key.sign_compact(h)); + signatures.push_back(key.sign_compact(sig_digest(chain_id))); return signatures.back(); } signature_type eos::chain::SignedTransaction::sign(const private_key_type& key, const chain_id_type& chain_id)const { - digest_type::encoder enc; - fc::raw::pack( enc, chain_id ); - fc::raw::pack( enc, static_cast(*this) ); - return key.sign_compact(enc.result()); + return key.sign_compact(sig_digest(chain_id)); } void SignedTransaction::set_reference_block(const block_id_type& reference_block) { @@ -74,17 +72,13 @@ bool SignedTransaction::verify_reference_block(const block_id_type& reference_bl flat_set SignedTransaction::get_signature_keys( const chain_id_type& chain_id )const { try { - auto d = sig_digest( chain_id ); - flat_set result; - for( const auto& sig : signatures ) - { - EOS_ASSERT( - result.insert( fc::ecc::public_key(sig,d) ).second, - tx_duplicate_sig, - "Duplicate Signature detected" ); - } - return result; -} FC_CAPTURE_AND_RETHROW() } + using boost::adaptors::transformed; + auto SigToKey = transformed([digest = sig_digest(chain_id)](const fc::ecc::compact_signature& signature) { + return public_key_type(fc::ecc::public_key(signature, digest)); + }); + auto keyRange = signatures | SigToKey; + return {keyRange.begin(), keyRange.end()}; + } FC_CAPTURE_AND_RETHROW() } eos::chain::digest_type SignedTransaction::merkle_digest() const { digest_type::encoder enc; diff --git a/libraries/native_contract/system_contract.cpp b/libraries/native_contract/system_contract.cpp index 01c731f3f4d9148825e70f4f9e0b6a8c041256e8..3e1d2b3e675b3b8f262c7edfcd41dae9629a562d 100644 --- a/libraries/native_contract/system_contract.cpp +++ b/libraries/native_contract/system_contract.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -50,9 +51,9 @@ void validate_system_newaccount(message_validate_context& context) { EOS_ASSERT(context.msg.has_notify(config::StakedBalanceContractName), message_validate_exception, "Must notify Staked Balance Contract (${name})", ("name", config::StakedBalanceContractName)); - EOS_ASSERT( eos::validate(create.owner), message_validate_exception, "Invalid owner authority"); - EOS_ASSERT( eos::validate(create.active), message_validate_exception, "Invalid active authority"); - EOS_ASSERT( eos::validate(create.recovery), message_validate_exception, "Invalid recovery authority"); + EOS_ASSERT( validate(create.owner), message_validate_exception, "Invalid owner authority"); + EOS_ASSERT( validate(create.active), message_validate_exception, "Invalid active authority"); + EOS_ASSERT( validate(create.recovery), message_validate_exception, "Invalid recovery authority"); } void precondition_system_newaccount(precondition_validate_context& context) { diff --git a/plugins/net_plugin/include/eos/net_plugin/net_plugin.hpp b/plugins/net_plugin/include/eos/net_plugin/net_plugin.hpp index 464e725c8d3b74ea1e33cdb0c1eb8629d6df8aa5..fc09d9a60ff8abb5657a2d47bbed0df461f527cb 100644 --- a/plugins/net_plugin/include/eos/net_plugin/net_plugin.hpp +++ b/plugins/net_plugin/include/eos/net_plugin/net_plugin.hpp @@ -18,6 +18,8 @@ namespace eos { void plugin_startup(); void plugin_shutdown(); + void broadcast_block(const chain::signed_block &sb); + private: std::unique_ptr my; }; diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 9c401f6eb38ee948b6db665e8b47fa8983618cfa..e87f6bac7ed584d27722613ff47925c6c878c11b 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -42,7 +43,7 @@ struct node_transaction_state { struct transaction_state { transaction_id_type id; bool is_known_by_peer = false; ///< true if we sent or received this trx to this peer or received notice from peer - bool is_noticed_to_peer = false; ///< have we sent peer noitce we know it (true if we reeive from this peer) + bool is_noticed_to_peer = false; ///< have we sent peer notice we know it (true if we receive from this peer) uint32_t block_num = -1; ///< the block number the transaction was included in time_point validated_time; ///< infinity for unvalidated time_point requested_time; /// incase we fetch large trx @@ -119,8 +120,12 @@ public: out_queue.push_back( m ); if( out_queue.size() == 1 ) send_next_message(); + else { + dlog ("send: out_queue size = ${s}", ("s",out_queue.size())); + } } + void send_next_message() { if( !out_queue.size() ) { if (out_sync_state.size() > 0) { @@ -140,7 +145,6 @@ public: boost::asio::async_write( *socket, boost::asio::buffer( buffer.data(), buffer.size() ), [this,buf=std::move(buffer)]( boost::system::error_code ec, std::size_t bytes_transferred ) { - ilog( "write message handler..." ); if( ec ) { elog( "Error sending message: ${msg}", ("msg",ec.message() ) ); } else { @@ -152,7 +156,6 @@ public: void write_block_backlog ( ) { try { - ilog ("write loop sending backlog "); if (out_sync_state.size() > 0) { chain_controller& cc = app().find_plugin()->chain(); auto ss = out_sync_state.begin(); @@ -160,6 +163,7 @@ public: num <= ss->end_block; num++) { fc::optional sb = cc.fetch_block_by_number(num); if (sb) { + dlog("write backlog, block #${num}",("num",num)); send( *sb ); } ss.get_node()->value().last = num; @@ -194,19 +198,20 @@ class net_plugin_impl { chain_plugin* chain_plug; - void connect( const string& ep ) { - auto host = ep.substr( 0, ep.find(':') ); - auto port = ep.substr( host.size()+1, host.size() ); + void connect( const string& peer_addr ) { + auto host = peer_addr.substr( 0, peer_addr.find(':') ); + auto port = peer_addr.substr( host.size()+1, host.size() ); idump((host)(port)); auto resolver = std::make_shared( std::ref( app().get_io_service() ) ); tcp::resolver::query query( tcp::v4(), host.c_str(), port.c_str() ); + // Note: need to add support for IPv6 too resolver->async_resolve( query, - [resolver,ep,this]( const boost::system::error_code& err, tcp::resolver::iterator endpoint_itr ){ + [resolver,peer_addr,this]( const boost::system::error_code& err, tcp::resolver::iterator endpoint_itr ){ if( !err ) { connect( resolver, endpoint_itr ); } else { - elog( "Unable to resolve ${ep}: ${error}", ( "ep", ep )("error", err.message() ) ); + elog( "Unable to resolve ${peer_addr}: ${error}", ( "peer_addr", peer_addr )("error", err.message() ) ); } }); } @@ -271,12 +276,21 @@ class net_plugin_impl { hello->os = "other"; #endif hello->agent = user_agent_name; - + update_handshake (); } void update_handshake () { - hello->last_irreversible_block_id = chain_plug->chain().get_block_id_for_num - (hello->last_irreversible_block_num = chain_plug->chain().last_irreversible_block_num()); + try { + hello->last_irreversible_block_id = chain_plug->chain().get_block_id_for_num + (hello->last_irreversible_block_num = chain_plug->chain().last_irreversible_block_num()); + ilog ("update_handshake my libnum = ${n}",("n",hello->last_irreversible_block_num)); + } + catch (const unknown_block_exception &ex) { + hello->last_irreversible_block_id = fc::sha256::hash(0); + hello->last_irreversible_block_num = 0; + ilog ("update_handshake my libnum = ${n}",("n",hello->last_irreversible_block_num)); + + } } void start_session( connection* con ) { @@ -327,7 +341,14 @@ class net_plugin_impl { ); } - void handle_message (connection &c, handshake_message &msg) { + template + void send_all (const T &msg) { + for (auto &c : connections) { + c->send(msg); + } + } + + void handle_message (connection &c, const handshake_message &msg) { if (!hello) { init_handshake(); } @@ -349,6 +370,7 @@ class net_plugin_impl { } chain_controller& cc = chain_plug->chain(); uint32_t head = cc.head_block_num (); + ilog ("My head block = ${h} their lib = ${lib}", ("h",head)("lib", msg.last_irreversible_block_num)); if ( msg.last_irreversible_block_num > head) { uint32_t delta = msg.last_irreversible_block_num - head; uint32_t count = connections.size(); @@ -373,47 +395,68 @@ class net_plugin_impl { } - void handle_message (connection &c, peer_message &msg) { + void handle_message (connection &c, const peer_message &msg) { ilog ("got a peer message"); } - void handle_message (connection &c, notice_message &msg) { + void handle_message (connection &c, const notice_message &msg) { ilog ("got a notice message"); } - void handle_message (connection &c, sync_request_message &msg) { + void handle_message (connection &c, const sync_request_message &msg) { ilog ("got a sync request message for blocks ${s} to ${e}", ("s",msg.start_block)("e", msg.end_block)); sync_state req = {msg.start_block,msg.end_block,0,time_point::now()}; c.out_sync_state.insert (req); c.write_block_backlog (); } - void handle_message (connection &c, block_summary_message &msg) { + void handle_message (connection &c, const block_summary_message &msg) { ilog ("got a block summary message"); } - void handle_message (connection &c, SignedTransaction &msg) { + void handle_message (connection &c, const SignedTransaction &msg) { ilog ("got a SignedTransacton"); + chain_plug->accept_transaction (msg); } - void handle_message (connection &c, signed_block &msg) { + void handle_message (connection &c, const signed_block &msg) { uint32_t bn = msg.block_num(); - ilog ("got a signed_block, num = ${n}", ("n", bn)); + dlog ("got a signed_block, num = ${n}", ("n", bn)); chain_controller &cc = chain_plug->chain(); if (cc.is_known_block(msg.id())) { - ilog ("block id ${id} is known", ("id", msg.id()) ); + dlog ("block id ${id} is known", ("id", msg.id()) ); return; } uint32_t num = msg.block_num(); + + bool syncing = false; for (auto &ss: c.in_sync_state) { if (num >= ss.end_block) { continue; } const_cast(ss).last = num; + syncing = true; break; } - // TODO: add block to global state + if (!syncing) { + try { + block_id_type id = cc.get_block_id_for_num (num-1); + dlog ("got the prevous block id = ${id}",("id",id)); + } + catch (const unknown_block_exception &ex) { + uint32_t head = cc.head_block_num(); + dlog ("block num ${n} is not known, head = ${h}",("n",(num-1))("h",head)); + sync_state req = {head+1, num-1, 0, time_point::now() }; + c.in_sync_state.insert (req); + sync_request_message srm = {req.start_block, req.end_block }; + c.send (srm); + + syncing = true; + } + + } + chain_plug->accept_block(msg, syncing); } @@ -422,37 +465,8 @@ class net_plugin_impl { connection &c; msgHandler (net_plugin_impl &imp, connection &conn) : impl(imp), c(conn) {} - void operator()(handshake_message &msg) - { - impl.handle_message (c, msg); - } - - void operator()(peer_message &msg) - { - impl.handle_message (c, msg); - } - - void operator()(notice_message &msg) - { - impl.handle_message (c, msg); - } - - void operator()(sync_request_message &msg) - { - impl.handle_message (c, msg); - } - - void operator()(block_summary_message &msg) - { - impl.handle_message (c, msg); - } - - void operator()(SignedTransaction &msg) - { - impl.handle_message (c, msg); - } - - void operator()(signed_block &msg) + template + void operator()(const T &msg) const { impl.handle_message (c, msg); } @@ -507,6 +521,7 @@ void net_plugin::set_program_options( options_description& cli, options_descript ("listen-endpoint", bpo::value()->default_value( "127.0.0.1:9876" ), "The local IP address and port to listen for incoming connections.") ("remote-endpoint", bpo::value< vector >()->composing(), "The IP address and port of a remote peer to sync with.") ("public-endpoint", bpo::value()->default_value( "0.0.0.0:9876" ), "The public IP address and port that should be advertized to peers.") + ("agent-name", bpo::value()->default_value("EOS Test Agent"), "The name supplied to identify this node amongst the peers.") ; } @@ -524,14 +539,16 @@ void net_plugin::plugin_initialize( const variables_map& options ) { if( options.count( "remote-endpoint" ) ) { my->seed_nodes = options.at( "remote-endpoint" ).as< vector >(); } - - my->user_agent_name = "EOS Test Agent"; + if (options.count("agent-name")) { + my->user_agent_name = options.at ("agent-name").as< string > (); + } my->chain_plug = app().find_plugin(); } void net_plugin::plugin_startup() { // boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port); if( my->acceptor ) { + my->acceptor->open(my->listen_endpoint.protocol()); my->acceptor->set_option(tcp::acceptor::reuse_address(true)); my->acceptor->bind(my->listen_endpoint); @@ -569,4 +586,8 @@ try { ilog( "exit shutdown" ); } FC_CAPTURE_AND_RETHROW() } + void net_plugin::broadcast_block (const chain::signed_block &sb) { + my->send_all (sb); + } + } diff --git a/plugins/producer_plugin/CMakeLists.txt b/plugins/producer_plugin/CMakeLists.txt index 57cc4879b8cb577692efaeaaa803a923dd08ebb1..602d4eec40655b1bb1a1afbc67e73cce3d2ba15a 100644 --- a/plugins/producer_plugin/CMakeLists.txt +++ b/plugins/producer_plugin/CMakeLists.txt @@ -5,7 +5,7 @@ add_library( producer_plugin ${HEADERS} ) -target_link_libraries( producer_plugin chain_plugin appbase eos_chain eos_utilities ) +target_link_libraries( producer_plugin net_plugin chain_plugin appbase eos_chain eos_utilities ) target_include_directories( producer_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 3f2f19126cd80065f402b2344c2430ba75b2ccc9..3590f24898b9816424836dbebf81713ffd68230c 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include +#include #include @@ -304,7 +305,7 @@ block_production_condition::block_production_condition_enum producer_plugin_impl ); capture("n", block.block_num())("t", block.timestamp)("c", now); -// app().get_plugin().broadcast_block(block); + app().get_plugin().broadcast_block(block); return block_production_condition::produced; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5bfe608deedf76953c881fa0a9b95762ef7af87c..43028bf321344a60cc747ee40eaf642acdae5249 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,3 +9,7 @@ endif() file(GLOB UNIT_TESTS "tests/*.cpp") add_executable( chain_test ${UNIT_TESTS} ${COMMON_SOURCES} ) target_link_libraries( chain_test eos_native_contract eos_chain chainbase eos_utilities eos_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) + +file(GLOB SLOW_TESTS "slow_tests/*.cpp") +add_executable( slow_test ${SLOW_TESTS} ${COMMON_SOURCES} ) +target_link_libraries( slow_test eos_native_contract eos_chain chainbase eos_utilities eos_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) diff --git a/tests/tests/main.cpp b/tests/common/main.cpp similarity index 100% rename from tests/tests/main.cpp rename to tests/common/main.cpp diff --git a/tests/slow_tests/slow_tests.cpp b/tests/slow_tests/slow_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..759071ce6cc76e379f09c4a4cb83f64d80a7daf1 --- /dev/null +++ b/tests/slow_tests/slow_tests.cpp @@ -0,0 +1,991 @@ +/* + * Copyright (c) 2017, Respective Authors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "../common/database_fixture.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace eos; +using namespace chain; + +BOOST_AUTO_TEST_SUITE(slow_tests) + +// Test that TaPoS still works after block 65535 (See Issue #55) +BOOST_FIXTURE_TEST_CASE(tapos_wrap, testing_fixture) +{ try { + Make_Blockchain(chain) + Make_Account(chain, acct); + Transfer_Asset(chain, system, acct, Asset(5)); + Stake_Asset(chain, acct, Asset(5).amount); + wlog("Hang on, this will take a minute..."); + chain.produce_blocks(65536); + Begin_Unstake_Asset(chain, acct, Asset(1).amount); +} FC_LOG_AND_RETHROW() } + +// Verify that staking and unstaking works +BOOST_FIXTURE_TEST_CASE(stake, testing_fixture) +{ try { + // Create account sam with default balance of 100, and stake 55 of it + Make_Blockchain(chain); + Make_Account(chain, sam); + Transfer_Asset(chain, inita, sam, Asset(55) ); + + // MakeAccount should start sam out with some staked balance + BOOST_REQUIRE_EQUAL(chain.get_staked_balance("sam"), Asset(100).amount); + + Stake_Asset(chain, sam, Asset(55).amount); + + // Check balances + BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(155).amount); + BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(0).amount); + BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(0).amount); + + chain.produce_blocks(); + + // Start unstaking 20, check balances + BOOST_CHECK_THROW(Begin_Unstake_Asset(chain, sam, Asset(156).amount), chain::message_precondition_exception); + Begin_Unstake_Asset(chain, sam, Asset(20).amount); + BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(135).amount); + BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(20).amount); + BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(0).amount); + + // Make sure we can't liquidate early + BOOST_CHECK_THROW(Finish_Unstake_Asset(chain, sam, Asset(10).amount), chain::message_precondition_exception); + + // Fast forward to when we can liquidate + wlog("Hang on, this will take a minute..."); + chain.produce_blocks(config::StakedBalanceCooldownSeconds / config::BlockIntervalSeconds + 1); + + BOOST_CHECK_THROW(Finish_Unstake_Asset(chain, sam, Asset(21).amount), chain::message_precondition_exception); + BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(135).amount); + BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(20).amount); + BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(0).amount); + + // Liquidate 10 of the 20 unstaking and check balances + Finish_Unstake_Asset(chain, sam, Asset(10).amount); + BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(135).amount); + BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(10).amount); + BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(10).amount); + + // Liquidate 2 of the 10 left unstaking and check balances + Finish_Unstake_Asset(chain, sam, Asset(2).amount); + BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(135).amount); + BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(8).amount); + BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(12).amount); + + // Ignore the 8 left in unstaking, and begin unstaking 5, which should restake the 8, and start over unstaking 5 + Begin_Unstake_Asset(chain, sam, Asset(5).amount); + BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(138).amount); + BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(5).amount); + BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(12).amount); + + // Begin unstaking 20, which should only deduct 15 from staked, since 5 was already in unstaking + Begin_Unstake_Asset(chain, sam, Asset(20).amount); + BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(123).amount); + BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(20).amount); + BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(12).amount); +} FC_LOG_AND_RETHROW() } + +vector assemble_wast( const std::string& wast ) { + // std::cout << "\n" << wast << "\n"; + IR::Module module; + std::vector parseErrors; + WAST::parseModule(wast.c_str(),wast.size(),module,parseErrors); + if(parseErrors.size()) + { + // Print any parse errors; + std::cerr << "Error parsing WebAssembly text file:" << std::endl; + for(auto& error : parseErrors) + { + std::cerr << ":" << error.locus.describe() << ": " << error.message.c_str() << std::endl; + std::cerr << error.locus.sourceLine << std::endl; + std::cerr << std::setw(error.locus.column(8)) << "^" << std::endl; + } + FC_ASSERT( !"error parsing wast" ); + } + + try + { + // Serialize the WebAssembly module. + Serialization::ArrayOutputStream stream; + WASM::serialize(stream,module); + return stream.getBytes(); + } + catch(Serialization::FatalSerializationException exception) + { + std::cerr << "Error serializing WebAssembly binary file:" << std::endl; + std::cerr << exception.message << std::endl; + throw; + } +} + +//Test account script processing +BOOST_FIXTURE_TEST_CASE(create_script, testing_fixture) +{ try { + Make_Blockchain(chain); + chain.produce_blocks(10); + Make_Account(chain, simplecoin); + chain.produce_blocks(1); + +#include "wast/simplecoin.wast" + + types::setcode handler; + handler.account = "simplecoin"; + + auto wasm = assemble_wast( simplecoin_wast ); + handler.code.resize(wasm.size()); + memcpy( handler.code.data(), wasm.data(), wasm.size() ); + + { + eos::chain::SignedTransaction trx; + trx.messages.resize(1); + trx.messages[0].sender = "simplecoin"; + trx.messages[0].recipient = config::SystemContractName; + trx.setMessage(0, "setcode", handler); + trx.expiration = chain.head_block_time() + 100; + trx.set_reference_block(chain.head_block_id()); + chain.push_transaction(trx); + chain.produce_blocks(1); + } + + + auto start = fc::time_point::now(); + for (uint32_t i = 0; i < 100000; ++i) + { + eos::chain::SignedTransaction trx; + trx.emplaceMessage("simplecoin", "simplecoin", vector{"inita"}, "transfer", + types::transfer{"simplecoin", "inita", 1+i, "hello"} ); + trx.expiration = chain.head_block_time() + 100; + trx.set_reference_block(chain.head_block_id()); + chain.push_transaction(trx); + } + auto end = fc::time_point::now(); + idump((100000*1000000.0 / (end-start).count())); + + chain.produce_blocks(10); + +} FC_LOG_AND_RETHROW() } + +//Test account script float rejection +BOOST_FIXTURE_TEST_CASE(create_script_w_float, testing_fixture) +{ try { + Make_Blockchain(chain); + chain.produce_blocks(10); + Make_Account(chain, simplecoin); + chain.produce_blocks(1); + + + +/* + auto c_apply = R"( +typedef long long uint64_t; +typedef unsigned int uint32_t; + +void print( char* string, int length ); +void printi( int ); +void printi64( uint64_t ); +void assert( int test, char* message ); +void store( const char* key, int keylength, const char* value, int valuelen ); +int load( const char* key, int keylength, char* value, int maxlen ); +int remove( const char* key, int keyLength ); +void* memcpy( void* dest, const void* src, uint32_t size ); +int readMessage( char* dest, int destsize ); + +void* malloc( unsigned int size ) { + static char dynamic_memory[1024*8]; + static int start = 0; + int old_start = start; + start += 8*((size+7)/8); + assert( start < sizeof(dynamic_memory), "out of memory" ); + return &dynamic_memory[old_start]; +} + + +typedef struct { + uint64_t name[4]; +} AccountName; + +typedef struct { + uint32_t length; + char data[]; +} String; + + +typedef struct { + char* start; + char* pos; + char* end; +} DataStream; + +void DataStream_init( DataStream* ds, char* start, int length ) { + ds->start = start; + ds->end = start + length; + ds->pos = start; +} +void AccountName_initString( AccountName* a, String* s ) { + assert( s->length <= sizeof(AccountName), "String is longer than account name allows" ); + memcpy( a, s->data, s->length ); +} +void AccountName_initCString( AccountName* a, const char* s, uint32_t len ) { + assert( len <= sizeof(AccountName), "String is longer than account name allows" ); + memcpy( a, s, len ); +} + +void AccountName_unpack( DataStream* ds, AccountName* account ); +void uint64_unpack( DataStream* ds, uint64_t* value ) { + assert( ds->pos + sizeof(uint64_t) <= ds->end, "read past end of stream" ); + memcpy( (char*)value, ds->pos, 8 ); + ds->pos += sizeof(uint64_t); +} +void Varint_unpack( DataStream* ds, uint32_t* value ); +void String_unpack( DataStream* ds, String** value ) { + static uint32_t size; + Varint_unpack( ds, &size ); + assert( ds->pos + size <= ds->end, "read past end of stream"); + String* str = (String*)malloc( size + sizeof(String) ); + memcpy( str->data, ds->pos, size ); + *value = str; +} + +/// END BUILT IN LIBRARY.... everything below this is "user contract" + + +typedef struct { + AccountName from; + AccountName to; + uint64_t amount; + String* memo; +} Transfer; + +void Transfer_unpack( DataStream* ds, Transfer* transfer ) +{ + AccountName_unpack( ds, &transfer->from ); + AccountName_unpack( ds, &transfer->to ); + uint64_unpack( ds, &transfer->amount ); + String_unpack( ds, &transfer->memo ); +} + +typedef struct { + uint64_t balance; +} Balance; + +void onInit() { + static Balance initial; + static AccountName simplecoin; + AccountName_initCString( &simplecoin, "simplecoin", 10 ); + initial.balance = 1000*1000; + + store( (const char*)&simplecoin, sizeof(AccountName), (const char*)&initial, sizeof(Balance)); +} + + +void onApply_Transfer_simplecoin() { + static char buffer[100]; + + int read = readMessage( buffer, 100 ); + static Transfer message; + static DataStream ds; + DataStream_init( &ds, buffer, read ); + Transfer_unpack( &ds, &message ); + + static Balance from_balance; + static Balance to_balance; + to_balance.balance = 0; + + read = load( (const char*)&message.from, sizeof(message.from), (char*)&from_balance.balance, +sizeof(from_balance.balance) ); + assert( read == sizeof(Balance), "no existing balance" ); + assert( from_balance.balance >= message.amount, "insufficient funds" ); + read = load( (const char*)&message.to, sizeof(message.to), (char*)&to_balance.balance, sizeof(to_balance.balance) ); + + to_balance.balance += message.amount; + from_balance.balance -= message.amount; + + double bal = to_balance.balance; + if( bal + 0.5 < 50.5 ) + return; + + if( from_balance.balance ) + store( (const char*)&message.from, sizeof(AccountName), (const char*)&from_balance.balance, +sizeof(from_balance.balance) ); + else + remove( (const char*)&message.from, sizeof(AccountName) ); + + store( (const char*)&message.to, sizeof(message.to), (const char*)&to_balance.balance, sizeof(to_balance.balance) ); +} + +"); +*/ +std::string wast_apply = +R"( +(module + (type $FUNCSIG$vii (func (param i32 i32))) + (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) + (type $FUNCSIG$iii (func (param i32 i32) (result i32))) + (type $FUNCSIG$iiiii (func (param i32 i32 i32 i32) (result i32))) + (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32))) + (import "env" "AccountName_unpack" (func $AccountName_unpack (param i32 i32))) + (import "env" "Varint_unpack" (func $Varint_unpack (param i32 i32))) + (import "env" "assert" (func $assert (param i32 i32))) + (import "env" "load" (func $load (param i32 i32 i32 i32) (result i32))) + (import "env" "memcpy" (func $memcpy (param i32 i32 i32) (result i32))) + (import "env" "readMessage" (func $readMessage (param i32 i32) (result i32))) + (import "env" "remove" (func $remove (param i32 i32) (result i32))) + (import "env" "store" (func $store (param i32 i32 i32 i32))) + (table 0 anyfunc) + (memory $0 1) + (data (i32.const 8224) "out of memory\00") + (data (i32.const 8240) "String is longer than account name allows\00") + (data (i32.const 8288) "read past end of stream\00") + (data (i32.const 8368) "simplecoin\00") + (data (i32.const 8608) "no existing balance\00") + (data (i32.const 8640) "insufficient funds\00") + (export "memory" (memory $0)) + (export "malloc" (func $malloc)) + (export "DataStream_init" (func $DataStream_init)) + (export "AccountName_initString" (func $AccountName_initString)) + (export "AccountName_initCString" (func $AccountName_initCString)) + (export "uint64_unpack" (func $uint64_unpack)) + (export "String_unpack" (func $String_unpack)) + (export "Transfer_unpack" (func $Transfer_unpack)) + (export "onInit" (func $onInit)) + (export "onApply_Transfer_simplecoin" (func $onApply_Transfer_simplecoin)) + (func $malloc (param $0 i32) (result i32) + (local $1 i32) + (i32.store offset=8208 + (i32.const 0) + (tee_local $0 + (i32.add + (tee_local $1 + (i32.load offset=8208 + (i32.const 0) + ) + ) + (i32.and + (i32.add + (get_local $0) + (i32.const 7) + ) + (i32.const -8) + ) + ) + ) + ) + (call $assert + (i32.lt_u + (get_local $0) + (i32.const 8192) + ) + (i32.const 8224) + ) + (i32.add + (get_local $1) + (i32.const 16) + ) + ) + (func $DataStream_init (param $0 i32) (param $1 i32) (param $2 i32) + (i32.store + (get_local $0) + (get_local $1) + ) + (i32.store offset=4 + (get_local $0) + (get_local $1) + ) + (i32.store offset=8 + (get_local $0) + (i32.add + (get_local $1) + (get_local $2) + ) + ) + ) + (func $AccountName_initString (param $0 i32) (param $1 i32) + (call $assert + (i32.lt_u + (i32.load + (get_local $1) + ) + (i32.const 33) + ) + (i32.const 8240) + ) + (drop + (call $memcpy + (get_local $0) + (i32.add + (get_local $1) + (i32.const 4) + ) + (i32.load + (get_local $1) + ) + ) + ) + ) + (func $AccountName_initCString (param $0 i32) (param $1 i32) (param $2 i32) + (call $assert + (i32.lt_u + (get_local $2) + (i32.const 33) + ) + (i32.const 8240) + ) + (drop + (call $memcpy + (get_local $0) + (get_local $1) + (get_local $2) + ) + ) + ) + (func $uint64_unpack (param $0 i32) (param $1 i32) + (call $assert + (i32.le_u + (i32.add + (i32.load offset=4 + (get_local $0) + ) + (i32.const 8) + ) + (i32.load offset=8 + (get_local $0) + ) + ) + (i32.const 8288) + ) + (i64.store align=1 + (get_local $1) + (i64.load align=1 + (i32.load offset=4 + (get_local $0) + ) + ) + ) + (i32.store offset=4 + (get_local $0) + (i32.add + (i32.load offset=4 + (get_local $0) + ) + (i32.const 8) + ) + ) + ) + (func $String_unpack (param $0 i32) (param $1 i32) + (local $2 i32) + (local $3 i32) + (call $Varint_unpack + (get_local $0) + (i32.const 8312) + ) + (call $assert + (i32.le_u + (i32.add + (i32.load offset=4 + (get_local $0) + ) + (i32.load offset=8312 + (i32.const 0) + ) + ) + (i32.load offset=8 + (get_local $0) + ) + ) + (i32.const 8288) + ) + (i32.store offset=8208 + (i32.const 0) + (tee_local $3 + (i32.add + (i32.and + (i32.add + (i32.load offset=8312 + (i32.const 0) + ) + (i32.const 11) + ) + (i32.const -8) + ) + (tee_local $2 + (i32.load offset=8208 + (i32.const 0) + ) + ) + ) + ) + ) + (call $assert + (i32.lt_u + (get_local $3) + (i32.const 8192) + ) + (i32.const 8224) + ) + (drop + (call $memcpy + (i32.add + (get_local $2) + (i32.const 20) + ) + (i32.load offset=4 + (get_local $0) + ) + (i32.load offset=8312 + (i32.const 0) + ) + ) + ) + (i32.store + (get_local $1) + (i32.add + (get_local $2) + (i32.const 16) + ) + ) + ) + (func $Transfer_unpack (param $0 i32) (param $1 i32) + (local $2 i32) + (local $3 i32) + (call $AccountName_unpack + (get_local $0) + (get_local $1) + ) + (call $AccountName_unpack + (get_local $0) + (i32.add + (get_local $1) + (i32.const 32) + ) + ) + (call $assert + (i32.le_u + (i32.add + (i32.load offset=4 + (get_local $0) + ) + (i32.const 8) + ) + (i32.load offset=8 + (get_local $0) + ) + ) + (i32.const 8288) + ) + (i64.store offset=64 align=1 + (get_local $1) + (i64.load align=1 + (i32.load offset=4 + (get_local $0) + ) + ) + ) + (i32.store offset=4 + (get_local $0) + (i32.add + (i32.load offset=4 + (get_local $0) + ) + (i32.const 8) + ) + ) + (call $Varint_unpack + (get_local $0) + (i32.const 8312) + ) + (call $assert + (i32.le_u + (i32.add + (i32.load offset=4 + (get_local $0) + ) + (i32.load offset=8312 + (i32.const 0) + ) + ) + (i32.load offset=8 + (get_local $0) + ) + ) + (i32.const 8288) + ) + (i32.store offset=8208 + (i32.const 0) + (tee_local $3 + (i32.add + (i32.and + (i32.add + (i32.load offset=8312 + (i32.const 0) + ) + (i32.const 11) + ) + (i32.const -8) + ) + (tee_local $2 + (i32.load offset=8208 + (i32.const 0) + ) + ) + ) + ) + ) + (call $assert + (i32.lt_u + (get_local $3) + (i32.const 8192) + ) + (i32.const 8224) + ) + (drop + (call $memcpy + (i32.add + (get_local $2) + (i32.const 20) + ) + (i32.load offset=4 + (get_local $0) + ) + (i32.load offset=8312 + (i32.const 0) + ) + ) + ) + (i32.store offset=72 + (get_local $1) + (i32.add + (get_local $2) + (i32.const 16) + ) + ) + ) + (func $onInit + (call $assert + (i32.const 1) + (i32.const 8240) + ) + (i64.store offset=8320 + (i32.const 0) + (i64.const 1000000) + ) + (i32.store16 offset=8336 + (i32.const 0) + (i32.load16_u offset=8376 align=1 + (i32.const 0) + ) + ) + (i64.store offset=8328 + (i32.const 0) + (i64.load offset=8368 align=1 + (i32.const 0) + ) + ) + (call $store + (i32.const 8328) + (i32.const 32) + (i32.const 8320) + (i32.const 8) + ) + ) + (func $onApply_Transfer_simplecoin + (local $0 i32) + (local $1 i32) + (local $2 i64) + (set_local $0 + (call $readMessage + (i32.const 8384) + (i32.const 100) + ) + ) + (i32.store offset=8568 + (i32.const 0) + (i32.const 8384) + ) + (i32.store offset=8572 + (i32.const 0) + (i32.const 8384) + ) + (i32.store offset=8576 + (i32.const 0) + (i32.add + (get_local $0) + (i32.const 8384) + ) + ) + (call $AccountName_unpack + (i32.const 8568) + (i32.const 8488) + ) + (call $AccountName_unpack + (i32.const 8568) + (i32.const 8520) + ) + (call $assert + (i32.le_u + (i32.add + (i32.load offset=8572 + (i32.const 0) + ) + (i32.const 8) + ) + (i32.load offset=8576 + (i32.const 0) + ) + ) + (i32.const 8288) + ) + (i64.store offset=8552 + (i32.const 0) + (i64.load align=1 + (tee_local $0 + (i32.load offset=8572 + (i32.const 0) + ) + ) + ) + ) + (i32.store offset=8572 + (i32.const 0) + (i32.add + (get_local $0) + (i32.const 8) + ) + ) + (call $Varint_unpack + (i32.const 8568) + (i32.const 8312) + ) + (call $assert + (i32.le_u + (i32.add + (i32.load offset=8572 + (i32.const 0) + ) + (i32.load offset=8312 + (i32.const 0) + ) + ) + (i32.load offset=8576 + (i32.const 0) + ) + ) + (i32.const 8288) + ) + (i32.store offset=8208 + (i32.const 0) + (tee_local $1 + (i32.add + (i32.and + (i32.add + (i32.load offset=8312 + (i32.const 0) + ) + (i32.const 11) + ) + (i32.const -8) + ) + (tee_local $0 + (i32.load offset=8208 + (i32.const 0) + ) + ) + ) + ) + ) + (call $assert + (i32.lt_u + (get_local $1) + (i32.const 8192) + ) + (i32.const 8224) + ) + (drop + (call $memcpy + (i32.add + (get_local $0) + (i32.const 20) + ) + (i32.load offset=8572 + (i32.const 0) + ) + (i32.load offset=8312 + (i32.const 0) + ) + ) + ) + (i64.store offset=8592 + (i32.const 0) + (i64.const 0) + ) + (i32.store offset=8560 + (i32.const 0) + (i32.add + (get_local $0) + (i32.const 16) + ) + ) + (call $assert + (i32.eq + (call $load + (i32.const 8488) + (i32.const 32) + (i32.const 8584) + (i32.const 8) + ) + (i32.const 8) + ) + (i32.const 8608) + ) + (call $assert + (i64.ge_s + (i64.load offset=8584 + (i32.const 0) + ) + (i64.load offset=8552 + (i32.const 0) + ) + ) + (i32.const 8640) + ) + (drop + (call $load + (i32.const 8520) + (i32.const 32) + (i32.const 8592) + (i32.const 8) + ) + ) + (i64.store offset=8592 + (i32.const 0) + (i64.add + (i64.load offset=8592 + (i32.const 0) + ) + (tee_local $2 + (i64.load offset=8552 + (i32.const 0) + ) + ) + ) + ) + (i64.store offset=8584 + (i32.const 0) + (tee_local $2 + (i64.sub + (i64.load offset=8584 + (i32.const 0) + ) + (get_local $2) + ) + ) + ) + (block $label$0 + (br_if $label$0 + (f64.lt + (f64.add + (f64.convert_s/i64 + (get_local $2) + ) + (f64.const 0.5) + ) + (f64.const 50.5) + ) + ) + (block $label$1 + (br_if $label$1 + (i64.eqz + (get_local $2) + ) + ) + (call $store + (i32.const 8488) + (i32.const 32) + (i32.const 8584) + (i32.const 8) + ) + (br $label$0) + ) + (drop + (call $remove + (i32.const 8488) + (i32.const 32) + ) + ) + ) + (call $store + (i32.const 8520) + (i32.const 32) + (i32.const 8592) + (i32.const 8) + ) + ) +) + +)"; + + types::setcode handler; + handler.account = "simplecoin"; + + auto wasm = assemble_wast( wast_apply ); + handler.code.resize(wasm.size()); + memcpy( handler.code.data(), wasm.data(), wasm.size() ); + + eos::chain::SignedTransaction trx; + trx.messages.resize(1); + trx.messages[0].sender = "simplecoin"; + trx.messages[0].recipient = config::SystemContractName; + trx.setMessage(0, "setcode", handler); + trx.expiration = chain.head_block_time() + 100; + trx.set_reference_block(chain.head_block_id()); + try { + chain.push_transaction(trx); + BOOST_FAIL("floating point instructions should be rejected"); +/* } catch (const Serialization::FatalSerializationException& fse) { + BOOST_CHECK_EQUAL("float instructions not allowed", fse.message); +*/ } catch (const std::exception& exp) { + BOOST_FAIL("Serialization::FatalSerializationException does not inherit from std::exception"); + } catch (...) { + // empty throw expected, since + } +} FC_LOG_AND_RETHROW() } + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/wast/simplecoin.cpp b/tests/slow_tests/wast/simplecoin.cpp similarity index 100% rename from tests/tests/wast/simplecoin.cpp rename to tests/slow_tests/wast/simplecoin.cpp diff --git a/tests/tests/wast/simplecoin.wast b/tests/slow_tests/wast/simplecoin.wast similarity index 100% rename from tests/tests/wast/simplecoin.wast rename to tests/slow_tests/wast/simplecoin.wast diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 64fbbd79233eaecf6d5e3b21bcd3222e2b55bcf2..ea98d5796d80505204ecaae6da02fb9e19954529 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -76,18 +76,6 @@ BOOST_FIXTURE_TEST_CASE(produce_blocks, testing_fixture) BOOST_CHECK_EQUAL(chain.head_block_num(), chain.get_global_properties().active_producers.size() + 6); } FC_LOG_AND_RETHROW() } -// Test that TaPoS still works after block 65535 (See Issue #55) -BOOST_FIXTURE_TEST_CASE(tapos_wrap, testing_fixture) -{ try { - Make_Blockchain(chain) - Make_Account(chain, acct); - Transfer_Asset(chain, system, acct, Asset(5)); - Stake_Asset(chain, acct, Asset(5).amount); - elog("Hang on, this will take a minute..."); - chain.produce_blocks(65536); - Begin_Unstake_Asset(chain, acct, Asset(1).amount); -} FC_LOG_AND_RETHROW() } - BOOST_FIXTURE_TEST_CASE(order_dependent_transactions, testing_fixture) { try { Make_Blockchain(chain); @@ -110,87 +98,6 @@ BOOST_FIXTURE_TEST_CASE(order_dependent_transactions, testing_fixture) BOOST_CHECK_EQUAL(chain.get_liquid_balance("inita"), Asset(100000-199)); } FC_LOG_AND_RETHROW() } - -vector assemble_wast( const std::string& wast ) { -// std::cout << "\n" << wast << "\n"; - IR::Module module; - std::vector parseErrors; - WAST::parseModule(wast.c_str(),wast.size(),module,parseErrors); - if(parseErrors.size()) - { - // Print any parse errors; - std::cerr << "Error parsing WebAssembly text file:" << std::endl; - for(auto& error : parseErrors) - { - std::cerr << ":" << error.locus.describe() << ": " << error.message.c_str() << std::endl; - std::cerr << error.locus.sourceLine << std::endl; - std::cerr << std::setw(error.locus.column(8)) << "^" << std::endl; - } - FC_ASSERT( !"error parsing wast" ); - } - - try - { - // Serialize the WebAssembly module. - Serialization::ArrayOutputStream stream; - WASM::serialize(stream,module); - return stream.getBytes(); - } - catch(Serialization::FatalSerializationException exception) - { - std::cerr << "Error serializing WebAssembly binary file:" << std::endl; - std::cerr << exception.message << std::endl; - throw; - } -} - -//Test account script processing -BOOST_FIXTURE_TEST_CASE(create_script, testing_fixture) -{ try { - Make_Blockchain(chain); - chain.produce_blocks(10); - Make_Account(chain, simplecoin); - chain.produce_blocks(1); - -#include "wast/simplecoin.wast" - - types::setcode handler; - handler.account = "simplecoin"; - - auto wasm = assemble_wast( simplecoin_wast ); - handler.code.resize(wasm.size()); - memcpy( handler.code.data(), wasm.data(), wasm.size() ); - - { - eos::chain::SignedTransaction trx; - trx.messages.resize(1); - trx.messages[0].sender = "simplecoin"; - trx.messages[0].recipient = config::SystemContractName; - trx.setMessage(0, "setcode", handler); - trx.expiration = chain.head_block_time() + 100; - trx.set_reference_block(chain.head_block_id()); - chain.push_transaction(trx); - chain.produce_blocks(1); - } - - - auto start = fc::time_point::now(); - for (uint32_t i = 0; i < 100000; ++i) - { - eos::chain::SignedTransaction trx; - trx.emplaceMessage("simplecoin", "simplecoin", vector{"inita"}, "transfer", - types::transfer{"simplecoin", "inita", 1+i, "hello"} ); - trx.expiration = chain.head_block_time() + 100; - trx.set_reference_block(chain.head_block_id()); - chain.push_transaction(trx); - } - auto end = fc::time_point::now(); - idump((100000*1000000.0 / (end-start).count())); - - chain.produce_blocks(10); - -} FC_LOG_AND_RETHROW() } - // Simple test of block production when a block is missed BOOST_FIXTURE_TEST_CASE(missed_blocks, testing_fixture) { try { @@ -526,789 +433,4 @@ BOOST_FIXTURE_TEST_CASE(wipe, testing_fixture) } } FC_LOG_AND_RETHROW() } -//Test account script float rejection -BOOST_FIXTURE_TEST_CASE(create_script_w_float, testing_fixture) -{ try { - Make_Blockchain(chain); - chain.produce_blocks(10); - Make_Account(chain, simplecoin); - chain.produce_blocks(1); - - - -/* - auto c_apply = R"( -typedef long long uint64_t; -typedef unsigned int uint32_t; - -void print( char* string, int length ); -void printi( int ); -void printi64( uint64_t ); -void assert( int test, char* message ); -void store( const char* key, int keylength, const char* value, int valuelen ); -int load( const char* key, int keylength, char* value, int maxlen ); -int remove( const char* key, int keyLength ); -void* memcpy( void* dest, const void* src, uint32_t size ); -int readMessage( char* dest, int destsize ); - -void* malloc( unsigned int size ) { - static char dynamic_memory[1024*8]; - static int start = 0; - int old_start = start; - start += 8*((size+7)/8); - assert( start < sizeof(dynamic_memory), "out of memory" ); - return &dynamic_memory[old_start]; -} - - -typedef struct { - uint64_t name[4]; -} AccountName; - -typedef struct { - uint32_t length; - char data[]; -} String; - - -typedef struct { - char* start; - char* pos; - char* end; -} DataStream; - -void DataStream_init( DataStream* ds, char* start, int length ) { - ds->start = start; - ds->end = start + length; - ds->pos = start; -} -void AccountName_initString( AccountName* a, String* s ) { - assert( s->length <= sizeof(AccountName), "String is longer than account name allows" ); - memcpy( a, s->data, s->length ); -} -void AccountName_initCString( AccountName* a, const char* s, uint32_t len ) { - assert( len <= sizeof(AccountName), "String is longer than account name allows" ); - memcpy( a, s, len ); -} - -void AccountName_unpack( DataStream* ds, AccountName* account ); -void uint64_unpack( DataStream* ds, uint64_t* value ) { - assert( ds->pos + sizeof(uint64_t) <= ds->end, "read past end of stream" ); - memcpy( (char*)value, ds->pos, 8 ); - ds->pos += sizeof(uint64_t); -} -void Varint_unpack( DataStream* ds, uint32_t* value ); -void String_unpack( DataStream* ds, String** value ) { - static uint32_t size; - Varint_unpack( ds, &size ); - assert( ds->pos + size <= ds->end, "read past end of stream"); - String* str = (String*)malloc( size + sizeof(String) ); - memcpy( str->data, ds->pos, size ); - *value = str; -} - -/// END BUILT IN LIBRARY.... everything below this is "user contract" - - -typedef struct { - AccountName from; - AccountName to; - uint64_t amount; - String* memo; -} Transfer; - -void Transfer_unpack( DataStream* ds, Transfer* transfer ) -{ - AccountName_unpack( ds, &transfer->from ); - AccountName_unpack( ds, &transfer->to ); - uint64_unpack( ds, &transfer->amount ); - String_unpack( ds, &transfer->memo ); -} - -typedef struct { - uint64_t balance; -} Balance; - -void onInit() { - static Balance initial; - static AccountName simplecoin; - AccountName_initCString( &simplecoin, "simplecoin", 10 ); - initial.balance = 1000*1000; - - store( (const char*)&simplecoin, sizeof(AccountName), (const char*)&initial, sizeof(Balance)); -} - - -void onApply_Transfer_simplecoin() { - static char buffer[100]; - - int read = readMessage( buffer, 100 ); - static Transfer message; - static DataStream ds; - DataStream_init( &ds, buffer, read ); - Transfer_unpack( &ds, &message ); - - static Balance from_balance; - static Balance to_balance; - to_balance.balance = 0; - - read = load( (const char*)&message.from, sizeof(message.from), (char*)&from_balance.balance, -sizeof(from_balance.balance) ); - assert( read == sizeof(Balance), "no existing balance" ); - assert( from_balance.balance >= message.amount, "insufficient funds" ); - read = load( (const char*)&message.to, sizeof(message.to), (char*)&to_balance.balance, sizeof(to_balance.balance) ); - - to_balance.balance += message.amount; - from_balance.balance -= message.amount; - - double bal = to_balance.balance; - if( bal + 0.5 < 50.5 ) - return; - - if( from_balance.balance ) - store( (const char*)&message.from, sizeof(AccountName), (const char*)&from_balance.balance, -sizeof(from_balance.balance) ); - else - remove( (const char*)&message.from, sizeof(AccountName) ); - - store( (const char*)&message.to, sizeof(message.to), (const char*)&to_balance.balance, sizeof(to_balance.balance) ); -} - -"); -*/ -std::string wast_apply = -R"( -(module - (type $FUNCSIG$vii (func (param i32 i32))) - (type $FUNCSIG$viiii (func (param i32 i32 i32 i32))) - (type $FUNCSIG$iii (func (param i32 i32) (result i32))) - (type $FUNCSIG$iiiii (func (param i32 i32 i32 i32) (result i32))) - (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32))) - (import "env" "AccountName_unpack" (func $AccountName_unpack (param i32 i32))) - (import "env" "Varint_unpack" (func $Varint_unpack (param i32 i32))) - (import "env" "assert" (func $assert (param i32 i32))) - (import "env" "load" (func $load (param i32 i32 i32 i32) (result i32))) - (import "env" "memcpy" (func $memcpy (param i32 i32 i32) (result i32))) - (import "env" "readMessage" (func $readMessage (param i32 i32) (result i32))) - (import "env" "remove" (func $remove (param i32 i32) (result i32))) - (import "env" "store" (func $store (param i32 i32 i32 i32))) - (table 0 anyfunc) - (memory $0 1) - (data (i32.const 8224) "out of memory\00") - (data (i32.const 8240) "String is longer than account name allows\00") - (data (i32.const 8288) "read past end of stream\00") - (data (i32.const 8368) "simplecoin\00") - (data (i32.const 8608) "no existing balance\00") - (data (i32.const 8640) "insufficient funds\00") - (export "memory" (memory $0)) - (export "malloc" (func $malloc)) - (export "DataStream_init" (func $DataStream_init)) - (export "AccountName_initString" (func $AccountName_initString)) - (export "AccountName_initCString" (func $AccountName_initCString)) - (export "uint64_unpack" (func $uint64_unpack)) - (export "String_unpack" (func $String_unpack)) - (export "Transfer_unpack" (func $Transfer_unpack)) - (export "onInit" (func $onInit)) - (export "onApply_Transfer_simplecoin" (func $onApply_Transfer_simplecoin)) - (func $malloc (param $0 i32) (result i32) - (local $1 i32) - (i32.store offset=8208 - (i32.const 0) - (tee_local $0 - (i32.add - (tee_local $1 - (i32.load offset=8208 - (i32.const 0) - ) - ) - (i32.and - (i32.add - (get_local $0) - (i32.const 7) - ) - (i32.const -8) - ) - ) - ) - ) - (call $assert - (i32.lt_u - (get_local $0) - (i32.const 8192) - ) - (i32.const 8224) - ) - (i32.add - (get_local $1) - (i32.const 16) - ) - ) - (func $DataStream_init (param $0 i32) (param $1 i32) (param $2 i32) - (i32.store - (get_local $0) - (get_local $1) - ) - (i32.store offset=4 - (get_local $0) - (get_local $1) - ) - (i32.store offset=8 - (get_local $0) - (i32.add - (get_local $1) - (get_local $2) - ) - ) - ) - (func $AccountName_initString (param $0 i32) (param $1 i32) - (call $assert - (i32.lt_u - (i32.load - (get_local $1) - ) - (i32.const 33) - ) - (i32.const 8240) - ) - (drop - (call $memcpy - (get_local $0) - (i32.add - (get_local $1) - (i32.const 4) - ) - (i32.load - (get_local $1) - ) - ) - ) - ) - (func $AccountName_initCString (param $0 i32) (param $1 i32) (param $2 i32) - (call $assert - (i32.lt_u - (get_local $2) - (i32.const 33) - ) - (i32.const 8240) - ) - (drop - (call $memcpy - (get_local $0) - (get_local $1) - (get_local $2) - ) - ) - ) - (func $uint64_unpack (param $0 i32) (param $1 i32) - (call $assert - (i32.le_u - (i32.add - (i32.load offset=4 - (get_local $0) - ) - (i32.const 8) - ) - (i32.load offset=8 - (get_local $0) - ) - ) - (i32.const 8288) - ) - (i64.store align=1 - (get_local $1) - (i64.load align=1 - (i32.load offset=4 - (get_local $0) - ) - ) - ) - (i32.store offset=4 - (get_local $0) - (i32.add - (i32.load offset=4 - (get_local $0) - ) - (i32.const 8) - ) - ) - ) - (func $String_unpack (param $0 i32) (param $1 i32) - (local $2 i32) - (local $3 i32) - (call $Varint_unpack - (get_local $0) - (i32.const 8312) - ) - (call $assert - (i32.le_u - (i32.add - (i32.load offset=4 - (get_local $0) - ) - (i32.load offset=8312 - (i32.const 0) - ) - ) - (i32.load offset=8 - (get_local $0) - ) - ) - (i32.const 8288) - ) - (i32.store offset=8208 - (i32.const 0) - (tee_local $3 - (i32.add - (i32.and - (i32.add - (i32.load offset=8312 - (i32.const 0) - ) - (i32.const 11) - ) - (i32.const -8) - ) - (tee_local $2 - (i32.load offset=8208 - (i32.const 0) - ) - ) - ) - ) - ) - (call $assert - (i32.lt_u - (get_local $3) - (i32.const 8192) - ) - (i32.const 8224) - ) - (drop - (call $memcpy - (i32.add - (get_local $2) - (i32.const 20) - ) - (i32.load offset=4 - (get_local $0) - ) - (i32.load offset=8312 - (i32.const 0) - ) - ) - ) - (i32.store - (get_local $1) - (i32.add - (get_local $2) - (i32.const 16) - ) - ) - ) - (func $Transfer_unpack (param $0 i32) (param $1 i32) - (local $2 i32) - (local $3 i32) - (call $AccountName_unpack - (get_local $0) - (get_local $1) - ) - (call $AccountName_unpack - (get_local $0) - (i32.add - (get_local $1) - (i32.const 32) - ) - ) - (call $assert - (i32.le_u - (i32.add - (i32.load offset=4 - (get_local $0) - ) - (i32.const 8) - ) - (i32.load offset=8 - (get_local $0) - ) - ) - (i32.const 8288) - ) - (i64.store offset=64 align=1 - (get_local $1) - (i64.load align=1 - (i32.load offset=4 - (get_local $0) - ) - ) - ) - (i32.store offset=4 - (get_local $0) - (i32.add - (i32.load offset=4 - (get_local $0) - ) - (i32.const 8) - ) - ) - (call $Varint_unpack - (get_local $0) - (i32.const 8312) - ) - (call $assert - (i32.le_u - (i32.add - (i32.load offset=4 - (get_local $0) - ) - (i32.load offset=8312 - (i32.const 0) - ) - ) - (i32.load offset=8 - (get_local $0) - ) - ) - (i32.const 8288) - ) - (i32.store offset=8208 - (i32.const 0) - (tee_local $3 - (i32.add - (i32.and - (i32.add - (i32.load offset=8312 - (i32.const 0) - ) - (i32.const 11) - ) - (i32.const -8) - ) - (tee_local $2 - (i32.load offset=8208 - (i32.const 0) - ) - ) - ) - ) - ) - (call $assert - (i32.lt_u - (get_local $3) - (i32.const 8192) - ) - (i32.const 8224) - ) - (drop - (call $memcpy - (i32.add - (get_local $2) - (i32.const 20) - ) - (i32.load offset=4 - (get_local $0) - ) - (i32.load offset=8312 - (i32.const 0) - ) - ) - ) - (i32.store offset=72 - (get_local $1) - (i32.add - (get_local $2) - (i32.const 16) - ) - ) - ) - (func $onInit - (call $assert - (i32.const 1) - (i32.const 8240) - ) - (i64.store offset=8320 - (i32.const 0) - (i64.const 1000000) - ) - (i32.store16 offset=8336 - (i32.const 0) - (i32.load16_u offset=8376 align=1 - (i32.const 0) - ) - ) - (i64.store offset=8328 - (i32.const 0) - (i64.load offset=8368 align=1 - (i32.const 0) - ) - ) - (call $store - (i32.const 8328) - (i32.const 32) - (i32.const 8320) - (i32.const 8) - ) - ) - (func $onApply_Transfer_simplecoin - (local $0 i32) - (local $1 i32) - (local $2 i64) - (set_local $0 - (call $readMessage - (i32.const 8384) - (i32.const 100) - ) - ) - (i32.store offset=8568 - (i32.const 0) - (i32.const 8384) - ) - (i32.store offset=8572 - (i32.const 0) - (i32.const 8384) - ) - (i32.store offset=8576 - (i32.const 0) - (i32.add - (get_local $0) - (i32.const 8384) - ) - ) - (call $AccountName_unpack - (i32.const 8568) - (i32.const 8488) - ) - (call $AccountName_unpack - (i32.const 8568) - (i32.const 8520) - ) - (call $assert - (i32.le_u - (i32.add - (i32.load offset=8572 - (i32.const 0) - ) - (i32.const 8) - ) - (i32.load offset=8576 - (i32.const 0) - ) - ) - (i32.const 8288) - ) - (i64.store offset=8552 - (i32.const 0) - (i64.load align=1 - (tee_local $0 - (i32.load offset=8572 - (i32.const 0) - ) - ) - ) - ) - (i32.store offset=8572 - (i32.const 0) - (i32.add - (get_local $0) - (i32.const 8) - ) - ) - (call $Varint_unpack - (i32.const 8568) - (i32.const 8312) - ) - (call $assert - (i32.le_u - (i32.add - (i32.load offset=8572 - (i32.const 0) - ) - (i32.load offset=8312 - (i32.const 0) - ) - ) - (i32.load offset=8576 - (i32.const 0) - ) - ) - (i32.const 8288) - ) - (i32.store offset=8208 - (i32.const 0) - (tee_local $1 - (i32.add - (i32.and - (i32.add - (i32.load offset=8312 - (i32.const 0) - ) - (i32.const 11) - ) - (i32.const -8) - ) - (tee_local $0 - (i32.load offset=8208 - (i32.const 0) - ) - ) - ) - ) - ) - (call $assert - (i32.lt_u - (get_local $1) - (i32.const 8192) - ) - (i32.const 8224) - ) - (drop - (call $memcpy - (i32.add - (get_local $0) - (i32.const 20) - ) - (i32.load offset=8572 - (i32.const 0) - ) - (i32.load offset=8312 - (i32.const 0) - ) - ) - ) - (i64.store offset=8592 - (i32.const 0) - (i64.const 0) - ) - (i32.store offset=8560 - (i32.const 0) - (i32.add - (get_local $0) - (i32.const 16) - ) - ) - (call $assert - (i32.eq - (call $load - (i32.const 8488) - (i32.const 32) - (i32.const 8584) - (i32.const 8) - ) - (i32.const 8) - ) - (i32.const 8608) - ) - (call $assert - (i64.ge_s - (i64.load offset=8584 - (i32.const 0) - ) - (i64.load offset=8552 - (i32.const 0) - ) - ) - (i32.const 8640) - ) - (drop - (call $load - (i32.const 8520) - (i32.const 32) - (i32.const 8592) - (i32.const 8) - ) - ) - (i64.store offset=8592 - (i32.const 0) - (i64.add - (i64.load offset=8592 - (i32.const 0) - ) - (tee_local $2 - (i64.load offset=8552 - (i32.const 0) - ) - ) - ) - ) - (i64.store offset=8584 - (i32.const 0) - (tee_local $2 - (i64.sub - (i64.load offset=8584 - (i32.const 0) - ) - (get_local $2) - ) - ) - ) - (block $label$0 - (br_if $label$0 - (f64.lt - (f64.add - (f64.convert_s/i64 - (get_local $2) - ) - (f64.const 0.5) - ) - (f64.const 50.5) - ) - ) - (block $label$1 - (br_if $label$1 - (i64.eqz - (get_local $2) - ) - ) - (call $store - (i32.const 8488) - (i32.const 32) - (i32.const 8584) - (i32.const 8) - ) - (br $label$0) - ) - (drop - (call $remove - (i32.const 8488) - (i32.const 32) - ) - ) - ) - (call $store - (i32.const 8520) - (i32.const 32) - (i32.const 8592) - (i32.const 8) - ) - ) -) - -)"; - - types::setcode handler; - handler.account = "simplecoin"; - - auto wasm = assemble_wast( wast_apply ); - handler.code.resize(wasm.size()); - memcpy( handler.code.data(), wasm.data(), wasm.size() ); - - eos::chain::SignedTransaction trx; - trx.messages.resize(1); - trx.messages[0].sender = "simplecoin"; - trx.messages[0].recipient = config::SystemContractName; - trx.setMessage(0, "setcode", handler); - trx.expiration = chain.head_block_time() + 100; - trx.set_reference_block(chain.head_block_id()); - try { - chain.push_transaction(trx); - BOOST_FAIL("floating point instructions should be rejected"); -/* } catch (const Serialization::FatalSerializationException& fse) { - BOOST_CHECK_EQUAL("float instructions not allowed", fse.message); -*/ } catch (const std::exception& exp) { - BOOST_FAIL("Serialization::FatalSerializationException does not inherit from std::exception"); - } catch (...) { - // empty throw expected, since - } -} FC_LOG_AND_RETHROW() } - - BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/misc_tests.cpp b/tests/tests/misc_tests.cpp index 127e705a4421ca95c72a8efad1d027926c4fc8b6..0220ab36a51463e5751c6db2e6b849bde4fd6e4d 100644 --- a/tests/tests/misc_tests.cpp +++ b/tests/tests/misc_tests.cpp @@ -1,4 +1,5 @@ #include +#include #include @@ -72,9 +73,62 @@ BOOST_AUTO_TEST_CASE(deterministic_distributions) rng.shuffle(nums); std::vector c{1, 0, 2}; BOOST_CHECK(std::equal(nums.begin(), nums.end(), c.begin())); - } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE(authority_checker) +{ try { + #define KEY(x) auto x = fc::ecc::private_key::regenerate(fc::sha256::hash(#x)).get_public_key() + + KEY(a); + KEY(b); + KEY(c); + + auto GetNullAuthority = [](auto){return Authority();}; + + Authority A(2, {{a, 1}, {b, 1}}, {}); + BOOST_CHECK(MakeAuthorityChecker(GetNullAuthority, {a, b}).satisfied(A)); + BOOST_CHECK(MakeAuthorityChecker(GetNullAuthority, {a, b, c}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetNullAuthority, {a, c}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetNullAuthority, {b, c}).satisfied(A)); + + A = Authority(3, {{a,1},{b,1},{c,1}}, {}); + BOOST_CHECK(MakeAuthorityChecker(GetNullAuthority, {c, b, a}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetNullAuthority, {a, b}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetNullAuthority, {a, c}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetNullAuthority, {b, c}).satisfied(A)); + + A = Authority(1, {{a, 1}, {b, 1}}, {}); + BOOST_CHECK(MakeAuthorityChecker(GetNullAuthority, {a}).satisfied(A)); + BOOST_CHECK(MakeAuthorityChecker(GetNullAuthority, {b}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetNullAuthority, {c}).satisfied(A)); + + A = Authority(1, {{a, 2}, {b, 1}}, {}); + BOOST_CHECK(MakeAuthorityChecker(GetNullAuthority, {a}).satisfied(A)); + BOOST_CHECK(MakeAuthorityChecker(GetNullAuthority, {b}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetNullAuthority, {c}).satisfied(A)); + + auto GetCAuthority = [c](auto){return Authority(1, {{c, 1}}, {});}; + + A = Authority(2, {{a, 2}, {b, 1}}, {{{"hello", "world"}, 1}}); + BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {a}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {b}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {c}).satisfied(A)); + BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {b,c}).satisfied(A)); + + A = Authority(2, {{a, 1}, {b, 1}}, {{{"hello", "world"}, 1}}); + BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {a}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {b}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {c}).satisfied(A)); + BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {a,b}).satisfied(A)); + BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {b,c}).satisfied(A)); + BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {a,c}).satisfied(A)); + + A = Authority(2, {{a, 1}, {b, 1}}, {{{"hello", "world"}, 2}}); + BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {a,b}).satisfied(A)); + BOOST_CHECK(MakeAuthorityChecker(GetCAuthority, {c}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {a}).satisfied(A)); + BOOST_CHECK(!MakeAuthorityChecker(GetCAuthority, {b}).satisfied(A)); +} FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/native_contract_tests.cpp b/tests/tests/native_contract_tests.cpp index 7e7bea547a0fe6c98f0aa8fce80229a24e7d8ceb..4e7b8e0da4f81adad64ef16a8b813c028c7b11f8 100644 --- a/tests/tests/native_contract_tests.cpp +++ b/tests/tests/native_contract_tests.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -76,70 +76,6 @@ BOOST_FIXTURE_TEST_CASE(create_account, testing_fixture) } } FC_LOG_AND_RETHROW() } -// Verify that staking and unstaking works -BOOST_FIXTURE_TEST_CASE(stake, testing_fixture) -{ try { - // Create account sam with default balance of 100, and stake 55 of it - Make_Blockchain(chain); - Make_Account(chain, sam); - Transfer_Asset(chain, inita, sam, Asset(55) ); - - // MakeAccount should start sam out with some staked balance - BOOST_REQUIRE_EQUAL(chain.get_staked_balance("sam"), Asset(100).amount); - - Stake_Asset(chain, sam, Asset(55).amount); - - // Check balances - BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(155).amount); - BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(0).amount); - BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(0).amount); - - chain.produce_blocks(); - - // Start unstaking 20, check balances - BOOST_CHECK_THROW(Begin_Unstake_Asset(chain, sam, Asset(156).amount), chain::message_precondition_exception); - Begin_Unstake_Asset(chain, sam, Asset(20).amount); - BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(135).amount); - BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(20).amount); - BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(0).amount); - - // Make sure we can't liquidate early - BOOST_CHECK_THROW(Finish_Unstake_Asset(chain, sam, Asset(10).amount), chain::message_precondition_exception); - - // Fast forward to when we can liquidate - wlog("Hang on, this will take a minute..."); - chain.produce_blocks(config::StakedBalanceCooldownSeconds / config::BlockIntervalSeconds + 1); - - BOOST_CHECK_THROW(Finish_Unstake_Asset(chain, sam, Asset(21).amount), chain::message_precondition_exception); - BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(135).amount); - BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(20).amount); - BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(0).amount); - - // Liquidate 10 of the 20 unstaking and check balances - Finish_Unstake_Asset(chain, sam, Asset(10).amount); - BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(135).amount); - BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(10).amount); - BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(10).amount); - - // Liquidate 2 of the 10 left unstaking and check balances - Finish_Unstake_Asset(chain, sam, Asset(2).amount); - BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(135).amount); - BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(8).amount); - BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(12).amount); - - // Ignore the 8 left in unstaking, and begin unstaking 5, which should restake the 8, and start over unstaking 5 - Begin_Unstake_Asset(chain, sam, Asset(5).amount); - BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(138).amount); - BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(5).amount); - BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(12).amount); - - // Begin unstaking 20, which should only deduct 15 from staked, since 5 was already in unstaking - Begin_Unstake_Asset(chain, sam, Asset(20).amount); - BOOST_CHECK_EQUAL(chain.get_staked_balance("sam"), Asset(123).amount); - BOOST_CHECK_EQUAL(chain.get_unstaking_balance("sam"), Asset(20).amount); - BOOST_CHECK_EQUAL(chain.get_liquid_balance("sam"), Asset(12).amount); -} FC_LOG_AND_RETHROW() } - // Simple test to verify a simple transfer transaction works BOOST_FIXTURE_TEST_CASE(transfer, testing_fixture) { try {