提交 9680ea4e 编写于 作者: A arhag

Merge branch 'slim' into 2794-update-permission-usage

......@@ -151,7 +151,7 @@ macro(add_wast_executable)
add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.wast
DEPENDS ${target}.s
COMMAND $<TARGET_FILE:eosio-s2wasm> -o ${DESTINATION_FOLDER}/${target}.wast -s 8192 ${MAX_MEMORY_PARAM} ${target}.s
COMMAND $<TARGET_FILE:eosio-s2wasm> -o ${DESTINATION_FOLDER}/${target}.wast -s 10240 ${MAX_MEMORY_PARAM} ${target}.s
COMMENT "Generating WAST ${target}.wast"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM
......
......@@ -126,7 +126,7 @@
{"name":"total_ram_bytes_reserved", "type":"uint64"},
{"name":"total_ram_stake", "type":"asset"},
{"name":"last_producer_schedule_update", "type":"time"},
{"name":"last_pervote_bucket_fill", "type":"time"},
{"name":"last_pervote_bucket_fill", "type":"uint64"},
{"name":"eos_bucket", "type":"asset"},
{"name":"savings", "type":"asset"},
{"name":"last_producer_schedule_id", "type":"checksum160"},
......@@ -141,10 +141,10 @@
{"name":"producer_key", "type":"public_key"},
{"name":"url", "type":"string"},
{"name":"produced_blocks", "type":"uint32"},
{"name":"last_claim_time", "type":"time"},
{"name":"last_claim_time", "type":"uint64"},
{"name":"location", "type":"uint16"},
{"name":"time_became_active", "type":"time"},
{"name":"last_produced_block_time", "type":"time"}
{"name":"time_became_active", "type":"uint32"},
{"name":"last_produced_block_time", "type":"uint32"}
]
},{
"name": "regproducer",
......
......@@ -16,7 +16,7 @@ namespace eosiosystem {
_global(_self,_self),
_rammarket(_self,_self)
{
print( "construct system\n" );
//print( "construct system\n" );
_gstate = _global.exists() ? _global.get() : get_default_parameters();
auto itr = _rammarket.find(S(4,RAMEOS));
......@@ -32,7 +32,7 @@ namespace eosiosystem {
m.quote.balance.symbol = S(4,EOS);
});
} else {
print( "ram market already created" );
//print( "ram market already created" );
}
}
......@@ -44,9 +44,9 @@ namespace eosiosystem {
system_contract::~system_contract() {
print( "destruct system\n" );
//print( "destruct system\n" );
_global.set( _gstate, _self );
eosio_exit(0);
//eosio_exit(0);
}
void system_contract::setram( uint64_t max_ram_size ) {
......
......@@ -32,7 +32,7 @@ namespace eosiosystem {
eosio::asset total_ram_stake;
block_timestamp last_producer_schedule_update = 0;
time last_pervote_bucket_fill = 0;
uint64_t last_pervote_bucket_fill = 0;
eosio::asset eos_bucket;
eosio::asset savings;
checksum160 last_producer_schedule_id;
......@@ -52,7 +52,7 @@ namespace eosiosystem {
eosio::public_key producer_key; /// a packed public key object
std::string url;
uint32_t produced_blocks;
time last_claim_time = 0;
uint64_t last_claim_time = 0;
uint16_t location = 0;
block_timestamp time_became_active = 0;
block_timestamp last_produced_block_time = 0;
......@@ -122,7 +122,7 @@ namespace eosiosystem {
public:
system_contract( account_name s );
[[noreturn]] ~system_contract();
~system_contract();
// Actions:
void onblock( uint32_t timestamp_slot, account_name producer );
......@@ -203,7 +203,7 @@ namespace eosiosystem {
static eosio_global_state get_default_parameters();
// defined in voting.cpp
void adjust_voting_power( account_name acnt, int64_t delta );
void propagate_weight_change( const voter_info& voter );
};
} /// eosiosystem
......@@ -13,6 +13,7 @@ namespace eosiosystem {
const uint32_t seconds_per_year = 52*7*24*3600;
const uint32_t blocks_per_day = 2 * 24 * 3600;
const uint32_t blocks_per_hour = 2 * 3600;
const uint64_t useconds_per_day = 24 * 3600 * uint64_t(1000000);
eosio::asset system_contract::payment_per_block( double rate, const eosio::asset& token_supply, uint32_t num_blocks ) {
const int64_t payment = static_cast<int64_t>( (rate * double(token_supply.amount) * double(num_blocks)) / double(blocks_per_year) );
......@@ -28,7 +29,7 @@ namespace eosiosystem {
using namespace eosio;
/** until activated stake crosses this threshold no new rewards are paid */
if( _gstate.total_activated_stake < 150'000'000'0000 )
if( _gstate.total_activated_stake < 1500000000000 /* 150'000'000'0000 */ )
return;
if( _gstate.last_pervote_bucket_fill == 0 ) /// start the presses
......@@ -98,15 +99,15 @@ namespace eosiosystem {
auto prod = _producers.find( owner );
eosio_assert( prod != _producers.end(), "account name is not in producer list" );
if( prod->last_claim_time > 0 ) {
eosio_assert(now() >= prod->last_claim_time + seconds_per_day, "already claimed rewards within a day");
eosio_assert(current_time() >= prod->last_claim_time + useconds_per_day, "already claimed rewards within a day");
}
auto parameters = _global.get();
auto parameters = _global.get();
const asset token_supply = token( N(eosio.token)).get_supply(symbol_type(system_token_symbol).name() );
const time time_since_last_fill = now() - parameters.last_pervote_bucket_fill;
const uint32_t secs_since_last_fill = static_cast<uint32_t>( (current_time() - parameters.last_pervote_bucket_fill) / 1000000 );
const asset to_eos_bucket = supply_growth( standby_rate, token_supply, time_since_last_fill );
const asset to_savings = supply_growth( continuous_rate - (perblock_rate + standby_rate), token_supply, time_since_last_fill );
const asset to_eos_bucket = supply_growth( standby_rate, token_supply, secs_since_last_fill );
const asset to_savings = supply_growth( continuous_rate - (perblock_rate + standby_rate), token_supply, secs_since_last_fill );
const asset perblock_pay = payment_per_block( perblock_rate, token_supply, prod->produced_blocks );
const asset issue_amount = to_eos_bucket + to_savings + perblock_pay;
......@@ -116,7 +117,7 @@ namespace eosiosystem {
const asset pervote_pay = payment_per_vote( owner, prod->total_votes, to_eos_bucket + parameters.eos_bucket );
parameters.eos_bucket += ( to_eos_bucket - pervote_pay );
parameters.last_pervote_bucket_fill = now();
parameters.last_pervote_bucket_fill = current_time();
parameters.savings += to_savings;
_global.set( parameters, _self );
......@@ -124,7 +125,7 @@ namespace eosiosystem {
{ N(eosio), owner, perblock_pay + pervote_pay, std::string("producer claiming rewards") } );
_producers.modify( prod, 0, [&](auto& p) {
p.last_claim_time = now();
p.last_claim_time = current_time();
p.produced_blocks = 0;
});
......
......@@ -61,7 +61,7 @@ namespace eosiosystem {
void system_contract::unregprod( const account_name producer ) {
require_auth( producer );
const auto& prod = _producers.get( producer );
const auto& prod = _producers.get( producer, "producer not found" );
_producers.modify( prod, 0, [&]( producer_info& info ){
info.producer_key = eosio::public_key();
......@@ -102,7 +102,10 @@ namespace eosiosystem {
_gstate.last_producer_schedule_update = block_time;
}
double stake2vote( int64_t staked ) {
double weight = int64_t(now() / (seconds_per_day * 7)) / double( 52 );
return double(staked) * std::pow( 2, weight );
}
/**
* @pre producers must be sorted from lowest to highest and must be registered and active
* @pre if proxy is set then no producers can be voted for
......@@ -146,59 +149,71 @@ namespace eosiosystem {
_gstate.total_activated_stake += voter->staked;
}
auto weight = int64_t(now() / (seconds_per_day * 7)) / double( 52 );
double new_vote_weight = double(voter->staked) * std::pow(2,weight);
auto new_vote_weight = stake2vote( voter->staked );
if( voter->is_proxy ) {
new_vote_weight += voter->proxied_vote_weight;
}
boost::container::flat_map<account_name, double> producer_deltas;
for( const auto& p : voter->producers ) {
producer_deltas[p] -= voter->last_vote_weight;
}
if( new_vote_weight >= 0 ) {
for( const auto& p : producers ) {
producer_deltas[p] += new_vote_weight;
boost::container::flat_map<account_name, pair<double, bool /*new*/> > producer_deltas;
if ( voter->last_vote_weight != 0 ) {
if( voter->proxy ) {
auto old_proxy = _voters.find( voter->proxy );
eosio_assert( old_proxy != _voters.end(), "old proxy not found" ); //data corruption
_voters.modify( old_proxy, 0, [&]( auto& vp ) {
vp.proxied_vote_weight -= voter->last_vote_weight;
});
propagate_weight_change( *old_proxy );
} else {
for( const auto& p : voter->producers ) {
auto& d = producer_deltas[p];
d.first -= voter->last_vote_weight;
d.second = false;
}
}
}
if( voter->proxy != account_name() ) {
auto old_proxy = _voters.find( voter->proxy );
_voters.modify( old_proxy, 0, [&]( auto& vp ) {
vp.proxied_vote_weight -= voter->last_vote_weight;
print( " vote weight: ", vp.last_vote_weight, "\n" );
});
}
if( proxy != account_name() && new_vote_weight > 0 ) {
if( proxy ) {
auto new_proxy = _voters.find( voter->proxy );
eosio_assert( new_proxy != _voters.end() && new_proxy->is_proxy, "invalid proxy specified" );
_voters.modify( new_proxy, 0, [&]( auto& vp ) {
vp.proxied_vote_weight += new_vote_weight;
print( " vote weight: ", vp.last_vote_weight, "\n" );
});
if ( new_vote_weight >= 0 ) {
_voters.modify( new_proxy, 0, [&]( auto& vp ) {
vp.proxied_vote_weight += new_vote_weight;
});
propagate_weight_change( *new_proxy );
}
} else {
if( new_vote_weight >= 0 ) {
for( const auto& p : producers ) {
auto& d = producer_deltas[p];
d.first += new_vote_weight;
d.second = true;
}
}
}
_voters.modify( voter, 0, [&]( auto& av ) {
print( "new_vote_weight: ", new_vote_weight, "\n" );
av.last_vote_weight = new_vote_weight;
av.producers = producers;
av.proxy = proxy;
print( " vote weight: ", av.last_vote_weight, "\n" );
});
for( const auto& pd : producer_deltas ) {
auto pitr = _producers.find( pd.first );
if( pitr != _producers.end() ) {
eosio_assert( pitr->active() || !pd.second.second /* not from new set */, "producer is not currently registered" );
_producers.modify( pitr, 0, [&]( auto& p ) {
p.total_votes += pd.second;
eosio_assert( p.total_votes >= 0, "something bad happened" );
eosio_assert( p.active(), "producer is not active" );
print( "orig total_votes: ", p.total_votes, " delta: ", pd.second.first, "\n" );
p.total_votes += pd.second.first;
print( "new total_votes: ", p.total_votes, "\n" );
//eosio_assert( p.total_votes >= 0, "something bad happened" );
});
} else {
eosio_assert( !pd.second.second /* not from new set */, "producer is not registered" );
}
}
_voters.modify( voter, 0, [&]( auto& av ) {
print( "last_vote_weight: ", av.last_vote_weight, "\n" );
print( "new_vote_weight: ", new_vote_weight, "\n" );
av.last_vote_weight = new_vote_weight;
av.producers = producers;
av.proxy = proxy;
print( " vote weight: ", av.last_vote_weight, "\n" );
});
}
/**
......@@ -215,13 +230,46 @@ namespace eosiosystem {
auto pitr = _voters.find(proxy);
eosio_assert( pitr != _voters.end(), "proxy must have some stake first" );
eosio_assert( !pitr->is_proxy, "account is already a proxy" );
//eosio_assert( !pitr->is_proxy, "account is already a proxy" );
eosio_assert( pitr->is_proxy != isproxy, "action has no effect" );
_voters.modify( pitr, 0, [&]( auto& p ) {
p.is_proxy = isproxy;
print( " vote weight: ", p.last_vote_weight, "\n" );
});
propagate_weight_change( *pitr );
}
void system_contract::propagate_weight_change( const voter_info& voter ) {
eosio_assert( voter.proxy == 0 || !voter.is_proxy, "account registered as a proxy is not allowed to use a proxy" );
double new_weight = stake2vote( voter.staked );
if ( voter.is_proxy ) {
new_weight += voter.proxied_vote_weight;
}
if ( new_weight != voter.last_vote_weight ) {
if ( voter.proxy ) {
auto& proxy = _voters.get( voter.proxy, "proxy not found" ); //data corruption
_voters.modify( proxy, 0, [&]( auto& p ) {
p.proxied_vote_weight += new_weight - voter.last_vote_weight;
}
);
propagate_weight_change( proxy );
} else {
for ( auto acnt : voter.producers ) {
auto& pitr = _producers.get( acnt, "producer not found" ); //data corruption
_producers.modify( pitr, 0, [&]( auto& p ) {
p.total_votes += new_weight - voter.last_vote_weight;
}
);
}
}
}
_voters.modify( voter, 0, [&]( auto& v ) {
v.last_vote_weight = new_weight;
}
);
}
} /// namespace eosiosystem
......@@ -38,9 +38,14 @@ void token::create( account_name issuer,
void token::issue( account_name to, asset quantity, string memo )
{
print( "issue" );
auto sym = quantity.symbol.name();
stats statstable( _self, sym );
const auto& st = statstable.get( sym );
auto sym = quantity.symbol;
eosio_assert( sym.is_valid(), "invalid symbol name" );
auto sym_name = sym.name();
stats statstable( _self, sym_name );
auto existing = statstable.find( sym_name );
eosio_assert( existing != statstable.end(), "token with symbol does not exist, create token before issue" );
const auto& st = *existing;
require_auth( st.issuer );
eosio_assert( quantity.is_valid(), "invalid quantity" );
......@@ -55,8 +60,7 @@ void token::issue( account_name to, asset quantity, string memo )
add_balance( st.issuer, quantity, st, st.issuer );
if( to != st.issuer )
{
if( to != st.issuer ) {
SEND_INLINE_ACTION( *this, transfer, {st.issuer,N(active)}, {st.issuer, to, quantity, memo} );
}
}
......
/**
* @file account.h
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosiolib/types.h>
/**
* @defgroup accountapi Account API
* @brief Define API for querying account data
* @ingroup contractdev
*/
/**
* @defgroup accountcapi Account C API
* @brief C API for querying account data
* @ingroup accountapi
* @{
*/
extern "C" {
/**
* @brief Retrieve the balance for the provided account
* @details Retrieve the balance for the provided account
*
* @param balance - a pointer to a range of memory to store balance data
* @param len - length of the range of memory to store balance data
* @return true if account information is retrieved
*
* @pre data is a valid pointer to a range of memory at least datalen bytes long
* @pre data is a pointer to a balance object
* @pre *((uint64_t*)data) stores the primary key
*
* Example:
* @code
* balance b;
* b.account = N(myaccount);
* balance(b, sizeof(balance));
* @endcode
*
*/
bool account_balance_get( void* balance, uint32_t len );
///@ } accountcapi
}
/**
* @file account.hpp
* @copyright defined in eos/LICENSE.txt
* @brief Defines types and ABI for account API interactions
*
*/
#pragma once
#include <eosiolib/account.h>
#include <eosiolib/print.hpp>
#include <eosiolib/asset.hpp>
namespace eosio { namespace account {
/**
* @defgroup accountcppapi Account C++ API
* @brief C++ API for querying account data, e.g. account balance
* @ingroup accountapi
*
* @{
*/
/**
* @brief The binary structure expected and populated by native balance function.
* @details
* Example:
* @code
* account_balance test1_balance;
* test1_balance.account = N(test1);
* if (account_api::get(test1_balance))
* {
* eosio::print("test1 balance=", test1_balance.eos_balance, "\n");
* }
* @endcode
* @{
*/
struct PACKED(account_balance) {
/**
* @brief Name of the account who's balance this is
* @details Name of the account who's balance this is
*/
account_name account;
/**
* @brief Balance for this account
* @details Balance for this account
*/
asset eos_balance;
/**
* @brief Staked balance for this account
* @details Staked balance for this account
*/
asset staked_balance;
/**
* @brief Unstaking balance for this account
* @details Unstaking balance for this account
*/
asset unstaking_balance;
/**
* @brief Time at which last unstaking occurred for this account
* @details Time at which last unstaking occurred for this account
*/
time last_unstaking_time;
};
/// @} account_balance
/**
* @brief Retrieve a populated balance structure
* @details Retrieve a populated balance structure
* @param acnt - account
* @return true if account's balance is found
*/
bool get(account_balance& acnt)
{
return account_balance_get(&acnt, sizeof(account_balance));
}
/// @} eosio
} }
......@@ -75,7 +75,11 @@ namespace eosio {
extern "C" { \
void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \
auto self = receiver; \
if( code == self ) { \
if( action == N(onerror)) { \
/* onerror is only valid if it is for the "eosio" code account and authorized by "eosio"'s "active permission */ \
eosio_assert(code == N(eosio), "onerror action's are only valid from the \"eosio\" system account"); \
} \
if( code == self || action == N(onerror) ) { \
TYPE thiscontract( self ); \
switch( action ) { \
EOSIO_API( TYPE, MEMBERS ) \
......
......@@ -751,9 +751,9 @@ class multi_index
});
}
const T& get( uint64_t primary )const {
const T& get( uint64_t primary, const char* error_msg = "unable to find key" )const {
auto result = find( primary );
eosio_assert( result != cend(), "unable to find key" );
eosio_assert( result != cend(), error_msg );
return *result;
}
......
......@@ -55,13 +55,17 @@ namespace eosio {
};
struct onerror {
uint128_t sender_id;
transaction sent_trx;
uint128_t sender_id;
bytes sent_trx;
static onerror from_current_action() {
return unpack_action_data<onerror>();
}
transaction unpack_sent_trx() const {
return unpack<transaction>(sent_trx);
}
EOSLIB_SERIALIZE( onerror, (sender_id)(sent_trx) )
};
......
......@@ -78,7 +78,7 @@ namespace proxy {
configs::store(code_config, self);
eosio::print("Resending Transaction: ", error.sender_id, " as ", id, "\n");
transaction dtrx = error.sent_trx;
transaction dtrx = error.unpack_sent_trx();
dtrx.delay_sec = code_config.delay;
dtrx.send(id, self);
}
......
......@@ -25,7 +25,8 @@ extern "C" {
if( code == N(eosio) && action == N(onerror) ) {
auto error = eosio::onerror::from_current_action();
eosio::print("onerror called\n");
auto error_action = error.sent_trx.actions.at(0).name;
auto error_trx = error.unpack_sent_trx();
auto error_action = error_trx.actions.at(0).name;
// Error handlers for deferred transactions in these tests currently only support the first action
......
......@@ -31,7 +31,7 @@ namespace eosio {
#define WASM_TEST_ERROR_HANDLER(CALLED_CLASS_STR, CALLED_METHOD_STR, HANDLER_CLASS, HANDLER_METHOD) \
if( error_action == WASM_TEST_ACTION(CALLED_CLASS_STR, CALLED_METHOD_STR) ) { \
HANDLER_CLASS::HANDLER_METHOD(error.sent_trx); \
HANDLER_CLASS::HANDLER_METHOD(error_trx); \
return; \
}
......
......@@ -203,9 +203,12 @@ void test_transaction::send_transaction_trigger_error_handler(uint64_t receiver,
}
void test_transaction::assert_false_error_handler(const eosio::transaction& dtrx) {
auto onerror_action = eosio::get_action(1, 0);
eosio_assert( onerror_action.authorization.at(0).actor == dtrx.actions.at(0).account,
"authorizer of onerror action does not match receiver of original action in the deferred transaction" );
eosio_assert(dtrx.actions.size() == 1, "transaction should only have one action");
eosio_assert(dtrx.actions[0].account == N(testapi), "transaction has wrong code");
eosio_assert(dtrx.actions[0].name == WASM_TEST_ACTION("test_action", "assert_false"), "transaction has wrong name");
eosio_assert(dtrx.actions[0].authorization.size() == 1, "action should only have one authorization");
eosio_assert(dtrx.actions[0].authorization[0].actor == N(testapi), "action's authorization has wrong actor");
eosio_assert(dtrx.actions[0].authorization[0].permission == N(active), "action's authorization has wrong permission");
}
/**
......
......@@ -245,7 +245,7 @@ namespace eosio { namespace chain {
void block_header_state::add_confirmation( const header_confirmation& conf ) {
for( const auto& c : confirmations )
FC_ASSERT( c.producer == conf.producer, "block already confirmed by this producer" );
FC_ASSERT( c.producer != conf.producer, "block already confirmed by this producer" );
auto key = active_schedule.get_producer_key( conf.producer );
FC_ASSERT( key != public_key_type(), "producer not in current schedule" );
......
......@@ -1029,6 +1029,8 @@ void controller::startup() {
chainbase::database& controller::db()const { return my->db; }
fork_database& controller::fork_db()const { return my->fork_db; }
void controller::start_block( block_timestamp_type when, uint16_t confirm_block_count ) {
my->start_block(when, confirm_block_count);
......
......@@ -8,7 +8,6 @@ abi_def eosio_contract_abi(const abi_def& eosio_system_abi)
eos_abi.types.push_back( type_def{"account_name","name"} );
eos_abi.types.push_back( type_def{"table_name","name"} );
eos_abi.types.push_back( type_def{"share_type","int64"} );
eos_abi.types.push_back( type_def{"onerror","bytes"} );
eos_abi.types.push_back( type_def{"context_free_type","bytes"} );
eos_abi.types.push_back( type_def{"weight_type","uint16"} );
eos_abi.types.push_back( type_def{"fields","field[]"} );
......@@ -288,6 +287,13 @@ abi_def eosio_contract_abi(const abi_def& eosio_system_abi)
}
});
eos_abi.structs.emplace_back( struct_def {
"onerror", "", {
{"sender_id", "uint128"},
{"sent_trx", "bytes"}
}
});
return eos_abi;
}
} } /// eosio::chain
......@@ -31,6 +31,8 @@ namespace eosio { namespace chain {
using resource_limits::resource_limits_manager;
using apply_handler = std::function<void(apply_context&)>;
class fork_database;
class controller {
public:
struct config {
......@@ -105,6 +107,8 @@ namespace eosio { namespace chain {
chainbase::database& db()const;
fork_database& fork_db()const;
const account_object& get_account( account_name n )const;
const global_property_object& get_global_properties()const;
const dynamic_global_property_object& get_dynamic_global_properties()const;
......
......@@ -30,10 +30,6 @@ namespace eosio { namespace chain {
void apply_eosio_setcode(apply_context&);
void apply_eosio_setabi(apply_context&);
/*
void apply_eosio_onerror(apply_context&);
*/
void apply_eosio_canceldelay(apply_context&);
///@} end action handlers
......
#pragma once
#include <eosio/chain/types.hpp>
#include <eosio/chain/config.hpp>
#include <eosio/chain/exceptions.hpp>
#include "multi_index_includes.hpp"
......@@ -18,6 +19,10 @@ namespace eosio { namespace chain { namespace resource_limits {
return (value * r.numerator) / r.denominator;
}
constexpr uint64_t integer_divide_ceil(uint64_t num, uint64_t den ) {
return (num / den) + ((num % den) > 0 ? 1 : 0);
}
/**
* This class accumulates and exponential moving average based on inputs
* This accumulator assumes there are no drops in input data
......@@ -28,6 +33,7 @@ namespace eosio { namespace chain { namespace resource_limits {
struct exponential_moving_average_accumulator
{
static_assert( Precision > 0, "Precision must be positive" );
static constexpr uint64_t max_raw_value = std::numeric_limits<uint64_t>::max() / Precision;
exponential_moving_average_accumulator()
: last_ordinal(0)
......@@ -44,11 +50,18 @@ namespace eosio { namespace chain { namespace resource_limits {
* return the average value
*/
uint64_t average() const {
return value_ex / Precision;
return integer_divide_ceil(value_ex, Precision);
}
void add( uint64_t units, uint32_t ordinal, uint32_t window_size /* must be positive */ )
{
// check for some numerical limits before doing any state mutations
EOS_ASSERT(units <= max_raw_value, rate_limiting_state_inconsistent, "Usage exceeds maximum value representable after extending for precision");
EOS_ASSERT(std::numeric_limits<decltype(consumed)>::max() - consumed >= units, rate_limiting_state_inconsistent, "Overflow in tracked usage when adding usage!");
auto value_ex_contrib = integer_divide_ceil(units * Precision, (uint64_t)window_size);
EOS_ASSERT(std::numeric_limits<decltype(value_ex)>::max() - value_ex >= value_ex_contrib, rate_limiting_state_inconsistent, "Overflow in accumulated value when adding usage!");
if( last_ordinal != ordinal ) {
if( ordinal <= last_ordinal )
wdump((ordinal)(last_ordinal));
......@@ -66,11 +79,11 @@ namespace eosio { namespace chain { namespace resource_limits {
}
last_ordinal = ordinal;
consumed = value_ex / Precision;
consumed = average();
}
consumed += units;
value_ex += units * Precision / (uint64_t)window_size;
value_ex += value_ex_contrib;
}
};
......@@ -145,6 +158,9 @@ namespace eosio { namespace chain { namespace resource_limits {
elastic_limit_parameters cpu_limit_parameters = {EOS_PERCENT(config::default_max_block_cpu_usage, config::default_target_block_cpu_usage_pct), config::default_max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}};
elastic_limit_parameters net_limit_parameters = {EOS_PERCENT(config::default_max_block_net_usage, config::default_target_block_net_usage_pct), config::default_max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}};
uint32_t account_cpu_usage_average_window = config::account_cpu_usage_average_window_ms / config::block_interval_ms;
uint32_t account_net_usage_average_window = config::account_net_usage_average_window_ms / config::block_interval_ms;
};
using resource_limits_config_index = chainbase::shared_multi_index_container<
......
......@@ -89,8 +89,8 @@ void resource_limits_manager::add_transaction_usage(const flat_set<account_name>
const auto& usage = _db.get<resource_usage_object,by_owner>( a );
const auto& limits = _db.get<resource_limits_object,by_owner>( boost::make_tuple(false, a));
_db.modify( usage, [&]( auto& bu ){
bu.net_usage.add( net_usage, time_slot, config.net_limit_parameters.periods );
bu.cpu_usage.add( cpu_usage, time_slot, config.cpu_limit_parameters.periods );
bu.net_usage.add( net_usage, time_slot, config.account_net_usage_average_window );
bu.cpu_usage.add( cpu_usage, time_slot, config.account_cpu_usage_average_window );
});
if (limits.cpu_weight >= 0) {
......
Subproject commit 71cd824247231f2fc7273e9a7839ec004d2975a9
Subproject commit cb51952ae12e550959fa5c4cf9bec5fa5c454b5a
......@@ -796,10 +796,10 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try {
);
control->push_next_scheduled_transaction();
#warning TODO: FIX THE FOLLOWING TESTS
#if 0
{
produce_blocks(10);
transaction_trace_ptr trace;
control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } );
auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t && t->receipt->status != transaction_receipt::executed) { trace = t; } } );
// test error handling on deferred transaction failure
CALL_TEST_FUNCTION(*this, "test_transaction", "send_transaction_trigger_error_handler", {});
......@@ -807,7 +807,7 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try {
BOOST_CHECK(trace);
BOOST_CHECK_EQUAL(trace->receipt->status, transaction_receipt::soft_fail);
#endif
}
// test test_transaction_size
CALL_TEST_FUNCTION(*this, "test_transaction", "test_transaction_size", fc::raw::pack(54) ); // TODO: Need a better way to test this.
......@@ -844,7 +844,7 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try {
//schedule
{
transaction_trace_ptr trace;
control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } );
auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } );
CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {} );
//check that it doesn't get executed immediately
control->push_next_scheduled_transaction();
......@@ -858,50 +858,51 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try {
//confirm printed message
BOOST_TEST(!trace->action_traces.empty());
BOOST_TEST(trace->action_traces.back().console == "deferred executed\n");
c.disconnect();
}
#warning TODO: FIX THE FOLLOWING TESTS
#if 0
produce_blocks(10);
//schedule twice (second deferred transaction should replace first one)
{
transaction_trace_ptr trace;
control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } );
uint32_t count = 0;
auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t && t->scheduled) { trace = t; ++count; } } );
CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {});
CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {});
produce_block( fc::seconds(2) );
//check that only one deferred transaction executed
control->push_next_scheduled_transaction();
control->push_next_scheduled_transaction();
BOOST_CHECK_EQUAL(1, count);
BOOST_CHECK(trace);
BOOST_CHECK_EQUAL( 1, trace->action_traces.size() );
c.disconnect();
}
produce_blocks(10);
//schedule and cancel
{
transaction_trace_ptr trace;
control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } );
auto c = control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t && t->scheduled) { trace = t; } } );
CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {});
CALL_TEST_FUNCTION(*this, "test_transaction", "cancel_deferred_transaction", {});
produce_block( fc::seconds(2) );
control->push_next_scheduled_transaction();
BOOST_CHECK(!trace);
// BOOST_CHECK_EQUAL( 0, traces.size() );
c.disconnect();
}
//cancel_deferred() before scheduling transaction should not prevent the transaction from being scheduled (check that previous bug is fixed)
CALL_TEST_FUNCTION(*this, "test_transaction", "cancel_deferred_transaction", {});
CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {});
produce_block( fc::seconds(2) );
traces = control->push_deferred_transactions( true );
BOOST_CHECK_EQUAL( 1, traces.size() );
//verify that deferred transaction is dependent on max_generated_transaction_count configuration property
const auto& gpo = control->get_global_properties();
control->get_mutable_database().modify(gpo, [&]( auto& props ) {
props.configuration.max_generated_transaction_count = 0;
});
BOOST_CHECK_THROW(CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {}), transaction_exception);
#endif
produce_blocks(10);
//cancel_deferred() fails if no transaction is scheduled
{
BOOST_CHECK_THROW(CALL_TEST_FUNCTION(*this, "test_transaction", "cancel_deferred_transaction", {}), transaction_exception);
}
produce_blocks(10);
{
// Trigger a tx which in turn sends a deferred tx with payer != receiver
......
此差异已折叠。
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/fork_database.hpp>
#include <eosio.token/eosio.token.wast.hpp>
#include <eosio.token/eosio.token.abi.hpp>
......@@ -258,6 +259,100 @@ BOOST_AUTO_TEST_CASE( prune_remove_branch ) try {
BOOST_AUTO_TEST_CASE(confirmation) try {
tester c;
c.produce_blocks(10);
auto r = c.create_accounts( {N(dan),N(sam),N(pam),N(scott)} );
auto res = c.set_producers( {N(dan),N(sam),N(pam),N(scott)} );
private_key_type priv_sam = c.get_private_key( N(sam), "active" );
private_key_type priv_dan = c.get_private_key( N(dan), "active" );
private_key_type priv_pam = c.get_private_key( N(pam), "active" );
private_key_type priv_scott = c.get_private_key( N(scott), "active" );
private_key_type priv_invalid = c.get_private_key( N(invalid), "active" );
wlog("set producer schedule to [dan,sam,pam,scott]");
c.produce_blocks(50);
c.control->abort_block(); // discard pending block
BOOST_REQUIRE_EQUAL(61, c.control->head_block_num());
// 55 is by dan
block_state_ptr blk = c.control->fork_db().get_block_in_current_chain_by_num(55);
block_state_ptr blk61 = c.control->fork_db().get_block_in_current_chain_by_num(61);
block_state_ptr blk50 = c.control->fork_db().get_block_in_current_chain_by_num(50);
BOOST_REQUIRE_EQUAL(0, blk->bft_irreversible_blocknum);
BOOST_REQUIRE_EQUAL(0, blk->confirmations.size());
printf("bft number is %d #confirms %d\n", blk->bft_irreversible_blocknum, (int)blk->confirmations.size());
// invalid signature
BOOST_REQUIRE_EXCEPTION(c.control->push_confirmation(header_confirmation{blk->id, N(sam), priv_invalid.sign(blk->sig_digest())}),
fc::exception,
[] (const fc::exception &ex)->bool {
return ex.to_detail_string().find("confirmation not signed by expected key") != std::string::npos;
});
// invalid schedule
BOOST_REQUIRE_EXCEPTION(c.control->push_confirmation(header_confirmation{blk->id, N(invalid), priv_invalid.sign(blk->sig_digest())}),
fc::exception,
[] (const fc::exception &ex)->bool {
return ex.to_detail_string().find("producer not in current schedule") != std::string::npos;
});
// signed by sam
c.control->push_confirmation(header_confirmation{blk->id, N(sam), priv_sam.sign(blk->sig_digest())});
BOOST_REQUIRE_EQUAL(0, blk->bft_irreversible_blocknum);
BOOST_REQUIRE_EQUAL(1, blk->confirmations.size());
printf("bft number is %d #confirms %d\n", blk->bft_irreversible_blocknum, (int)blk->confirmations.size());
// double confirm not allowed
BOOST_REQUIRE_EXCEPTION(c.control->push_confirmation(header_confirmation{blk->id, N(sam), priv_sam.sign(blk->sig_digest())}),
fc::exception,
[] (const fc::exception &ex)->bool {
return ex.to_detail_string().find("block already confirmed by this producer") != std::string::npos;
});
// signed by dan
c.control->push_confirmation(header_confirmation{blk->id, N(dan), priv_dan.sign(blk->sig_digest())});
BOOST_REQUIRE_EQUAL(0, blk->bft_irreversible_blocknum);
BOOST_REQUIRE_EQUAL(2, blk->confirmations.size());
printf("bft number is %d #confirms %d\n", blk->bft_irreversible_blocknum, (int)blk->confirmations.size());
// signed by pam
c.control->push_confirmation(header_confirmation{blk->id, N(pam), priv_pam.sign(blk->sig_digest())});
// we have more than 2/3 of confirmations, bft irreversible number should be set
BOOST_REQUIRE_EQUAL(55, blk->bft_irreversible_blocknum);
BOOST_REQUIRE_EQUAL(55, blk61->bft_irreversible_blocknum); // bft irreversible number will propagate to higher block
BOOST_REQUIRE_EQUAL(0, blk50->bft_irreversible_blocknum); // bft irreversible number will not propagate to lower block
BOOST_REQUIRE_EQUAL(3, blk->confirmations.size());
printf("bft number is %d #confirms %d\n", blk->bft_irreversible_blocknum, (int)blk->confirmations.size());
// signed by scott
c.control->push_confirmation(header_confirmation{blk->id, N(scott), priv_scott.sign(blk->sig_digest())});
BOOST_REQUIRE_EQUAL(55, blk->bft_irreversible_blocknum);
BOOST_REQUIRE_EQUAL(4, blk->confirmations.size());
printf("bft number is %d #confirms %d\n", blk->bft_irreversible_blocknum, (int)blk->confirmations.size());
// let's confirm block 50 as well
c.control->push_confirmation(header_confirmation{blk50->id, N(sam), priv_sam.sign(blk50->sig_digest())});
c.control->push_confirmation(header_confirmation{blk50->id, N(dan), priv_dan.sign(blk50->sig_digest())});
c.control->push_confirmation(header_confirmation{blk50->id, N(pam), priv_pam.sign(blk50->sig_digest())});
BOOST_REQUIRE_EQUAL(50, blk50->bft_irreversible_blocknum); // bft irreversible number will not propagate to lower block
block_state_ptr blk54 = c.control->fork_db().get_block_in_current_chain_by_num(54);
BOOST_REQUIRE_EQUAL(50, blk54->bft_irreversible_blocknum);
BOOST_REQUIRE_EQUAL(55, blk->bft_irreversible_blocknum); // bft irreversible number will not be updated to lower value
BOOST_REQUIRE_EQUAL(55, blk61->bft_irreversible_blocknum);
c.produce_blocks(20);
block_state_ptr blk81 = c.control->fork_db().get_block_in_current_chain_by_num(81);
BOOST_REQUIRE_EQUAL(55, blk81->bft_irreversible_blocknum); // bft irreversible number will propagate into new blocks
} FC_LOG_AND_RETHROW()
BOOST_AUTO_TEST_SUITE_END()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册