Skip to content

Commit

Permalink
check derived output against the outputs encoded in a block. fixes EO…
Browse files Browse the repository at this point in the history
  • Loading branch information
wanderingbort committed Aug 25, 2017
1 parent d54bc83 commit 96ebf95
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 11 deletions.
158 changes: 151 additions & 7 deletions libraries/chain/chain_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,132 @@ void chain_controller::apply_block(const signed_block& next_block, uint32_t skip
});
}

template<typename T>
void check_output(const T& expected, const T& actual) {
EOS_ASSERT((expected == actual), block_tx_output_exception,
"Value mismatch, expected: ${expected}, actual: ${actual}", ("expected", expected)("actual", actual));
}

template<typename T>
void check_output(const vector<T>& expected, const vector<T>& actual) {
EOS_ASSERT((expected.size() == actual.size()), block_tx_output_exception,
"Vector size mismatch, expected: ${expected}, actual: ${actual}", ("expected", expected.size())("actual", actual.size()));

for(int idx=0; idx < expected.size(); idx++) {
const auto &expected_element = expected.at(idx);
const auto &actual_element = actual.at(idx);
try {
check_output(expected_element, actual_element);
} FC_RETHROW_EXCEPTIONS( warn, "at index ${idx}", ("idx", idx ) );
}
}

template<>
void check_output(const types::Bytes& expected, const types::Bytes& actual) {
EOS_ASSERT((expected.size() == actual.size()), block_tx_output_exception,
"Binary blob size mismatch, expected: ${expected}, actual: ${actual}", ("expected", expected.size())("actual", actual.size()));

EOS_ASSERT((std::memcmp(expected.data(), actual.data(), expected.size()) == 0), block_tx_output_exception,
"Binary blob contents differ");
}

template<>
void check_output(const types::AccountPermission& expected, const types::AccountPermission& actual) {
try {
check_output(expected.account, actual.account);
} FC_RETHROW_EXCEPTIONS(warn, "in .account");
try {
check_output(expected.permission, actual.permission);
} FC_RETHROW_EXCEPTIONS(warn, "in .permission");
}

template<>
void check_output(const types::Message& expected, const types::Message& actual) {
try {
check_output(expected.code, actual.code);
} FC_RETHROW_EXCEPTIONS(warn, "in .code");
try {
check_output(expected.type, actual.type);
} FC_RETHROW_EXCEPTIONS(warn, "in .type");
try {
check_output(expected.authorization, actual.authorization);
} FC_RETHROW_EXCEPTIONS(warn, "in .authorization");
try {
check_output(expected.data, actual.data);
} FC_RETHROW_EXCEPTIONS(warn, "in .data");
}

template<>
void check_output(const MessageOutput& expected, const MessageOutput& actual);

template<>
void check_output(const NotifyOutput& expected, const NotifyOutput& actual) {
try {
check_output(expected.name, actual.name);
} FC_RETHROW_EXCEPTIONS(warn, "in .name");
try {
check_output(expected.output, actual.output);
} FC_RETHROW_EXCEPTIONS(warn, "in .output");
}

template<>
void check_output(const Transaction& expected, const Transaction& actual) {
try {
check_output(expected.refBlockNum, actual.refBlockNum);
} FC_RETHROW_EXCEPTIONS(warn, "in .refBlockNum");
try {
check_output(expected.refBlockPrefix, actual.refBlockPrefix);
} FC_RETHROW_EXCEPTIONS(warn, "in .refBlockPrefix");
try {
check_output(expected.expiration, actual.expiration);
} FC_RETHROW_EXCEPTIONS(warn, "in .expiration");
try {
check_output(expected.scope, actual.scope);
} FC_RETHROW_EXCEPTIONS(warn, "in .scope");
try {
check_output(expected.messages, actual.messages);
} FC_RETHROW_EXCEPTIONS(warn, "in .messages");
}


template<>
void check_output(const ProcessedSyncTransaction& expected, const ProcessedSyncTransaction& actual) {
check_output<Transaction>(expected, actual);
try {
check_output(expected.output, actual.output);
} FC_RETHROW_EXCEPTIONS(warn, "in .output");
}

template<>
void check_output(const GeneratedTransaction& expected, const GeneratedTransaction& actual) {
try {
check_output(expected.id, actual.id);
} FC_RETHROW_EXCEPTIONS(warn, "in .id");
check_output<Transaction>(expected, actual);
}

template<>
void check_output(const MessageOutput& expected, const MessageOutput& actual) {
try {
check_output(expected.notify, actual.notify);
} FC_RETHROW_EXCEPTIONS(warn, "in .notify");

try {
check_output(expected.sync_transactions, actual.sync_transactions);
} FC_RETHROW_EXCEPTIONS(warn, "in .sync_transactions");

try {
check_output(expected.async_transactions, actual.async_transactions);
} FC_RETHROW_EXCEPTIONS(warn, "in .async_transactions");
}

template<typename T>
void chain_controller::check_transaction_output(const T& expected, const T& actual)const {
if (!(_skip_flags & skip_output_check)) {
check_output(expected.output, actual.output);
}
}

