提交 3ced3f0e 编写于 作者: B Bart Wyatt

merging changes to master at 76c2b3dc

......@@ -20,6 +20,7 @@ matrix:
- libgmp-dev
- libclang-4.0-dev
- python3
- sharutils
- os: osx
osx_image: xcode9.1
before_install:
......
......@@ -138,10 +138,11 @@ macro(add_wast_target target INCLUDE_FOLDERS DESTINATION_FOLDER)
VERBATIM
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.wast)
STRING (REPLACE "." "_" TARGET_VARIABLE "${target}")
add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.wast.hpp
DEPENDS ${DESTINATION_FOLDER}/${target}.wast
COMMAND echo "const char* ${target}_wast = R\"=====(" > ${DESTINATION_FOLDER}/${target}.wast.hpp
COMMAND echo "const char* ${TARGET_VARIABLE}_wast = R\"=====(" > ${DESTINATION_FOLDER}/${target}.wast.hpp
COMMAND cat ${DESTINATION_FOLDER}/${target}.wast >> ${DESTINATION_FOLDER}/${target}.wast.hpp
COMMAND echo ")=====\";" >> ${DESTINATION_FOLDER}/${target}.wast.hpp
COMMENT "Generating ${target}.wast.hpp"
......@@ -151,7 +152,7 @@ macro(add_wast_target target INCLUDE_FOLDERS DESTINATION_FOLDER)
if (EXISTS ${DESTINATION_FOLDER}/${target}.abi )
add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.abi.hpp
DEPENDS ${DESTINATION_FOLDER}/${target}.abi
COMMAND echo "const char* ${target}_abi = R\"=====(" > ${DESTINATION_FOLDER}/${target}.abi.hpp
COMMAND echo "const char* ${TARGET_VARIABLE}_abi = R\"=====(" > ${DESTINATION_FOLDER}/${target}.abi.hpp
COMMAND cat ${DESTINATION_FOLDER}/${target}.abi >> ${DESTINATION_FOLDER}/${target}.abi.hpp
COMMAND echo ")=====\";" >> ${DESTINATION_FOLDER}/${target}.abi.hpp
COMMENT "Generating ${target}.abi.hpp"
......
......@@ -27,7 +27,7 @@ The public testnet described in the [wiki](https://github.com/EOSIO/eos/wiki/Tes
2. [Setting up a build/development environment](#setup)
1. [Automated build script](#autobuild)
1. [Clean install Ubuntu 16.10 for a local testnet](#autoubuntulocal)
2. [Clean install Ubuntu 16.10 for the public testnet](#autobuntupublic)
2. [Clean install Ubuntu 16.10 for the public testnet](#autoubuntupublic)
3. [MacOS Sierra 10.12.6 for a local testnet](#automaclocal)
4. [MacOS Sierra 10.12.6 for the public testnet](#automacpublic)
3. [Building EOS and running a node](#runanode)
......
......@@ -10,7 +10,15 @@
"fields": [
{"name":"from", "type":"account_name"},
{"name":"to", "type":"account_name"},
{"name":"quantity", "type":"uint64"}
{"name":"quantity", "type":"asset"},
{"name":"memo", "type":"string"}
]
},{
"name": "issue",
"base": "",
"fields": [
{"name":"to", "type":"account_name"},
{"name":"quantity", "type":"asset"}
]
},{
"name": "account",
......@@ -24,6 +32,9 @@
"actions": [{
"name": "transfer",
"type": "transfer"
},{
"name": "issue",
"type": "issue"
}
],
"tables": [{
......
......@@ -19,6 +19,34 @@ namespace eosiosystem {
static const account_name system_account = N(eosio.system);
typedef eosio::generic_currency< eosio::token<system_account,S(4,EOS)> > currency;
struct total_bandwidth {
account_name owner;
typename currency::token_type total_net_weight;
typename currency::token_type total_cpu_weight;
};
typedef eosio::table64<SystemAccount, N(totalband), total_bandwidth> total_bandwidth;
struct delegated_bandwidth {
account_name from;
account_name to;
typename currency::token_type net_weight;
typename currency::token_type cpu_weight;
uint32_t start_pending_net_withdraw = 0;
typename currency::token_type pending_net_withdraw;
uint64_t deferred_net_withdraw_handler = 0;
uint32_t start_pending_cpu_withdraw = 0;
typename currency::token_type pending_cpu_withdraw;
uint64_t deferred_cpu_withdraw_handler = 0;
};
ACTION( SystemAccount, finshundel ) {
account_name from;
account_name to;
};
ACTION( SystemAccount, regproducer ) {
account_name producer_to_register;
......@@ -31,6 +59,29 @@ namespace eosiosystem {
EOSLIB_SERIALIZE( regproxy, (proxy_to_register) );
};
ACTION( SystemAccount, delnetbw ) {
account_name from;
account_name receiver;
typename currency::token_type stake_quantity;
EOSLIB_SERIALIZE( delnetbw, (delegator)(receiver)(stake_quantity) )
};
ACTION( SystemAccount, undelnetbw ) {
account_name from;
account_name receiver;
typename currency::token_type stake_quantity;
EOSLIB_SERIALIZE( delnetbw, (delegator)(receiver)(stake_quantity) )
};
static void on( const delnetbw& del ) {
require_auth( del.from );
// require_account( receiver );
currency::inline_transfer( del.from, SystemAccount, del.stake_quantity, "stake bandwidth" );
}
static void on( const regproducer& reg ) {
require_auth( reg.producer_to_register );
}
......@@ -41,15 +92,11 @@ namespace eosiosystem {
static void apply( account_name code, action_name act ) {
if( !eosio::dispatch<contract,
// typename currency::transfer_memo,
// typename currency::issue,
regproducer,
regproxy
>( code, act) )
{
if( !eosio::dispatch<contract, regproducer, regproxy>( code, act) ) {
if ( !eosio::dispatch<currency, typename currency::transfer_memo, typename currency::issue>( code, act ) ) {
assert( false, "received unexpected action" );
}
}
} /// apply
};
......
......@@ -104,7 +104,7 @@ Get information related to an account.
@subsubsection examplegetaccount Example get_account Usage
```
$ curl http://127.0.0.1:8888/v1/chain/get_account -X POST -d '{"name":"inita"}'
$ curl http://127.0.0.1:8888/v1/chain/get_account -X POST -d '{"account_name":"inita"}'
```
@subsubsection examplegetaccountresult Example get_account Result
......
......@@ -22,8 +22,6 @@ add_library( eosio_chain
chain_controller.cpp
contracts/eosio_contract.cpp
contracts/producer_objects.cpp
contracts/staked_balance_objects.cpp
contracts/chain_initializer.cpp
contracts/genesis_state.cpp
contracts/abi_serializer.cpp
......@@ -36,6 +34,7 @@ target_link_libraries( eosio_chain eos_utilities fc chainbase Logging IR WAST WA
target_include_directories( eosio_chain
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include"
"${CMAKE_BINARY_DIR}/contracts"
)
if(MSVC)
......
......@@ -17,6 +17,7 @@ void apply_context::exec_one()
(*native)(*this);
} else {
const auto &a = mutable_controller.get_database().get<account_object, by_name>(receiver);
privileged = a.privileged;
if (a.code.size() > 0) {
// get code from cache
......@@ -101,7 +102,7 @@ void apply_context::exec()
}
for( uint32_t i = 0; i < _inline_actions.size(); ++i ) {
apply_context ncontext( mutable_controller, mutable_db, _inline_actions[i], trx_meta);
apply_context ncontext( mutable_controller, mutable_db, _inline_actions[i], trx_meta, _checktime_limit);
ncontext.exec();
append_results(move(ncontext.results));
}
......@@ -233,6 +234,16 @@ vector<account_name> apply_context::get_active_producers() const {
return accounts;
}
void apply_context::checktime_start() {
_checktime_start = fc::time_point::now();
}
void apply_context::checktime() const {
if ((fc::time_point::now() - _checktime_start).count() > _checktime_limit) {
throw checktime_exceeded();
}
}
const bytes& apply_context::get_packed_transaction() {
if( !trx_meta.packed_trx.size() ) {
......@@ -247,7 +258,5 @@ const bytes& apply_context::get_packed_transaction() {
}
return trx_meta.packed_trx;
}
} } /// eosio::chain
......@@ -4,7 +4,6 @@
*/
#include <eosio/chain/chain_controller.hpp>
#include <eosio/chain/contracts/staked_balance_objects.hpp>
#include <eosio/chain/block_summary_object.hpp>
#include <eosio/chain/global_property_object.hpp>
......@@ -16,7 +15,6 @@
#include <eosio/chain/permission_link_object.hpp>
#include <eosio/chain/authority_checker.hpp>
#include <eosio/chain/contracts/chain_initializer.hpp>
#include <eosio/chain/contracts/producer_objects.hpp>
#include <eosio/chain/scope_sequence_object.hpp>
#include <eosio/chain/merkle.hpp>
......@@ -41,15 +39,32 @@
namespace eosio { namespace chain {
bool is_start_of_round( block_num_type block_num ) {
return (block_num % config::blocks_per_round) == 0;
#ifdef NDEBUG
const uint32_t chain_controller::default_received_block_transaction_execution_time_ms = 12;
const uint32_t chain_controller::default_transaction_execution_time_ms = 3;
const uint32_t chain_controller::default_create_block_transaction_execution_time_ms = 3;
#else
const uint32_t chain_controller::default_received_block_transaction_execution_time_ms = 72;
const uint32_t chain_controller::default_transaction_execution_time_ms = 18;
const uint32_t chain_controller::default_create_block_transaction_execution_time_ms = 18;
#endif
bool chain_controller::is_start_of_round( block_num_type block_num )const {
return 0 == (block_num % blocks_per_round());
}
uint32_t chain_controller::blocks_per_round()const {
return get_global_properties().active_producers.producers.size()*config::producer_repititions;
}
chain_controller::chain_controller( const chain_controller::controller_config& cfg )
:_db( cfg.shared_memory_dir,
(cfg.read_only ? database::read_only : database::read_write),
cfg.shared_memory_size),
_block_log(cfg.block_log_dir)
_block_log(cfg.block_log_dir),
_create_block_txn_execution_time(default_create_block_transaction_execution_time_ms * 1000),
_rcvd_block_txn_execution_time(default_received_block_transaction_execution_time_ms * 1000),
_txn_execution_time(default_transaction_execution_time_ms * 1000)
{
_initialize_indexes();
......@@ -425,11 +440,12 @@ void chain_controller::_finalize_block( const block_trace& trace ) { try {
update_global_properties( b );
update_global_dynamic_data( b );
update_signing_producer(signing_producer, b);
update_last_irreversible_block();
create_block_summary(b);
clear_expired_transactions();
update_last_irreversible_block();
applied_block( trace ); //emit
if (_currently_replaying_blocks)
applied_irreversible_block(b);
......@@ -443,7 +459,7 @@ signed_block chain_controller::generate_block(
uint32_t skip /* = 0 */
)
{ try {
return with_skip_flags( skip, [&](){
return with_skip_flags( skip | created_block, [&](){
return _db.with_write_lock( [&](){
return _generate_block( when, producer, block_signing_private_key );
});
......@@ -454,6 +470,8 @@ signed_block chain_controller::_generate_block( block_timestamp_type when,
account_name producer,
const private_key_type& block_signing_key )
{ try {
try {
uint32_t skip = _skip_flags;
uint32_t slot_num = get_slot_at_time( when );
FC_ASSERT( slot_num > 0 );
......@@ -478,7 +496,6 @@ signed_block chain_controller::_generate_block( block_timestamp_type when,
_pending_block->transaction_mroot = transaction_metadata::calculate_transaction_merkle_root( _pending_transaction_metas );
_pending_block->action_mroot = _pending_block_trace->calculate_action_merkle_root();
if( is_start_of_round( _pending_block->block_num() ) ) {
auto latest_producer_schedule = _calculate_producer_schedule();
if( latest_producer_schedule != _head_producer_schedule() )
......@@ -500,6 +517,13 @@ signed_block chain_controller::_generate_block( block_timestamp_type when,
_fork_db.push_block(result);
}
return result;
} catch ( ... ) {
clear_pending();
elog( "error while producing block" );
_start_pending_block();
throw;
}
} FC_CAPTURE_AND_RETHROW( (producer) ) }
......@@ -861,7 +885,8 @@ const producer_object& chain_controller::validate_block_header(uint32_t skip, co
elog("Did not produce block within block_interval ${bi}ms, took ${t}ms)",
("bi", config::block_interval_ms)("t", (time_point(next_block.timestamp) - head_block_time()).count() / 1000));
}
if (next_block.block_num() % config::blocks_per_round != 0) {
if( !is_start_of_round( next_block.block_num() ) ) {
EOS_ASSERT(!next_block.new_producers, block_validate_exception,
"Producer changes may only occur at the end of a round.");
}
......@@ -895,18 +920,8 @@ void chain_controller::create_block_summary(const signed_block& next_block) {
* block_signing_key is null.
*/
producer_schedule_type chain_controller::_calculate_producer_schedule()const {
const auto& producers_by_vote = _db.get_index<contracts::producer_votes_multi_index,contracts::by_votes>();
auto itr = producers_by_vote.begin();
producer_schedule_type schedule;
uint32_t count = 0;
while( itr != producers_by_vote.end() && count < schedule.producers.size() ) {
schedule.producers[count].producer_name = itr->owner_name;
schedule.producers[count].block_signing_key = get_producer(itr->owner_name).signing_key;
++itr;
if( schedule.producers[count].block_signing_key != public_key_type() ) {
++count;
}
}
producer_schedule_type schedule = get_global_properties().new_active_producers;
const auto& hps = _head_producer_schedule();
schedule.version = hps.version;
if( hps != schedule )
......@@ -917,7 +932,7 @@ producer_schedule_type chain_controller::_calculate_producer_schedule()const {
/**
* Returns the most recent and/or pending producer schedule
*/
const producer_schedule_type& chain_controller::_head_producer_schedule()const {
const shared_producer_schedule_type& chain_controller::_head_producer_schedule()const {
const auto& gpo = get_global_properties();
if( gpo.pending_active_producers.size() )
return gpo.pending_active_producers.back().second;
......@@ -943,9 +958,14 @@ void chain_controller::update_global_properties(const signed_block& b) { try {
if( props.pending_active_producers.size() && props.pending_active_producers.back().first == b.block_num() )
props.pending_active_producers.back().second = schedule;
else
props.pending_active_producers.push_back( make_pair(b.block_num(),schedule) );
});
{
props.pending_active_producers.emplace_back( props.pending_active_producers.get_allocator() );// props.pending_active_producers.size()+1, props.pending_active_producers.get_allocator() );
auto& back = props.pending_active_producers.back();
back.first = b.block_num();
back.second = schedule;
}
});
auto active_producers_authority = authority(config::producers_authority_threshold, {}, {});
......@@ -1049,6 +1069,8 @@ void chain_controller::_initialize_chain(contracts::chain_initializer& starter)
const auto& gp = _db.create<global_property_object>([&starter](global_property_object& p) {
p.configuration = starter.get_chain_start_configuration();
p.active_producers = starter.get_chain_start_producers();
p.new_active_producers = starter.get_chain_start_producers();
wdump((starter.get_chain_start_producers()));
});
_db.create<dynamic_global_property_object>([&](dynamic_global_property_object& p) {
......@@ -1223,7 +1245,7 @@ void chain_controller::update_global_dynamic_data(const signed_block& b) {
dgp.recent_slots_filled += 1;
dgp.recent_slots_filled <<= missed_blocks;
} else
if(config::percent_100 * get_global_properties().active_producers.producers.size() / config::blocks_per_round > config::required_producer_participation)
if(config::percent_100 * get_global_properties().active_producers.producers.size() / blocks_per_round() > config::required_producer_participation)
dgp.recent_slots_filled = uint64_t(-1);
else
dgp.recent_slots_filled = 0;
......@@ -1253,7 +1275,8 @@ void chain_controller::update_last_irreversible_block()
vector<const producer_object*> producer_objs;
producer_objs.reserve(gpo.active_producers.producers.size());
std::transform(gpo.active_producers.producers.begin(), gpo.active_producers.producers.end(), std::back_inserter(producer_objs),
std::transform(gpo.active_producers.producers.begin(),
gpo.active_producers.producers.end(), std::back_inserter(producer_objs),
[this](const producer_key& pk) { return &get_producer(pk.producer_name); });
static_assert(config::irreversible_threshold_percent > 0, "irreversible threshold must be nonzero");
......@@ -1264,7 +1287,8 @@ void chain_controller::update_last_irreversible_block()
return a->last_confirmed_block_num < b->last_confirmed_block_num;
});
uint32_t new_last_irreversible_block_num = producer_objs[offset]->last_confirmed_block_num;
uint32_t new_last_irreversible_block_num = producer_objs[offset]->last_confirmed_block_num - 1;
if (new_last_irreversible_block_num > dpo.last_irreversible_block_num) {
_db.modify(dpo, [&](dynamic_global_property_object& _dpo) {
......@@ -1284,7 +1308,7 @@ void chain_controller::update_last_irreversible_block()
block_to_write <= new_last_irreversible_block_num;
++block_to_write) {
auto block = fetch_block_by_number(block_to_write);
assert(block);
FC_ASSERT( block, "unable to find last irreversible block to write" );
_block_log.append(*block);
applied_irreversible_block(*block);
}
......@@ -1309,7 +1333,6 @@ void chain_controller::update_last_irreversible_block()
}
}
// Trim fork_database and undo histories
_fork_db.set_max_size(head_block_num() - new_last_irreversible_block_num + 1);
_db.commit(new_last_irreversible_block_num);
......@@ -1341,10 +1364,12 @@ account_name chain_controller::get_scheduled_producer(uint32_t slot_num)const
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
uint64_t current_aslot = dpo.current_absolute_slot + slot_num;
const auto& gpo = _db.get<global_property_object>();
//auto number_of_active_producers = gpo.active_producers.size();
auto index = current_aslot % (config::blocks_per_round); //TODO configure number of repetitions by producer
auto number_of_active_producers = gpo.active_producers.producers.size();
auto index = current_aslot % (number_of_active_producers);
index /= config::producer_repititions;
FC_ASSERT( gpo.active_producers.producers.size() > 0, "no producers defined" );
return gpo.active_producers.producers[index].producer_name;
}
......@@ -1397,7 +1422,7 @@ 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().actions) {
apply_context context(*this, _db, act, meta);
apply_context context(*this, _db, act, meta, txn_execution_time());
context.exec();
fc::move_append(result.action_traces, std::move(context.results.applied_actions));
fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));
......@@ -1450,7 +1475,7 @@ transaction_trace chain_controller::_apply_error( transaction_metadata& meta ) {
try {
auto temp_session = _db.start_undo_session(true);
apply_context context(*this, _db, etrx.actions.front(), meta);
apply_context context(*this, _db, etrx.actions.front(), meta, txn_execution_time());
context.exec();
fc::move_append(result.action_traces, std::move(context.results.applied_actions));
fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));
......@@ -1548,37 +1573,32 @@ void chain_controller::update_usage( transaction_metadata& meta, uint32_t act_us
auto head_time = head_block_time();
for( const auto& authaccnt : authorizing_accounts ) {
const auto& buo = _db.get<bandwidth_usage_object,by_owner>( authaccnt.first );
_db.modify( buo, [&]( auto& bu ){
bu.bytes.add_usage( trx_size, head_time );
bu.acts.add_usage( act_usage, head_time );
});
const auto& sbo = _db.get<contracts::staked_balance_object, contracts::by_owner_name>(authaccnt.first);
// TODO enable this after fixing divide by 0 with virtual_net_bandwidth and total_staked_tokens
/// note: buo.bytes.value is in ubytes and virtual_net_bandwidth is in bytes, so
// we convert to fixed int uin128_t with 60 bits of precision, divide by rate limiting precision
// then divide by virtual max_block_size which gives us % of virtual max block size in fixed width
uint128_t used_ubytes = buo.bytes.value;
uint128_t used_uacts = buo.acts.value;
uint128_t virtual_max_ubytes = dgpo.virtual_net_bandwidth * config::rate_limiting_precision;
uint128_t virtual_max_uacts = dgpo.virtual_act_bandwidth * config::rate_limiting_precision;
uint64_t user_stake = sbo.staked_balance;
if( !(_skip_flags & genesis_setup) ) {
FC_ASSERT( (used_ubytes * dgpo.total_staked_tokens) <= (user_stake * virtual_max_ubytes), "authorizing account '${n}' has insufficient net bandwidth for this transaction",
FC_ASSERT( (used_ubytes * dgpo.total_net_weight) <= (buo.net_weight * virtual_max_ubytes), "authorizing account '${n}' has insufficient net bandwidth for this transaction",
("n",name(authaccnt.first))
("used_bytes",double(used_ubytes)/1000000.)
("user_stake",user_stake)
("user_net_weight",buo.net_weight)
("virtual_max_bytes", double(virtual_max_ubytes)/1000000. )
("total_staked_tokens", dgpo.total_staked_tokens)
("total_net_weight", dgpo.total_net_weight)
);
FC_ASSERT( (used_uacts * dgpo.total_staked_tokens) <= (user_stake * virtual_max_uacts), "authorizing account '${n}' has insufficient compute bandwidth for this transaction",
FC_ASSERT( (used_uacts * dgpo.total_cpu_weight) <= (buo.cpu_weight* virtual_max_uacts), "authorizing account '${n}' has insufficient compute bandwidth for this transaction",
("n",name(authaccnt.first))
("used_acts",double(used_uacts)/1000000.)
("user_stake",user_stake)
("user_cpu_weight",buo.cpu_weight)
("virtual_max_uacts", double(virtual_max_uacts)/1000000. )
("total_staked_tokens", dgpo.total_staked_tokens)
("total_cpu_tokens", dgpo.total_cpu_weight)
);
}
......@@ -1616,4 +1636,20 @@ const apply_handler* chain_controller::find_apply_handler( account_name receiver
return nullptr;
}
void chain_controller::set_txn_execution_times(uint32_t create_block_txn_execution_time, uint32_t rcvd_block_txn_execution_time, uint32_t txn_execution_time)
{
_create_block_txn_execution_time = create_block_txn_execution_time;
_rcvd_block_txn_execution_time = rcvd_block_txn_execution_time;
_txn_execution_time = txn_execution_time;
}
uint32_t chain_controller::txn_execution_time() const
{
return _skip_flags & received_block
? _rcvd_block_txn_execution_time
: (_skip_flags && created_block
? _create_block_txn_execution_time
: _txn_execution_time);
}
} } /// eosio::chain
......@@ -98,7 +98,6 @@ namespace eosio { namespace chain { namespace contracts {
built_in_types.emplace("action_def", pack_unpack<action_def>());
built_in_types.emplace("table_def", pack_unpack<table_def>());
built_in_types.emplace("abi_def", pack_unpack<abi_def>());
built_in_types.emplace("nonce", pack_unpack<nonce>());
}
void abi_serializer::set_abi(const abi_def& abi) {
......
......@@ -3,12 +3,17 @@
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/chain/contracts/chain_initializer.hpp>
#include <eosio/chain/contracts/objects.hpp>
#include <eosio/chain/contracts/eos_contract.hpp>
#include <eosio/chain/contracts/types.hpp>
#include <eosio/chain/producer_object.hpp>
#include <eosio/chain/permission_object.hpp>
#include <eosio/chain/wast_to_wasm.hpp>
#include <eosio.system/eosio.system.wast.hpp>
#include <eosio.system/eosio.system.abi.hpp>
#include <fc/io/json.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>
......@@ -25,34 +30,23 @@ chain_config chain_initializer::get_chain_start_configuration() {
producer_schedule_type chain_initializer::get_chain_start_producers() {
producer_schedule_type result;
std::transform(genesis.initial_producers.begin(), genesis.initial_producers.end(), result.producers.begin(),
[](const auto& p) { return producer_key{p.owner_name,p.block_signing_key}; });
result.producers.push_back( {config::system_account_name, genesis.initial_key} );
idump((result));
return result;
}
void chain_initializer::register_types(chain_controller& chain, chainbase::database& db) {
// Install the native contract's indexes; we can't do anything until our objects are recognized
db.add_index<staked_balance_multi_index>();
db.add_index<producer_votes_multi_index>();
#define SET_APP_HANDLER( contract, scope, action, nspace ) \
chain._set_apply_handler( #contract, #scope, #action, &BOOST_PP_CAT(contracts::apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) )
SET_APP_HANDLER( eosio, eosio, setproducer, eosio );
SET_APP_HANDLER( eosio, eosio, newaccount, eosio );
SET_APP_HANDLER( eosio, eosio, transfer, eosio );
SET_APP_HANDLER( eosio, eosio, lock, eosio );
SET_APP_HANDLER( eosio, eosio, claim, eosio );
SET_APP_HANDLER( eosio, eosio, unlock, eosio );
SET_APP_HANDLER( eosio, eosio, okproducer, eosio );
SET_APP_HANDLER( eosio, eosio, setproxy, eosio );
SET_APP_HANDLER( eosio, eosio, setcode, eosio );
SET_APP_HANDLER( eosio, eosio, setabi, eosio );
SET_APP_HANDLER( eosio, eosio, updateauth, eosio );
SET_APP_HANDLER( eosio, eosio, deleteauth, eosio );
SET_APP_HANDLER( eosio, eosio, linkauth, eosio );
SET_APP_HANDLER( eosio, eosio, unlinkauth, eosio );
SET_APP_HANDLER( eosio, eosio, nonce, eosio );
SET_APP_HANDLER( eosio, eosio, onerror, eosio );
SET_APP_HANDLER( eosio, eosio, postrecovery, eosio );
SET_APP_HANDLER( eosio, eosio, passrecovery, eosio );
......@@ -66,13 +60,6 @@ abi_def chain_initializer::eos_contract_abi()
eos_abi.types.push_back( type_def{"account_name","name"} );
eos_abi.types.push_back( type_def{"share_type","int64"} );
eos_abi.types.push_back( type_def{"onerror","bytes"} );
eos_abi.actions.push_back( action_def{name("transfer"), "transfer"} );
eos_abi.actions.push_back( action_def{name("lock"), "lock"} );
eos_abi.actions.push_back( action_def{name("unlock"), "unlock"} );
eos_abi.actions.push_back( action_def{name("claim"), "claim"} );
eos_abi.actions.push_back( action_def{name("okproducer"), "okproducer"} );
eos_abi.actions.push_back( action_def{name("setproducer"), "setproducer"} );
eos_abi.actions.push_back( action_def{name("setproxy"), "setproxy"} );
eos_abi.actions.push_back( action_def{name("setcode"), "setcode"} );
eos_abi.actions.push_back( action_def{name("setabi"), "setabi"} );
eos_abi.actions.push_back( action_def{name("linkauth"), "linkauth"} );
......@@ -84,62 +71,9 @@ abi_def chain_initializer::eos_contract_abi()
eos_abi.actions.push_back( action_def{name("passrecovery"), "passrecovery"} );
eos_abi.actions.push_back( action_def{name("vetorecovery"), "vetorecovery"} );
eos_abi.actions.push_back( action_def{name("onerror"), "onerror"} );
eos_abi.actions.push_back( action_def{name("nonce"), "nonce"} );
// ACTION PAYLOADS
eos_abi.structs.emplace_back( struct_def {
"transfer", "", {
{"from", "account_name"},
{"to", "account_name"},
{"amount", "uint64"},
{"memo", "string"},
}
});
eos_abi.structs.emplace_back( struct_def {
"lock", "", {
{"from", "account_name"},
{"to", "account_name"},
{"amount", "share_type"},
}
});
eos_abi.structs.emplace_back( struct_def {
"unlock", "", {
{"account", "account_name"},
{"amount", "share_type"},
}
});
eos_abi.structs.emplace_back( struct_def {
"claim", "", {
{"account", "account_name"},
{"amount", "share_type"},
}
});
eos_abi.structs.emplace_back( struct_def {
"okproducer", "", {
{"voter", "account_name"},
{"producer", "account_name"},
{"approve", "int8"},
}
});
eos_abi.structs.emplace_back( struct_def {
"setproducer", "", {
{"name", "account_name"},
{"key", "public_key"},
{"configuration", "chain_config"},
}
});
eos_abi.structs.emplace_back( struct_def {
"setproxy", "", {
{"stakeholder", "account_name"},
{"proxy", "account_name"},
}
});
eos_abi.structs.emplace_back( struct_def {
"setcode", "", {
......@@ -197,7 +131,6 @@ abi_def chain_initializer::eos_contract_abi()
{"owner", "authority"},
{"active", "authority"},
{"recovery", "authority"},
{"deposit", "asset"},
}
});
......@@ -221,12 +154,6 @@ abi_def chain_initializer::eos_contract_abi()
}
});
eos_abi.structs.emplace_back( struct_def {
"nonce", "", {
{"value", "name"}
}
});
// DATABASE RECORDS
eos_abi.structs.emplace_back( struct_def {
"account", "", {
......@@ -275,57 +202,76 @@ std::vector<action> chain_initializer::prepare_database( chain_controller& chain
std::vector<action> messages_to_process;
/// Create the native contract accounts manually; sadly, we can't run their contracts to make them create themselves
auto create_native_account = [this, &db](account_name name, auto liquid_balance) {
auto create_native_account = [this, &db](account_name name) {
db.create<account_object>([this, &name](account_object& a) {
a.name = name;
a.creation_date = genesis.initial_timestamp;
a.privileged = true;
if( name == config::system_account_name ) {
a.set_abi(eos_contract_abi());
}
});
const auto& owner = db.create<permission_object>([&name](permission_object& p) {
const auto& owner = db.create<permission_object>([&](permission_object& p) {
p.owner = name;
p.name = "owner";
p.auth.threshold = 1;
p.auth.keys.push_back( key_weight{ .key = genesis.initial_key, .weight = 1 } );
});
db.create<permission_object>([&name, &owner](permission_object& p) {
db.create<permission_object>([&](permission_object& p) {
p.owner = name;
p.parent = owner.id;
p.name = "active";
p.auth.threshold = 1;
p.auth.keys.push_back( key_weight{ .key = genesis.initial_key, .weight = 1 } );
});
db.create<bandwidth_usage_object>([&](auto& sb) {
sb.owner = name;
sb.net_weight = -1;
sb.cpu_weight = -1;
sb.db_reserved_capacity = -1;
});
db.create<producer_object>( [&]( auto& pro ) {
pro.owner = config::system_account_name;
pro.signing_key = genesis.initial_key;
});
intialize_eosio_tokens(db, name, liquid_balance);
db.create<staked_balance_object>([&](auto& sb) { sb.owner_name = name; });
db.create<bandwidth_usage_object>([&](auto& sb) { sb.owner = name; });
};
create_native_account(config::system_account_name, config::initial_token_supply);
create_native_account(config::system_account_name);
// Queue up messages which will run contracts to create the initial accounts
auto init_eosio_sytem = genesis_state_type::initial_account_type(name(config::eosio_system_acount_name).to_string(), 0, 0, genesis.initial_key, genesis.initial_key);
genesis.initial_accounts.emplace_back(move(init_eosio_sytem));
for (const auto& acct : genesis.initial_accounts) {
action message( {{config::system_account_name, config::active_name}},
newaccount{ config::system_account_name, acct.name,
authority(acct.owner_key),
authority(acct.active_key),
authority(acct.owner_key),
acct.staking_balance});
messages_to_process.emplace_back(move(message));
authority(acct.owner_key)
});
if (acct.liquid_balance > asset(0)) {
message = action( {{config::system_account_name, config::active_name}},
transfer{ .from = config::system_account_name, .to = acct.name,
.amount = acct.liquid_balance.amount, .memo = "Genesis Allocation"});
messages_to_process.emplace_back(move(message));
}
}
// Create initial producers
auto create_producer = boost::adaptors::transformed([config = genesis.initial_configuration](const auto& p) {
return action( {{p.owner_name, config::active_name}},
setproducer(p.owner_name, p.block_signing_key, config));
// Create initial contracts eosio.system
auto wasm = wast_to_wasm(eosio_system_wast);
action eosio_system_setcode({{config::eosio_system_acount_name, config::active_name}},
contracts::setcode{
.account = config::eosio_system_acount_name,
.vmtype = 0,
.vmversion = 0,
.code = bytes(wasm.begin(), wasm.end())
});
boost::copy(genesis.initial_producers | create_producer, std::back_inserter(messages_to_process));
auto abi = fc::json::from_string(eosio_system_abi).template as<contracts::abi_def>();
action eosio_system_setabi({{config::eosio_system_acount_name, config::active_name}},
contracts::setabi{
.account = config::eosio_system_acount_name,
.abi = abi
});
messages_to_process.emplace_back(move(eosio_system_setcode));
messages_to_process.emplace_back(move(eosio_system_setabi));
// Create special accounts
auto create_special_account = [this, &db](account_name name, const auto& owner, const auto& active) {
......@@ -349,9 +295,7 @@ std::vector<action> chain_initializer::prepare_database( chain_controller& chain
auto empty_authority = authority(0, {}, {});
auto active_producers_authority = authority(config::producers_authority_threshold, {}, {});
for(auto& p : genesis.initial_producers) {
active_producers_authority.accounts.push_back({{p.owner_name, config::active_name}, 1});
}
active_producers_authority.accounts.push_back({{config::system_account_name, config::active_name}, 1});
create_special_account(config::nobody_account_name, empty_authority, empty_authority);
create_special_account(config::producers_account_name, empty_authority, active_producers_authority);
......
......@@ -15,8 +15,6 @@
#include <eosio/chain/permission_object.hpp>
#include <eosio/chain/permission_link_object.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <eosio/chain/contracts/staked_balance_objects.hpp>
#include <eosio/chain/contracts/producer_objects.hpp>
#include <eosio/chain/contracts/types.hpp>
#include <eosio/chain/producer_object.hpp>
......@@ -52,21 +50,6 @@ static void modify_eosio_balance( apply_context& context, const account_name& ac
context.store_record<key_value_object>(t_id, &key, (const char *)&balance, sizeof(balance));
}
share_type get_eosio_balance( const chainbase::database& db, const account_name &account ) {
const auto* t_id = db.find<table_id_object, by_scope_code_table>(boost::make_tuple(account, config::system_account_name, N(currency)));
if (!t_id) {
return share_type(0);
}
const auto& idx = db.get_index<key_value_index, by_scope_primary>();
auto itr = idx.lower_bound(boost::make_tuple(t_id->id));
if ( itr == idx.end() || itr->t_id != t_id->id ) {
return share_type(0);
}
FC_ASSERT(itr->value.size() == sizeof(share_type), "Invalid data in EOSIO balance table");
return *reinterpret_cast<const share_type *>(itr->value.data());
}
void validate_authority_precondition( const apply_context& context, const authority& auth ) {
for(const auto& a : auth.accounts) {
......@@ -76,9 +59,7 @@ void validate_authority_precondition( const apply_context& context, const author
}
/**
* This method is called assuming precondition_system_newaccount succeeds and proceeds to
* deduct the balance of the account creator by deposit, this deposit is supposed to be
* credited to the staked balance the new account in the @staked contract.
* This method is called assuming precondition_system_newaccount succeeds a
*/
void apply_eosio_newaccount(apply_context& context) {
auto create = context.act.as<newaccount>();
......@@ -118,104 +99,10 @@ void apply_eosio_newaccount(apply_context& context) {
const auto& owner_permission = create_permission("owner", 0, std::move(create.owner));
create_permission("active", owner_permission.id, std::move(create.active));
share_type creator_balance = get_eosio_balance(context.db, create.creator);
EOS_ASSERT(creator_balance >= create.deposit.amount, action_validate_exception,
"Creator '${c}' has insufficient funds to make account creation deposit of ${a}",
("c", create.creator)("a", create.deposit));
modify_eosio_balance(context, create.creator, -create.deposit.amount);
const auto& sbo = context.mutable_db.create<staked_balance_object>([&]( staked_balance_object& sbo) {
sbo.owner_name = create.name;
sbo.staked_balance = 0;
});
sbo.stake_tokens( create.deposit.amount, context.mutable_db );
db.create<bandwidth_usage_object>([&]( auto& bu ) { bu.owner = create.name; });
} FC_CAPTURE_AND_RETHROW( (create) ) }
/**
*
* @ingroup native_eos
* @defgroup eos_eosio_transfer eosio::eos_transfer
*/
///@{
void apply_eosio_transfer(apply_context& context) {
auto transfer = context.act.as<contracts::transfer>();
try {
EOS_ASSERT(transfer.amount > 0, action_validate_exception, "Must transfer a positive amount");
context.require_write_lock(transfer.to);
context.require_write_lock(transfer.from);
context.require_authorization(transfer.from);
context.require_recipient(transfer.to);
context.require_recipient(transfer.from);
} FC_CAPTURE_AND_RETHROW((transfer))
try {
auto& db = context.mutable_db;
share_type from_balance = get_eosio_balance(db, transfer.from);
EOS_ASSERT(from_balance >= transfer.amount, action_validate_exception, "Insufficient Funds",
("from_balance", from_balance)("transfer.amount",transfer.amount));
modify_eosio_balance(context, transfer.from, - share_type(transfer.amount) );
modify_eosio_balance(context, transfer.to, share_type(transfer.amount) );
} FC_CAPTURE_AND_RETHROW( (transfer) )
}
///@}
/**
* Deduct the balance from the from account.
*/
void apply_eosio_lock(apply_context& context) {
auto lock = context.act.as<contracts::lock>();
EOS_ASSERT(lock.amount > 0, action_validate_exception, "Locked amount must be positive");
context.require_write_lock(lock.to);
context.require_write_lock(lock.from);
context.require_write_lock(config::system_account_name);
context.require_authorization(lock.from);
context.require_recipient(lock.to);
context.require_recipient(lock.from);
share_type locker_balance = get_eosio_balance(context.db, lock.from);
EOS_ASSERT( locker_balance >= lock.amount, action_validate_exception,
"Account ${a} lacks sufficient funds to lock ${amt} EOS", ("a", lock.from)("amt", lock.amount)("available",locker_balance) );
modify_eosio_balance(context, lock.from, -share_type(lock.amount));
const auto& balance = context.db.get<staked_balance_object, by_owner_name>(lock.to);
balance.stake_tokens(lock.amount, context.mutable_db);
}
void apply_eosio_unlock(apply_context& context) {
auto unlock = context.act.as<contracts::unlock>();
context.require_authorization(unlock.account);
EOS_ASSERT(unlock.amount >= 0, action_validate_exception, "Unlock amount cannot be negative");
const auto& balance = context.db.get<staked_balance_object, by_owner_name>(unlock.account);
EOS_ASSERT(balance.staked_balance >= unlock.amount, action_validate_exception,
"Insufficient locked funds to unlock ${a}", ("a", unlock.amount));
balance.begin_unstaking_tokens(unlock.amount, context.mutable_db);
}
void apply_eosio_setcode(apply_context& context) {
auto& db = context.mutable_db;
......@@ -262,148 +149,6 @@ void apply_eosio_setabi(apply_context& context) {
});
}
void apply_eosio_claim(apply_context& context) {
auto claim = context.act.as<contracts::claim>();
EOS_ASSERT(claim.amount > 0, action_validate_exception, "Claim amount must be positive");
context.require_authorization(claim.account);
auto balance = context.db.find<staked_balance_object, by_owner_name>(claim.account);
EOS_ASSERT(balance != nullptr, action_validate_exception,
"Could not find staked balance for ${name}", ("name", claim.account));
auto balance_release_time = balance->last_unstaking_time + fc::seconds(config::staked_balance_cooldown_sec);
auto now = context.controller.head_block_time();
EOS_ASSERT(now >= balance_release_time, action_validate_exception,
"Cannot claim balance until ${releaseDate}", ("releaseDate", balance_release_time));
EOS_ASSERT(balance->unstaking_balance >= claim.amount, action_validate_exception,
"Cannot claim ${claimAmount} as only ${available} is available for claim",
("claimAmount", claim.amount)("available", balance->unstaking_balance));
const auto& staked_balance = context.db.get<staked_balance_object, by_owner_name>(claim.account);
staked_balance.finish_unstaking_tokens(claim.amount, context.mutable_db);
modify_eosio_balance(context, claim.account, share_type(claim.amount));
}
void apply_eosio_setproducer(apply_context& context) {
auto update = context.act.as<setproducer>();
context.require_authorization(update.name);
EOS_ASSERT(update.name.good(), action_validate_exception, "Producer owner name cannot be empty");
auto& db = context.mutable_db;
auto producer = db.find<producer_object, by_owner>(update.name);
if (producer) {
EOS_ASSERT(producer->signing_key != update.key || producer->configuration != update.configuration,
action_validate_exception, "Producer's new settings may not be identical to old settings");
db.modify(*producer, [&](producer_object& p) {
p.signing_key = update.key;
p.configuration = update.configuration;
});
} else {
db.create<producer_object>([&](producer_object& p) {
p.owner = update.name;
p.signing_key = update.key;
p.configuration = update.configuration;
});
db.create<producer_votes_object>([&](producer_votes_object& pvo) {
pvo.owner_name = update.name;
});
}
}
void apply_eosio_okproducer(apply_context& context) {
auto approve = context.act.as<okproducer>();
EOS_ASSERT(approve.approve == 0 || approve.approve == 1, action_validate_exception,
"Unknown approval value: ${val}; must be either 0 or 1", ("val", approve.approve));
context.require_recipient(approve.voter);
context.require_recipient(approve.producer);
context.require_write_lock(config::system_account_name);
context.require_write_lock(approve.voter);
context.require_authorization(approve.voter);
auto& db = context.mutable_db;
const auto& producer = db.get<producer_votes_object, by_owner_name>(approve.producer);
const auto& voter = db.get<staked_balance_object, by_owner_name>(approve.voter);
EOS_ASSERT(voter.producer_votes.contains<producer_slate>(), action_validate_exception,
"Cannot approve producer; approving account '${name}' proxies its votes to '${proxy}'",
("name", voter.owner_name)("proxy", voter.producer_votes.get<account_name>()));
const auto& slate = voter.producer_votes.get<producer_slate>();
EOS_ASSERT(slate.size < config::max_producer_votes, action_validate_exception,
"Cannot approve producer; approved producer count is already at maximum");
if (approve.approve)
EOS_ASSERT(!slate.contains(producer.owner_name), action_validate_exception,
"Cannot add approval to producer '${name}'; producer is already approved",
("name", producer.owner_name));
else
EOS_ASSERT(slate.contains(producer.owner_name), action_validate_exception,
"Cannot remove approval from producer '${name}'; producer is not approved",
("name", producer.owner_name));
auto total_voting_stake = voter.staked_balance;
// Add/remove votes from producer
db.modify(producer, [approve = approve.approve, total_voting_stake](producer_votes_object& pvo) {
if (approve)
pvo.update_votes(total_voting_stake);
else
pvo.update_votes(-total_voting_stake);
});
// Add/remove producer from voter's approved producer list
db.modify(voter, [&approve, producer = producer.owner_name](staked_balance_object& sbo) {
auto& slate = sbo.producer_votes.get<producer_slate>();
if (approve.approve)
slate.add(producer);
else
slate.remove(producer);
});
}
void apply_eosio_setproxy(apply_context& context) {
auto svp = context.act.as<setproxy>();
FC_ASSERT( !"Not Implemented Yet" );
/*
context.require_authorization( spv.stakeholder );
context.require_recipient(svp.stakeholder);
context.require_recipient(svp.proxy);
auto& db = context.mutable_db;
const auto& proxy = db.get<proxy_vote_object, by_target_name>(context.act.recipient(svp.proxy));
const auto& balance = db.get<staked_balance_object, by_owner_name>(context.act.recipient(svp.stakeholder));
auto proxy = db.find<proxy_vote_object, by_target_name>(context.act.recipient(svp.proxy));
if (svp.proxy != svp.stakeholder) {
// We are enabling proxying to svp.proxy
proxy.add_proxy_source(context.act.recipient(svp.stakeholder), balance.staked_balance, db);
db.modify(balance, [target = proxy.proxy_target](staked_balance_object& sbo) { sbo.producer_votes = target; });
} else {
// We are disabling proxying to balance.producer_votes.get<account_name>()
proxy.remove_proxy_source(context.act.recipient(svp.stakeholder), balance.staked_balance, db);
db.modify(balance, [](staked_balance_object& sbo) { sbo.producer_votes = producer_slate{}; });
}
*/
}
void apply_eosio_updateauth(apply_context& context) {
context.require_write_lock( config::eosio_auth_scope );
......@@ -548,9 +293,6 @@ void apply_eosio_unlinkauth(apply_context& context) {
db.remove(*link);
}
void apply_eosio_nonce(apply_context&) {
/// do nothing
}
void apply_eosio_onerror(apply_context& context) {
assert(context.trx_meta.sender);
......
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/chain/contracts/producer_objects.hpp>
#include <eosio/chain/contracts/staked_balance_objects.hpp>
#include <eosio/chain/producer_object.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/algorithm_ext.hpp>
namespace eosio { namespace chain { namespace contracts {
} } } // namespace eosio::chain::contracts
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosio/chain/contracts/staked_balance_objects.hpp>
#include <eosio/chain/contracts/producer_objects.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <boost/range/algorithm/for_each.hpp>
namespace eosio { namespace chain { namespace contracts {
void staked_balance_object::stake_tokens(share_type new_stake, chainbase::database& db) const {
// Update the staked balance
db.modify(*this, [&new_stake](staked_balance_object& sbo) {
sbo.staked_balance += new_stake;
});
db.modify( db.get<dynamic_global_property_object>(), [&]( auto& dgpo ){
dgpo.total_staked_tokens += new_stake;
});
propagate_votes(new_stake, db);
}
void staked_balance_object::begin_unstaking_tokens(share_type amount, chainbase::database& db) const {
// Remember there might be stake left over from a previous, uncompleted unstaking in unstaking_balance
auto delta_stake = unstaking_balance - amount;
// Update actual stake balance and invariants around it
stake_tokens(delta_stake, db);
// Update stats for unstaking process
db.modify(*this, [&amount, &db](staked_balance_object& sbo) {
sbo.unstaking_balance = amount;
sbo.last_unstaking_time = db.get(dynamic_global_property_object::id_type()).time;
});
}
void staked_balance_object::finish_unstaking_tokens(share_type amount, chainbase::database& db) const {
db.modify(*this, [&amount](staked_balance_object& sbo) {
sbo.unstaking_balance -= amount;
});
db.modify( db.get<dynamic_global_property_object>(), [&]( auto& dgpo ){
dgpo.total_staked_tokens -= amount;
});
}
void staked_balance_object::propagate_votes(share_type staked_delta, chainbase::database& db) const {
if (producer_votes.contains<producer_slate>())
// This account votes for producers directly; update their stakes
boost::for_each(producer_votes.get<producer_slate>().range(), [&db, &staked_delta](const account_name& name) {
db.modify(db.get<producer_votes_object, by_owner_name>(name), [&db, &staked_delta](producer_votes_object& pvo) {
pvo.update_votes(staked_delta);
});
});
else {
}
}
} } } // namespace eosio::chain::contracts
......@@ -13,8 +13,8 @@ fc::variant_object get_config()
{
fc::mutable_variant_object result;
result["block_interval_ms"] = config::block_interval_ms;
result["producer_count"] = config::producer_count;
// result["block_interval_ms"] = config::block_interval_ms;
// result["producer_count"] = config::producer_count;
/// TODO: add extra config parms
return result;
}
......
......@@ -19,6 +19,9 @@ namespace eosio { namespace chain {
account_name name;
uint8_t vm_type = 0;
uint8_t vm_version = 0;
bool privileged = false;
bool frozen = false;
time_point_sec last_code_update;
digest_type code_version;
block_timestamp_type creation_date;
......
......@@ -19,11 +19,11 @@ class chain_controller;
class apply_context {
public:
apply_context(chain_controller& con, chainbase::database& db, const action& a, const transaction_metadata& trx_meta)
apply_context(chain_controller& con, chainbase::database& db, const action& a, const transaction_metadata& trx_meta, uint32_t checktime_limit)
:controller(con), db(db), act(a), mutable_controller(con),
mutable_db(db), used_authorizations(act.authorization.size(), false),
trx_meta(trx_meta) {}
trx_meta(trx_meta), _checktime_limit(checktime_limit) {}
void exec();
......@@ -102,6 +102,7 @@ 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;
chain_controller& mutable_controller;
chainbase::database& mutable_db;
......@@ -180,6 +181,9 @@ class apply_context {
console_append(fc::format_string(fmt, vo));
}
void checktime_start();
void checktime() const;
private:
void append_results(apply_results &&other) {
......@@ -197,6 +201,8 @@ class apply_context {
vector<shard_lock> _read_locks;
vector<scope_name> _write_scopes;
bytes _cached_trx;
fc::time_point _checktime_start;
const uint32_t _checktime_limit;
};
using apply_handler = std::function<void(apply_context&)>;
......
......@@ -121,6 +121,8 @@ namespace eosio { namespace chain {
* @return True if the controller is now applying a block; false otherwise
*/
bool is_applying_block()const { return _currently_applying_block; }
bool is_start_of_round( block_num_type n )const;
uint32_t blocks_per_round()const;
chain_id_type get_chain_id()const { return chain_id_type(); } /// TODO: make this hash of constitution
......@@ -292,10 +294,17 @@ namespace eosio { namespace chain {
)const;
void set_txn_execution_times(uint32_t create_block_txn_execution_time, uint32_t rcvd_block_txn_execution_time, uint32_t txn_execution_time);
static const uint32_t default_received_block_transaction_execution_time_ms;
static const uint32_t default_transaction_execution_time_ms;
static const uint32_t default_create_block_transaction_execution_time_ms;
private:
const apply_handler* find_apply_handler( account_name contract, scope_name scope, action_name act )const;
uint32_t txn_execution_time() const;
friend class contracts::chain_initializer;
friend class apply_context;
......@@ -321,7 +330,7 @@ namespace eosio { namespace chain {
void _initialize_chain(contracts::chain_initializer& starter);
producer_schedule_type _calculate_producer_schedule()const;
const producer_schedule_type& _head_producer_schedule()const;
const shared_producer_schedule_type& _head_producer_schedule()const;
void replay();
......@@ -432,6 +441,10 @@ namespace eosio { namespace chain {
map< account_name, map<handler_key, apply_handler> > _apply_handlers;
wasm_cache _wasm_cache;
uint32_t _create_block_txn_execution_time;
uint32_t _rcvd_block_txn_execution_time;
uint32_t _txn_execution_time;
};
} }
......@@ -13,12 +13,12 @@ typedef __uint128_t uint128_t;
const static auto default_block_log_dir = "block_log";
const static auto default_shared_memory_dir = "shared_mem";
const static auto default_shared_memory_size = 1024*1024*1024ll;
const static int producer_count = 21;
const static uint64_t system_account_name = N(eosio);
const static uint64_t nobody_account_name = N(nobody);
const static uint64_t anybody_account_name = N(anybody);
const static uint64_t producers_account_name = N(producers);
const static uint64_t eosio_system_acount_name = N(eosio.system);
const static uint64_t eosio_auth_scope = N(eosio.auth);
const static uint64_t eosio_all_scope = N(eosio.all);
......@@ -71,13 +71,13 @@ const static uint16_t max_recursion_depth = 6;
/**
* The number of sequential blocks produced by a single producer
*/
const static int producer_repititions = 6;
const static int producer_repititions = 12;
/**
* The number of blocks produced per round is based upon all producers having a chance
* to produce all of their consecutive blocks.
*/
const static int blocks_per_round = producer_count * producer_repititions;
//const static int blocks_per_round = producer_count * producer_repititions;
const static int irreversible_threshold_percent= 70 * percent_1;
const static int max_producer_votes = 30;
......
......@@ -25,23 +25,10 @@ namespace eosio { namespace chain { namespace contracts {
void apply_eosio_passrecovery(apply_context&);
void apply_eosio_vetorecovery(apply_context&);
void apply_eosio_transfer(apply_context& context);
void apply_eosio_lock(apply_context& context);
void apply_eosio_claim(apply_context&);
void apply_eosio_unlock(apply_context&);
void apply_eosio_okproducer(apply_context&);
void apply_eosio_setproducer(apply_context&);
void apply_eosio_setproxy(apply_context&);
void apply_eosio_setcode(apply_context&);
void apply_eosio_setabi(apply_context&);
void apply_eosio_nonce(apply_context&);
void apply_eosio_onerror(apply_context&);
///@} end action handlers
share_type get_eosio_balance( const chainbase::database& db, const account_name& account );
} } } /// namespace eosio::contracts
......@@ -61,6 +61,8 @@ struct genesis_state_type {
};
time_point initial_timestamp;
public_key_type initial_key;
vector<initial_account_type> initial_accounts;
vector<initial_producer_type> initial_producers;
......@@ -85,5 +87,5 @@ FC_REFLECT(eosio::chain::contracts::genesis_state_type::initial_account_type,
FC_REFLECT(eosio::chain::contracts::genesis_state_type::initial_producer_type, (owner_name)(block_signing_key))
FC_REFLECT(eosio::chain::contracts::genesis_state_type,
(initial_timestamp)(initial_configuration)(initial_accounts)
(initial_timestamp)(initial_key)(initial_configuration)(initial_accounts)
(initial_producers)(initial_chain_id))
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
/// @file This file #include's all database objects/indices used by the C++ native contract implementation
#include <eosio/chain/contracts/staked_balance_objects.hpp>
#include <eosio/chain/contracts/producer_objects.hpp>
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosio/chain/config.hpp>
#include <eosio/chain/types.hpp>
#include <eosio/chain/multi_index_includes.hpp>
#include <eosio/utilities/exception_macros.hpp>
#include <chainbase/chainbase.hpp>
#include <boost/multi_index/mem_fun.hpp>
namespace eosio { namespace chain { namespace contracts {
FC_DECLARE_EXCEPTION(producer_race_overflow_exception, 10000000, "Producer Virtual Race time has overflowed");
/**
* @brief The producer_votes_object class tracks all votes for and by the block producers
*
* This class tracks the voting for block producers, as well as the virtual time 'race' to select the runner-up block
* producer.
*
* This class also tracks the votes cast by block producers on various chain configuration options and key documents.
*/
class producer_votes_object : public chainbase::object<producer_votes_object_type, producer_votes_object> {
OBJECT_CTOR(producer_votes_object)
id_type id;
account_name owner_name;
share_type votes = 0;
/**
* @brief Update the tally of votes for the producer
* @param delta_votes The change in votes since the last update
*/
void update_votes(share_type delta_votes) {
votes += delta_votes;
}
};
using boost::multi_index::const_mem_fun;
/// Index producers by their owner's name
struct by_owner_name;
/// Index producers by projected race finishing time, from soonest to latest
struct by_projected_race_finish_time;
/// Index producers by votes, from greatest to least
struct by_votes;
using producer_votes_multi_index = chainbase::shared_multi_index_container<
producer_votes_object,
indexed_by<
ordered_unique< tag<by_id>,
member<producer_votes_object, producer_votes_object::id_type, &producer_votes_object::id>
>,
ordered_unique< tag<by_owner_name>,
member<producer_votes_object, account_name, &producer_votes_object::owner_name>
>,
ordered_unique< tag<by_votes>,
composite_key<producer_votes_object,
member<producer_votes_object, share_type, &producer_votes_object::votes>,
member<producer_votes_object, producer_votes_object::id_type, &producer_votes_object::id>
>,
composite_key_compare< std::greater<share_type>,std::less<producer_votes_object::id_type> >
>
>
>;
/// Index proxies by the proxy target account name
struct by_target_name;
} } } // namespace eosio::chain::contracts
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::producer_votes_object, eosio::chain::contracts::producer_votes_multi_index)
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosio/chain/types.hpp>
#include <eosio/chain/config.hpp>
#include <eosio/chain/multi_index_includes.hpp>
#include <chainbase/chainbase.hpp>
#include <fc/static_variant.hpp>
namespace eosio { namespace chain { namespace contracts {
/**
* @brief The producer_slate struct stores a list of producers voted on by an account
*/
struct producer_slate {
std::array<account_name, config::max_producer_votes> votes;
size_t size = 0;
void add(account_name producer) {
votes[size++] = producer;
std::inplace_merge(votes.begin(), votes.begin() + size - 1, votes.begin() + size);
}
void remove(account_name producer) {
auto itr = std::remove(votes.begin(), votes.begin() + size, producer);
size = std::distance(votes.begin(), itr);
}
bool contains(account_name producer) const {
return std::binary_search(votes.begin(), votes.begin() + size, producer);
}
auto range() { return boost::make_iterator_range_n(votes.begin(), size); }
auto range() const { return boost::make_iterator_range_n(votes.begin(), size); }
};
/**
* @brief The staked_balance_object class tracks the staked balance (voting balance) for accounts
*/
class staked_balance_object : public chainbase::object<staked_balance_object_type, staked_balance_object> {
OBJECT_CTOR(staked_balance_object)
id_type id;
account_name owner_name;
share_type staked_balance = 0;
share_type unstaking_balance = 0;
time_point last_unstaking_time = time_point::maximum();
uint128_t staked_balance_percent = 0;
/// The account's vote on producers. This may either be a list of approved producers, or an account to proxy vote to
fc::static_variant<producer_slate, account_name> producer_votes = producer_slate{};
/**
* @brief Add the provided stake to this balance, maintaining invariants
* @param new_stake The new stake to add to the balance
* @param db Read-write reference to the database
*
* This method will update this object with the new stake, while maintaining invariants around the stake balance,
* such as by updating vote tallies
*/
void stake_tokens(share_type new_stake, chainbase::database& db) const;
/**
* @brief Begin unstaking the specified amount of stake, maintaining invariants
* @param amount The amount of stake to begin unstaking
* @param db Read-write reference to the database
*
* This method will update this object's balances while maintaining invariants around the stake balances, such as by
* updating vote tallies
*/
void begin_unstaking_tokens(share_type amount, chainbase::database& db) const;
/**
* @brief Finish unstaking the specified amount of stake
* @param amount The amount of stake to finish unstaking
* @param db Read-write reference to the database
*
* This method will update this object's balances. There aren't really any invariants to maintain on this call, as
* the tokens are already unstaked and removed from vote tallies, but it is provided for completeness' sake.
*/
void finish_unstaking_tokens(share_type amount, chainbase::database& db) const;
/**
* @brief Propagate the specified change in stake to the producer votes or the proxy
* @param staked_delta The change in stake
* @param db Read-write reference to the database
*
* This method will apply the provided delta in voting stake to the next stage in the producer voting pipeline,
* whether that be the producers in the slate, or the account the votes are proxied to.
*
* This method will *not* update this object in any way. It will not adjust @ref staked_balance, etc
*/
void propagate_votes(share_type staked_delta, chainbase::database& db) const;
};
struct by_owner_name;
using staked_balance_multi_index = chainbase::shared_multi_index_container<
staked_balance_object,
indexed_by<
ordered_unique<tag<by_id>,
member<staked_balance_object, staked_balance_object::id_type, &staked_balance_object::id>
>,
ordered_unique<tag<by_owner_name>,
member<staked_balance_object, account_name, &staked_balance_object::owner_name>
>
>
>;
} } } // namespace eosio::chain::contracts
CHAINBASE_SET_INDEX_TYPE(eosio::chain::contracts::staked_balance_object, eosio::chain::contracts::staked_balance_multi_index)
......@@ -118,60 +118,6 @@ struct transfer {
}
};
struct lock {
lock() = default;
lock(const account_name& from, const account_name& to, const share_type& amount)
:from(from), to(to), amount(amount)
{}
account_name from;
account_name to;
share_type amount;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(lock);
}
};
struct unlock {
unlock() = default;
unlock(const account_name& account, const share_type& amount)
:account(account), amount(amount)
{}
account_name account;
share_type amount;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(unlock);
}
};
struct claim {
claim() = default;
claim(const account_name& account, const share_type& amount)
:account(account), amount(amount)
{}
account_name account;
share_type amount;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(claim);
}
};
struct newaccount {
account_name creator;
......@@ -179,7 +125,6 @@ struct newaccount {
authority owner;
authority active;
authority recovery;
asset deposit;
static account_name get_account() {
return config::system_account_name;
......@@ -218,61 +163,6 @@ struct setabi {
}
};
struct setproducer {
setproducer() = default;
setproducer(const account_name& name, const public_key_type& key, const chain_config& configuration)
:name(name), key(key), configuration(configuration)
{}
account_name name;
public_key_type key;
chain_config configuration;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(setproducer);
}
};
struct okproducer {
okproducer() = default;
okproducer(const account_name& voter, const account_name& producer, const int8_t& approve)
:voter(voter), producer(producer), approve(approve)
{}
account_name voter;
account_name producer;
int8_t approve;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(okproducer);
}
};
struct setproxy {
setproxy() = default;
setproxy(const account_name& stakeholder, const account_name& proxy)
:stakeholder(stakeholder), proxy(proxy)
{}
account_name stakeholder;
account_name proxy;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(setproxy);
}
};
struct updateauth {
account_name account;
......@@ -397,18 +287,6 @@ struct vetorecovery {
}
};
using nonce_type = name;
struct nonce {
nonce_type value;
static account_name get_account() {
return config::system_account_name;
}
static action_name get_name() {
return N(nonce);
}
};
} } } /// namespace eosio::chain::contracts
......@@ -418,16 +296,10 @@ FC_REFLECT( eosio::chain::contracts::struct_def , (name)(b
FC_REFLECT( eosio::chain::contracts::action_def , (name)(type) )
FC_REFLECT( eosio::chain::contracts::table_def , (name)(index_type)(key_names)(key_types)(type) )
FC_REFLECT( eosio::chain::contracts::abi_def , (types)(structs)(actions)(tables) )
FC_REFLECT( eosio::chain::contracts::transfer , (from)(to)(amount)(memo) )
FC_REFLECT( eosio::chain::contracts::lock , (from)(to)(amount) )
FC_REFLECT( eosio::chain::contracts::unlock , (account)(amount) )
FC_REFLECT( eosio::chain::contracts::claim , (account)(amount) )
FC_REFLECT( eosio::chain::contracts::newaccount , (creator)(name)(owner)(active)(recovery)(deposit) )
FC_REFLECT( eosio::chain::contracts::newaccount , (creator)(name)(owner)(active)(recovery) )
FC_REFLECT( eosio::chain::contracts::setcode , (account)(vmtype)(vmversion)(code) ) //abi
FC_REFLECT( eosio::chain::contracts::setabi , (account)(abi) )
FC_REFLECT( eosio::chain::contracts::setproducer , (name)(key)(configuration) )
FC_REFLECT( eosio::chain::contracts::okproducer , (voter)(producer)(approve) )
FC_REFLECT( eosio::chain::contracts::setproxy , (stakeholder)(proxy) )
FC_REFLECT( eosio::chain::contracts::updateauth , (account)(permission)(parent)(data) )
FC_REFLECT( eosio::chain::contracts::deleteauth , (account)(permission) )
FC_REFLECT( eosio::chain::contracts::linkauth , (account)(code)(type)(requirement) )
......@@ -435,5 +307,4 @@ FC_REFLECT( eosio::chain::contracts::unlinkauth , (account
FC_REFLECT( eosio::chain::contracts::postrecovery , (account)(data)(memo) )
FC_REFLECT( eosio::chain::contracts::passrecovery , (account) )
FC_REFLECT( eosio::chain::contracts::vetorecovery , (account) )
FC_REFLECT( eosio::chain::contracts::nonce , (value) )
......@@ -18,6 +18,14 @@
namespace eosio { namespace chain {
struct blocknum_producer_schedule {
blocknum_producer_schedule( allocator<char> a )
:second(a){}
block_num_type first;
shared_producer_schedule_type second;
};
/**
* @class global_property_object
* @brief Maintains global state information (committee_member list, current fees)
......@@ -28,18 +36,19 @@ namespace eosio { namespace chain {
*/
class global_property_object : public chainbase::object<global_property_object_type, global_property_object>
{
OBJECT_CTOR(global_property_object, (pending_active_producers) )
OBJECT_CTOR(global_property_object, (active_producers)(new_active_producers)(pending_active_producers) )
id_type id;
chain_config configuration;
producer_schedule_type active_producers;
shared_producer_schedule_type active_producers;
shared_producer_schedule_type new_active_producers;
/** every block that has change in producer schedule gets inserted into this list, this includes
* all blocks that see a change in producer signing keys or vote order.
*
* TODO: consider moving this to a more effeicent datatype
*/
shared_vector< pair<block_num_type, producer_schedule_type> > pending_active_producers;
shared_vector< blocknum_producer_schedule > pending_active_producers;
};
......@@ -63,7 +72,10 @@ namespace eosio { namespace chain {
time_point time;
account_name current_producer;
share_type total_staked_tokens;
uint64_t total_net_weight = 1;
uint64_t total_cpu_weight = 1;
uint64_t total_db_capacity = 1024*1024*1024ull*1024ull;
uint64_t total_db_reserved = 0;
/**
* The current absolute slot number. Equal to the total
......
#pragma once
#include <eosio/chain/config.hpp>
#include <eosio/chain/types.hpp>
#include <chainbase/chainbase.hpp>
namespace eosio { namespace chain {
......@@ -23,7 +24,31 @@ namespace eosio { namespace chain {
*/
struct producer_schedule_type {
uint32_t version = 0; ///< sequentially incrementing version number
fc::array<producer_key,config::producer_count> producers;
vector<producer_key> producers;
};
struct shared_producer_schedule_type {
shared_producer_schedule_type( chainbase::allocator<char> alloc )
:producers(alloc){}
shared_producer_schedule_type& operator=( const producer_schedule_type& a ) {
version = a.version;
producers.reserve( a.producers.size() );
for( const auto& p : a.producers )
producers.push_back(p);
return *this;
}
operator producer_schedule_type()const {
producer_schedule_type result;
result.producers.reserve(producers.size());
for( const auto& p : producers )
result.producers.push_back(p);
return result;
}
uint32_t version = 0; ///< sequentially incrementing version number
shared_vector<producer_key> producers;
};
......
......@@ -55,6 +55,10 @@ namespace eosio { namespace chain {
id_type id;
account_name owner;
uint64_t net_weight = 0;
uint64_t cpu_weight = 0;
uint64_t db_reserved_capacity = 0; /// bytes
average_accumulator<config::bandwidth_average_window_ms> bytes;
average_accumulator<config::compute_average_window_ms> acts; ///< tracks a logical number of actions processed
......
......@@ -5,6 +5,7 @@
#include <boost/core/ignore_unused.hpp>
#include <eosio/chain/wasm_interface_private.hpp>
#include <fc/exception/exception.hpp>
#include <fc/io/raw.hpp>
#include <fc/utf8.hpp>
#include <Runtime/Runtime.h>
......@@ -218,7 +219,7 @@ namespace eosio { namespace chain {
try {
Serialization::MemoryInputStream stream((const U8 *) wasm_binary, wasm_binary_size);
#warning TODO: restore checktime injection?
WASM::serialize(stream, *module);
WASM::serializeWithInjection(stream, *module);
root_resolver resolver;
LinkResult link_result = linkModule(*module, resolver);
......@@ -367,6 +368,7 @@ namespace eosio { namespace chain {
FC_ASSERT( getFunctionType(call)->parameters.size() == args.size() );
auto context_guard = scoped_context(current_context, code, context);
context.checktime_start();
runInstanceStartFunc(code.instance);
Runtime::invokeFunction(call,args);
} catch( const Runtime::Exception& e ) {
......@@ -416,6 +418,106 @@ class context_aware_api {
apply_context& context;
};
class privileged_api : public context_aware_api {
public:
privileged_api( wasm_interface& wasm )
:context_aware_api(wasm)
{
FC_ASSERT( context.privileged, "${code} does not have permission to call this API", ("code",context.receiver) );
}
/**
* This should schedule the feature to be activated once the
* block that includes this call is irreversible. It should
* fail if the feature is already pending.
*
* Feature name should be base32 encoded name.
*/
void activate_feature( int64_t feature_name ) {
FC_ASSERT( !"Unsupported Harfork Detected" );
}
/**
* This should return true if a feature is active and irreversible, false if not.
*
* Irreversiblity by fork-database is not consensus safe, therefore, this defines
* irreversiblity only by block headers not by BFT short-cut.
*/
int is_feature_active( int64_t feature_name ) {
return false;
}
void set_resource_limits( account_name account,
int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight,
int64_t cpu_usec_per_period ) {
auto& buo = context.db.get<bandwidth_usage_object,by_owner>( account );
FC_ASSERT( buo.db_usage <= ram_bytes, "attempt to free to much space" );
auto& gdp = context.controller.get_dynamic_global_properties();
context.mutable_db.modify( gdp, [&]( auto& p ) {
p.total_net_weight -= buo.net_weight;
p.total_net_weight += net_weight;
p.total_cpu_weight -= buo.cpu_weight;
p.total_cpu_weight += cpu_weight;
p.total_db_reserved -= buo.db_reserved_capacity;
p.total_db_reserved += ram_bytes;
});
context.mutable_db.modify( buo, [&]( auto& o ){
o.net_weight = net_weight;
o.cpu_weight = cpu_weight;
o.db_reserved_capacity = ram_bytes;
});
}
void get_resource_limits( account_name account,
uint64_t& ram_bytes, uint64_t& net_weight, uint64_t cpu_weight ) {
}
void set_active_producers( array_ptr<char> packed_producer_schedule, size_t datalen) {
datastream<const char*> ds( packed_producer_schedule, datalen );
producer_schedule_type psch;
fc::raw::unpack(ds, psch);
context.mutable_db.modify( context.controller.get_global_properties(),
[&]( auto& gprops ) {
gprops.new_active_producers = psch;
});
}
bool is_privileged( account_name n )const {
return context.db.get<account_object, by_name>( n ).privileged;
}
bool is_frozen( account_name n )const {
return context.db.get<account_object, by_name>( n ).frozen;
}
void set_privileged( account_name n, bool is_priv ) {
const auto& a = context.db.get<account_object, by_name>( n );
context.mutable_db.modify( a, [&]( auto& ma ){
ma.privileged = is_priv;
});
}
void freeze_account( account_name n , bool should_freeze ) {
const auto& a = context.db.get<account_object, by_name>( n );
context.mutable_db.modify( a, [&]( auto& ma ){
ma.frozen = should_freeze;
});
}
/// TODO: add inline/deferred with support for arbitrary permissions rather than code/current auth
};
class checktime_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
void checktime() {
context.checktime();
}
};
class producer_api : public context_aware_api {
public:
using context_aware_api::context_aware_api;
......@@ -739,6 +841,22 @@ class transaction_api : public context_aware_api {
};
REGISTER_INTRINSICS(privileged_api,
(activate_feature, void(int64_t))
(is_feature_active, int(int64_t))
(set_resource_limits, void(int64_t,int64_t,int64_t,int64_t,int64_t))
(set_active_producers, void(int,int))
(is_privileged, int(int64_t))
(set_privileged, void(int64_t, int))
(freeze_account, void(int64_t, int))
(is_frozen, int(int64_t))
);
REGISTER_INTRINSICS(checktime_api,
(checktime, void())
);
REGISTER_INTRINSICS(producer_api,
(get_active_producers, int(int, int))
);
......
......@@ -37,8 +37,8 @@ namespace eosio { namespace testing {
void create_account( account_name name, asset initial_balance = asset(), account_name creator = N(inita), bool multisig = false );
void create_account( account_name name, string balance = "0.0000 EOS", account_name creator = N(inita), bool multisig = false );
transaction_trace transfer( account_name from, account_name to, asset amount, string memo = "" );
transaction_trace transfer( account_name from, account_name to, string amount, string memo = "" );
transaction_trace transfer( account_name from, account_name to, asset amount, string memo = "", account_name currency = config::eosio_system_acount_name );
transaction_trace transfer( account_name from, account_name to, string amount, string memo = "", account_name currency = config::eosio_system_acount_name );
template<typename ObjectType, typename IndexBy, typename... Args>
const auto& get( Args&&... args ) {
......
......@@ -3,6 +3,7 @@
#include <eosio/chain/contracts/types.hpp>
#include <eosio/chain/contracts/eos_contract.hpp>
#include <eosio/chain/contracts/contract_table_objects.hpp>
#include <eosio/chain/contracts/abi_serializer.hpp>
#include <fc/utility.hpp>
#include <fc/io/json.hpp>
......@@ -20,24 +21,7 @@ namespace eosio { namespace testing {
cfg.shared_memory_size = 1024*1024*8;
cfg.genesis.initial_timestamp = fc::time_point::from_iso_string("2020-01-01T00:00:00.000");
cfg.genesis.initial_accounts.resize( config::producer_count );
cfg.genesis.initial_producers.resize( config::producer_count );
// uint64_t init_name = N(inita);
string init_name = "inita";
for( uint32_t i = 0; i < config::producer_count; ++i ) {
auto pubkey = get_public_key(init_name);
cfg.genesis.initial_accounts[i].name = string(account_name(init_name));
cfg.genesis.initial_accounts[i].owner_key = get_public_key(init_name,"owner");
cfg.genesis.initial_accounts[i].active_key = get_public_key(init_name,"active");
cfg.genesis.initial_accounts[i].liquid_balance = asset::from_string( "1000000.0000 EOS" );
cfg.genesis.initial_accounts[i].staking_balance = asset::from_string( "1000000.0000 EOS" );
cfg.genesis.initial_producers[i].owner_name = string(account_name(init_name));
cfg.genesis.initial_producers[i].block_signing_key = get_public_key( init_name, "producer" );
init_name[4]++;
}
cfg.genesis.initial_key = get_public_key( config::system_account_name, "active" );
open();
}
......@@ -110,7 +94,6 @@ namespace eosio { namespace testing {
.owner = owner_auth,
.active = authority( get_public_key( a, "active" ) ),
.recovery = authority( get_public_key( a, "recovery" ) ),
.deposit = initial_balance
});
set_tapos(trx);
......@@ -132,21 +115,47 @@ namespace eosio { namespace testing {
}
transaction_trace tester::transfer( account_name from, account_name to, string amount, string memo ) {
transaction_trace tester::transfer( account_name from, account_name to, string amount, string memo, account_name currency ) {
return transfer( from, to, asset::from_string(amount), memo );
}
transaction_trace tester::transfer( account_name from, account_name to, asset amount, string memo ) {
transaction_trace tester::transfer( account_name from, account_name to, asset amount, string memo, account_name currency ) {
auto resolver = [this]( const account_name& name ) -> optional<contracts::abi_serializer> {
try {
const auto& accnt = control->get_database().get<account_object,by_name>( name );
contracts::abi_def abi;
if (contracts::abi_serializer::to_abi(accnt.abi, abi)) {
return contracts::abi_serializer(abi);
}
return optional<contracts::abi_serializer>();
} FC_RETHROW_EXCEPTIONS(error, "Failed to find or parse ABI for ${name}", ("name", name))
};
variant pretty_trx = fc::mutable_variant_object()
("actions", fc::variants({
fc::mutable_variant_object()
("account", currency)
("name", "transfer")
("authorization", fc::variants({
fc::mutable_variant_object()
("actor", from)
("permission", name(config::active_name))
}))
("data", fc::mutable_variant_object()
("from", from)
("to", to)
("amount", amount)
("memo", memo)
)
})
);
signed_transaction trx;
trx.actions.emplace_back( vector<permission_level>{{from,config::active_name}},
contracts::transfer{
.from = from,
.to = to,
.amount = amount.amount,
.memo = memo
} );
contracts::abi_serializer::from_variant(pretty_trx, trx, resolver);
set_tapos( trx );
set_tapos(trx);
trx.sign( get_private_key( from, "active" ), chain_id_type() );
trx.sign( get_private_key( from, name(config::active_name).to_string() ), chain_id_type() );
return push_transaction( trx );
}
......@@ -249,10 +258,8 @@ namespace eosio { namespace testing {
}
share_type tester::get_balance( const account_name& account ) const {
const auto& db = control->get_database();
return contracts::get_eosio_balance(db, account);
return get_currency_balance( config::system_account_name, EOS_SYMBOL, account ).amount;
}
/**
* Reads balance as stored by generic_currency contract
*/
......
......@@ -238,13 +238,18 @@ public:
{
}
void adjustIfFunctionIndex(Uptr& index, ObjectKind kind)
{
if (kind == ObjectKind::function)
++index;
}
void adjustExportIndex(Module& module)
{
// all function exports need to have their index increased to account for inserted definition
for (auto& exportDef : module.exports)
{
if (exportDef.kind == ObjectKind::function)
++exportDef.index;
adjustIfFunctionIndex(exportDef.index, exportDef.kind);
}
}
......@@ -271,6 +276,7 @@ struct NoOpInjection
void addImport(Module& ) {}
template<typename Imm>
void conditionallyAddCall(Opcode , const Imm& , const Module& , Serialization::OutputStream& ) {}
void adjustIfFunctionIndex(Uptr& , ObjectKind ) {}
void adjustExportIndex(Module& ) {}
template<typename Imm>
void adjustCallIndex(const Module& , Imm& ) {}
......@@ -859,6 +865,7 @@ namespace WASM
{
serializeVarUInt32(sectionStream,module.startFunctionIndex);
});
injection.adjustIfFunctionIndex(module.startFunctionIndex, ObjectKind::function);
}
template<typename Stream>
......
......@@ -8,6 +8,6 @@ add_subdirectory(account_history_plugin)
add_subdirectory(account_history_api_plugin)
add_subdirectory(wallet_plugin)
add_subdirectory(wallet_api_plugin)
add_subdirectory(txn_test_gen_plugin)
#add_subdirectory(txn_test_gen_plugin)
add_subdirectory(faucet_testnet_plugin)
add_subdirectory(mongo_db_plugin)
......@@ -13,7 +13,6 @@
#include <eosio/chain/contracts/chain_initializer.hpp>
#include <eosio/chain/contracts/staked_balance_objects.hpp>
#include <eosio/chain/contracts/genesis_state.hpp>
#include <eosio/chain/contracts/eos_contract.hpp>
......@@ -30,7 +29,6 @@ using namespace eosio::chain;
using namespace eosio::chain::config;
using fc::flat_map;
#warning TODO: rate limiting
//using txn_msg_rate_limits = chain_controller::txn_msg_rate_limits;
......@@ -54,17 +52,6 @@ public:
//txn_msg_rate_limits rate_limits;
};
#ifdef NDEBUG
const uint32_t chain_plugin::default_received_block_transaction_execution_time = 12;
const uint32_t chain_plugin::default_transaction_execution_time = 3;
const uint32_t chain_plugin::default_create_block_transaction_execution_time = 3;
#else
const uint32_t chain_plugin::default_received_block_transaction_execution_time = 72;
const uint32_t chain_plugin::default_transaction_execution_time = 18;
const uint32_t chain_plugin::default_create_block_transaction_execution_time = 18;
#endif
chain_plugin::chain_plugin()
:my(new chain_plugin_impl()) {
}
......@@ -79,11 +66,11 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip
("block-log-dir", bpo::value<bfs::path>()->default_value("blocks"),
"the location of the block log (absolute path or relative to application data dir)")
("checkpoint,c", bpo::value<vector<string>>()->composing(), "Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints.")
("rcvd-block-trans-execution-time", bpo::value<uint32_t>()->default_value(default_received_block_transaction_execution_time),
("rcvd-block-trans-execution-time", bpo::value<uint32_t>()->default_value(chain_controller::default_received_block_transaction_execution_time_ms),
"Limits the maximum time (in milliseconds) that is allowed a transaction's code to execute from a received block.")
("trans-execution-time", bpo::value<uint32_t>()->default_value(default_transaction_execution_time),
("trans-execution-time", bpo::value<uint32_t>()->default_value(chain_controller::default_transaction_execution_time_ms),
"Limits the maximum time (in milliseconds) that is allowed a pushed transaction's code to execute.")
("create-block-trans-execution-time", bpo::value<uint32_t>()->default_value(default_create_block_transaction_execution_time),
("create-block-trans-execution-time", bpo::value<uint32_t>()->default_value(chain_controller::default_create_block_transaction_execution_time_ms),
"Limits the maximum time (in milliseconds) that is allowed a transaction's code to execute while creating a block.")
#warning TODO: rate limiting
/*("per-authorized-account-transaction-msg-rate-limit-time-frame-sec", bpo::value<uint32_t>()->default_value(default_per_auth_account_time_frame_seconds),
......@@ -450,13 +437,6 @@ read_only::get_account_results read_only::get_account( const get_account_params&
result.account_name = params.account_name;
const auto& d = db.get_database();
share_type balance = contracts::get_eosio_balance(d, params.account_name );
const auto& staked_balance = d.get<staked_balance_object,by_owner_name>( params.account_name );
result.eos_balance = asset(balance, EOS_SYMBOL);
result.staked_balance = asset(staked_balance.staked_balance);
result.unstaking_balance = asset(staked_balance.unstaking_balance);
result.last_unstaking_time = staked_balance.last_unstaking_time;
const auto& permissions = d.get_index<permission_index,by_owner>();
auto perm = permissions.lower_bound( boost::make_tuple( params.account_name ) );
......
......@@ -77,13 +77,9 @@ public:
struct get_account_results {
name account_name;
asset eos_balance = asset(0,EOS_SYMBOL);
asset staked_balance;
asset unstaking_balance;
fc::time_point_sec last_unstaking_time;
vector<permission> permissions;
optional<producer_info> producer;
};
struct get_account_params {
name account_name;
};
......@@ -356,10 +352,6 @@ public:
void get_chain_id (chain::chain_id_type &cid) const;
static const uint32_t default_received_block_transaction_execution_time;
static const uint32_t default_transaction_execution_time;
static const uint32_t default_create_block_transaction_execution_time;
private:
unique_ptr<class chain_plugin_impl> my;
};
......@@ -383,7 +375,7 @@ FC_REFLECT( eosio::chain_apis::read_only::get_currency_balance_params, (code)(ac
FC_REFLECT( eosio::chain_apis::read_only::get_currency_stats_params, (code)(symbol));
FC_REFLECT( eosio::chain_apis::read_only::get_currency_stats_result, (supply));
FC_REFLECT( eosio::chain_apis::read_only::get_account_results, (account_name)(eos_balance)(staked_balance)(unstaking_balance)(last_unstaking_time)(permissions)(producer) )
FC_REFLECT( eosio::chain_apis::read_only::get_account_results, (account_name)(permissions) )
FC_REFLECT( eosio::chain_apis::read_only::get_code_results, (account_name)(code_hash)(wast)(abi) )
FC_REFLECT( eosio::chain_apis::read_only::get_account_params, (account_name) )
FC_REFLECT( eosio::chain_apis::read_only::get_code_params, (account_name) )
......
......@@ -222,7 +222,6 @@ struct faucet_testnet_plugin_impl {
auto& plugin = _app.get_plugin<chain_plugin>();
plugin.get_chain_id(chainid);
chain_controller& cc = plugin.chain();
const asset deposit(1);
signed_transaction trx;
auto memo = fc::variant(fc::time_point::now()).as_string() + " " + fc::variant(fc::time_point::now().time_since_epoch()).as_string();
......@@ -233,7 +232,7 @@ struct faucet_testnet_plugin_impl {
auto recovery_auth = chain::authority{1, {}, {{{_create_account_name, "active"}, 1}}};
trx.actions.emplace_back(vector<chain::permission_level>{{_create_account_name,"active"}},
contracts::newaccount{_create_account_name, new_account_name, owner_auth, active_auth, recovery_auth, deposit});
contracts::newaccount{_create_account_name, new_account_name, owner_auth, active_auth, recovery_auth});
trx.expiration = cc.head_block_time() + fc::seconds(30);
trx.set_reference_block(cc.head_block_id());
......
......@@ -403,6 +403,7 @@ void mongo_db_plugin_impl::update_account(const chain::action& msg) {
if (msg.name == transfer) {
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()});
/* todo need to follow eosio.system transfer
auto transfer = msg.as<chain::contracts::transfer>();
auto from_name = transfer.from.to_string();
auto to_name = transfer.to.to_string();
......@@ -425,34 +426,17 @@ void mongo_db_plugin_impl::update_account(const chain::action& msg) {
accounts.update_one(document{} << "_id" << from_account.view()["_id"].get_oid() << finalize, update_from.view());
accounts.update_one(document{} << "_id" << to_account.view()["_id"].get_oid() << finalize, update_to.view());
*/
} else if (msg.name == newaccount) {
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()});
auto newaccount = msg.as<chain::contracts::newaccount>();
// find creator to update its balance
auto from_name = newaccount.creator.to_string();
document find_from{};
find_from << "name" << from_name;
auto from_account = accounts.find_one(find_from.view());
if (!from_account) {
elog("Unable to find account ${n}", ("n", from_name));
return;
}
// decrease creator by deposit amount
auto from_view = from_account->view();
asset from_balance = asset::from_string(from_view["eos_balance"].get_utf8().value.to_string());
from_balance -= newaccount.deposit;
document update_from{};
update_from << "$set" << open_document << "eos_balance" << from_balance.to_string() << close_document;
accounts.update_one(find_from.view(), update_from.view());
// create new account with staked deposit amount
// create new account
bsoncxx::builder::stream::document doc{};
doc << "name" << newaccount.name.to_string()
<< "eos_balance" << asset().to_string()
<< "staked_balance" << newaccount.deposit.to_string()
<< "staked_balance" << asset().to_string()
<< "unstaking_balance" << asset().to_string()
<< "createdAt" << b_date{now}
<< "updatedAt" << b_date{now};
......@@ -460,72 +444,6 @@ void mongo_db_plugin_impl::update_account(const chain::action& msg) {
elog("Failed to insert account ${n}", ("n", newaccount.name));
}
} else if (msg.name == lock) {
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()});
auto lock = msg.as<chain::contracts::lock>();
auto from_account = find_account(accounts, lock.from);
auto to_account = find_account(accounts, lock.to);
asset from_balance = asset::from_string(from_account.view()["eos_balance"].get_utf8().value.to_string());
asset to_balance = asset::from_string(to_account.view()["stacked_balance"].get_utf8().value.to_string());
from_balance -= asset(lock.amount);
to_balance += asset(lock.amount);
document update_from{};
update_from << "$set" << open_document << "eos_balance" << from_balance.to_string()
<< "updatedAt" << b_date{now}
<< close_document;
document update_to{};
update_to << "$set" << open_document << "stacked_balance" << to_balance.to_string()
<< "updatedAt" << b_date{now}
<< close_document;
accounts.update_one(document{} << "_id" << from_account.view()["_id"].get_oid() << finalize, update_from.view());
accounts.update_one(document{} << "_id" << to_account.view()["_id"].get_oid() << finalize, update_to.view());
} else if (msg.name == unlock) {
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()});
auto unlock = msg.as<chain::contracts::unlock>();
auto from_account = find_account(accounts, unlock.account);
asset unstack_balance = asset::from_string(from_account.view()["unstacking_balance"].get_utf8().value.to_string());
asset stack_balance = asset::from_string(from_account.view()["stacked_balance"].get_utf8().value.to_string());
auto deltaStake = unstack_balance - asset(unlock.amount);
stack_balance += deltaStake;
unstack_balance = asset(unlock.amount);
// TODO: proxies and last_unstaking_time
document update_from{};
update_from << "$set" << open_document
<< "staked_balance" << stack_balance.to_string()
<< "unstacking_balance" << unstack_balance.to_string()
<< "updatedAt" << b_date{now}
<< close_document;
accounts.update_one(document{} << "_id" << from_account.view()["_id"].get_oid() << finalize, update_from.view());
} else if (msg.name == claim) {
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()});
auto claim = msg.as<chain::contracts::claim>();
auto from_account = find_account(accounts, claim.account);
asset balance = asset::from_string(from_account.view()["eos_balance"].get_utf8().value.to_string());
asset unstack_balance = asset::from_string(from_account.view()["unstacking_balance"].get_utf8().value.to_string());
unstack_balance -= asset(claim.amount);
balance += asset(claim.amount);
document update_from{};
update_from << "$set" << open_document
<< "eos_balance" << balance.to_string()
<< "unstacking_balance" << unstack_balance.to_string()
<< "updatedAt" << b_date{now}
<< close_document;
accounts.update_one(document{} << "_id" << from_account.view()["_id"].get_oid() << finalize, update_from.view());
} else if (msg.name == setabi) {
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::microseconds{fc::time_point::now().time_since_epoch().count()});
......
......@@ -224,7 +224,7 @@ block_production_condition::block_production_condition_enum producer_plugin_impl
ilog("Not producing block because production is disabled until we receive a recent block (see: --enable-stale-production)");
break;
case block_production_condition::not_my_turn:
ilog("Not producing block because it isn't my turn");
ilog("Not producing block because it isn't my turn, its ${scheduled_producer}", (capture) );
break;
case block_production_condition::not_time_yet:
ilog("Not producing block because slot has not yet arrived");
......
......@@ -75,14 +75,14 @@ struct txn_test_gen_plugin_impl {
signed_transaction trx;
trx.expiration = cc.head_block_time() + fc::seconds(30);
trx.set_reference_block(cc.head_block_id());
trx.actions.emplace_back(vector<chain::permission_level>{{creator,"active"}}, contracts::lock{creator, creator, 300});
//todo trx.actions.emplace_back(vector<chain::permission_level>{{creator,"active"}}, contracts::lock{creator, creator, 300});
//create "A" account
{
auto owner_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}};
auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_A_pub_key, 1}}, {}};
auto recovery_auth = eosio::chain::authority{1, {}, {{{creator, "active"}, 1}}};
trx.actions.emplace_back(vector<chain::permission_level>{{creator,"active"}}, contracts::newaccount{creator, newaccountA, owner_auth, active_auth, recovery_auth, stake});
//todo trx.actions.emplace_back(vector<chain::permission_level>{{creator,"active"}}, contracts::newaccount{creator, newaccountA, owner_auth, active_auth, recovery_auth, stake});
}
//create "B" account
{
......@@ -90,7 +90,7 @@ struct txn_test_gen_plugin_impl {
auto active_auth = eosio::chain::authority{1, {{txn_text_receiver_B_pub_key, 1}}, {}};
auto recovery_auth = eosio::chain::authority{1, {}, {{{creator, "active"}, 1}}};
trx.actions.emplace_back(vector<chain::permission_level>{{creator,"active"}}, contracts::newaccount{creator, newaccountB, owner_auth, active_auth, recovery_auth, stake});
//todo trx.actions.emplace_back(vector<chain::permission_level>{{creator,"active"}}, contracts::newaccount{creator, newaccountB, owner_auth, active_auth, recovery_auth, stake});
}
trx.sign(creator_priv_key, chainid);
cc.push_transaction(packed_transaction(trx));
......
......@@ -227,7 +227,8 @@ uint64_t generate_nonce_value() {
}
chain::action generate_nonce() {
return chain::action( {}, contracts::nonce{.value = generate_nonce_value()} );
auto v = generate_nonce_value();
return chain::action( {}, config::eosio_system_acount_name, "nonce", fc::raw::pack(v));
}
vector<chain::permission_level> get_account_permissions(const vector<string>& permissions) {
......@@ -300,18 +301,16 @@ void send_transaction( signed_transaction& trx, bool skip_sign, packed_transacti
std::cout << fc::json::to_pretty_string(push_transaction(trx, skip_sign, compression)) << std::endl;
}
void create_account(name creator, name newaccount, public_key_type owner, public_key_type active, bool sign, uint64_t staked_deposit) {
void create_account(name creator, name newaccount, public_key_type owner, public_key_type active, bool skip_sign) {
auto owner_auth = eosio::chain::authority{1, {{owner, 1}}, {}};
auto active_auth = eosio::chain::authority{1, {{active, 1}}, {}};
auto recovery_auth = eosio::chain::authority{1, {}, {{{creator, "active"}, 1}}};
asset deposit(staked_deposit);
vector<chain::action> actions;
actions.emplace_back( vector<chain::permission_level>{{creator,"active"}},
contracts::newaccount{creator, newaccount, owner_auth, active_auth, recovery_auth, deposit});
contracts::newaccount{creator, newaccount, owner_auth, active_auth, recovery_auth});
send_actions(std::move(actions), !sign);
send_actions(std::move(actions), skip_sign);
}
chain::action create_updateauth(const name& account, const name& permission, const name& parent, const authority& auth, const name& permissionAuth) {
......@@ -482,37 +481,15 @@ int main( int argc, char** argv ) {
string ownerKey;
string activeKey;
bool skip_sign = false;
uint64_t staked_deposit=10000;
auto createAccount = create->add_subcommand("account", localized("Create a new account on the blockchain"), false);
createAccount->add_option("creator", creator, localized("The name of the account creating the new account"))->required();
createAccount->add_option("name", account_name, localized("The name of the new account"))->required();
createAccount->add_option("OwnerKey", ownerKey, localized("The owner public key for the account"))->required();
createAccount->add_option("ActiveKey", activeKey, localized("The active public key for the account"))->required();
createAccount->add_flag("-s,--skip-signature", skip_sign, localized("Specify that unlocked wallet keys should not be used to sign transaction"));
createAccount->add_option("--staked-deposit", staked_deposit, localized("the staked deposit transfered to the new account"));
add_standard_transaction_options(createAccount);
createAccount->set_callback([&] {
create_account(creator, account_name, public_key_type(ownerKey), public_key_type(activeKey), !skip_sign, staked_deposit);
});
// create producer
vector<string> permissions;
auto createProducer = create->add_subcommand("producer", localized("Create a new producer on the blockchain"), false);
createProducer->add_option("name", account_name, localized("The name of the new producer"))->required();
createProducer->add_option("OwnerKey", ownerKey, localized("The public key for the producer"))->required();
createProducer->add_option("-p,--permission", permissions,
localized("An account and permission level to authorize, as in 'account@permission' (default user@active)"));
createProducer->add_flag("-s,--skip-signature", skip_sign, localized("Specify that unlocked wallet keys should not be used to sign transaction"));
add_standard_transaction_options(createProducer);
createProducer->set_callback([&account_name, &ownerKey, &permissions, &skip_sign] {
if (permissions.empty()) {
permissions.push_back(account_name + "@active");
}
auto account_permissions = get_account_permissions(permissions);
vector<chain::action> actions;
actions.emplace_back( account_permissions, contracts::setproducer{account_name, public_key_type(ownerKey), chain_config{}} );
send_actions(std::move(actions), skip_sign);
create_account(creator, account_name, public_key_type(ownerKey), public_key_type(activeKey), skip_sign);
});
// Get subcommand
......@@ -751,59 +728,6 @@ int main( int argc, char** argv ) {
send_actions(std::move(actions), skip_sign, packed_transaction::zlib);
});
// set producer approve/unapprove subcommand
string producer;
auto producerSubcommand = setSubcommand->add_subcommand("producer", localized("Approve/unapprove producer"));
producerSubcommand->require_subcommand();
auto approveCommand = producerSubcommand->add_subcommand("approve", localized("Approve producer"));
producerSubcommand->add_subcommand("unapprove", localized("Unapprove producer"));
producerSubcommand->add_option("user-name", account_name, localized("The name of the account approving"))->required();
producerSubcommand->add_option("producer-name", producer, localized("The name of the producer to approve"))->required();
producerSubcommand->add_option("-p,--permission", permissions,
localized("An account and permission level to authorize, as in 'account@permission' (default user@active)"));
producerSubcommand->add_flag("-s,--skip-signature", skip_sign, localized("Specify that unlocked wallet keys should not be used to sign transaction"));
add_standard_transaction_options(producerSubcommand);
producerSubcommand->set_callback([&] {
// don't need to check unapproveCommand because one of approve or unapprove is required
bool approve = producerSubcommand->got_subcommand(approveCommand);
if (permissions.empty()) {
permissions.push_back(account_name + "@active");
}
auto account_permissions = get_account_permissions(permissions);
vector<chain::action> actions;
actions.emplace_back( account_permissions, contracts::okproducer{account_name, producer, approve});
push_actions(std::move(actions), skip_sign);
std::cout << localized("Set producer approval from ${name} for ${producer} to ${approve}",
("name", account_name)("producer", producer)("value", approve ? "approve" : "unapprove")) << std::endl;
});
// set proxy subcommand
string proxy;
auto proxySubcommand = setSubcommand->add_subcommand("proxy", localized("Set proxy account for voting"));
proxySubcommand->add_option("user-name", account_name, localized("The name of the account to proxy from"))->required();
proxySubcommand->add_option("proxy-name", proxy, localized("The name of the account to proxy (unproxy if not provided)"));
proxySubcommand->add_option("-p,--permission", permissions,
localized("An account and permission level to authorize, as in 'account@permission' (default user@active)"));
proxySubcommand->add_flag("-s,--skip-signature", skip_sign, localized("Specify that unlocked wallet keys should not be used to sign transaction"));
add_standard_transaction_options(proxySubcommand);
proxySubcommand->set_callback([&] {
if (permissions.empty()) {
permissions.push_back(account_name + "@active");
}
auto account_permissions = get_account_permissions(permissions);
if (proxy.empty()) {
proxy = account_name;
}
vector<chain::action> actions;
actions.emplace_back( account_permissions, contracts::setproxy{account_name, proxy});
push_actions(std::move(actions), skip_sign);
std::cout << localized("Set proxy for ${name} to ${proxy}", ("name", account_name)("proxy", proxy)) << std::endl;
});
// set account
auto setAccount = setSubcommand->add_subcommand("account", localized("set or update blockchain account state"))->require_subcommand();
......@@ -829,20 +753,25 @@ int main( int argc, char** argv ) {
transfer->add_flag("-s,--skip-sign", skip_sign, localized("Specify that unlocked wallet keys should not be used to sign transaction"));
add_standard_transaction_options(transfer);
transfer->set_callback([&] {
auto transfer = fc::mutable_variant_object
("from", sender)
("to", recipient)
("quantity", asset(amount))
("memo", memo);
auto args = fc::mutable_variant_object
("code", name(config::eosio_system_acount_name))
("action", "transfer")
("args", transfer);
auto result = call(json_to_bin_func, args);
std::vector<chain::action> actions;
actions.emplace_back(vector<chain::permission_level>{{sender,"active"}},
config::eosio_system_acount_name, "transfer", result.get_object()["binargs"].as<bytes>());
if (tx_force_unique) {
if (memo.size() == 0) {
// use the memo to add a nonce
memo = fc::to_string(generate_nonce_value());
} else {
// add a nonce actions
actions.emplace_back( generate_nonce() );
}
}
actions.emplace_back( vector<chain::permission_level>{{sender,"active"}},
contracts::transfer{ .from = sender, .to = recipient, .amount = amount, .memo = memo});
send_actions(std::move(actions), skip_sign);
});
......@@ -972,150 +901,6 @@ int main( int argc, char** argv ) {
std::cout << fc::json::to_pretty_string(v) << std::endl;
});
// Benchmark subcommand
auto benchmark = app.add_subcommand( "benchmark", localized("Configure and execute benchmarks"), false );
benchmark->require_subcommand();
auto benchmark_setup = benchmark->add_subcommand( "setup", localized("Configures initial condition for benchmark") );
uint64_t number_of_accounts = 2;
benchmark_setup->add_option("accounts", number_of_accounts, localized("the number of accounts in transfer among"))->required();
string c_account;
benchmark_setup->add_option("creator", c_account, localized("The creator account for benchmark accounts"))->required();
string owner_key;
string active_key;
benchmark_setup->add_option("owner", owner_key, localized("The owner key to use for account creation"))->required();
benchmark_setup->add_option("active", active_key, localized("The active key to use for account creation"))->required();
add_standard_transaction_options(benchmark_setup);
benchmark_setup->set_callback([&]{
auto controlling_account_arg = fc::mutable_variant_object( "controlling_account", c_account);
auto response_servants = call(get_controlled_accounts_func, controlling_account_arg);
fc::variant_object response_var;
fc::from_variant(response_servants, response_var);
std::vector<std::string> controlled_accounts_vec;
fc::from_variant(response_var["controlled_accounts"], controlled_accounts_vec);
long num_existing_accounts = std::count_if(controlled_accounts_vec.begin(),
controlled_accounts_vec.end(),
[](auto const &s) { return s.find("benchmark") != std::string::npos;});
boost::format fmter("%1% accounts already exist");
fmter % num_existing_accounts;
EOSC_ASSERT( number_of_accounts > num_existing_accounts, fmter.str().c_str());
number_of_accounts -= num_existing_accounts;
std::cerr << localized("Creating ${number_of_accounts} accounts with initial balances", ("number_of_accounts",number_of_accounts)) << std::endl;
if (num_existing_accounts == 0) {
EOSC_ASSERT( number_of_accounts >= 2, "must create at least 2 accounts" );
}
auto info = get_info();
vector<signed_transaction> batch;
batch.reserve( number_of_accounts );
for( uint32_t i = num_existing_accounts; i < num_existing_accounts + number_of_accounts; ++i ) {
name newaccount( name("benchmark").value + i );
public_key_type owner(owner_key), active(active_key);
name creator(c_account);
auto owner_auth = eosio::chain::authority{1, {{owner, 1}}, {}};
auto active_auth = eosio::chain::authority{1, {{active, 1}}, {}};
auto recovery_auth = eosio::chain::authority{1, {}, {{{creator, "active"}, 1}}};
asset deposit(1);
signed_transaction trx;
trx.actions.emplace_back( vector<chain::permission_level>{{creator,"active"}},
contracts::newaccount{creator, newaccount, owner_auth, active_auth, recovery_auth, deposit});
trx.expiration = info.head_block_time + tx_expiration;
trx.set_reference_block(info.head_block_id);
batch.emplace_back(trx);
info = get_info();
}
auto result = call( push_txns_func, batch );
std::cout << fc::json::to_pretty_string(result) << std::endl;
});
auto benchmark_transfer = benchmark->add_subcommand( "transfer", localized("executes random transfers among accounts") );
uint64_t number_of_transfers = 0;
bool loop = false;
benchmark_transfer->add_option("accounts", number_of_accounts, localized("the number of accounts in transfer among"))->required();
benchmark_transfer->add_option("count", number_of_transfers, localized("the number of transfers to execute"))->required();
benchmark_transfer->add_option("loop", loop, localized("whether or not to loop for ever"));
add_standard_transaction_options(benchmark_transfer);
benchmark_transfer->set_callback([&]{
EOSC_ASSERT( number_of_accounts >= 2, "must create at least 2 accounts" );
std::cerr << localized("Funding ${number_of_accounts} accounts from init", ("number_of_accounts",number_of_accounts)) << std::endl;
auto info = get_info();
vector<signed_transaction> batch;
batch.reserve(100);
for( uint32_t i = 0; i < number_of_accounts; ++i ) {
name sender( "initb" );
name recipient( name("benchmark").value + i);
uint32_t amount = 100000;
signed_transaction trx;
trx.actions.emplace_back( vector<chain::permission_level>{{sender,"active"}},
contracts::transfer{ .from = sender, .to = recipient, .amount = amount, .memo = memo});
trx.expiration = info.head_block_time + tx_expiration;
trx.set_reference_block(info.head_block_id);
batch.emplace_back(trx);
if( batch.size() == 100 ) {
auto result = call( push_txns_func, batch );
// std::cout << fc::json::to_pretty_string(result) << std::endl;
batch.resize(0);
}
}
if( batch.size() ) {
auto result = call( push_txns_func, batch );
//std::cout << fc::json::to_pretty_string(result) << std::endl;
batch.resize(0);
}
std::cerr << localized("Generating random ${number_of_transfers} transfers among ${number_of_accounts}",("number_of_transfers",number_of_transfers)("number_of_accounts",number_of_accounts)) << std::endl;
while( true ) {
auto info = get_info();
uint64_t amount = 1;
for( uint32_t i = 0; i < number_of_transfers; ++i ) {
signed_transaction trx;
name sender( name("benchmark").value + rand() % number_of_accounts );
name recipient( name("benchmark").value + rand() % number_of_accounts );
while( recipient == sender )
recipient = name( name("benchmark").value + rand() % number_of_accounts );
auto memo = fc::variant(fc::time_point::now()).as_string() + " " + fc::variant(fc::time_point::now().time_since_epoch()).as_string();
trx.actions.emplace_back( vector<chain::permission_level>{{sender,"active"}},
contracts::transfer{ .from = sender, .to = recipient, .amount = amount, .memo = memo});
trx.expiration = info.head_block_time + tx_expiration;
trx.set_reference_block( info.head_block_id);
batch.emplace_back(trx);
if( batch.size() == 40 ) {
auto result = call( push_txns_func, batch );
//std::cout << fc::json::to_pretty_string(result) << std::endl;
batch.resize(0);
info = get_info();
}
}
if (batch.size() > 0) {
auto result = call( push_txns_func, batch );
std::cout << fc::json::to_pretty_string(result) << std::endl;
batch.resize(0);
info = get_info();
}
if( !loop ) break;
}
});
// Push subcommand
auto push = app.add_subcommand("push", localized("Push arbitrary transactions to the blockchain"), false);
push->require_subcommand();
......@@ -1124,6 +909,7 @@ int main( int argc, char** argv ) {
string contract;
string action;
string data;
vector<string> permissions;
auto actionsSubcommand = push->add_subcommand("action", localized("Push a transaction with a single action"));
actionsSubcommand->fallthrough(false);
actionsSubcommand->add_option("contract", contract,
......
......@@ -46,7 +46,7 @@ target_link_libraries( eosiod
PRIVATE -Wl,${whole_archive_flag} account_history_api_plugin -Wl,${no_whole_archive_flag} account_history_plugin
PRIVATE -Wl,${whole_archive_flag} chain_api_plugin -Wl,${no_whole_archive_flag} producer_plugin chain_plugin
PRIVATE -Wl,${whole_archive_flag} wallet_api_plugin -Wl,${no_whole_archive_flag}
PRIVATE net_plugin net_api_plugin -Wl,${whole_archive_flag} txn_test_gen_plugin -Wl,${no_whole_archive_flag}
PRIVATE net_plugin net_api_plugin -Wl,${whole_archive_flag} -Wl,${no_whole_archive_flag}
PRIVATE http_plugin -Wl,${whole_archive_flag} faucet_testnet_plugin -Wl,${no_whole_archive_flag}
PRIVATE eosio_chain fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} )
......
......@@ -60,6 +60,7 @@ endif()
#endif()
#
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/p2p_tests/sync/test.sh ${CMAKE_CURRENT_BINARY_DIR}/p2p_tests/sync/test.sh COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/p2p_tests/dawn_515/test.sh ${CMAKE_CURRENT_BINARY_DIR}/p2p_tests/dawn_515/test.sh COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/trans_sync_across_mixed_cluster_test.sh ${CMAKE_CURRENT_BINARY_DIR}/trans_sync_across_mixed_cluster_test.sh COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/distributed-transactions-test.py ${CMAKE_CURRENT_BINARY_DIR}/distributed-transactions-test.py COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/distributed-transactions-remote-test.py ${CMAKE_CURRENT_BINARY_DIR}/distributed-transactions-remote-test.py COPYONLY)
......@@ -73,6 +74,7 @@ add_test(NAME eosiod_run_test COMMAND tests/eosiod_run_test.py --dump-error-deta
add_test(NAME p2p_sync_test COMMAND tests/p2p_tests/sync/test.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_test(NAME p2p_sync_test_p2_d10 COMMAND tests/p2p_tests/sync/test.sh -p 2 -d 10 WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_test(NAME message_storm COMMAND tests/p2p_tests/sync/test.sh -m -p 21 -n 21 -d 5 -l WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_test(NAME p2p_dawn515_test COMMAND tests/p2p_tests/dawn_515/test.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_test(NAME eosiod_run_remote_test COMMAND tests/eosiod_run_remote_test.py --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
if(BUILD_MONGO_DB_PLUGIN)
add_test(NAME eosiod_run_test-mongodb COMMAND tests/eosiod_run_test.py --mongodb --exit-early --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
......
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/contracts/staked_balance_objects.hpp>
using namespace eosio;
using namespace eosio::chain;
......@@ -40,10 +38,10 @@ auto make_vetorecovery(const tester &t, account_name account, permission_name ve
auto push_nonce(tester &t, const string& role) {
// ensure the old owner key is valid
signed_transaction trx;
auto v = t.control->head_block_num();
trx.actions.emplace_back( vector<permission_level>{{N(alice),config::owner_name}},
nonce{
.value = t.control->head_block_num()
} );
config::eosio_system_acount_name, N(nonce),
fc::raw::pack(v) );
t.set_tapos(trx);
trx.sign(t.get_private_key(N(alice), role), chain_id_type());
t.push_transaction(trx);
......
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/contracts/staked_balance_objects.hpp>
#include <eosio/chain/contracts/abi_serializer.hpp>
using namespace eosio;
using namespace eosio::chain;
......@@ -53,22 +51,44 @@ BOOST_AUTO_TEST_CASE( transfer_test ) { try {
/// should throw because -1 becomes uint64 max which is greater than balance
BOOST_REQUIRE_THROW(test.transfer(N(bart),N(dan), asset(-1), "memo"), action_validate_exception);
auto resolver = [&]( const account_name& name ) -> optional<abi_serializer> {
try {
const auto& accnt = test.control->get_database().get<account_object,by_name>( name );
abi_def abi;
if (abi_serializer::to_abi(accnt.abi, abi)) {
return abi_serializer(abi);
}
return optional<abi_serializer>();
} FC_RETHROW_EXCEPTIONS(error, "Failed to find or parse ABI for ${name}", ("name", name))
};
{
auto from = N(bart);
auto to = N(dan);
asset amount(1);
signed_transaction trx;
trx.actions.emplace_back( vector<permission_level>{{from,config::active_name}},
contracts::transfer{
.from = from,
.to = to,
.amount = amount.amount,
.memo = "memo"
} );
variant pretty_trx = mutable_variant_object()
("actions", variants({
mutable_variant_object()
("account", name(config::eosio_system_acount_name))
("name", "transfer")
("authorization", variants({
mutable_variant_object()
("actor", "bart")
("permission", name(config::active_name).to_string())
}))
("data", mutable_variant_object()
("from", "bart")
("to", "dan")
("amount", amount)
("memo", "memo")
)
})
);
signed_transaction trx;
abi_serializer::from_variant(pretty_trx, trx, resolver);
test.set_tapos( trx );
BOOST_REQUIRE_THROW( test.push_transaction( trx ), tx_missing_sigs );
trx.sign( test.get_private_key( from, "active" ), chain_id_type() );
test.push_transaction( trx );
......@@ -78,16 +98,29 @@ BOOST_AUTO_TEST_CASE( transfer_test ) { try {
auto from = N(bart);
auto to = N(dan);
asset amount(1);
signed_transaction trx;
trx.actions.emplace_back( vector<permission_level>{{to,config::active_name}},
contracts::transfer{
.from = from,
.to = to,
.amount = amount.amount,
.memo = "memo"
} );
variant pretty_trx = mutable_variant_object()
("actions", variants({
mutable_variant_object()
("account", name(config::eosio_system_acount_name))
("name", "transfer")
("authorization", variants({
mutable_variant_object()
("actor", "dan")
("permission", name(config::active_name).to_string())
}))
("data", mutable_variant_object()
("from", "bart")
("to", "dan")
("amount", amount)
("memo", "memo")
)
})
);
signed_transaction trx;
abi_serializer::from_variant(pretty_trx, trx, resolver);
test.set_tapos( trx );
trx.sign( test.get_private_key( to, "active" ), chain_id_type() );
/// action not provided from authority
BOOST_REQUIRE_THROW( test.push_transaction( trx ), tx_missing_auth);
......@@ -122,23 +155,45 @@ BOOST_AUTO_TEST_CASE( transfer_delegation ) { try {
test.produce_block( fc::hours(2) ); ///< skip 2 hours
auto resolver = [&]( const account_name& name ) -> optional<abi_serializer> {
try {
const auto& accnt = test.control->get_database().get<account_object,by_name>( name );
abi_def abi;
if (abi_serializer::to_abi(accnt.abi, abi)) {
return abi_serializer(abi);
}
return optional<abi_serializer>();
} FC_RETHROW_EXCEPTIONS(error, "Failed to find or parse ABI for ${name}", ("name", name))
};
/// execute a transfer from dan to bart signed by trust
{
auto from = N(dan);
auto to = N(bart);
auto from = N(bart);
auto to = N(dan);
asset amount(1);
variant pretty_trx = mutable_variant_object()
("actions", variants({
mutable_variant_object()
("account", name(config::eosio_system_acount_name))
("name", "transfer")
("authorization", variants({
mutable_variant_object()
("actor", "bart")
("permission", name(config::active_name).to_string())
}))
("data", mutable_variant_object()
("from", "bart")
("to", "dan")
("amount", amount)
("memo", "memo")
)
})
);
signed_transaction trx;
trx.actions.emplace_back( vector<permission_level>{{from,config::active_name}},
contracts::transfer{
.from = from,
.to = to,
.amount = amount.amount,
.memo = "memo"
} );
abi_serializer::from_variant(pretty_trx, trx, resolver);
test.set_tapos( trx );
trx.sign( test.get_private_key( N(trust), "active" ), chain_id_type() );
wdump((fc::raw::pack_size(trx)));
......
#!/bin/bash
###############################################################
# Extracts staging directory and launchs cluster.
###############################################################
pnodes=1
total_nodes=3
topo=star
delay=1
read -d '' config00 << EOF
shared-file-size = 8192
p2p-server-address = localhost:9876
plugin = eosio::producer_plugin
plugin = eosio::chain_api_plugin
plugin = eosio::account_history_plugin
plugin = eosio::account_history_api_plugin
required-participation = true
shared-file-dir = blockchain
http-server-address = 127.0.0.1:8888
block-log-dir = blocks
p2p-listen-endpoint = 0.0.0.0:9876
allowed-connection = any
private-key = ['EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV','5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3']
send-whole-blocks = true
readonly = 0
genesis-json = ./genesis.json
producer-name = inita
producer-name = initb
producer-name = initc
producer-name = initd
producer-name = inite
producer-name = initf
producer-name = initg
producer-name = inith
producer-name = initi
producer-name = initj
producer-name = initk
producer-name = initl
producer-name = initm
producer-name = initn
producer-name = inito
producer-name = initp
producer-name = initq
producer-name = initr
producer-name = inits
producer-name = initt
producer-name = initu
EOF
read -d '' config01 << EOF
genesis-json = ./genesis.json
block-log-dir = blocks
readonly = 0
send-whole-blocks = true
shared-file-dir = blockchain
shared-file-size = 8192
http-server-address = 127.0.0.1:8889
p2p-listen-endpoint = 0.0.0.0:9877
p2p-server-address = localhost:9877
allowed-connection = any
p2p-peer-address = localhost:9876
plugin = eosio::chain_api_plugin
plugin = eosio::account_history_plugin
plugin = eosio::account_history_api_plugin
EOF
read -d '' config02 << EOF
genesis-json = ./genesis.json
block-log-dir = blocks
readonly = 0
send-whole-blocks = true
shared-file-dir = blockchain
shared-file-size = 8192
http-server-address = 127.0.0.1:8890
p2p-listen-endpoint = 0.0.0.0:9878
p2p-server-address = localhost:9877
allowed-connection = any
p2p-peer-address = localhost:9876
plugin = eosio::chain_api_plugin
plugin = eosio::account_history_plugin
plugin = eosio::account_history_api_plugin
EOF
read -d '' logging00 << EOF
{
"includes": [],
"appenders": [{
"name": "stderr",
"type": "console",
"args": {
"stream": "std_error",
"level_colors": [{
"level": "debug",
"color": "green"
},{
"level": "warn",
"color": "brown"
},{
"level": "error",
"color": "red"
}
]
},
"enabled": true
},{
"name": "stdout",
"type": "console",
"args": {
"stream": "std_out",
"level_colors": [{
"level": "debug",
"color": "green"
},{
"level": "warn",
"color": "brown"
},{
"level": "error",
"color": "red"
}
]
},
"enabled": true
}
],
"loggers": [{
"name": "default",
"level": "debug",
"enabled": true,
"additivity": false,
"appenders": [
"stderr"
]
}
]
}
EOF
read -d '' logging01 << EOF
{
"includes": [],
"appenders": [{
"name": "stderr",
"type": "console",
"args": {
"stream": "std_error",
"level_colors": [{
"level": "debug",
"color": "green"
},{
"level": "warn",
"color": "brown"
},{
"level": "error",
"color": "red"
}
]
},
"enabled": true
},{
"name": "stdout",
"type": "console",
"args": {
"stream": "std_out",
"level_colors": [{
"level": "debug",
"color": "green"
},{
"level": "warn",
"color": "brown"
},{
"level": "error",
"color": "red"
}
]
},
"enabled": true
}
],
"loggers": [{
"name": "default",
"level": "debug",
"enabled": true,
"additivity": false,
"appenders": [
"stderr"
]
}
]
}
EOF
read -d '' logging02 << EOF
{
"includes": [],
"appenders": [{
"name": "stderr",
"type": "console",
"args": {
"stream": "std_error",
"level_colors": [{
"level": "debug",
"color": "green"
},{
"level": "warn",
"color": "brown"
},{
"level": "error",
"color": "red"
}
]
},
"enabled": true
},{
"name": "stdout",
"type": "console",
"args": {
"stream": "std_out",
"level_colors": [{
"level": "debug",
"color": "green"
},{
"level": "warn",
"color": "brown"
},{
"level": "error",
"color": "red"
}
]
},
"enabled": true
}
],
"loggers": [{
"name": "default",
"level": "debug",
"enabled": true,
"additivity": false,
"appenders": [
"stderr"
]
}
]
}
EOF
rm -rf staging
rm -rf tn_data_*
cName=config.ini
lName=logging.json
path=staging/tn_data_00
mkdir -p $path
echo "$config00" > $path/$cName
echo "$logging00" > $path/$lName
path=staging/tn_data_01
mkdir -p $path
echo "$config01" > $path/$cName
echo "$logging01" > $path/$lName
path=staging/tn_data_02
mkdir -p $path
echo "$config02" > $path/$cName
echo "$logging02" > $path/$lName
programs/launcher/launcher -p $pnodes -n $total_nodes --nogen -d $delay
sleep 1
res=$(grep "reason = duplicate" tn_data_0*/stderr.txt | wc -l)
if [ $res -ne 0 ]; then
echo FAILURE: got a \"duplicate\" message
else
echo "SUCCESS"
fi
programs/launcher/launcher -k 15
rm -rf staging
rm -rf tn_data_*
exit $res
......@@ -1573,244 +1573,6 @@ BOOST_AUTO_TEST_CASE(abi_cycle)
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(transfer)
{ try {
abi_serializer abis(chain_initializer::eos_contract_abi());
const char* test_data = R"=====(
{
"from" : "from.acct",
"to" : "to.acct",
"amount" : 18446744073709551515,
"memo" : "really important transfer"
}
)=====";
auto var = fc::json::from_string(test_data);
auto transfer = var.as<contracts::transfer>();
BOOST_TEST("from.acct" == transfer.from);
BOOST_TEST("to.acct" == transfer.to);
BOOST_TEST(18446744073709551515u == transfer.amount);
BOOST_TEST("really important transfer" == transfer.memo);
auto var2 = verify_round_trip_conversion( abis, "transfer", var );
auto transfer2 = var2.as<contracts::transfer>();
BOOST_TEST(transfer.from == transfer2.from);
BOOST_TEST(transfer.to == transfer2.to);
BOOST_TEST(transfer.amount == transfer2.amount);
BOOST_TEST(transfer.memo == transfer2.memo);
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(lock)
{ try {
abi_serializer abis(chain_initializer::eos_contract_abi());
BOOST_CHECK(true);
const char* test_data = R"=====(
{
"from" : "from.acct",
"to" : "to.acct",
"amount" : -9223372036854775807,
}
)=====";
auto var = fc::json::from_string(test_data);
auto lock = var.as<contracts::lock>();
BOOST_TEST("from.acct" == lock.from);
BOOST_TEST("to.acct" == lock.to);
BOOST_TEST(-9223372036854775807 == lock.amount);
auto var2 = verify_round_trip_conversion( abis, "lock", var );
auto lock2 = var2.as<contracts::lock>();
BOOST_TEST(lock.from == lock2.from);
BOOST_TEST(lock.to == lock2.to);
BOOST_TEST(lock.amount == lock2.amount);
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(unlock)
{ try {
abi_serializer abis(chain_initializer::eos_contract_abi());
BOOST_CHECK(true);
const char* test_data = R"=====(
{
"account" : "an.acct",
"amount" : -9223372036854775807,
}
)=====";
auto var = fc::json::from_string(test_data);
auto unlock = var.as<contracts::unlock>();
BOOST_TEST("an.acct" == unlock.account);
BOOST_TEST(-9223372036854775807 == unlock.amount);
auto var2 = verify_round_trip_conversion( abis, "unlock", var );
auto unlock2 = var2.as<contracts::unlock>();
BOOST_TEST(unlock.account == unlock2.account);
BOOST_TEST(unlock.amount == unlock2.amount);
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(claim)
{ try {
abi_serializer abis(chain_initializer::eos_contract_abi());
BOOST_CHECK(true);
const char* test_data = R"=====(
{
"account" : "an.acct",
"amount" : -9223372036854775807,
}
)=====";
auto var = fc::json::from_string(test_data);
auto claim = var.as<contracts::claim>();
BOOST_TEST("an.acct" == claim.account);
BOOST_TEST(-9223372036854775807 == claim.amount);
auto var2 = verify_round_trip_conversion( abis, "claim", var );
auto claim2 = var2.as<contracts::claim>();
BOOST_TEST(claim.account == claim2.account);
BOOST_TEST(claim.amount == claim2.amount);
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(okproducer)
{ try {
abi_serializer abis(chain_initializer::eos_contract_abi());
BOOST_CHECK(true);
const char* test_data = R"=====(
{
"voter" : "an.acct",
"producer" : "an.acct2",
"approve" : -128,
}
)=====";
auto var = fc::json::from_string(test_data);
auto okproducer = var.as<contracts::okproducer>();
BOOST_TEST("an.acct" == okproducer.voter);
BOOST_TEST("an.acct2" == okproducer.producer);
BOOST_TEST(-128 == okproducer.approve);
auto var2 = verify_round_trip_conversion( abis, "okproducer", var );
auto okproducer2 = var2.as<contracts::okproducer>();
BOOST_TEST(okproducer.voter == okproducer2.voter);
BOOST_TEST(okproducer.producer == okproducer2.producer);
BOOST_TEST(okproducer.approve == okproducer2.approve);
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(setproducer)
{ try {
abi_serializer abis(chain_initializer::eos_contract_abi());
const char* test_data = R"=====(
{
"name" : "acct.name",
"key" : "EOS5PnYq6BZn7H9GvL68cCLjWUZThRemTJoJmybCn1iEpVUXLb5Az",
"configuration" : {
"producer_pay": "-9223372036854775717",
"target_block_size": "2147483145",
"max_block_size": "2147483135",
"target_block_acts_per_scope": "2147473155",
"max_block_acts_per_scope": "2147483165",
"target_block_acts": "4194967295",
"max_block_acts": "4294957295",
"real_threads": "9223372036854772717",
"max_storage_size": "9223372036854775805",
"max_transaction_lifetime": "2147483125",
"max_authority_depth": "63777",
"max_transaction_exec_time": "2146483015",
"max_inline_depth": "64267",
"max_inline_action_size": "4294867295",
"max_generated_transaction_size": "4292967295"
}
}
)=====";
auto var = fc::json::from_string(test_data);
auto setproducer = var.as<contracts::setproducer>();
BOOST_TEST("acct.name" == setproducer.name);
BOOST_TEST("EOS5PnYq6BZn7H9GvL68cCLjWUZThRemTJoJmybCn1iEpVUXLb5Az" == (string)setproducer.key);
BOOST_TEST(-9223372036854775717 == setproducer.configuration.producer_pay);
BOOST_TEST(2147483145u == setproducer.configuration.target_block_size);
BOOST_TEST(2147483135u == setproducer.configuration.max_block_size);
BOOST_TEST(2147473155u == setproducer.configuration.target_block_acts_per_scope);
BOOST_TEST(2147483165u == setproducer.configuration.max_block_acts_per_scope);
BOOST_TEST(4194967295u == setproducer.configuration.target_block_acts);
BOOST_TEST(4294957295u == setproducer.configuration.max_block_acts);
BOOST_TEST(9223372036854772717u == setproducer.configuration.real_threads);
BOOST_TEST(9223372036854775805u == setproducer.configuration.max_storage_size);
BOOST_TEST(2147483125u == setproducer.configuration.max_transaction_lifetime);
BOOST_TEST(63777u == setproducer.configuration.max_authority_depth);
BOOST_TEST(2146483015u == setproducer.configuration.max_transaction_exec_time);
BOOST_TEST(64267u == setproducer.configuration.max_inline_depth);
BOOST_TEST(4294867295u == setproducer.configuration.max_inline_action_size);
BOOST_TEST(4292967295u == setproducer.configuration.max_generated_transaction_size);
auto var2 = verify_round_trip_conversion( abis, "setproducer", var );
auto setproducer2 = var2.as<contracts::setproducer>();
BOOST_TEST(setproducer.name == setproducer2.name);
BOOST_TEST((string)setproducer.key == (string)setproducer2.key);
BOOST_TEST(setproducer.configuration.producer_pay == setproducer2.configuration.producer_pay);
BOOST_TEST(setproducer.configuration.target_block_size == setproducer2.configuration.target_block_size);
BOOST_TEST(setproducer.configuration.max_block_size == setproducer2.configuration.max_block_size);
BOOST_TEST(setproducer.configuration.target_block_acts_per_scope == setproducer2.configuration.target_block_acts_per_scope);
BOOST_TEST(setproducer.configuration.max_block_acts_per_scope == setproducer2.configuration.max_block_acts_per_scope);
BOOST_TEST(setproducer.configuration.target_block_acts == setproducer2.configuration.target_block_acts);
BOOST_TEST(setproducer.configuration.max_block_acts == setproducer2.configuration.max_block_acts);
BOOST_TEST(setproducer.configuration.real_threads == setproducer2.configuration.real_threads);
BOOST_TEST(setproducer.configuration.max_storage_size == setproducer2.configuration.max_storage_size);
BOOST_TEST(setproducer.configuration.max_transaction_lifetime == setproducer2.configuration.max_transaction_lifetime);
BOOST_TEST(setproducer.configuration.max_authority_depth == setproducer2.configuration.max_authority_depth);
BOOST_TEST(setproducer.configuration.max_transaction_exec_time == setproducer2.configuration.max_transaction_exec_time);
BOOST_TEST(setproducer.configuration.max_inline_depth == setproducer2.configuration.max_inline_depth);
BOOST_TEST(setproducer.configuration.max_inline_action_size == setproducer2.configuration.max_inline_action_size);
BOOST_TEST(setproducer.configuration.max_generated_transaction_size == setproducer2.configuration.max_generated_transaction_size);
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(setproxy)
{ try {
abi_serializer abis(chain_initializer::eos_contract_abi());
BOOST_CHECK(true);
const char* test_data = R"=====(
{
"stakeholder" : "stake.hldr",
"proxy" : "stkhdr.prxy"
}
)=====";
auto var = fc::json::from_string(test_data);
auto setproxy = var.as<contracts::setproxy>();
BOOST_TEST("stake.hldr" == setproxy.stakeholder);
BOOST_TEST("stkhdr.prxy" == setproxy.proxy);
auto var2 = verify_round_trip_conversion( abis, "setproxy", var );
auto setproxy2 = var2.as<contracts::setproxy>();
BOOST_TEST(setproxy.stakeholder == setproxy2.stakeholder);
BOOST_TEST(setproxy.proxy == setproxy2.proxy);
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(linkauth)
{ try {
......@@ -1995,8 +1757,7 @@ BOOST_AUTO_TEST_CASE(newaccount)
{"key" : "EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf", "weight" : 57605} ],
"accounts" : [ {"permission" : {"actor" : "prm.acct1", "permission" : "prm.prm1"}, "weight" : 53005 },
{"permission" : {"actor" : "prm.acct2", "permission" : "prm.prm2"}, "weight" : 53405 }]
},
"deposit" : "-90000000.0000 EOS"
}
}
)=====";
......@@ -2054,9 +1815,6 @@ BOOST_AUTO_TEST_CASE(newaccount)
BOOST_TEST("prm.prm2" == newaccount.recovery.accounts[1].permission.permission);
BOOST_TEST(53405u == newaccount.recovery.accounts[1].weight);
BOOST_TEST(-900000000000 == newaccount.deposit.amount);
BOOST_TEST(symbol(EOS_SYMBOL) == newaccount.deposit.symbol());
auto var2 = verify_round_trip_conversion( abis, "newaccount", var );
auto newaccount2 = var2.as<contracts::newaccount>();
BOOST_TEST(newaccount.creator == newaccount2.creator);
......@@ -2110,9 +1868,6 @@ BOOST_AUTO_TEST_CASE(newaccount)
BOOST_TEST(newaccount.recovery.accounts[1].permission.permission == newaccount2.recovery.accounts[1].permission.permission);
BOOST_TEST(newaccount.recovery.accounts[1].weight == newaccount2.recovery.accounts[1].weight);
BOOST_TEST(newaccount.deposit.amount == newaccount2.deposit.amount);
BOOST_TEST(newaccount.deposit.symbol() == newaccount2.deposit.symbol());
} FC_LOG_AND_RETHROW() }
......@@ -2404,29 +2159,6 @@ BOOST_AUTO_TEST_CASE(vetorecovery)
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(nonce)
{ try {
abi_serializer abis(chain_initializer::eos_contract_abi());
const char* test_data = R"=====(
{
"value" : "nonce.value"
}
)=====";
auto var = fc::json::from_string(test_data);
auto nonce = var.as<contracts::nonce>();
BOOST_TEST("nonce.value" == nonce.value);
auto var2 = verify_round_trip_conversion( abis, "nonce", var );
auto nonce2 = var2.as<contracts::nonce>();
BOOST_TEST(nonce.value == nonce2.value);
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(abi_type_repeat)
{ try {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册