提交 7bce267c 编写于 作者: A Anton Perkov

Merge branch 'master' into multisig-optimization-and-system-contract-upgrade

......@@ -162,7 +162,7 @@ namespace eosiosystem {
eosio_assert( bytes_out > 0, "must reserve a positive amount" );
_gstate.total_ram_bytes_reserved += uint64_t(bytes_out);
_gstate.total_ram_stake.amount += quant.amount;
_gstate.total_ram_stake += quant.amount;
user_resources_table userres( _self, receiver );
auto res_itr = userres.find( receiver );
......@@ -185,28 +185,28 @@ namespace eosiosystem {
* refunds the purchase price to the account. In this way there is no profit to be made through buying
* and selling ram.
*/
void system_contract::sellram( account_name account, uint64_t bytes ) {
void system_contract::sellram( account_name account, int64_t bytes ) {
require_auth( account );
int64_t ibytes = static_cast<int64_t>(bytes);
eosio_assert( bytes > 0, "cannot sell negative byte" );
user_resources_table userres( _self, account );
auto res_itr = userres.find( account );
eosio_assert( res_itr != userres.end(), "no resource row" );
eosio_assert( res_itr->ram_bytes >= ibytes, "insufficient quota" );
eosio_assert( res_itr->ram_bytes >= bytes, "insufficient quota" );
asset tokens_out;
auto itr = _rammarket.find(S(4,RAMEOS));
_rammarket.modify( itr, 0, [&]( auto& es ) {
/// the cast to int64_t of bytes is safe because we certify bytes is <= quota which is limited by prior purchases
tokens_out = es.convert( asset(ibytes,S(0,RAM)), S(4,EOS) );
tokens_out = es.convert( asset(bytes,S(0,RAM)), S(4,EOS) );
// print( "out: ", tokens_out, "\n" );
});
_gstate.total_ram_bytes_reserved -= bytes;
_gstate.total_ram_stake.amount -= tokens_out.amount;
_gstate.total_ram_stake -= tokens_out.amount;
//// this shouldn't happen, but just in case it does we should prevent it
eosio_assert( _gstate.total_ram_stake.amount >= 0, "error, attempt to unstake more tokens than previously staked" );
eosio_assert( _gstate.total_ram_stake >= 0, "error, attempt to unstake more tokens than previously staked" );
userres.modify( res_itr, account, [&]( auto& res ) {
res.ram_bytes -= bytes;
......
......@@ -87,24 +87,26 @@
"name": "blockchain_parameters",
"base": "",
"fields": [
{"name":"max_block_net_usage", "type": "uint32"},
{"name":"target_block_net_usage_pct", "type": "uint32"},
{"name":"max_transaction_net_usage", "type":"uint32"},
{"name":"base_per_transaction_net_usage", "type":"uint32"},
{"name":"net_usage_leeway", "type":"uint32"},
{"name":"max_block_net_usage", "type":"uint64"},
{"name":"target_block_net_usage_pct", "type":"uint32"},
{"name":"max_transaction_net_usage", "type":"uint32"},
{"name":"base_per_transaction_net_usage", "type":"uint32"},
{"name":"net_usage_leeway", "type":"uint32"},
{"name":"context_free_discount_net_usage_num", "type":"uint32"},
{"name":"context_free_discount_net_usage_den", "type":"uint32"},
{"name":"max_block_cpu_usage", "type": "uint64"},
{"name":"target_block_cpu_usage_pct", "type": "uint32"},
{"name":"max_transaction_cpu_usage", "type":"uint32"},
{"name":"min_transaction_cpu_usage", "type":"uint32"},
{"name":"max_transaction_lifetime", "type":"uint32"},
{"name":"deferred_trx_expiration_window", "type":"uint32"},
{"name":"max_transaction_delay", "type":"uint32"},
{"name":"max_inline_action_size", "type":"uint32"},
{"name":"max_inline_action_depth", "type":"uint16"},
{"name":"max_authority_depth", "type":"uint16"},
{"name":"max_generated_transaction_count", "type":"uint32"}
{"name":"max_block_cpu_usage", "type":"uint32"},
{"name":"target_block_cpu_usage_pct", "type":"uint32"},
{"name":"max_transaction_cpu_usage", "type":"uint32"},
{"name":"min_transaction_cpu_usage", "type":"uint32"},
{"name":"max_transaction_lifetime", "type":"uint32"},
{"name":"deferred_trx_expiration_window", "type":"uint32"},
{"name":"max_transaction_delay", "type":"uint32"},
{"name":"max_inline_action_size", "type":"uint32"},
{"name":"max_inline_action_depth", "type":"uint16"},
{"name":"max_authority_depth", "type":"uint16"},
{"name":"max_generated_transaction_count", "type":"uint32"}
]
},{
"name": "eosio_parameters",
......@@ -117,13 +119,16 @@
"base": "eosio_parameters",
"fields": [
{"name":"total_ram_bytes_reserved", "type":"uint64"},
{"name":"total_ram_stake", "type":"asset"},
{"name":"total_ram_stake", "type":"int64"},
{"name":"last_producer_schedule_update", "type":"time_point_sec"},
{"name":"last_pervote_bucket_fill", "type":"uint64"},
{"name":"pervote_bucket", "type":"asset"},
{"name":"savings", "type":"asset"},
{"name":"pervote_bucket", "type":"int64"},
{"name":"perblock_bucket", "type":"int64"},
{"name":"savings", "type":"int64"},
{"name":"total_unpaid_blocks", "type":"uint32"},
{"name":"total_activated_stake", "type":"int64"},
{"name":"last_producer_schedule_id", "type":"checksum160"},
{"name":"total_activatied_stake", "type":"int64"}
{"name":"total_producer_vote_weight", "type":"float64"}
]
},{
"name": "producer_info",
......@@ -133,7 +138,7 @@
{"name":"total_votes", "type":"float64"},
{"name":"producer_key", "type":"public_key"},
{"name":"url", "type":"string"},
{"name":"produced_blocks", "type":"uint32"},
{"name":"unpaid_blocks", "type":"uint32"},
{"name":"last_claim_time", "type":"uint64"},
{"name":"location", "type":"uint16"},
{"name":"time_became_active", "type":"uint32"},
......
......@@ -6,6 +6,7 @@
#include <eosio.system/native.hpp>
#include <eosiolib/asset.hpp>
#include <eosiolib/time.hpp>
#include <eosiolib/privileged.hpp>
#include <eosiolib/singleton.hpp>
#include <eosio.system/exchange_state.hpp>
......@@ -17,6 +18,7 @@ namespace eosiosystem {
using eosio::asset;
using eosio::indexed_by;
using eosio::const_mem_fun;
using eosio::block_timestamp;
struct eosio_parameters : eosio::blockchain_parameters {
uint64_t max_ram_size = 64ll*1024 * 1024 * 1024;
......@@ -29,21 +31,23 @@ namespace eosiosystem {
uint64_t free_ram()const { return max_ram_size - total_ram_bytes_reserved; }
uint64_t total_ram_bytes_reserved = 0;
eosio::asset total_ram_stake;
int64_t total_ram_stake = 0;
block_timestamp last_producer_schedule_update = 0;
block_timestamp last_producer_schedule_update;
uint64_t last_pervote_bucket_fill = 0;
eosio::asset pervote_bucket;
eosio::asset savings;
checksum160 last_producer_schedule_id;
int64_t pervote_bucket = 0;
int64_t perblock_bucket = 0;
int64_t savings = 0;
uint32_t total_unpaid_blocks = 0; /// all blocks which have been produced but not paid
int64_t total_activated_stake = 0;
checksum160 last_producer_schedule_id;
double total_producer_vote_weight = 0; /// the sum of all producer votes
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE_DERIVED( eosio_global_state, eosio_parameters, (total_ram_bytes_reserved)(total_ram_stake)
(last_producer_schedule_update)
(last_pervote_bucket_fill)
(pervote_bucket)(savings)(last_producer_schedule_id)(total_activated_stake) )
(pervote_bucket)(perblock_bucket)(savings)(total_unpaid_blocks)(total_activated_stake)(last_producer_schedule_id)(total_producer_vote_weight) )
};
struct producer_info {
......@@ -51,11 +55,11 @@ namespace eosiosystem {
double total_votes = 0;
eosio::public_key producer_key; /// a packed public key object
std::string url;
uint32_t produced_blocks;
uint32_t unpaid_blocks = 0;
uint64_t last_claim_time = 0;
uint16_t location = 0;
block_timestamp time_became_active = 0;
block_timestamp last_produced_block_time = 0;
block_timestamp time_became_active;
block_timestamp last_produced_block_time;
uint64_t primary_key()const { return owner; }
double by_votes()const { return -total_votes; }
......@@ -63,7 +67,7 @@ namespace eosiosystem {
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE( producer_info, (owner)(total_votes)(producer_key)(url)
(produced_blocks)(last_claim_time)(location)
(unpaid_blocks)(last_claim_time)(location)
(time_became_active)(last_produced_block_time) )
};
......@@ -125,7 +129,7 @@ namespace eosiosystem {
~system_contract();
// Actions:
void onblock( uint32_t timestamp_slot, account_name producer );
void onblock( block_timestamp timestamp, account_name producer );
// const block_header& header ); /// only parse first 3 fields of block header
// functions defined in delegate_bandwidth.cpp
......@@ -171,7 +175,7 @@ namespace eosiosystem {
* Reduces quota my bytes and then performs an inline transfer of tokens
* to receiver based upon the average purchase price of the original quota.
*/
void sellram( account_name receiver, uint64_t bytes );
void sellram( account_name receiver, int64_t bytes );
/**
* This action is called after the delegation-period to claim all pending
......@@ -197,12 +201,6 @@ namespace eosiosystem {
void setpriv( account_name account, uint8_t ispriv );
private:
eosio::asset payment_per_block( double rate, const eosio::asset& token_supply, uint32_t num_blocks );
eosio::asset payment_per_vote( const account_name& owner, double owners_votes, const eosio::asset& pervote_bucket );
eosio::asset supply_growth( double rate, const eosio::asset& token_supply, time seconds );
void update_elected_producers( block_timestamp timestamp );
// Implementation details:
......
......@@ -6,24 +6,16 @@ namespace eosiosystem {
const int64_t min_daily_tokens = 100;
const double continuous_rate = 0.04879; // 5% annual rate
const double perblock_rate = 0.0025; // 0.25%
const double standby_rate = 0.0075; // 0.75%
const uint32_t blocks_per_year = 52*7*24*2*3600; // half seconds per year
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) );
return eosio::asset( payment, token_supply.symbol );
}
const double continuous_rate = 0.04879; // 5% annual rate
const double perblock_rate = 0.0025; // 0.25%
const double standby_rate = 0.0075; // 0.75%
const uint32_t blocks_per_year = 52*7*24*2*3600; // half seconds per year
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);
const uint64_t useconds_per_year = seconds_per_year*1000000ll;
eosio::asset system_contract::supply_growth( double rate, const eosio::asset& token_supply, time seconds ) {
const int64_t payment = static_cast<int64_t>( (rate * double(token_supply.amount) * double(seconds)) / double(seconds_per_year) );
return eosio::asset( payment, token_supply.symbol );
}
void system_contract::onblock( block_timestamp timestamp, account_name producer ) {
using namespace eosio;
......@@ -37,107 +29,78 @@ namespace eosiosystem {
if( _gstate.last_pervote_bucket_fill == 0 ) /// start the presses
_gstate.last_pervote_bucket_fill = current_time();
/**
* At startup the initial producer may not be one that is registered / elected
* and therefore there may be no producer object for them.
*/
auto prod = _producers.find(producer);
if ( prod != _producers.end() ) {
_gstate.total_unpaid_blocks++;
_producers.modify( prod, 0, [&](auto& p ) {
p.produced_blocks++;
p.unpaid_blocks++;
p.last_produced_block_time = timestamp;
});
}
/// only update block producers once every minute, block_timestamp is in half seconds
if( timestamp - _gstate.last_producer_schedule_update > 120 ) {
if( timestamp.slot - _gstate.last_producer_schedule_update.slot > 120 ) {
update_elected_producers( timestamp );
}
}
eosio::asset system_contract::payment_per_vote( const account_name& owner, double owners_votes, const eosio::asset& pervote_bucket ) {
eosio::asset payment(0, S(4,EOS));
const int64_t min_daily_amount = 100 * 10000;
if ( pervote_bucket.amount < min_daily_amount ) {
return payment;
}
auto idx = _producers.template get_index<N(prototalvote)>();
double total_producer_votes = 0;
double running_payment_amount = 0;
bool to_be_payed = false;
for ( auto itr = idx.cbegin(); itr != idx.cend(); ++itr ) {
if ( !(itr->total_votes > 0) ) {
break;
}
if ( !itr->active() ) {
continue;
}
if ( itr->owner == owner ) {
to_be_payed = true;
}
total_producer_votes += itr->total_votes;
running_payment_amount = (itr->total_votes) * double(pervote_bucket.amount) / total_producer_votes;
if ( running_payment_amount < min_daily_amount ) {
if ( itr->owner == owner ) {
to_be_payed = false;
}
total_producer_votes -= itr->total_votes;
break;
}
}
if ( to_be_payed ) {
payment.amount = static_cast<int64_t>( (double(pervote_bucket.amount) * owners_votes) / total_producer_votes );
}
return payment;
}
using namespace eosio;
void system_contract::claimrewards( const account_name& owner ) {
using namespace eosio;
require_auth(owner);
auto prod = _producers.find( owner );
eosio_assert( prod != _producers.end(), "account name is not in producer list" );
eosio_assert( prod->active(), "producer does not have an active key" );
if( prod->last_claim_time > 0 ) {
eosio_assert(current_time() >= prod->last_claim_time + useconds_per_day, "already claimed rewards within a day");
}
const auto& prod = _producers.get( owner );
eosio_assert( prod.active(), "producer does not have an active key" );
const asset token_supply = token( N(eosio.token)).get_supply(symbol_type(system_token_symbol).name() );
const uint32_t secs_since_last_fill = static_cast<uint32_t>( (current_time() - _gstate.last_pervote_bucket_fill) / 1000000 );
auto ct = current_time();
const asset to_pervote_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_pervote_bucket + to_savings + perblock_pay;
const asset pervote_pay = payment_per_vote( owner, prod->total_votes, to_pervote_bucket + _gstate.pervote_bucket );
eosio_assert( ct - prod.last_claim_time > useconds_per_day, "already claimed rewards within past day" );
if ( perblock_pay.amount + pervote_pay.amount == 0 ) {
_producers.modify( prod, 0, [&](auto& p) {
p.last_claim_time = current_time();
});
return;
const asset token_supply = token( N(eosio.token)).get_supply(symbol_type(system_token_symbol).name() );
const auto usecs_since_last_fill = ct - _gstate.last_pervote_bucket_fill;
if( usecs_since_last_fill > 0 ) {
auto new_tokens = static_cast<int64_t>( (continuous_rate * double(token_supply.amount) * double(usecs_since_last_fill)) / double(useconds_per_year) );
auto to_producers = new_tokens / 5;
auto to_savings = new_tokens - to_producers;
auto to_per_block_pay = to_producers / 4;
auto to_per_vote_pay = to_producers - to_per_block_pay;
INLINE_ACTION_SENDER(eosio::token, issue)( N(eosio.token), {{N(eosio),N(active)}},
{N(eosio), asset(new_tokens), std::string("issue tokens for producer pay and savings")} );
_gstate.pervote_bucket += to_per_vote_pay;
_gstate.perblock_bucket += to_per_block_pay;
_gstate.savings += to_savings;
_gstate.last_pervote_bucket_fill = ct;
}
INLINE_ACTION_SENDER(eosio::token, issue)( N(eosio.token), {{N(eosio),N(active)}},
{N(eosio), issue_amount, std::string("issue tokens for producer pay and savings")} );
_gstate.pervote_bucket += ( to_pervote_bucket - pervote_pay );
_gstate.last_pervote_bucket_fill = current_time();
_gstate.savings += to_savings;
INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)},
{ N(eosio), owner, perblock_pay + pervote_pay, std::string("producer claiming rewards") } );
int64_t producer_per_block_pay = (_gstate.perblock_bucket * prod.unpaid_blocks) / _gstate.total_unpaid_blocks;
int64_t producer_per_vote_pay = int64_t((_gstate.pervote_bucket * prod.total_votes ) / _gstate.total_producer_vote_weight);
if( producer_per_vote_pay < 100'0000 ) {
producer_per_vote_pay = 0;
}
int64_t total_pay = producer_per_block_pay + producer_per_vote_pay;
_producers.modify( prod, 0, [&](auto& p) {
p.last_claim_time = current_time();
p.produced_blocks = 0;
});
_gstate.pervote_bucket -= producer_per_vote_pay;
_gstate.perblock_bucket -= producer_per_block_pay;
_gstate.total_unpaid_blocks -= prod.unpaid_blocks;
_producers.modify( prod, 0, [&](auto& p) {
p.last_claim_time = ct;
p.unpaid_blocks = 0;
});
if( total_pay > 0 ) {
INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)},
{ N(eosio), owner, asset(total_pay), std::string("producer pay") } );
}
}
} //namespace eosiosystem
......@@ -53,7 +53,7 @@ namespace eosiosystem {
_producers.emplace( producer, [&]( producer_info& info ){
info.owner = producer;
info.total_votes = 0;
info.producer_key = producer_key;
info.producer_key = producer_key;
info.url = url;
info.location = location;
});
......@@ -81,15 +81,15 @@ namespace eosiosystem {
for ( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes; ++it ) {
if( !it->active() ) continue;
if ( it->time_became_active == 0 ) {
if ( it->time_became_active.slot == 0 ) {
_producers.modify( *it, 0, [&](auto& p) {
p.time_became_active = block_time;
});
} else if ( block_time > 2 * 21 * 12 + it->time_became_active &&
block_time > it->last_produced_block_time + blocks_per_day ) {
} else if ( block_time.slot > 2 * 21 * 12 + it->time_became_active.slot &&
block_time.slot > it->last_produced_block_time.slot + blocks_per_day ) {
_producers.modify( *it, 0, [&](auto& p) {
p.producer_key = public_key();
p.time_became_active = 0;
p.time_became_active.slot = 0;
});
continue;
......@@ -216,9 +216,8 @@ namespace eosiosystem {
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 ) {
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" );
_gstate.total_producer_vote_weight += pd.second.first;
//eosio_assert( p.total_votes >= 0, "something bad happened" );
});
} else {
......@@ -282,12 +281,13 @@ namespace eosiosystem {
);
propagate_weight_change( proxy );
} else {
auto delta = new_weight - voter.last_vote_weight;
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;
}
);
p.total_votes += delta;
_gstate.total_producer_vote_weight += delta;
});
}
}
}
......
......@@ -209,7 +209,7 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, bool& d) {
*/
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const checksum256& d) {
ds.write( (const char*)&d, sizeof(d) );
ds.write( (const char*)&d.hash[0], sizeof(d.hash) );
return ds;
}
/**
......@@ -220,7 +220,7 @@ inline datastream<Stream>& operator<<(datastream<Stream>& ds, const checksum256&
*/
template<typename Stream>
inline datastream<Stream>& operator>>(datastream<Stream>& ds, checksum256& d) {
ds.read((char*)&d, sizeof(d) );
ds.read((char*)&d.hash[0], sizeof(d.hash) );
return ds;
}
......@@ -514,25 +514,25 @@ bytes pack( const T& value ) {
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const checksum160& cs) {
ds.write((const char*)&cs, sizeof(cs));
ds.write((const char*)&cs.hash[0], sizeof(cs.hash));
return ds;
}
template<typename Stream>
inline datastream<Stream>& operator>>(datastream<Stream>& ds, checksum160& cs) {
ds.read((char*)&cs, sizeof(cs));
ds.read((char*)&cs.hash[0], sizeof(cs.hash));
return ds;
}
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const checksum512& cs) {
ds.write((const char*)&cs, sizeof(cs));
ds.write((const char*)&cs.hash[0], sizeof(cs.hash));
return ds;
}
template<typename Stream>
inline datastream<Stream>& operator>>(datastream<Stream>& ds, checksum512& cs) {
ds.read((char*)&cs, sizeof(cs));
ds.read((char*)&cs.hash[0], sizeof(cs.hash));
return ds;
}
......
......@@ -24,7 +24,6 @@ typedef uint64_t permission_name;
typedef uint64_t token_name;
typedef uint64_t table_name;
typedef uint32_t time;
typedef uint32_t block_timestamp;
typedef uint64_t scope_name;
typedef uint64_t action_name;
typedef uint16_t region_id;
......
......@@ -7,7 +7,7 @@
#include <eosio/chain/types.hpp>
#include <eosio/chain/symbol.hpp>
/// eos with 8 digits of precision
/// eos with 4 digits of precision
#define EOS_SYMBOL_VALUE (int64_t(4) | (uint64_t('E') << 8) | (uint64_t('O') << 16) | (uint64_t('S') << 24))
static const eosio::chain::symbol EOS_SYMBOL(EOS_SYMBOL_VALUE);
......
......@@ -101,6 +101,9 @@ try:
cluster.initializeNodes(defproduceraPrvtKey=defproduceraPrvtKey, defproducerbPrvtKey=defproducerbPrvtKey)
killEosInstances=False
Print("Validating system accounts after bootstrap")
cluster.validateAccounts(None)
accounts=testUtils.Cluster.createAccountKeys(3)
if accounts is None:
errorExit("FAILURE - create keys")
......@@ -223,12 +226,31 @@ try:
if node is None:
errorExit("Cluster in bad state, received None node")
Print("Validating accounts before user accounts creation")
cluster.validateAccounts(None)
Print("Create new account %s via %s" % (testeraAccount.name, defproduceraAccount.name))
transId=node.createInitializeAccount(testeraAccount, defproduceraAccount, stakedDeposit=0, waitForTransBlock=False)
if transId is None:
cmdError("%s create account" % (ClientName))
cmdError("%s create account" % (testeraAccount.name))
errorExit("Failed to create account %s" % (testeraAccount.name))
Print("Create new account %s via %s" % (currencyAccount.name, defproducerbAccount.name))
transId=node.createInitializeAccount(currencyAccount, defproducerbAccount, stakedDeposit=5000)
if transId is None:
cmdError("%s create account" % (ClientName))
errorExit("Failed to create account %s" % (currencyAccount.name))
Print("Create new account %s via %s" % (exchangeAccount.name, defproduceraAccount.name))
transId=node.createInitializeAccount(exchangeAccount, defproduceraAccount, waitForTransBlock=True)
if transId is None:
cmdError("%s create account" % (ClientName))
errorExit("Failed to create account %s" % (exchangeAccount.name))
Print("Validating accounts after user accounts creation")
accounts=[testeraAccount, currencyAccount, exchangeAccount]
cluster.validateAccounts(accounts)
Print("Verify account %s" % (testeraAccount))
if not node.verifyAccount(testeraAccount):
errorExit("FAILURE - account creation failed.", raw=True)
......@@ -262,17 +284,9 @@ try:
cmdError("FAILURE - transfer failed")
errorExit("Transfer verification failed. Excepted %s, actual: %s" % (expectedAmount, actualAmount))
Print("Create new account %s via %s" % (currencyAccount.name, defproducerbAccount.name))
transId=node.createInitializeAccount(currencyAccount, defproducerbAccount, stakedDeposit=5000)
if transId is None:
cmdError("%s create account" % (ClientName))
errorExit("Failed to create account %s" % (currencyAccount.name))
Print("Create new account %s via %s" % (exchangeAccount.name, defproduceraAccount.name))
transId=node.createInitializeAccount(exchangeAccount, defproduceraAccount, waitForTransBlock=True)
if transId is None:
cmdError("%s create account" % (ClientName))
errorExit("Failed to create account %s" % (exchangeAccount.name))
Print("Validating accounts after some user trasactions")
accounts=[testeraAccount, currencyAccount, exchangeAccount]
cluster.validateAccounts(accounts)
Print("Locking all wallets.")
if not walletMgr.lockAllWallets():
......@@ -306,7 +320,7 @@ try:
assert(actions)
try:
assert(actions["actions"][0]["action_trace"]["act"]["name"] == "transfer")
except (AssertionError, KeyError) as e:
except (AssertionError, TypeError, KeyError) as e:
Print("Last action validation failed. Actions: %s" % (actions))
raise
......@@ -381,7 +395,7 @@ try:
typeVal= transaction["name"]
amountVal=transaction["data"]["quantity"]
amountVal=int(decimal.Decimal(amountVal.split()[0])*10000)
except (AssertionError, KeyError) as e:
except (TypeError, KeyError) as e:
Print("Transaction validation parsing failed. Transaction: %s" % (transaction))
raise
......@@ -605,7 +619,7 @@ try:
# errorExit("mongo get messages by transaction id %s" % (transId))
Print("Request invalid block numbered %d. This will generate an extpected error message." % (currentBlockNum+1000))
Print("Request invalid block numbered %d. This will generate an expected error message." % (currentBlockNum+1000))
block=node.getBlock(currentBlockNum+1000, silentErrors=True, retry=False)
if block is not None:
errorExit("ERROR: Received block where not expected")
......@@ -627,6 +641,10 @@ try:
Print("WARNING: Asserts in var/lib/node_00/stderr.txt")
#errorExit("FAILURE - Assert in var/lib/node_00/stderr.txt")
Print("Validating accounts at end of test")
accounts=[testeraAccount, currencyAccount, exchangeAccount]
cluster.validateAccounts(accounts)
testSuccessful=True
finally:
if testSuccessful:
......
......@@ -278,6 +278,22 @@ class Node(object):
def setWalletEndpointArgs(self, args):
self.endpointArgs="--url http://%s:%d %s" % (self.host, self.port, args)
def validateAccounts(self, accounts):
assert(accounts)
assert(isinstance(accounts, list))
for account in accounts:
assert(account)
assert(isinstance(account, Account))
if Utils.Debug: Utils.Print("Validating account %s" % (account.name))
accountInfo=self.getEosAccount(account.name)
try:
assert(accountInfo)
assert(accountInfo["account_name"] == account.name)
except (AssertionError, TypeError, KeyError) as _:
Utils.Print("account validation failed. account: %s" % (account.name))
raise
# pylint: disable=too-many-branches
def getBlock(self, blockNum, retry=True, silentErrors=False):
if not self.enableMongo:
......@@ -337,15 +353,18 @@ class Node(object):
def doesNodeHaveBlockNum(self, blockNum):
assert isinstance(blockNum, int)
assert (blockNum > 0)
info=self.getInfo(silentErrors=True)
if info is None:
return False
last_irreversible_block_num=int(info["last_irreversible_block_num"])
if blockNum > last_irreversible_block_num:
return False
else:
return True
assert(info)
last_irreversible_block_num=0
try:
last_irreversible_block_num=int(info["last_irreversible_block_num"])
except (TypeError, KeyError) as _:
Utils.Print("Failure in get info parsing. %s" % (trans))
raise
return True if blockNum <= last_irreversible_block_num else True
# pylint: disable=too-many-branches
def getTransaction(self, transId, retry=True, silentErrors=False):
......@@ -452,16 +471,21 @@ class Node(object):
return None
def doesNodeHaveTransId(self, transId):
trans=self.getTransaction(transId, silentErrors=True)
def doesNodeHaveTransId(self, transId, silentErrors=True):
trans=self.getTransaction(transId, silentErrors)
if trans is None:
return False
blockNum=None
if not self.enableMongo:
blockNum=int(trans["trx"]["trx"]["ref_block_num"])
else:
blockNum=int(trans["ref_block_num"])
try:
if not self.enableMongo:
blockNum=int(trans["trx"]["trx"]["ref_block_num"])
else:
blockNum=int(trans["ref_block_num"])
except (TypeError, KeyError) as _:
if not silentErrors:
Utils.Print("Failure in transaction parsing. %s" % (trans))
return False
blockNum += 1
if Utils.Debug: Utils.Print("Check if block %d is irreversible." % (blockNum))
......@@ -521,6 +545,7 @@ class Node(object):
return trans
def getEosAccount(self, name):
assert(isinstance(name, str))
cmd="%s %s get account -j %s" % (Utils.EosClientPath, self.endpointArgs, name)
if Utils.Debug: Utils.Print("cmd: %s" % (cmd))
try:
......@@ -563,7 +588,7 @@ class Node(object):
assert(trans)
try:
return trans["rows"][0]["balance"]
except (AssertionError, KeyError) as e:
except (TypeError, KeyError) as e:
print("Transaction parsing failed. Transaction: %s" % (trans))
raise
......@@ -1595,6 +1620,19 @@ class Cluster(object):
return True
def validateAccounts(self, accounts, testSysAccounts=True):
assert(len(self.nodes) > 0)
node=self.nodes[0]
myAccounts = []
if testSysAccounts:
myAccounts += [self.eosioAccount, self.defproduceraAccount, self.defproducerbAccount]
if accounts:
assert(isinstance(accounts, list))
myAccounts += accounts
node.validateAccounts(myAccounts)
# create account, verify account and return transaction id
def createAccountAndVerify(self, account, creator, stakedDeposit=1000):
assert(len(self.nodes) > 0)
......@@ -1746,7 +1784,9 @@ class Cluster(object):
Utils.Print("Creating accounts: %s " % ", ".join(producerKeys.keys()))
producerKeys.pop(eosioName)
accounts=[]
for name, keys in producerKeys.items():
initx = None
initx = Account(name)
initx.ownerPrivateKey=keys["private"]
initx.ownerPublicKey=keys["public"]
......@@ -1757,10 +1797,14 @@ class Cluster(object):
Utils.Print("ERROR: Failed to create account %s" % (name))
return False
Node.validateTransaction(trans)
accounts.append(initx)
transId=Node.getTransId(trans)
biosNode.waitForTransIdOnNode(transId)
Utils.Print("Validating system accounts within bootstrap")
biosNode.validateAccounts(accounts)
if not onlyBios:
if prodCount == -1:
setProdsFile="setprods.json"
......@@ -1845,6 +1889,8 @@ class Cluster(object):
return False
Node.validateTransaction(trans[1])
transId=Node.getTransId(trans[1])
biosNode.waitForTransIdOnNode(transId)
contract=eosioTokenAccount.name
Utils.Print("push issue action to %s contract" % (contract))
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册