void chain_controller::_apply_block(const signed_block& next_block)
{ try {
uint32_t next_block_num = next_block.block_num();
Expand All @@ -522,14 +648,32 @@ void chain_controller::_apply_block(const signed_block& next_block)
* for transactions when validating broadcast transactions or
* when building a block.
*/
for (const auto& cycle : next_block.cycles) {
for (const auto& thread : cycle) {
for(const auto& ptrx : thread.generated_input ) {
auto const trx = get_generated_transaction(ptrx.id);
apply_transaction(trx);
for (int c_idx = 0; c_idx < next_block.cycles.size(); c_idx++) {
const auto& cycle = next_block.cycles.at(c_idx);

for (int t_idx = 0; t_idx < cycle.size(); t_idx++) {
const auto& thread = cycle.at(t_idx);

for(int p_idx = 0; p_idx < thread.generated_input.size(); p_idx++ ) {
const auto& ptrx = thread.generated_input.at(p_idx);
const auto& trx = get_generated_transaction(ptrx.id);
auto processed = apply_transaction(trx);
try {
check_transaction_output(ptrx, processed);
} FC_RETHROW_EXCEPTIONS(warn,
"cycle: ${c_idx}, thread: ${t_idx}, generated_input: ${p_idx}",
("c_idx", c_idx)("t_idx", t_idx)("p_idx", p_idx) );
}
for(const auto& trx : thread.user_input ) {
apply_transaction(trx);

for(int p_idx = 0; p_idx < thread.user_input.size(); p_idx++ ) {
const auto& ptrx = thread.user_input.at(p_idx);
const SignedTransaction& trx = ptrx;
auto processed = apply_transaction(trx);
try {
check_transaction_output(ptrx, processed);
} FC_RETHROW_EXCEPTIONS(warn,
"cycle: ${c_idx}, thread: ${t_idx}, user_input: ${p_idx}",
("c_idx", c_idx)("t_idx", t_idx)("p_idx", p_idx) );
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion libraries/chain/include/eos/chain/chain_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ namespace eos { namespace chain {
skip_undo_history_check = 1 << 9, ///< used while reindexing
skip_producer_schedule_check= 1 << 10, ///< used while reindexing
skip_validate = 1 << 11, ///< used prior to checkpoint, skips validate() call on transaction
skip_scope_check = 1 << 12 ///< used to skip checks for proper scope
skip_scope_check = 1 << 12, ///< used to skip checks for proper scope
skip_output_check = 1 << 13 ///< used to skip checks for outputs in block exactly matching those created from apply
};

/**
Expand Down Expand Up @@ -277,6 +278,9 @@ namespace eos { namespace chain {

void check_transaction_authorization(const SignedTransaction& trx, bool allow_unused_signatures = false)const;

template<typename T>
void check_transaction_output(const T& expected, const T& actual)const;

template<typename T>
typename T::Processed apply_transaction(const T& trx);

Expand Down
2 changes: 2 additions & 0 deletions libraries/chain/include/eos/chain/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ 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( block_tx_output_exception, eos::chain::block_validate_exception, 3020001, "transaction outputs in block do not match transaction outputs from applying block" )

FC_DECLARE_DERIVED_EXCEPTION( tx_missing_auth, eos::chain::transaction_exception, 3030001, "missing required authority" )
FC_DECLARE_DERIVED_EXCEPTION( tx_missing_sigs, eos::chain::transaction_exception, 3030002, "signatures do not satisfy declared authorizations" )
FC_DECLARE_DERIVED_EXCEPTION( tx_irrelevant_auth, eos::chain::transaction_exception, 3030003, "irrelevant authority included" )
Expand Down
15 changes: 12 additions & 3 deletions libraries/chain/include/eos/chain/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ namespace eos { namespace chain {
*/

struct ProcessedTransaction;
struct ProcessedSyncTransaction;
struct ProcessedGeneratedTransaction;


Expand Down Expand Up @@ -160,9 +161,9 @@ namespace eos { namespace chain {
* Output generated by applying a particular message.
*/
struct MessageOutput {
vector<NotifyOutput> notify; ///< accounts to notify, may only be notified once
vector<ProcessedTransaction> sync_transactions; ///< transactions generated and applied after notify
vector<GeneratedTransaction> async_transactions; ///< transactions generated but not applied
vector<NotifyOutput> notify; ///< accounts to notify, may only be notified once
vector<ProcessedSyncTransaction> sync_transactions; ///< transactions generated and applied after notify
vector<GeneratedTransaction> async_transactions; ///< transactions generated but not applied
};

struct NotifyOutput {
Expand All @@ -177,6 +178,13 @@ namespace eos { namespace chain {
vector<MessageOutput> output;
};

struct ProcessedSyncTransaction : public Transaction {
explicit ProcessedSyncTransaction( const Transaction& t ):Transaction(t){}
ProcessedSyncTransaction(){}

vector<MessageOutput> output;
};

struct ProcessedGeneratedTransaction {
explicit ProcessedGeneratedTransaction( const generated_transaction_id_type& _id ):id(_id){}
explicit ProcessedGeneratedTransaction( const GeneratedTransaction& t ):id(t.id){}
Expand All @@ -193,5 +201,6 @@ FC_REFLECT(eos::chain::GeneratedTransaction, (id))
FC_REFLECT_DERIVED(eos::chain::SignedTransaction, (eos::types::SignedTransaction), )
FC_REFLECT(eos::chain::MessageOutput, (notify)(sync_transactions)(async_transactions) )
FC_REFLECT_DERIVED(eos::chain::ProcessedTransaction, (eos::types::SignedTransaction), (output) )
FC_REFLECT_DERIVED(eos::chain::ProcessedSyncTransaction, (eos::types::Transaction), (output) )
FC_REFLECT(eos::chain::ProcessedGeneratedTransaction, (id)(output) )
FC_REFLECT(eos::chain::NotifyOutput, (name)(output) )

0 comments on commit 96ebf95

Please sign in to comment.