Skip to content

Commit

Permalink
allow validation of GeneratedTransactions and unify as much code as p…
Browse files Browse the repository at this point in the history
…ossible. ref EOSIO#174
  • Loading branch information
wanderingbort committed Aug 25, 2017
1 parent 54b2387 commit d432b6c
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 125 deletions.
2 changes: 1 addition & 1 deletion libraries/chain/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ namespace eos { namespace chain {
*/

for( const auto& trx : user_input )
ids.push_back( trx.digest() );
ids.push_back( transaction_helpers::digest(trx) );

/**
* When generating the merkle hash of an output transaction we hash it
Expand Down
27 changes: 9 additions & 18 deletions libraries/chain/chain_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
*/

#include <eos/chain/chain_controller.hpp>
#include <eos/chain/exceptions.hpp>

#include <eos/chain/block_summary_object.hpp>
#include <eos/chain/global_property_object.hpp>
Expand Down Expand Up @@ -57,7 +56,6 @@
#include <iostream>

//#include <Wren++.h>

namespace eos { namespace chain {


Expand Down Expand Up @@ -585,18 +583,7 @@ ProcessedTransaction chain_controller::apply_transaction(const SignedTransaction
return with_skip_flags( skip, [&]() { return _apply_transaction(trx); });
}

void chain_controller::validate_transaction(const SignedTransaction& trx)const {
try {
EOS_ASSERT(trx.messages.size() > 0, transaction_exception, "A transaction must have at least one message");

validate_scope(trx);
validate_expiration(trx);
validate_uniqueness(trx);
validate_tapos(trx);

} FC_CAPTURE_AND_RETHROW( (trx) ) }

void chain_controller::validate_scope( const SignedTransaction& trx )const {
void chain_controller::validate_scope( const Transaction& trx )const {
EOS_ASSERT(trx.scope.size() > 0, transaction_exception, "No scope specified by transaction" );
for( uint32_t i = 1; i < trx.scope.size(); ++i )
EOS_ASSERT( trx.scope[i-1] < trx.scope[i], transaction_exception, "Scopes must be sorted and unique" );
Expand Down Expand Up @@ -630,18 +617,22 @@ void chain_controller::validate_uniqueness( const SignedTransaction& trx )const
EOS_ASSERT(transaction == nullptr, tx_duplicate, "Transaction is not unique");
}

void chain_controller::validate_tapos(const SignedTransaction& trx)const {
void chain_controller::validate_uniqueness( const GeneratedTransaction& trx )const {
if( !should_check_for_duplicate_transactions() ) return;
}

void chain_controller::validate_tapos(const Transaction& trx)const {
if (!should_check_tapos()) return;

const auto& tapos_block_summary = _db.get<block_summary_object>((uint16_t)trx.refBlockNum);

//Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
EOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), transaction_exception,
EOS_ASSERT(transaction_helpers::verify_reference_block(trx, tapos_block_summary.block_id), transaction_exception,
"Transaction's reference block did not match. Is this transaction from a different fork?",
("tapos_summary", tapos_block_summary));
}

void chain_controller::validate_referenced_accounts(const SignedTransaction& trx)const {
void chain_controller::validate_referenced_accounts(const Transaction& trx)const {
for (const auto& scope : trx.scope)
require_account(scope);
for (const auto& msg : trx.messages) {
Expand All @@ -651,7 +642,7 @@ void chain_controller::validate_referenced_accounts(const SignedTransaction& trx
}
}

void chain_controller::validate_expiration(const SignedTransaction& trx) const
void chain_controller::validate_expiration(const Transaction& trx) const
{ try {
fc::time_point_sec now = head_block_time();
const BlockchainConfiguration& chain_configuration = get_global_properties().configuration;
Expand Down
25 changes: 19 additions & 6 deletions libraries/chain/include/eos/chain/chain_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <eos/chain/message_handling_contexts.hpp>
#include <eos/chain/chain_initializer_interface.hpp>
#include <eos/chain/chain_administration_interface.hpp>
#include <eos/chain/exceptions.hpp>

#include <fc/log/logger.hpp>

Expand Down Expand Up @@ -282,15 +283,27 @@ namespace eos { namespace chain {

/**
* This method performs some consistency checks on a transaction.
* @return true if the transaction would validate
* @thow transaction_exception if the transaction is invalid
*/
void validate_transaction(const SignedTransaction& trx)const;
template<typename T>
void validate_transaction(const T& trx) const {
try {
EOS_ASSERT(trx.messages.size() > 0, transaction_exception, "A transaction must have at least one message");

validate_scope(trx);
validate_expiration(trx);
validate_uniqueness(trx);
validate_tapos(trx);

} FC_CAPTURE_AND_RETHROW( (trx) ) }

/// Validate transaction helpers @{
void validate_uniqueness(const SignedTransaction& trx)const;
void validate_tapos(const SignedTransaction& trx)const;
void validate_referenced_accounts(const SignedTransaction& trx)const;
void validate_expiration(const SignedTransaction& trx) const;
void validate_scope(const SignedTransaction& trx) const;
void validate_uniqueness(const GeneratedTransaction& trx)const;
void validate_tapos(const Transaction& trx)const;
void validate_referenced_accounts(const Transaction& trx)const;
void validate_expiration(const Transaction& trx) const;
void validate_scope(const Transaction& trx) const;
/// @}

/**
Expand Down
75 changes: 50 additions & 25 deletions libraries/chain/include/eos/chain/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,49 @@ namespace eos { namespace chain {
* @{
*/



/**
* @brief A base transaction without any explicit or implied authorizations.
*
* This is a utility class for sharing common operations between inheriting types which defines
* additional features and requirements.
*/
namespace transaction_helpers {
/// Calculate the digest for a transaction
digest_type digest(const Transaction& t);

void set_reference_block(Transaction& t, const block_id_type& reference_block);

bool verify_reference_block(const Transaction& t, const block_id_type& reference_block);

template <typename T>
void set_message(Transaction& t, int index, const types::FuncName& type, T&& value) {
Message m(t.messages[index]);
m.set(type, std::forward<T>(value));
t.messages[index] = m;
}

template <typename T>
T message_as(Transaction& t, int index) {
Message m(t.messages[index]);
return m.as<T>();
}

template <typename... Args>
void emplace_message(Transaction& t, Args&&... a) {
t.messages.emplace_back(Message(std::forward<Args>(a)...));
}

/**
* clear all common data
*/
inline
void clear(Transaction& t) {
t.messages.clear();
}
}

/**
* @brief A generated_transaction is a transaction which was internally generated by the blockchain, typically as a
* result of running a contract.
Expand All @@ -65,7 +108,7 @@ namespace eos { namespace chain {
* sequential ID, then stored in the block that generated them. These generated transactions can then be included in
* subsequent blocks by referencing this ID.
*/
struct GeneratedTransaction : public Transaction {
struct GeneratedTransaction : public types::Transaction {
generated_transaction_id_type id;

digest_type merkle_digest() const;
Expand All @@ -78,17 +121,15 @@ namespace eos { namespace chain {
* and the signatures backing those authorizations.
*/
struct SignedTransaction : public types::SignedTransaction {
using types::SignedTransaction::SignedTransaction;
typedef types::SignedTransaction super;
using super::super;

/// Calculate the digest for a transaction
digest_type digest()const;
/// Calculate the id of the transaction
transaction_id_type id()const;

/// Calculate the digest used for signature validation
digest_type sig_digest(const chain_id_type& chain_id)const;

void set_reference_block(const block_id_type& reference_block);
bool verify_reference_block(const block_id_type& reference_block)const;

/** signs and appends to signatures */
const signature_type& sign(const private_key_type& key, const chain_id_type& chain_id);

Expand All @@ -97,28 +138,12 @@ namespace eos { namespace chain {

flat_set<public_key_type> get_signature_keys(const chain_id_type& chain_id)const;

template <typename T>
void setMessage(int messageIndex, const types::FuncName& type, T&& value) {
Message m(messages[messageIndex]);
m.set(type, std::forward<T>(value));
messages[messageIndex] = m;
}
template <typename T>
T messageAs(int messageIndex) {
Message m(messages[messageIndex]);
return m.as<T>();
}
template <typename... Args>
void emplaceMessage(Args&&... a) {
messages.emplace_back(Message(std::forward<Args>(a)...));
}

/**
* Removes all messages, signatures, and authorizations
*/
void clear() { messages.clear(); signatures.clear(); }
void clear() { transaction_helpers::clear(*this); signatures.clear(); }

digest_type merkle_digest()const;
digest_type merkle_digest() const;
};

struct ProcessedTransaction;
Expand Down
30 changes: 17 additions & 13 deletions libraries/chain/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,26 @@

namespace eos { namespace chain {

digest_type SignedTransaction::digest()const {
namespace transaction_helpers {

digest_type digest(const Transaction& t) {
digest_type::encoder enc;
fc::raw::pack( enc, static_cast<const types::Transaction&>(*this) );
fc::raw::pack( enc, t );
return enc.result();
}

void set_reference_block(Transaction& t, const block_id_type& reference_block) {
t.refBlockNum = fc::endian_reverse_u32(reference_block._hash[0]);
t.refBlockPrefix = reference_block._hash[1];
}

bool verify_reference_block(const Transaction& t, const block_id_type& reference_block) {
return t.refBlockNum == (decltype(t.refBlockNum))fc::endian_reverse_u32(reference_block._hash[0]) &&
t.refBlockPrefix == (decltype(t.refBlockPrefix))reference_block._hash[1];
}

} // namespace transaction_helpers

digest_type SignedTransaction::sig_digest( const chain_id_type& chain_id )const {
digest_type::encoder enc;
fc::raw::pack( enc, chain_id );
Expand All @@ -45,7 +59,7 @@ digest_type SignedTransaction::sig_digest( const chain_id_type& chain_id )const
}

eos::chain::transaction_id_type SignedTransaction::id() const {
auto h = digest();
auto h = transaction_helpers::digest(*this);
transaction_id_type result;
memcpy(result._hash, h._hash, std::min(sizeof(result), sizeof(h)));
return result;
Expand All @@ -60,16 +74,6 @@ signature_type eos::chain::SignedTransaction::sign(const private_key_type& key,
return key.sign_compact(sig_digest(chain_id));
}

void SignedTransaction::set_reference_block(const block_id_type& reference_block) {
refBlockNum = fc::endian_reverse_u32(reference_block._hash[0]);
refBlockPrefix = reference_block._hash[1];
}

bool SignedTransaction::verify_reference_block(const block_id_type& reference_block) const {
return refBlockNum == (decltype(refBlockNum))fc::endian_reverse_u32(reference_block._hash[0]) &&
refBlockPrefix == (decltype(refBlockPrefix))reference_block._hash[1];
}

flat_set<public_key_type> SignedTransaction::get_signature_keys( const chain_id_type& chain_id )const
{ try {
using boost::adaptors::transformed;
Expand Down
10 changes: 5 additions & 5 deletions programs/eosc/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ eos::chain_apis::read_only::get_info_results get_info() {
fc::variant push_transaction( SignedTransaction& trx ) {
auto info = get_info();
trx.expiration = info.head_block_time + 100; //chain.head_block_time() + 100;
trx.set_reference_block(info.head_block_id);
transaction_helpers::set_reference_block(trx, info.head_block_id);
boost::sort( trx.scope );

return call( push_txn_func, trx );
Expand All @@ -127,7 +127,7 @@ void create_account( const vector<string>& cmd_line ) {

SignedTransaction trx;
trx.scope = sort_names({creator,eosaccnt});
trx.emplaceMessage(config::EosContractName, vector<types::AccountPermission>{{creator,"active"}}, "newaccount",
transaction_helpers::emplace_message(trx, config::EosContractName, vector<types::AccountPermission>{{creator,"active"}}, "newaccount",
types::newaccount{creator, newaccount, owner_auth,
active_auth, recovery_auth, deposit});

Expand Down Expand Up @@ -308,7 +308,7 @@ int send_command (const vector<string> &cmd_line)

SignedTransaction trx;
trx.scope = { config::EosContractName, account };
trx.emplaceMessage( config::EosContractName, vector<types::AccountPermission>{{account,"active"}},
transaction_helpers::emplace_message(trx, config::EosContractName, vector<types::AccountPermission>{{account,"active"}},
"setcode", handler );

std::cout << fc::json::to_pretty_string( push_transaction(trx) ) << std::endl;
Expand All @@ -322,11 +322,11 @@ int send_command (const vector<string> &cmd_line)

SignedTransaction trx;
trx.scope = sort_names({sender,recipient});
trx.emplaceMessage(config::EosContractName, vector<types::AccountPermission>{{sender,"active"}}, "transfer",
transaction_helpers::emplace_message(trx, config::EosContractName, vector<types::AccountPermission>{{sender,"active"}}, "transfer",
types::transfer{sender, recipient, amount});
auto info = get_info();
trx.expiration = info.head_block_time + 100; //chain.head_block_time() + 100;
trx.set_reference_block(info.head_block_id);
transaction_helpers::set_reference_block(trx, info.head_block_id);

std::cout << fc::json::to_pretty_string( call( push_txn_func, trx )) << std::endl;
}
Expand Down
8 changes: 4 additions & 4 deletions tests/api_tests/api_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ uint32_t CallFunction( testing_blockchain& chain, const types::Message& msg, con
std::copy(data.begin(), data.end(), std::back_inserter(dest));

//std::cout << "MANDO: " << msg.code << " " << msg.type << std::endl;
trx.emplaceMessage(msg);
transaction_helpers::emplace_message(trx, msg);

trx.expiration = chain.head_block_time() + expiration++;
trx.set_reference_block(chain.head_block_id());
transaction_helpers::set_reference_block(trx, chain.head_block_id());
//idump((trx));
chain.push_transaction(trx);

Expand Down Expand Up @@ -177,9 +177,9 @@ void send_set_code_message(testing_blockchain& chain, types::setcode& handler, A
trx.messages.resize(1);
trx.messages[0].authorization = {{account,"active"}};
trx.messages[0].code = config::EosContractName;
trx.setMessage(0, "setcode", handler);
transaction_helpers::set_message(trx, 0, "setcode", handler);
trx.expiration = chain.head_block_time() + 100;
trx.set_reference_block(chain.head_block_id());
transaction_helpers::set_reference_block(trx, chain.head_block_id());
chain.push_transaction(trx);
chain.produce_blocks(1);
}
Expand Down
Loading

0 comments on commit d432b6c

Please sign in to comment.