提交 596244e1 编写于 作者: D Daniel Larimer

add context free api

上级 27b89b2d
......@@ -36,11 +36,14 @@ namespace eosio {
time expiration;
region_id region;
uint16_t ref_block_num;
uint32_t ref_block_id;
uint32_t ref_block_prefix;
uint16_t packed_bandwidth_words = 0; /// number of 8 byte words this transaction can compress into
uint16_t context_free_cpu_bandwidth = 0; /// number of CPU usage units to bill transaction for
vector<action> context_free_actions;
vector<action> actions;
EOSLIB_SERIALIZE( transaction, (expiration)(region)(ref_block_num)(ref_block_id)(actions) );
EOSLIB_SERIALIZE( transaction, (expiration)(region)(ref_block_num)(ref_block_prefix)(packed_bandwidth_words)(context_free_cpu_bandwidth)(context_free_actions)(actions) );
};
class deferred_transaction : public transaction {
......
......@@ -304,6 +304,45 @@ void apply_context::update_db_usage( const account_name& payer, int64_t delta )
}
int apply_context::get_action( uint32_t type, uint32_t index, char* buffer, size_t buffer_size )const
{
const transaction& trx = trx_meta.trx();
const action* act = nullptr;
if( type == 0 ) {
if( index >= trx.context_free_actions.size() )
return -1;
act = &trx.context_free_actions[index];
}
else if( type == 1 ) {
if( index >= trx.actions.size() )
return -1;
act = &trx.actions[index];
}
auto ps = fc::raw::pack_size( *act );
if( ps <= buffer_size ) {
fc::datastream<char*> ds(buffer, buffer_size);
fc::raw::pack( ds, *act );
}
return ps;
}
int apply_context::get_context_free_data( uint32_t index, char* buffer, size_t buffer_size )const {
if( index >= trx_meta.context_free_data.size() ) return -1;
auto s = trx_meta.context_free_data[index].size();
if( buffer_size == 0 ) return s;
if( buffer_size < s )
memcpy( buffer, trx_meta.context_free_data.data(), buffer_size );
else
memcpy( buffer, trx_meta.context_free_data.data(), s );
return s;
}
int apply_context::db_store_i64( uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) {
require_write_lock( scope );
const auto& tab = find_or_create_table( receiver, scope, table );
......
......@@ -1406,9 +1406,23 @@ static void log_handled_exceptions(const transaction& trx) {
transaction_trace chain_controller::__apply_transaction( transaction_metadata& meta ) {
transaction_trace result(meta.id);
for (const auto &act : meta.trx().context_free_actions) {
FC_ASSERT( act.authorization.size() == 0, "context free actions cannot require authorization" );
apply_context context(*this, _db, act, meta);
context.context_free = true;
context.exec();
fc::move_append(result.action_traces, std::move(context.results.applied_actions));
FC_ASSERT( result.deferred_transactions.size() == 0 );
FC_ASSERT( result.canceled_deferred.size() == 0 );
}
for (const auto &act : meta.trx().actions) {
apply_context context(*this, _db, act, meta);
context.exec();
context.used_context_free_api |= act.authorization.size();
FC_ASSERT( context.used_context_free_api, "action did not reference database state, it should be moved to context_free_actions", ("act",act) );
fc::move_append(result.action_traces, std::move(context.results.applied_actions));
fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));
fc::move_append(result.canceled_deferred, std::move(context.results.canceled_deferred));
......
......@@ -389,7 +389,9 @@ class apply_context {
const chainbase::database& db; ///< database where state is stored
const action& act; ///< message being applied
account_name receiver; ///< the code that is currently running
bool privileged = false;
bool privileged = false;
bool context_free = false;
bool used_context_free_api = false;
chain_controller& mutable_controller;
chainbase::database& mutable_db;
......@@ -425,6 +427,9 @@ class apply_context {
void checktime(uint32_t instruction_count) const;
int get_action( uint32_t type, uint32_t index, char* buffer, size_t buffer_size )const;
int get_context_free_data( uint32_t index, char* buffer, size_t buffer_size )const;
void update_db_usage( const account_name& payer, int64_t delta );
int db_store_i64( uint64_t scope, uint64_t table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size );
void db_update_i64( int iterator, account_name payer, const char* buffer, size_t buffer_size );
......
......@@ -115,6 +115,8 @@ namespace eosio { namespace chain {
uint16_t region = 0; ///< the computational memory region this transaction applies to.
uint16_t ref_block_num = 0; ///< specifies a block num in the last 2^16 blocks.
uint32_t ref_block_prefix = 0; ///< specifies the lower 32 bits of the blockid at get_ref_blocknum
uint16_t packed_bandwidth_words = 0; /// number of 8 byte words this transaction can compress into
uint16_t context_free_cpu_bandwidth = 0; /// number of CPU usage units to bill transaction for
/**
* @return the absolute block number given the relative ref_block_num
......@@ -132,6 +134,7 @@ namespace eosio { namespace chain {
* read and write scopes.
*/
struct transaction : public transaction_header {
vector<action> context_free_actions;
vector<action> actions;
transaction_id_type id()const;
......@@ -152,6 +155,7 @@ namespace eosio { namespace chain {
}
vector<signature_type> signatures;
vector<vector<char>> context_free_data; ///< for each context-free action, there is an entry here
const signature_type& sign(const private_key_type& key, const chain_id_type& chain_id);
signature_type sign(const private_key_type& key, const chain_id_type& chain_id)const;
......@@ -252,9 +256,9 @@ namespace eosio { namespace chain {
FC_REFLECT( eosio::chain::permission_level, (actor)(permission) )
FC_REFLECT( eosio::chain::action, (account)(name)(authorization)(data) )
FC_REFLECT( eosio::chain::transaction_header, (expiration)(region)(ref_block_num)(ref_block_prefix) )
FC_REFLECT_DERIVED( eosio::chain::transaction, (eosio::chain::transaction_header), (actions) )
FC_REFLECT_DERIVED( eosio::chain::signed_transaction, (eosio::chain::transaction), (signatures) )
FC_REFLECT( eosio::chain::transaction_header, (expiration)(region)(ref_block_num)(ref_block_prefix)(packed_bandwidth_words)(context_free_cpu_bandwidth) )
FC_REFLECT_DERIVED( eosio::chain::transaction, (eosio::chain::transaction_header), (context_free_actions)(actions) )
FC_REFLECT_DERIVED( eosio::chain::signed_transaction, (eosio::chain::transaction), (signatures)(context_free_data) )
FC_REFLECT_ENUM( eosio::chain::packed_transaction::compression_type, (none)(zlib))
FC_REFLECT( eosio::chain::packed_transaction, (signatures)(compression)(data) )
FC_REFLECT_DERIVED( eosio::chain::deferred_transaction, (eosio::chain::transaction), (sender_id)(sender)(execute_after) )
......
......@@ -27,6 +27,7 @@ class transaction_metadata {
// things for packed_transaction
optional<bytes> raw_trx;
optional<transaction> decompressed_trx;
vector<vector<char>> context_free_data;
// things for signed/packed transactions
optional<flat_set<public_key_type>> signing_keys;
......
......@@ -408,10 +408,15 @@ namespace eosio { namespace chain {
class context_aware_api {
public:
context_aware_api(wasm_interface& wasm)
:context(intrinsics_accessor::get_context(wasm).context), code(intrinsics_accessor::get_context(wasm).code),
sbrk_bytes(intrinsics_accessor::get_context(wasm).sbrk_bytes)
{}
context_aware_api(wasm_interface& wasm, bool context_free = false )
:sbrk_bytes(intrinsics_accessor::get_context(wasm).sbrk_bytes),
code(intrinsics_accessor::get_context(wasm).code),
context(intrinsics_accessor::get_context(wasm).context)
{
if( context.context_free )
FC_ASSERT( context_free, "only context free api's can be used in this context" );
context.used_context_free_api |= !context_free;
}
protected:
uint32_t& sbrk_bytes;
......@@ -419,6 +424,18 @@ class context_aware_api {
apply_context& context;
};
class context_free_api : public context_aware_api {
public:
context_free_api( wasm_interface& wasm )
:context_aware_api(wasm, true) {
/* the context_free_data is not available during normal application because it is prunable */
FC_ASSERT( context.context_free, "this API may only be called from context_free apply" );
}
int get_context_free_data( uint32_t index, array_ptr<char> buffer, size_t buffer_size )const {
return context.get_context_free_data( index, buffer, buffer_size );
}
};
class privileged_api : public context_aware_api {
public:
privileged_api( wasm_interface& wasm )
......@@ -909,7 +926,8 @@ class db_index_api : public context_aware_api {
class memory_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
memory_api( wasm_interface& wasm )
:context_aware_api(wasm,true){}
char* memcpy( array_ptr<char> dest, array_ptr<const char> src, size_t length) {
return (char *)::memcpy(dest, src, length);
......@@ -966,6 +984,36 @@ class transaction_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
void send_inline( array_ptr<char> data, size_t data_len ) {
// TODO: use global properties object for dynamic configuration of this default_max_gen_trx_size
FC_ASSERT( data_len < config::default_max_inline_action_size, "inline action too big" );
action act;
fc::raw::unpack<action>(data, data_len, act);
context.execute_inline(std::move(act));
}
void send_deferred( uint32_t sender_id, const fc::time_point_sec& execute_after, array_ptr<char> data, size_t data_len ) {
try {
// TODO: use global properties object for dynamic configuration of this default_max_gen_trx_size
FC_ASSERT(data_len < config::default_max_gen_trx_size, "generated transaction too big");
deferred_transaction dtrx;
fc::raw::unpack<transaction>(data, data_len, dtrx);
dtrx.sender = context.receiver;
dtrx.sender_id = sender_id;
dtrx.execute_after = execute_after;
context.execute_deferred(std::move(dtrx));
} FC_CAPTURE_AND_RETHROW((fc::to_hex(data, data_len)));
}
};
class context_free_transaction_api : public context_aware_api {
public:
context_free_transaction_api( wasm_interface& wasm )
:context_aware_api(wasm,true){}
int read_transaction( array_ptr<char> data, size_t data_len ) {
bytes trx = context.get_packed_transaction();
if (data_len >= trx.size()) {
......@@ -989,28 +1037,8 @@ class transaction_api : public context_aware_api {
return context.trx_meta.trx().ref_block_prefix;
}
void send_inline( array_ptr<char> data, size_t data_len ) {
// TODO: use global properties object for dynamic configuration of this default_max_gen_trx_size
FC_ASSERT( data_len < config::default_max_inline_action_size, "inline action too big" );
action act;
fc::raw::unpack<action>(data, data_len, act);
context.execute_inline(std::move(act));
}
void send_deferred( uint32_t sender_id, const fc::time_point_sec& execute_after, array_ptr<char> data, size_t data_len ) {
try {
// TODO: use global properties object for dynamic configuration of this default_max_gen_trx_size
FC_ASSERT(data_len < config::default_max_gen_trx_size, "generated transaction too big");
deferred_transaction dtrx;
fc::raw::unpack<transaction>(data, data_len, dtrx);
dtrx.sender = context.receiver;
dtrx.sender_id = sender_id;
dtrx.execute_after = execute_after;
context.execute_deferred(std::move(dtrx));
} FC_CAPTURE_AND_RETHROW((fc::to_hex(data, data_len)));
int get_action( uint32_t type, uint32_t index, array_ptr<char> buffer, size_t buffer_size )const {
return context.get_action( type, index, buffer, buffer_size );
}
};
......@@ -1113,16 +1141,24 @@ REGISTER_INTRINSICS(console_api,
(printhex, void(int, int) )
);
REGISTER_INTRINSICS(transaction_api,
REGISTER_INTRINSICS(context_free_transaction_api,
(read_transaction, int(int, int) )
(transaction_size, int() )
(expiration, int() )
(tapos_block_prefix, int() )
(tapos_block_num, int() )
(get_action, int (int, int, int, int) )
);
REGISTER_INTRINSICS(transaction_api,
(send_inline, void(int, int) )
(send_deferred, void(int, int, int, int) )
);
REGISTER_INTRINSICS(context_free_api,
(get_context_free_data, int(int, int, int) )
)
REGISTER_INTRINSICS(memory_api,
(memcpy, int(int, int, int) )
(memmove, int(int, int, int) )
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册