Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

fixes to contract whitelist/blacklist #3921

Merged
merged 8 commits into from
Jun 7, 2018
4 changes: 2 additions & 2 deletions contracts/eosiolib/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ namespace eosio {
public:
transaction(time_point_sec exp = time_point_sec(now() + 60)) : transaction_header( exp ) {}

void send(uint64_t sender_id, account_name payer, bool replace_existing = false) const {
void send(const uint128_t& sender_id, account_name payer, bool replace_existing = false) const {
auto serialize = pack(*this);
send_deferred(sender_id, payer, serialize.data(), serialize.size(), replace_existing);
}

vector<action> context_free_actions;
vector<action> actions;
extensions_type transaction_extensions;
extensions_type transaction_extensions;

EOSLIB_SERIALIZE_DERIVED( transaction, transaction_header, (context_free_actions)(actions)(transaction_extensions) )
};
Expand Down
8 changes: 4 additions & 4 deletions libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ action_trace apply_context::exec_one()
privileged = a.privileged;
auto native = control.find_apply_handler(receiver, act.account, act.name);
if( native ) {
if( control.is_producing_block() ) {
if( !trx_context.cannot_subjectively_fail && control.is_producing_block() ) {
control.check_contract_list( receiver );
}
(*native)(*this);
Expand All @@ -48,7 +48,7 @@ action_trace apply_context::exec_one()
if( a.code.size() > 0
&& !(act.account == config::system_account_name && act.name == N(setcode) && receiver == config::system_account_name) )
{
if( control.is_producing_block() ) {
if( !trx_context.cannot_subjectively_fail && control.is_producing_block() ) {
control.check_contract_list( receiver );
}
try {
Expand Down Expand Up @@ -375,8 +375,8 @@ int apply_context::get_action( uint32_t type, uint32_t index, char* buffer, size
return -1;
act_ptr = &trx.actions[index];
}
FC_ASSERT(act_ptr, "action is not found" );

FC_ASSERT(act_ptr, "action is not found" );

auto ps = fc::raw::pack_size( *act_ptr );
if( ps <= buffer_size ) {
Expand Down
22 changes: 15 additions & 7 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,10 +492,14 @@ struct controller_impl {

bool failure_is_subjective( const fc::exception& e ) {
auto code = e.code();
return (code == block_net_usage_exceeded::code_value) ||
(code == block_cpu_usage_exceeded::code_value) ||
(code == deadline_exception::code_value) ||
(code == leeway_deadline_exception::code_value);
return (code == block_net_usage_exceeded::code_value)
|| (code == block_cpu_usage_exceeded::code_value)
|| (code == deadline_exception::code_value)
|| (code == leeway_deadline_exception::code_value)
|| (code == actor_whitelist_exception::code_value)
|| (code == actor_blacklist_exception::code_value)
|| (code == contract_whitelist_exception::code_value)
|| (code == contract_blacklist_exception::code_value);
}

transaction_trace_ptr push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline, uint32_t billed_cpu_time_us ) {
Expand Down Expand Up @@ -633,13 +637,14 @@ struct controller_impl {
try {
if( implicit ) {
trx_context.init_for_implicit_trx();
trx_context.cannot_subjectively_fail = true;
} else {
trx_context.init_for_input_trx( trx->packed_trx.get_unprunable_size(),
trx->packed_trx.get_prunable_size(),
trx->trx.signatures.size() );
}

if( !implicit && pending->_block_status == controller::block_status::incomplete ) {
if( !trx_context.cannot_subjectively_fail && pending->_block_status == controller::block_status::incomplete ) {
check_actor_list( trx_context.bill_to_accounts ); // Assumes bill_to_accounts is the set of actors authorizing the transaction
}

Expand Down Expand Up @@ -791,10 +796,13 @@ struct controller_impl {
auto& pt = receipt.trx.get<packed_transaction>();
auto mtrx = std::make_shared<transaction_metadata>(pt);
push_transaction( mtrx, fc::time_point::maximum(), false, receipt.cpu_usage_us );
}
else if( receipt.trx.contains<transaction_id_type>() ) {
} else if( receipt.trx.contains<transaction_id_type>() ) {
push_scheduled_transaction( receipt.trx.get<transaction_id_type>(), fc::time_point::maximum(), receipt.cpu_usage_us );
}
const transaction_receipt_header& r = pending->_pending_block_state->block->transactions.back();
FC_ASSERT( r == static_cast<const transaction_receipt_header&>(receipt),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be made into an EOS_ASSERT with a proper type

"receipt does not match",
("producer_receipt", receipt)("validator_receipt", pending->_pending_block_state->block->transactions.back()) );
}

finalize_block();
Expand Down
4 changes: 4 additions & 0 deletions libraries/chain/include/eosio/chain/block.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ namespace eosio { namespace chain {
transaction_receipt_header():status(hard_fail){}
transaction_receipt_header( status_enum s ):status(s){}

friend inline bool operator ==( const transaction_receipt_header& lhs, const transaction_receipt_header& rhs ) {
return std::tie(lhs.status, lhs.cpu_usage_us, lhs.net_usage_words) == std::tie(rhs.status, rhs.cpu_usage_us, rhs.net_usage_words);
}

fc::enum_type<uint8_t,status_enum> status;
uint32_t cpu_usage_us; ///< total billed CPU usage (microseconds)
fc::unsigned_int net_usage_words; ///< total billed NET usage, so we can reconstruct resource state when skipping context free data... hard failures...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ namespace eosio { namespace chain {
fc::microseconds delay;
bool is_input = false;
bool apply_context_free = true;
bool cannot_subjectively_fail = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The double negative name is probably more confusing than an alternative like can_subjectively_fail = true/false. I realize that will invert all the usages of it but there were enough "Not cannot" checks that I got concerned


fc::time_point deadline = fc::time_point::maximum();
fc::microseconds leeway = fc::microseconds(3000);
Expand Down
9 changes: 7 additions & 2 deletions libraries/testing/include/eosio/testing/tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ namespace eosio { namespace testing {

vector<char> get_row_by_account( uint64_t code, uint64_t scope, uint64_t table, const account_name& act );

map<account_name, block_id_type> get_last_produced_block_map()const { return last_produced_block; };
void set_last_produced_block_map( const map<account_name, block_id_type>& lpb ) { last_produced_block = lpb; }

static vector<uint8_t> to_uint8_vector(const string& s);

static vector<uint8_t> to_uint8_vector(uint64_t x);
Expand Down Expand Up @@ -303,7 +306,8 @@ namespace eosio { namespace testing {
public:
virtual ~validating_tester() {
try {
produce_block();
if( num_blocks_to_producer_before_shutdown > 0 )
produce_blocks( num_blocks_to_producer_before_shutdown );
BOOST_REQUIRE_EQUAL( validate(), true );
} catch( const fc::exception& e ) {
wdump((e.to_detail_string()));
Expand Down Expand Up @@ -385,7 +389,8 @@ namespace eosio { namespace testing {
return ok;
}

unique_ptr<controller> validating_node;
unique_ptr<controller> validating_node;
uint32_t num_blocks_to_producer_before_shutdown = 0;
};

/**
Expand Down
22 changes: 22 additions & 0 deletions scripts/abigen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash

if (( $# < 3 )); then
echo "$0 SOURCE_DIR BUILD_DIR ARGS..."
exit 0
fi

function get_absolute_dir_path() {
pushd $1 > /dev/null
echo $PWD
popd > /dev/null
}

SOURCE_DIR=$(get_absolute_dir_path $1)

BUILD_DIR=$2

shift; shift

#echo "Source directory: ${SOURCE_DIR}"

eval "${BUILD_DIR}/programs/eosio-abigen/eosio-abigen -extra-arg=--std=c++14 -extra-arg=--target=wasm32 -extra-arg=\"-I${SOURCE_DIR}/contracts/libc++/upstream/include\" -extra-arg=\"-I${SOURCE_DIR}/contracts/musl/upstream/include\" -extra-arg=\"-I${SOURCE_DIR}/externals/magic_get/include\" -extra-arg=\"-I${SOURCE_DIR}/contracts\" $@"
3 changes: 3 additions & 0 deletions unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ link_directories(${LLVM_LIBRARY_DIR})

set( CMAKE_CXX_STANDARD 14 )

add_subdirectory(contracts)

include_directories("${CMAKE_BINARY_DIR}/contracts")
include_directories("${CMAKE_SOURCE_DIR}/contracts")
include_directories("${CMAKE_BINARY_DIR}/unittests/contracts")
include_directories("${CMAKE_SOURCE_DIR}/unittests/contracts")
include_directories("${CMAKE_SOURCE_DIR}/libraries/testing/include")

Expand Down
7 changes: 7 additions & 0 deletions unittests/contracts/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# will be implictly used for any compilation unit if not overrided by SYSTEM_INCLUDE_FOLDERS parameter
# these directories go as -isystem <dir> to avoid warnings from code of third-party libraries
set(DEFAULT_SYSTEM_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts/libc++/upstream/include ${CMAKE_SOURCE_DIR}/contracts/musl/upstream/include ${Boost_INCLUDE_DIR})

set(STANDARD_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts ${CMAKE_SOURCE_DIR}/unittests/contracts ${CMAKE_SOURCE_DIR}/externals/magic_get/include)

add_subdirectory(deferred_test)
8 changes: 8 additions & 0 deletions unittests/contracts/deferred_test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
file(GLOB ABI_FILES "*.abi")
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)

add_wast_executable(TARGET deferred_test
INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" ${Boost_INCLUDE_DIR}
LIBRARIES libc++ libc eosiolib
DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR}
)
45 changes: 45 additions & 0 deletions unittests/contracts/deferred_test/deferred_test.abi
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"version": "eosio::abi/1.0",
"types": [],
"structs": [{
"name": "defercall",
"base": "",
"fields": [{
"name": "payer",
"type": "name"
},{
"name": "sender_id",
"type": "uint64"
},{
"name": "contract",
"type": "name"
},{
"name": "payload",
"type": "uint64"
}
]
},{
"name": "deferfunc",
"base": "",
"fields": [{
"name": "payload",
"type": "uint64"
}
]
}
],
"actions": [{
"name": "defercall",
"type": "defercall",
"ricardian_contract": ""
},{
"name": "deferfunc",
"type": "deferfunc",
"ricardian_contract": ""
}
],
"tables": [],
"ricardian_clauses": [],
"error_messages": [],
"abi_extensions": []
}
60 changes: 60 additions & 0 deletions unittests/contracts/deferred_test/deferred_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/

#include <eosiolib/eosio.hpp>
#include <eosiolib/transaction.hpp>
#include <eosiolib/dispatcher.hpp>

using namespace eosio;

class deferred_test : public eosio::contract {
public:
using contract::contract;

struct deferfunc_args {
uint64_t payload;
};

//@abi action
void defercall( account_name payer, uint64_t sender_id, account_name contract, uint64_t payload ) {
print( "defercall called on ", name{_self}, "\n" );
require_auth( payer );

print( "deferred send of deferfunc action to ", name{contract}, " by ", name{payer}, " with sender id ", sender_id );
transaction trx;
deferfunc_args a = {.payload = payload};
trx.actions.emplace_back(permission_level{_self, N(active)}, contract, N(deferfunc), a);
trx.send( (static_cast<uint128_t>(payer) << 64) | sender_id, payer);
}

//@abi action
void deferfunc( uint64_t payload ) {
print("deferfunc called on ", name{_self}, "\n");
}

private:
};

void apply_onerror(uint64_t receiver, const onerror& error ) {
print("onerror called on ", name{receiver}, "\n");
}

extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t receiver, uint64_t code, uint64_t action ) {
if( code == N(eosio) && action == N(onerror) ) {
apply_onerror( receiver, onerror::from_current_action() );
} else if( code == receiver ) {
deferred_test thiscontract(receiver);
if( action == N(defercall) ) {
execute_action( &thiscontract, &deferred_test::defercall );
} else if( action == N(deferfunc) ) {
execute_action( &thiscontract, &deferred_test::deferfunc );
}
}
}
}

//EOSIO_ABI( deferred_test, (defercall)(deferfunc) )
Loading