提交 07f027c4 编写于 作者: N Nathan Hourt

Remove operations and evaluators

Also remove transaction_evaluation_state and the size_checker program.
上级 f986bb3b
......@@ -27,6 +27,7 @@
#include <eos/app/plugin.hpp>
#include <eos/chain/protocol/types.hpp>
#include <eos/chain/exceptions.hpp>
#include <eos/chain/producer_object.hpp>
#include <eos/egenesis/egenesis.hpp>
......
......@@ -8,15 +8,12 @@ add_library( eos_chain
fork_database.cpp
protocol/types.cpp
protocol/operations.cpp
protocol/transaction.cpp
protocol/block.cpp
genesis_state.cpp
get_config.cpp
evaluator.cpp
block_database.cpp
${HEADERS}
......
......@@ -25,7 +25,6 @@
#include <eos/chain/database.hpp>
#include <eos/chain/db_with.hpp>
#include <eos/chain/exceptions.hpp>
#include <eos/chain/evaluator.hpp>
#include <eos/chain/block_summary_object.hpp>
#include <eos/chain/chain_property_object.hpp>
......@@ -482,9 +481,7 @@ signed_transaction database::_apply_transaction(const signed_transaction& trx)
auto trx_id = trx.id();
FC_ASSERT( (skip & skip_transaction_dupe_check) ||
trx_idx.indices().get<by_trx_id>().find(trx_id) == trx_idx.indices().get<by_trx_id>().end() );
transaction_evaluation_state eval_state(this);
const chain_parameters& chain_parameters = get_global_properties().parameters;
eval_state._trx = &trx;
//Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is
//expired, and TaPoS makes no sense as no blocks exist.
......@@ -514,32 +511,18 @@ signed_transaction database::_apply_transaction(const signed_transaction& trx)
});
}
//Finally process the operations
//Finally, process the messages
signed_transaction ptrx(trx);
_current_op_in_trx = 0;
for( const auto& op : ptrx.operations )
_current_message_in_trx = 0;
for( const auto& msg : ptrx.messages )
{
apply_operation(eval_state, op);
++_current_op_in_trx;
#warning TODO: Process messages in transaction
++_current_message_in_trx;
}
return ptrx;
} FC_CAPTURE_AND_RETHROW( (trx) ) }
void database::apply_operation(transaction_evaluation_state& eval_state, const operation& op)
{ try {
int i_which = op.which();
uint64_t u_which = uint64_t( i_which );
if( i_which < 0 )
assert( "Negative operation tag" && false );
if( u_which >= _operation_evaluators.size() )
assert( "No registered evaluator for this operation" && false );
unique_ptr<op_evaluator>& eval = _operation_evaluators[ u_which ];
if( !eval )
assert( "No registered evaluator for this operation" && false );
eval->evaluate( eval_state, op, true );
} FC_CAPTURE_AND_RETHROW( (op) ) }
const producer_object& database::validate_block_header( uint32_t skip, const signed_block& next_block )const
{
FC_ASSERT( head_block_id() == next_block.previous, "", ("head_block_id",head_block_id())("next.prev",next_block.previous) );
......@@ -663,21 +646,6 @@ uint32_t database::last_non_undoable_block_num() const
return 1; //head_block_num() - _undo_db.size();
}
// C++ requires that static class variables declared and initialized
// in headers must also have a definition in a single source file,
// else linker errors will occur [1].
//
// The purpose of this source file is to collect such definitions in
// a single place.
//
// [1] http://stackoverflow.com/questions/8016780/undefined-reference-to-static-constexpr-char
void database::initialize_evaluators()
{
_operation_evaluators.resize(255);
// TODO: Figure out how to do this
}
void database::initialize_indexes()
{
add_index<account_multi_index>();
......@@ -717,7 +685,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
});
}
// Create initial producers
std::vector<producer_id_type> initialProducers;
std::vector<producer_id_type> initial_producers;
for (const auto& producer : genesis_state.initial_producers) {
auto owner = find<account_object, by_name>(producer.owner_name);
FC_ASSERT(owner != nullptr, "Producer belongs to an unknown account: ${acct}", ("acct", producer.owner_name));
......@@ -725,19 +693,18 @@ void database::init_genesis(const genesis_state_type& genesis_state)
w.signing_key = producer.block_signing_key;
w.owner_name = producer.owner_name.c_str();
}).id;
initialProducers.push_back(id);
initial_producers.push_back(id);
}
transaction_evaluation_state genesis_eval_state(this);
// Initialize block summary index
#warning TODO: Figure out how to do this
chain_id_type chain_id = genesis_state.compute_chain_id();
// Create global properties
create<global_property_object>([&](global_property_object& p) {
p.parameters = genesis_state.initial_parameters;
p.active_producers = initialProducers;
p.active_producers = initial_producers;
});
create<dynamic_global_property_object>([&](dynamic_global_property_object& p) {
p.time = genesis_state.initial_timestamp;
......@@ -753,11 +720,6 @@ void database::init_genesis(const genesis_state_type& genesis_state)
p.immutable_parameters = genesis_state.immutable_parameters;
} );
create<block_summary_object>([&](block_summary_object&) {});
//TODO: Figure out how to do this
// Create initial accounts
// Create initial producers
// Set active producers
} FC_CAPTURE_AND_RETHROW() }
database::database()
......@@ -838,7 +800,6 @@ void database::open(const fc::path& data_dir, uint64_t shared_file_size,
chainbase::database::open(data_dir, read_write, shared_file_size);
initialize_indexes();
initialize_evaluators();
_block_id_to_block.open(data_dir / "database" / "block_num_to_block");
......
/*
* 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 <eos/chain/database.hpp>
#include <eos/chain/evaluator.hpp>
#include <eos/chain/exceptions.hpp>
#include <eos/chain/transaction_evaluation_state.hpp>
#include <fc/uint128.hpp>
namespace eos { namespace chain {
database& generic_evaluator::db()const { return trx_state->db(); }
void generic_evaluator::start_evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply )
{ try {
trx_state = &eval_state;
evaluate( op );
if( apply ) this->apply( op );
} FC_CAPTURE_AND_RETHROW() }
} }
......@@ -27,7 +27,6 @@
#include <eos/chain/fork_database.hpp>
#include <eos/chain/block_database.hpp>
#include <eos/chain/genesis_state.hpp>
#include <eos/chain/evaluator.hpp>
#include <chainbase/chainbase.hpp>
#include <fc/signals.hpp>
......@@ -39,11 +38,6 @@
#include <map>
namespace eos { namespace chain {
class op_evaluator;
class transaction_evaluation_state;
struct budget_record;
/**
* @class database
* @brief tracks the blockchain state in an extensible manner
......@@ -217,7 +211,6 @@ namespace eos { namespace chain {
uint32_t last_non_undoable_block_num() const;
void initialize_evaluators();
/// Reset the object graph in-memory
void initialize_indexes();
void init_genesis(const genesis_state_type& genesis_state = genesis_state_type());
......@@ -239,13 +232,11 @@ namespace eos { namespace chain {
private:
optional<session> _pending_tx_session;
vector<unique_ptr<op_evaluator>> _operation_evaluators;
public:
// these were formerly private, but they have a fairly well-defined API, so let's make them public
void apply_block( const signed_block& next_block, uint32_t skip = skip_nothing );
signed_transaction apply_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing );
void apply_operation( transaction_evaluation_state& eval_state, const operation& op );
private:
void _apply_block( const signed_block& next_block );
signed_transaction _apply_transaction( const signed_transaction& trx );
......@@ -278,7 +269,7 @@ namespace eos { namespace chain {
uint32_t _current_block_num = 0;
uint16_t _current_trx_in_block = 0;
uint16_t _current_op_in_trx = 0;
uint16_t _current_message_in_trx = 0;
uint16_t _current_virtual_op = 0;
vector<uint64_t> _vote_tally_buffer;
......
/*
* 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 <eos/chain/exceptions.hpp>
#include <eos/chain/transaction_evaluation_state.hpp>
#include <eos/chain/protocol/operations.hpp>
namespace eos { namespace chain {
class database;
struct signed_transaction;
class generic_evaluator;
class transaction_evaluation_state;
class generic_evaluator
{
public:
virtual ~generic_evaluator(){}
virtual int get_type()const = 0;
virtual void start_evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply);
/**
* @note derived classes should ASSUME that the default validation that is
* indepenent of chain state should be performed by op.validate() and should
* not perform these extra checks.
*/
virtual void evaluate(const operation& op) = 0;
virtual void apply(const operation& op) = 0;
database& db()const;
protected:
transaction_evaluation_state* trx_state;
};
class op_evaluator
{
public:
virtual ~op_evaluator(){}
virtual void evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply) = 0;
};
template<typename T>
class op_evaluator_impl : public op_evaluator
{
public:
virtual void evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply = true) override
{
T eval;
eval.start_evaluate(eval_state, op, apply);
}
};
template<typename DerivedEvaluator>
class evaluator : public generic_evaluator
{
public:
virtual int get_type()const override { return operation::tag<typename DerivedEvaluator::operation_type>::value; }
virtual void evaluate(const operation& o) final override
{
auto* eval = static_cast<DerivedEvaluator*>(this);
const auto& op = o.get<typename DerivedEvaluator::operation_type>();
eval->do_evaluate(op);
}
virtual void apply(const operation& o) final override
{
auto* eval = static_cast<DerivedEvaluator*>(this);
const auto& op = o.get<typename DerivedEvaluator::operation_type>();
eval->do_apply(op);
}
};
} }
/*
* 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 <eos/chain/protocol/base.hpp>
namespace eos { namespace chain {
/**
* @ingroup operations
*
* Defines the set of valid operations as a discriminated union type.
*/
typedef fc::static_variant<
// List all operations known to chain here
> operation;
/// @} // operations group
void operation_validate( const operation& op );
} } // eos::chain
FC_REFLECT_TYPENAME( eos::chain::operation )
......@@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
#pragma once
#include <eos/chain/protocol/operations.hpp>
#include <eos/chain/protocol/types.hpp>
#include <numeric>
......@@ -82,7 +81,7 @@ namespace eos { namespace chain {
*/
fc::time_point_sec expiration;
vector<operation> operations;
vector<string> messages;
/// Calculate the digest for a transaction
digest_type digest()const;
......@@ -113,8 +112,8 @@ namespace eos { namespace chain {
vector<signature_type> signatures;
/// Removes all operations and signatures
void clear() { operations.clear(); signatures.clear(); }
/// Removes all messages and signatures
void clear() { messages.clear(); signatures.clear(); }
digest_type merkle_digest()const;
};
......@@ -123,5 +122,5 @@ namespace eos { namespace chain {
} } // eos::chain
FC_REFLECT( eos::chain::transaction, (ref_block_num)(ref_block_prefix)(expiration)(operations) )
FC_REFLECT( eos::chain::transaction, (ref_block_num)(ref_block_prefix)(expiration)(messages) )
FC_REFLECT_DERIVED( eos::chain::signed_transaction, (eos::chain::transaction), (signatures) )
/*
* 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 <eos/chain/protocol/operations.hpp>
namespace eos { namespace chain {
class database;
struct signed_transaction;
/**
* Place holder for state tracked while processing a transaction. This class provides helper methods that are
* common to many different operations and also tracks which keys have signed the transaction
*/
class transaction_evaluation_state
{
public:
transaction_evaluation_state( database* db = nullptr )
:_db(db){}
database& db()const { assert( _db ); return *_db; }
const signed_transaction* _trx = nullptr;
database* _db = nullptr;
bool _is_proposed_trx = false;
};
} } // namespace eos::chain
/*
* 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 <eos/chain/protocol/operations.hpp>
namespace eos { namespace chain {
/**
* @brief Used to validate operations in a polymorphic manner
*/
struct operation_validator
{
typedef void result_type;
template<typename T>
void operator()( const T& v )const { v.validate(); }
};
void operation_validate( const operation& op )
{
op.visit( operation_validator() );
}
} } // namespace eos::chain
......@@ -46,9 +46,8 @@ digest_type transaction::sig_digest( const chain_id_type& chain_id )const
void transaction::validate() const
{
FC_ASSERT( operations.size() > 0, "A transaction must have at least one operation", ("trx",*this) );
for( const auto& op : operations )
operation_validate(op);
FC_ASSERT( messages.size() > 0, "A transaction must have at least one message", ("trx",*this) );
#warning TODO: Figure out how to validate trxs
}
eos::chain::transaction_id_type eos::chain::transaction::id() const
......
add_subdirectory( build_helpers )
add_subdirectory( producer_node )
add_subdirectory( debug_node )
add_subdirectory( size_checker )
add_executable( size_checker main.cpp )
if( UNIX AND NOT APPLE )
set(rt_library rt )
endif()
target_link_libraries( size_checker
PRIVATE eos_chain eos_egenesis_none fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} )
install( TARGETS
size_checker
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
/*
* 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 <fc/io/json.hpp>
#include <fc/smart_ref_impl.hpp>
#include <fc/variant.hpp>
#include <fc/variant_object.hpp>
#include <eos/chain/protocol/protocol.hpp>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace eos::chain;
vector< fc::variant_object > g_op_types;
template< typename T >
uint64_t get_wire_size()
{
T data;
return fc::raw::pack( data ).size();
}
struct size_check_type_visitor
{
typedef void result_type;
int t = 0;
size_check_type_visitor(int _t ):t(_t){}
template<typename Type>
result_type operator()( const Type& op )const
{
fc::mutable_variant_object vo;
vo["name"] = fc::get_typename<Type>::name();
vo["mem_size"] = sizeof( Type );
vo["wire_size"] = get_wire_size<Type>();
g_op_types.push_back( vo );
}
};
int main( int argc, char** argv )
{
try
{
eos::chain::operation op;
vector<uint64_t> produceres; produceres.resize(50);
for( uint32_t i = 0; i < 60*60*24*30; ++i )
{
produceres[ rand() % 50 ]++;
}
std::sort( produceres.begin(), produceres.end() );
idump((produceres.back() - produceres.front()) );
idump((60*60*24*30/50));
idump(("deviation: ")((60*60*24*30/50-produceres.front())/(60*60*24*30/50.0)));
idump( (produceres) );
for( int32_t i = 0; i < op.count(); ++i )
{
op.set_which(i);
op.visit( size_check_type_visitor(i) );
}
// sort them by mem size
std::stable_sort( g_op_types.begin(), g_op_types.end(),
[](const variant_object& oa, const variant_object& ob) {
return oa["mem_size"].as_uint64() > ob["mem_size"].as_uint64();
});
std::cout << "[\n";
for( size_t i=0; i<g_op_types.size(); i++ )
{
std::cout << " " << fc::json::to_string( g_op_types[i] );
if( i < g_op_types.size()-1 )
std::cout << ",\n";
else
std::cout << "\n";
}
std::cout << "]\n";
std::cerr << "Size of block header: " << sizeof( block_header ) << " " << fc::raw::pack_size( block_header() ) << "\n";
}
catch ( const fc::exception& e ){ edump((e.to_detail_string())); }
idump((sizeof(signed_block)));
idump((fc::raw::pack_size(signed_block())));
return 0;
}
......@@ -79,7 +79,7 @@ genesis_state_type&testing_fixture::genesis_state() {
private_key_type testing_fixture::get_private_key(const public_key_type& public_key) const {
auto itr = key_ring.find(public_key);
EOS_ASSERT(itr != key_ring.end(), testing_exception,
EOS_ASSERT(itr != key_ring.end(), missing_key_exception,
"Private key corresponding to public key ${k} not known.", ("k", public_key));
return itr->second;
}
......
......@@ -26,6 +26,7 @@
#include <eos/app/application.hpp>
#include <eos/chain/database.hpp>
#include <eos/chain/producer_object.hpp>
#include <eos/chain/exceptions.hpp>
#include <eos/utilities/tempdir.hpp>
#include <fc/io/json.hpp>
#include <fc/smart_ref_impl.hpp>
......@@ -40,10 +41,6 @@ using namespace eos::chain;
extern uint32_t EOS_TESTING_GENESIS_TIMESTAMP;
namespace eos { namespace chain {
FC_DECLARE_EXCEPTION(testing_exception, 6000000, "test framework exception")
} }
#define TEST_DB_SIZE (1024*1024*10)
#define EOS_REQUIRE_THROW( expr, exc_type ) \
......@@ -83,6 +80,8 @@ FC_DECLARE_EXCEPTION(testing_exception, 6000000, "test framework exception")
}
namespace eos { namespace chain {
FC_DECLARE_EXCEPTION(testing_exception, 6000000, "test framework exception")
FC_DECLARE_DERIVED_EXCEPTION(missing_key_exception, eos::chain::testing_exception, 6010000, "key could not be found")
/**
* @brief The testing_fixture class provides various services relevant to testing the database.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册