未验证 提交 221b6a6a 编写于 作者: D Daniel Larimer 提交者: GitHub

Merge pull request #1699 from EOSIO/system-contract-voting-2

New system contract first revision
#pragma once
#include <eosiolib/eosio.hpp>
#include <eosiolib/generic_currency.hpp>
#include <eosiolib/multi_index.hpp>
#include <eosiolib/privileged.hpp>
#include <eosiolib/singleton.hpp>
namespace eosiosystem {
template<account_name SystemAccount>
class common {
public:
static constexpr account_name system_account = SystemAccount;
typedef eosio::generic_currency< eosio::token<system_account,S(4,EOS)> > currency;
typedef typename currency::token_type system_token_type;
static constexpr uint64_t currency_symbol = currency::symbol; // S(4,EOS)
static constexpr uint32_t max_inflation_rate = 5; // 5% annual inflation
static constexpr uint32_t blocks_per_producer = 12;
static constexpr uint32_t seconds_per_day = 24 * 3600;
static constexpr uint32_t days_per_4years = 1461;
struct eosio_parameters : eosio::blockchain_parameters {
uint32_t percent_of_max_inflation_rate = 0;
uint32_t storage_reserve_ratio = 1000; // ratio * 1000
EOSLIB_SERIALIZE_DERIVED( eosio_parameters, eosio::blockchain_parameters, (percent_of_max_inflation_rate)(storage_reserve_ratio) )
};
struct eosio_global_state : eosio_parameters {
uint64_t total_storage_bytes_reserved = 0;
system_token_type total_storage_stake;
system_token_type payment_per_block = system_token_type();
system_token_type payment_to_eos_bucket = system_token_type();
time first_block_time_in_cycle = 0;
uint32_t blocks_per_cycle = 0;
time last_bucket_fill_time = 0;
system_token_type eos_bucket = system_token_type();
EOSLIB_SERIALIZE_DERIVED( eosio_global_state, eosio_parameters, (total_storage_bytes_reserved)(total_storage_stake)
(payment_per_block)(payment_to_eos_bucket)(first_block_time_in_cycle)(blocks_per_cycle)
(last_bucket_fill_time)(eos_bucket) )
};
typedef eosio::singleton<SystemAccount, N(inflation), SystemAccount, eosio_global_state> global_state_singleton;
static eosio_global_state& get_default_parameters() {
static eosio_global_state dp;
get_blockchain_parameters(dp);
return dp;
}
};
}
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include "common.hpp"
#include "voting.hpp"
#include <eosiolib/eosio.hpp>
#include <eosiolib/token.hpp>
#include <eosiolib/print.hpp>
#include <eosiolib/generic_currency.hpp>
#include <eosiolib/datastream.hpp>
#include <eosiolib/serialize.hpp>
#include <eosiolib/multi_index.hpp>
#include <eosiolib/privileged.h>
#include <eosiolib/transaction.hpp>
#include <map>
namespace eosiosystem {
using eosio::asset;
using eosio::indexed_by;
using eosio::const_mem_fun;
using eosio::bytes;
using eosio::print;
using eosio::permission_level;
using std::map;
using std::pair;
template<account_name SystemAccount>
class delegate_bandwidth : public voting<SystemAccount> {
public:
static constexpr account_name system_account = SystemAccount;
static constexpr time refund_delay = 3*24*3600;
static constexpr time refund_expiration_time = 3600;
using currency = typename common<SystemAccount>::currency;
using system_token_type = typename common<SystemAccount>::system_token_type;
using eosio_parameters = typename common<SystemAccount>::eosio_parameters;
using global_state_singleton = typename common<SystemAccount>::global_state_singleton;
struct total_resources {
account_name owner;
typename currency::token_type net_weight;
typename currency::token_type cpu_weight;
typename currency::token_type storage_stake;
uint64_t storage_bytes = 0;
uint64_t primary_key()const { return owner; }
EOSLIB_SERIALIZE( total_resources, (owner)(net_weight)(cpu_weight)(storage_stake)(storage_bytes) )
};
/**
* Every user 'from' has a scope/table that uses every receipient 'to' as the primary key.
*/
struct delegated_bandwidth {
account_name from;
account_name to;
typename currency::token_type net_weight;
typename currency::token_type cpu_weight;
typename currency::token_type storage_stake;
uint64_t storage_bytes = 0;
uint64_t primary_key()const { return to; }
EOSLIB_SERIALIZE( delegated_bandwidth, (from)(to)(net_weight)(cpu_weight)(storage_stake)(storage_bytes) )
};
struct refund_request {
account_name owner;
time request_time;
typename currency::token_type amount;
uint64_t primary_key()const { return owner; }
EOSLIB_SERIALIZE( refund_request, (owner)(request_time)(amount) )
};
typedef eosio::multi_index< N(totalband), total_resources> total_resources_table;
typedef eosio::multi_index< N(delband), delegated_bandwidth> del_bandwidth_table;
typedef eosio::multi_index< N(refunds), refund_request> refunds_table;
ACTION( SystemAccount, delegatebw ) {
account_name from;
account_name receiver;
asset stake_net_quantity;
asset stake_cpu_quantity;
asset stake_storage_quantity;
EOSLIB_SERIALIZE( delegatebw, (from)(receiver)(stake_net_quantity)(stake_cpu_quantity)(stake_storage_quantity) )
};
ACTION( SystemAccount, undelegatebw ) {
account_name from;
account_name receiver;
asset unstake_net_quantity;
asset unstake_cpu_quantity;
uint64_t unstake_storage_bytes;
EOSLIB_SERIALIZE( undelegatebw, (from)(receiver)(unstake_net_quantity)(unstake_cpu_quantity)(unstake_storage_bytes) )
};
ACTION( SystemAccount, refund ) {
account_name owner;
EOSLIB_SERIALIZE( refund, (owner) )
};
static void on( const delegatebw& del ) {
eosio_assert( del.stake_cpu_quantity.amount >= 0, "must stake a positive amount" );
eosio_assert( del.stake_net_quantity.amount >= 0, "must stake a positive amount" );
eosio_assert( del.stake_storage_quantity.amount >= 0, "must stake a positive amount" );
system_token_type total_stake = del.stake_cpu_quantity + del.stake_net_quantity + del.stake_storage_quantity;
eosio_assert( total_stake.quantity > 0, "must stake a positive amount" );
require_auth( del.from );
//eosio_assert( is_account( del.receiver ), "can only delegate resources to an existing account" );
uint64_t storage_bytes = 0;
if ( 0 < del.stake_storage_quantity.amount ) {
auto parameters = global_state_singleton::exists() ? global_state_singleton::get()
: common<SystemAccount>::get_default_parameters();
auto token_supply = currency::get_total_supply();
//make sure that there is no posibility of overflow here
uint64_t storage_bytes_estimated = ( parameters.max_storage_size - parameters.total_storage_bytes_reserved )
* parameters.storage_reserve_ratio * system_token_type(del.stake_storage_quantity)
/ ( token_supply - parameters.total_storage_stake ) / 1000 /* reserve ratio coefficient */;
storage_bytes = ( parameters.max_storage_size - parameters.total_storage_bytes_reserved - storage_bytes_estimated )
* parameters.storage_reserve_ratio * system_token_type(del.stake_storage_quantity)
/ ( token_supply - del.stake_storage_quantity - parameters.total_storage_stake ) / 1000 /* reserve ratio coefficient */;
eosio_assert( 0 < storage_bytes, "stake is too small to increase storage even by 1 byte" );
parameters.total_storage_bytes_reserved += storage_bytes;
parameters.total_storage_stake += del.stake_storage_quantity;
global_state_singleton::set(parameters);
}
del_bandwidth_table del_tbl( SystemAccount, del.from );
auto itr = del_tbl.find( del.receiver );
if( itr == del_tbl.end() ) {
del_tbl.emplace( del.from, [&]( auto& dbo ){
dbo.from = del.from;
dbo.to = del.receiver;
dbo.net_weight = del.stake_net_quantity;
dbo.cpu_weight = del.stake_cpu_quantity;
dbo.storage_stake = del.stake_storage_quantity;
dbo.storage_bytes = storage_bytes;
});
}
else {
del_tbl.modify( itr, del.from, [&]( auto& dbo ){
dbo.net_weight += del.stake_net_quantity;
dbo.cpu_weight += del.stake_cpu_quantity;
dbo.storage_stake += del.stake_storage_quantity;
dbo.storage_bytes += storage_bytes;
});
}
total_resources_table totals_tbl( SystemAccount, del.receiver );
auto tot_itr = totals_tbl.find( del.receiver );
if( tot_itr == totals_tbl.end() ) {
tot_itr = totals_tbl.emplace( del.from, [&]( auto& tot ) {
tot.owner = del.receiver;
tot.net_weight = del.stake_net_quantity;
tot.cpu_weight = del.stake_cpu_quantity;
tot.storage_stake = del.stake_storage_quantity;
tot.storage_bytes = storage_bytes;
});
} else {
totals_tbl.modify( tot_itr, del.from == del.receiver ? del.from : 0, [&]( auto& tot ) {
tot.net_weight += del.stake_net_quantity;
tot.cpu_weight += del.stake_cpu_quantity;
tot.storage_stake += del.stake_storage_quantity;
tot.storage_bytes += storage_bytes;
});
}
set_resource_limits( tot_itr->owner, tot_itr->storage_bytes, tot_itr->net_weight.quantity, tot_itr->cpu_weight.quantity );
currency::inline_transfer( del.from, SystemAccount, total_stake, "stake bandwidth" );
if ( asset(0) < del.stake_net_quantity + del.stake_cpu_quantity ) {
voting<SystemAccount>::increase_voting_power( del.from, del.stake_net_quantity + del.stake_cpu_quantity );
}
} // delegatebw
static void on( const undelegatebw& del ) {
eosio_assert( del.unstake_cpu_quantity.amount >= 0, "must unstake a positive amount" );
eosio_assert( del.unstake_net_quantity.amount >= 0, "must unstake a positive amount" );
require_auth( del.from );
//eosio_assert( is_account( del.receiver ), "can only delegate resources to an existing account" );
del_bandwidth_table del_tbl( SystemAccount, del.from );
const auto& dbw = del_tbl.get( del.receiver );
eosio_assert( dbw.net_weight >= del.unstake_net_quantity, "insufficient staked net bandwidth" );
eosio_assert( dbw.cpu_weight >= del.unstake_cpu_quantity, "insufficient staked cpu bandwidth" );
eosio_assert( dbw.storage_bytes >= del.unstake_storage_bytes, "insufficient staked storage" );
system_token_type storage_stake_decrease = system_token_type(0);
if ( 0 < del.unstake_storage_bytes ) {
storage_stake_decrease = 0 < dbw.storage_bytes ?
dbw.storage_stake * del.unstake_storage_bytes / dbw.storage_bytes
: system_token_type(0);
auto parameters = global_state_singleton::get();
parameters.total_storage_bytes_reserved -= del.unstake_storage_bytes;
parameters.total_storage_stake -= storage_stake_decrease;
global_state_singleton::set( parameters );
}
auto total_refund = system_token_type(del.unstake_cpu_quantity)
+ system_token_type(del.unstake_net_quantity) + storage_stake_decrease;
eosio_assert( total_refund.quantity > 0, "must unstake a positive amount" );
del_tbl.modify( dbw, del.from, [&]( auto& dbo ){
dbo.net_weight -= del.unstake_net_quantity;
dbo.cpu_weight -= del.unstake_cpu_quantity;
dbo.storage_stake -= storage_stake_decrease;
dbo.storage_bytes -= del.unstake_storage_bytes;
});
total_resources_table totals_tbl( SystemAccount, del.receiver );
const auto& totals = totals_tbl.get( del.receiver );
totals_tbl.modify( totals, 0, [&]( auto& tot ) {
tot.net_weight -= del.unstake_net_quantity;
tot.cpu_weight -= del.unstake_cpu_quantity;
tot.storage_stake -= storage_stake_decrease;
tot.storage_bytes -= del.unstake_storage_bytes;
});
set_resource_limits( totals.owner, totals.storage_bytes, totals.net_weight.quantity, totals.cpu_weight.quantity );
refunds_table refunds_tbl( SystemAccount, del.from );
//create refund request
auto req = refunds_tbl.find( del.from );
if ( req != refunds_tbl.end() ) {
refunds_tbl.modify( req, 0, [&]( refund_request& r ) {
r.amount += del.unstake_net_quantity + del.unstake_cpu_quantity + storage_stake_decrease;
r.request_time = now();
});
} else {
refunds_tbl.emplace( del.from, [&]( refund_request& r ) {
r.owner = del.from;
r.amount = del.unstake_net_quantity + del.unstake_cpu_quantity + storage_stake_decrease;
r.request_time = now();
});
}
//cancel previous deferred transaction if we have one
//because of an implementation bug currently it would cancel transaction
//that will be created later in this action
//commenting out for now
//cancel_deferred( del.from );
//create new deferred transaction
const auto self = current_receiver();
refund act;
act.owner = del.from;
transaction out( now() + refund_delay + refund_expiration_time );
out.actions.emplace_back( permission_level{ del.from, N(active) }, self, N(refund), act );
out.send( del.from, now() + refund_delay );
if ( asset(0) < del.unstake_net_quantity + del.unstake_cpu_quantity ) {
voting<SystemAccount>::decrease_voting_power( del.from, del.unstake_net_quantity + del.unstake_cpu_quantity );
}
} // undelegatebw
static void on( const refund& r ) {
require_auth( r.owner );
refunds_table refunds_tbl( SystemAccount, r.owner );
auto req = refunds_tbl.find( r.owner );
eosio_assert( req != refunds_tbl.end(), "refund request not found" );
eosio_assert( req->request_time + refund_delay <= now(), "refund is not available yet" );
// Until now() becomes NOW, the fact that now() is the timestamp of the previous block could in theory
// allow people to get their tokens earlier than the 3 day delay if the unstake happened immediately after many
// consecutive missed blocks.
currency::inline_transfer( SystemAccount, req->owner, req->amount, "unstake" );
refunds_tbl.erase( req );
}
};
}
{
"types": [],
"structs": [{
"name": "nonce",
"base": "",
"fields": [
{"name":"value", "type":"string"}
]
},{
"name": "transfer",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"to", "type":"account_name"},
{"name":"quantity", "type":"asset"},
{"name":"memo", "type":"string"}
{"name":"from", "type":"account_name"},
{"name":"to", "type":"account_name"},
{"name":"quantity", "type":"asset"},
{"name":"memo", "type":"string"}
]
},{
"name": "issue",
......@@ -20,31 +26,159 @@
"name": "account",
"base": "",
"fields": [
{"name":"key", "type":"name"},
{"name":"currency", "type":"uint64"},
{"name":"balance", "type":"uint64"}
]
},{
"name": "nonce",
"name": "currency_stats",
"base": "",
"fields": [
{"name":"currency", "type":"uint64"},
{"name":"supply", "type":"uint64"}
]
},{
"name": "delegatebw",
"base": "",
"fields": [
{"name":"value", "type":"string"}
{"name":"from", "type":"account_name"},
{"name":"receiver", "type":"account_name"},
{"name":"stake_net", "type":"asset"},
{"name":"stake_cpu", "type":"asset"},
{"name":"stake_storage", "type":"asset"}
]
},{
"name": "undelegatebw",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"receiver", "type":"account_name"},
{"name":"unstake_net", "type":"asset"},
{"name":"unstake_cpu", "type":"asset"},
{"name":"unstake_bytes", "type":"uint64"}
]
},{
"name": "refund",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"}
]
},{
"name": "delegated_bandwidth",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"to", "type":"account_name"},
{"name":"net_weight", "type":"asset"},
{"name":"cpu_weight", "type":"asset"},
{"name":"storage_stake", "type":"asset"},
{"name":"storage_bytes", "type":"uint64"}
]
},{
"name": "total_resources",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"},
{"name":"net_weight", "type":"uint64"},
{"name":"cpu_weight", "type":"uint64"},
{"name":"storage_stake", "type":"uint64"},
{"name":"storage_bytes", "type":"uint64"}
]
},{
"name": "eosio_parameters",
"base": "",
"fields": [
{"name":"target_block_size", "type":"uint32"},
{"name":"max_block_size", "type":"uint32"},
{"name":"target_block_acts_per_scope", "type":"uint32"},
{"name":"max_block_acts_per_scope", "type":"uint32"},
{"name":"target_block_acts", "type":"uint32"},
{"name":"max_block_acts", "type":"uint32"},
{"name":"max_storage_size", "type":"uint64"},
{"name":"max_transaction_lifetime", "type":"uint32"},
{"name":"max_transaction_exec_time", "type":"uint32"},
{"name":"max_authority_depth", "type":"uint16"},
{"name":"max_inline_depth", "type":"uint16"},
{"name":"max_inline_action_size", "type":"uint32"},
{"name":"max_generated_transaction_size", "type":"uint32"},
{"name":"percent_of_max_inflation_rate", "type":"uint32"},
{"name":"storage_reserve_ratio", "type":"uint32"}
]
},{
"name": "eosio_global_state",
"base": "eosio_parameters",
"fields": [
{"name":"total_storage_bytes_reserved", "type":"uint64"},
{"name":"total_storage_stake", "type":"uint64"},
{"name":"payment_per_block", "type":"uint64"}
]
},{
"name": "producer_info",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"},
{"name":"total_votes", "type":"uint128"},
{"name":"prefs", "type":"eosio_parameters"},
{"name":"packed_key", "type":"uint8[]"},
{"name":"per_block_payments", "type":"uint64"},
{"name":"last_claim_time", "type":"uint32"}
]
},{
"name": "regproducer",
"base": "",
"fields": [
{"name":"producer", "type":"account_name"},
{"name":"producer_key", "type":"bytes"}
{"name":"producer", "type":"account_name"},
{"name":"producer_key", "type":"bytes"},
{"name":"prefs", "type":"eosio_parameters"}
]
},{
"name": "unregprod",
"base": "",
"fields": [
{"name":"producer", "type":"account_name"}
]
},{
"name": "regproxy",
"base": "",
"fields": [
{"name":"proxy", "type":"account_name"}
]
},{
"name": "unregproxy",
"base": "",
"fields": [
{"name":"proxy", "type":"account_name"}
]
},{
"name": "voteproducer",
"base": "",
"fields": [
{"name":"voter", "type":"account_name"},
{"name":"proxy", "type":"account_name"},
{"name":"producers", "type":"account_name[]"}
]
},{
"name": "stakevote",
"name": "voter_info",
"base": "",
"fields": [
{"name":"voter", "type":"account_name"},
{"name":"amount", "type":"asset"}
{"name":"owner", "type":"account_name"},
{"name":"proxy", "type":"account_name"},
{"name":"last_update", "type":"uint32"},
{"name":"is_proxy", "type":"uint32"},
{"name":"staked", "type":"uint64"},
{"name":"unstaking", "type":"uint64"},
{"name":"unstake_per_week", "type":"uint64"},
{"name":"proxied_votes", "type":"uint128"},
{"name":"producers", "type":"account_name[]"},
{"name":"deferred_trx_id", "type":"uint32"},
{"name":"last_unstake", "type":"uint32"}
]
},{
"name": "claimrewards",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"}
]
}
],
"actions": [{
"name": "transfer",
......@@ -53,22 +187,37 @@
"name": "issue",
"type": "issue"
},{
"name": "nonce",
"type": "nonce"
"name": "delegatebw",
"type": "delegatebw"
},{
"name": "undelegatebw",
"type": "undelegatebw"
},{
"name": "refund",
"type": "refund"
},{
"name": "regproducer",
"type": "regproducer"
},{
"name": "stakevote",
"type": "stakevote"
"name": "unregprod",
"type": "unregprod"
},{
"name": "regproxy",
"type": "regproxy"
},{
"name": "unregproxy",
"type": "unregproxy"
},{
"name": "voteproducer",
"type": "voteproducer"
},{
"name": "claimrewards",
"type": "claimrewards"
},{
"name": "nonce",
"type": "nonce"
}
],
"tables": [{
"name": "account",
"type": "account",
"index_type": "i64",
"key_names" : ["key"],
"key_types" : ["name"]
}
"tables": [
]
}
......@@ -11,7 +11,7 @@ extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t act ) {
print( eosio::name(code), "::", eosio::name(act) );
//print( eosio::name(code), "::", eosio::name(act) );
eosiosystem::contract<N(eosio)>::apply( code, act );
}
}
此差异已折叠。
......@@ -133,20 +133,97 @@ namespace eosio {
return r;
}
friend asset operator + ( const asset& a, const asset& b ) {
eosio_assert( a.symbol == b.symbol, "type mismatch" );
int64_t sum = a.amount + b.amount;
eosio_assert( -max_amount <= sum, "underflow" );
eosio_assert( sum <= max_amount, "overflow" );
return asset{sum, a.symbol};
asset& operator-=( const asset& a ) {
eosio_assert( a.symbol == symbol, "attempt to subtract asset with different symbol" );
amount -= a.amount;
eosio_assert( -max_amount <= amount, "subtraction underflow" );
eosio_assert( amount <= max_amount, "subtraction overflow" );
return *this;
}
friend asset operator - ( const asset& a, const asset& b ) {
eosio_assert( a.symbol == b.symbol, "type mismatch" );
int64_t difference = a.amount - b.amount;
eosio_assert( -max_amount <= difference, "underflow" );
eosio_assert( difference <= max_amount, "overflow" );
return asset{difference, a.symbol};
asset& operator+=( const asset& a ) {
eosio_assert( a.symbol == symbol, "attempt to add asset with different symbol" );
amount += a.amount;
eosio_assert( -max_amount <= amount, "addition underflow" );
eosio_assert( amount <= max_amount, "addition overflow" );
return *this;
}
inline friend asset operator+( const asset& a, const asset& b ) {
asset result = a;
result += b;
return result;
}
inline friend asset operator-( const asset& a, const asset& b ) {
asset result = a;
result -= b;
return result;
}
asset& operator*=( int64_t a ) {
eosio_assert( a == 0 || (amount * a) / a == amount, "multiplication overflow or underflow" );
eosio_assert( -max_amount <= amount, "multiplication underflow" );
eosio_assert( amount <= max_amount, "multiplication overflow" );
amount *= a;
return *this;
}
friend asset operator*( const asset& a, int64_t b ) {
asset result = a;
result *= b;
return result;
}
friend asset operator*( int64_t b, const asset& a ) {
asset result = a;
result *= b;
return result;
}
asset& operator/=( int64_t a ) {
amount /= a;
return *this;
}
friend asset operator/( const asset& a, int64_t b ) {
asset result = a;
result /= b;
return result;
}
friend int64_t operator/( const asset& a, const asset& b ) {
eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount / b.amount;
}
friend bool operator==( const asset& a, const asset& b ) {
eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount < b.amount;
}
friend bool operator!=( const asset& a, const asset& b ) {
return !( a == b);
}
friend bool operator<( const asset& a, const asset& b ) {
eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount < b.amount;
}
friend bool operator<=( const asset& a, const asset& b ) {
eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount <= b.amount;
}
friend bool operator>( const asset& a, const asset& b ) {
eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount > b.amount;
}
friend bool operator>=( const asset& a, const asset& b ) {
eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" );
return a.amount >= b.amount;
}
void print()const {
......@@ -172,10 +249,6 @@ namespace eosio {
symbol.print(false);
}
asset& operator+=( const asset& a ) {
return *this = (*this + a);
}
EOSLIB_SERIALIZE( asset, (amount)(symbol) )
};
......
......@@ -166,7 +166,7 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, key256& d) {
/**
* Serialize a float into a stream
* @brief Serialize a float
* @brief Serialize a float
* @param ds stream to write
* @param d value to serialize
*/
......@@ -634,4 +634,40 @@ bytes pack( const T& value ) {
return result;
}
} /// namespace eosio
template<typename Stream>
inline eosio::datastream<Stream>& operator<<(eosio::datastream<Stream>& ds, const public_key pk) {
ds.write((const char*)&pk, sizeof(pk));
return ds;
}
template<typename Stream>
inline eosio::datastream<Stream>& operator>>(eosio::datastream<Stream>& ds, public_key& pk) {
ds.read((char*)&pk, sizeof(pk));
return ds;
}
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const checksum160& cs) {
ds.write((const char*)&cs, sizeof(cs));
return ds;
}
template<typename Stream>
inline datastream<Stream>& operator>>(datastream<Stream>& ds, checksum160& cs) {
ds.read((char*)&cs, sizeof(cs));
return ds;
}
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const checksum512& cs) {
ds.write((const char*)&cs, sizeof(cs));
return ds;
}
template<typename Stream>
inline datastream<Stream>& operator>>(datastream<Stream>& ds, checksum512& cs) {
ds.read((char*)&cs, sizeof(cs));
return ds;
}
}
#include "datastream.hpp"
#include "memory.hpp"
#include "privileged.hpp"
void* sbrk(size_t num_bytes) {
constexpr uint32_t NBPPL2 = 16U;
......@@ -38,6 +40,21 @@ void* sbrk(size_t num_bytes) {
namespace eosio {
void set_blockchain_parameters(const eosio::blockchain_parameters& params) {
char buf[sizeof(eosio::blockchain_parameters)];
eosio::datastream<char *> ds( buf, sizeof(buf) );
ds << params;
set_blockchain_parameters_packed( buf, ds.tellp() );
}
void get_blockchain_parameters(eosio::blockchain_parameters& params) {
char buf[sizeof(eosio::blockchain_parameters)];
size_t size = get_blockchain_parameters_packed( buf, sizeof(buf) );
eosio_assert( size <= sizeof(buf), "buffer is too small" );
eosio::datastream<const char*> ds( buf, size_t(size) );
ds >> params;
}
using ::memset;
using ::memcpy;
......@@ -76,7 +93,7 @@ namespace eosio {
const uint32_t current_memory_size = reinterpret_cast<uint32_t>(sbrk(0));
if(static_cast<int32_t>(current_memory_size) < 0)
return nullptr;
//grab up to the end of the current WASM memory page provided that it has 1KiB remaining, otherwise
// grow to end of next page
uint32_t heap_adj;
......@@ -324,7 +341,7 @@ namespace eosio {
return nullptr;
}
if( *orig_ptr_size > size )
if( *orig_ptr_size > size )
{
// use a buffer_ptr to allocate the memory to free
char* const new_ptr = ptr + size + _size_marker;
......@@ -515,7 +532,8 @@ namespace eosio {
};
memory_manager memory_heap;
}
} /// namespace eosio
extern "C" {
......
......@@ -23,6 +23,9 @@ namespace eosio {
ACTION( code, issue ) {
typedef action_meta<code,N(issue)> meta;
issue() { }
issue(account_name a, asset q): to(a), quantity(q) { }
account_name to;
asset quantity;
......@@ -136,6 +139,17 @@ namespace eosio {
act.send();
}
static void inline_issue(account_name to, token_type quantity)
{
action act(permission_level(code, N(active)), issue(to, asset(quantity)));
act.send();
}
static token_type get_total_supply() {
stats t( code, code );
auto ptr = t.find( symbol );
return ptr != t.end() ? ptr->supply : token_type(0);
}
static void apply( account_name c, action_name act) {
eosio::dispatch<generic_currency, transfer, issue>(c,act);
......
......@@ -15,11 +15,7 @@
#include <algorithm>
#include <memory>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <eosiolib/types.hpp>
#include <eosiolib/serialize.hpp>
......
#pragma once
#include <utility>
namespace eosio {
template<typename T>
class optional {
public:
typedef T value_type;
typedef typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_type;
optional():_valid(false){}
~optional(){ reset(); }
optional( optional& o )
:_valid(false)
{
if( o._valid ) new (ptr()) T( *o );
_valid = o._valid;
}
optional( const optional& o )
:_valid(false)
{
if( o._valid ) new (ptr()) T( *o );
_valid = o._valid;
}
optional( optional&& o )
:_valid(false)
{
if( o._valid ) new (ptr()) T( std::move(*o) );
_valid = o._valid;
o.reset();
}
template<typename U>
optional( const optional<U>& o )
:_valid(false)
{
if( o._valid ) new (ptr()) T( *o );
_valid = o._valid;
}
template<typename U>
optional( optional<U>& o )
:_valid(false)
{
if( o._valid )
{
new (ptr()) T( *o );
}
_valid = o._valid;
}
template<typename U>
optional( optional<U>&& o )
:_valid(false)
{
if( o._valid ) new (ptr()) T( std::move(*o) );
_valid = o._valid;
o.reset();
}
template<typename U>
optional( U&& u )
:_valid(true)
{
new ((char*)ptr()) T( std::forward<U>(u) );
}
template<typename U>
optional& operator=( U&& u )
{
reset();
new (ptr()) T( std::forward<U>(u) );
_valid = true;
return *this;
}
template<typename ...Args>
void emplace(Args&& ... args) {
if (_valid) {
reset();
}
new ((char*)ptr()) T( std::forward<Args>(args)... );
_valid = true;
}
template<typename U>
optional& operator=( optional<U>& o ) {
if (this != &o) {
if( _valid && o._valid ) {
ref() = *o;
} else if( !_valid && o._valid ) {
new (ptr()) T( *o );
_valid = true;
} else if (_valid) {
reset();
}
}
return *this;
}
template<typename U>
optional& operator=( const optional<U>& o ) {
if (this != &o) {
if( _valid && o._valid ) {
ref() = *o;
} else if( !_valid && o._valid ) {
new (ptr()) T( *o );
_valid = true;
} else if (_valid) {
reset();
}
}
return *this;
}
optional& operator=( optional& o ) {
if (this != &o) {
if( _valid && o._valid ) {
ref() = *o;
} else if( !_valid && o._valid ) {
new (ptr()) T( *o );
_valid = true;
} else if (_valid) {
reset();
}
}
return *this;
}
optional& operator=( const optional& o ) {
if (this != &o) {
if( _valid && o._valid ) {
ref() = *o;
} else if( !_valid && o._valid ) {
new (ptr()) T( *o );
_valid = true;
} else if (_valid) {
reset();
}
}
return *this;
}
template<typename U>
optional& operator=( optional<U>&& o )
{
if (this != &o)
{
if( _valid && o._valid )
{
ref() = std::move(*o);
o.reset();
} else if ( !_valid && o._valid ) {
*this = std::move(*o);
} else if (_valid) {
reset();
}
}
return *this;
}
optional& operator=( optional&& o )
{
if (this != &o)
{
if( _valid && o._valid )
{
ref() = std::move(*o);
o.reset();
} else if ( !_valid && o._valid ) {
*this = std::move(*o);
} else if (_valid) {
reset();
}
}
return *this;
}
bool valid()const { return _valid; }
bool operator!()const { return !_valid; }
// this operation is not safe and can result in unintential
// casts and comparisons, use valid() or !!
explicit operator bool()const { return _valid; }
T& operator*() { eosio_assert(_valid, "dereference of empty optional"); return ref(); }
const T& operator*()const { eosio_assert(_valid, "dereference of empty optional"); return ref(); }
T* operator->()
{
eosio_assert(_valid, "dereference of empty optional");
return ptr();
}
const T* operator->()const
{
eosio_assert(_valid, "dereference of empty optional");
return ptr();
}
optional& operator=(std::nullptr_t)
{
reset();
return *this;
}
void reset()
{
if( _valid ) {
ref().~T(); // cal destructor
}
_valid = false;
}
friend bool operator < ( const optional a, optional b )
{
if( a.valid() && b.valid() ) return *a < *b;
return a.valid() < b.valid();
}
friend bool operator == ( const optional a, optional b )
{
if( a.valid() && b.valid() ) return *a == *b;
return a.valid() == b.valid();
}
template<typename Stream>
friend inline eosio::datastream<Stream>& operator>> (eosio::datastream<Stream>& ds, optional& op)
{
char valid = 0;
ds >> valid;
if (valid) {
op._valid = true;
ds >> *op;
}
return ds;
}
template<typename Stream>
friend inline eosio::datastream<Stream>& operator<< (eosio::datastream<Stream>& ds, const optional& op)
{
char valid = op._valid;
ds << valid;
if (valid) ds << *op;
return ds;
}
private:
template<typename U> friend class optional;
T& ref() { return *ptr(); }
const T& ref()const { return *ptr(); }
T* ptr() { return reinterpret_cast<T*>(&_value); }
const T* ptr()const { return reinterpret_cast<const T*>(&_value); }
bool _valid;
storage_type _value;
};
template<typename T>
bool operator == ( const optional<T>& left, const optional<T>& right ) {
return (!left == !right) || (!!left && *left == *right);
}
template<typename T, typename U>
bool operator == ( const optional<T>& left, const U& u ) {
return !!left && *left == u;
}
template<typename T>
bool operator != ( const optional<T>& left, const optional<T>& right ) {
return (!left != !right) || (!!left && *left != *right);
}
template<typename T, typename U>
bool operator != ( const optional<T>& left, const U& u ) {
return !left || *left != u;
}
} // namespace eosio
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup privilegedapi Privileged API
......@@ -18,17 +20,19 @@ extern "C" {
void set_resource_limits( account_name account, uint64_t ram_bytes, uint64_t net_weight, uint64_t cpu_weight );
void set_active_producers( char *producer_data, size_t producer_data_size );
void set_active_producers( char *producer_data, uint32_t producer_data_size );
bool is_privileged( account_name account );
void set_privileged( account_name account, bool is_priv );
void activate_feature( int64_t f );
void set_blockchain_parameters_packed(char* data, uint32_t datalen);
uint32_t get_blockchain_parameters_packed(char* data, uint32_t datalen);
void activate_feature( int64_t f );
///@ } privilegedcapi
#ifdef __cplusplus
}
#endif
#pragma once
#include "privileged.h"
#include "serialize.hpp"
#include "types.h"
namespace eosio {
struct blockchain_parameters {
uint32_t target_block_size;
uint32_t max_block_size;
uint32_t target_block_acts_per_scope;
uint32_t max_block_acts_per_scope;
uint32_t target_block_acts; ///< regardless of the amount of parallelism, this defines target compute time per block
uint32_t max_block_acts; ///< regardless of the amount of parallelism, this maximum compute time per block
uint64_t max_storage_size;
uint32_t max_transaction_lifetime;
uint32_t max_transaction_exec_time;
uint16_t max_authority_depth;
uint16_t max_inline_depth;
uint32_t max_inline_action_size;
uint32_t max_generated_transaction_size;
EOSLIB_SERIALIZE( blockchain_parameters, (target_block_size)(max_block_size)(target_block_acts_per_scope)
(max_block_acts_per_scope)(target_block_acts)(max_block_acts)(max_storage_size)
(max_transaction_lifetime)(max_transaction_exec_time)(max_authority_depth)
(max_inline_depth)(max_inline_action_size)(max_generated_transaction_size)
)
};
void set_blockchain_parameters(const eosio::blockchain_parameters& params);
void get_blockchain_parameters(eosio::blockchain_parameters& params);
struct producer_key {
account_name producer_name;
public_key block_signing_key;
EOSLIB_SERIALIZE( producer_key, (producer_name)(block_signing_key) )
};
struct producer_schedule {
uint32_t version = 0; ///< sequentially incrementing version number
std::vector<producer_key> producers;
EOSLIB_SERIALIZE( producer_schedule, (version)(producers) )
};
}
......@@ -30,7 +30,7 @@ namespace eosio {
static bool exists( scope_name scope = Code ) {
table t( Code, scope );
return t.find( pk_value );
return t.find( pk_value ) != t.end();
}
static T get( scope_name scope = Code ) {
......
......@@ -46,10 +46,11 @@ namespace eosio {
template<typename Base, typename Quote>
friend price<Base,Quote> operator / ( const Base& b, const Quote& q );
operator asset()const { return asset( int64_t(quantity), Symbol ); }
explicit operator asset()const { return asset( int64_t(quantity), Symbol ); }
token( const asset& a ):quantity(NumberType(a.amount)) {
eosio_assert( a.symbol == Symbol, "attempt to construct token from asset with different symbol" );
eosio_assert( 0 <= a.amount, "attemt to convert asset with negative value to token" );
}
/**
......@@ -119,6 +120,85 @@ namespace eosio {
return result;
}
/**
* Multiplies quantity of token by an integer
* Throws an exception if overflow
* @brief Multiplies quantity of token by an integer
* @param a multipier
* @return this token after addition
*/
token& operator*=( uint64_t a ) {
eosio_assert( a == 0 || (quantity * a) / a == quantity, "integer overflow multiplying token balance" );
quantity *= a;
return *this;
}
/**
* Multiplies token and integer
* Throws an exception if overflow
* @brief Multiplies quantity of two tokens and return a new token
* @param a token to be multiplied
* @param b multipier
* @return result of addition as a new token
*/
inline friend token operator*( const token& a, uint64_t b ) {
token result = a;
result *= b;
return result;
}
/**
* Multiplies token and integer
* Throws an exception if overflow
* @brief Multiplies quantity of two tokens and return a new token
* @param a token to be multiplied
* @param b multipier
* @return result of addition as a new token
*/
inline friend token operator*( uint64_t b, const token& a ) {
token result = a;
result *= b;
return result;
}
/**
* Divides quantity of token by an integer
* Throws an exception if overflow
* @brief Divides quantity of token by an integer
* @param a multipier
* @return this token after addition
*/
token& operator/=( uint64_t a ) {
quantity /= a;
return *this;
}
/**
* Divides token and integer
* Throws an exception if overflow
* @brief Divides quantity of two tokens and return a new token
* @param a token to be multiplied
* @param b multipier
* @return result of addition as a new token
*/
inline friend token operator/( const token& a, uint64_t b ) {
token result = a;
result /= b;
return result;
}
/**
* Divides two tokens
* Throws an exception if overflow
* @brief Divides quantity of two tokens and return a new token
* @param a token
* @param b token
* @return result of addition as a new token
*/
inline friend NumberType operator/( const token& a, const token& b ) {
return a.quantity / b.quantity;
}
/**
* Less than or equal to comparison operator
* @brief Less than or equal to comparison operator
......
......@@ -59,7 +59,9 @@ extern "C" {
* @{
*/
void send_deferred(uint32_t sender_id, time delay_until, char *serialized_transaction, size_t size);
void send_deferred(uint64_t sender_id, time delay_until, char *serialized_transaction, size_t size);
void cancel_deferred(uint64_t sender_id);
/**
* access a copy of the currently executing transaction
......
......@@ -28,7 +28,7 @@ namespace eosio {
:expiration(exp),region(r)
{}
void send(uint32_t sender_id, time delay_until = 0) const {
void send(uint64_t sender_id, time delay_until = 0) const {
auto serialize = pack(*this);
send_deferred(sender_id, delay_until, serialize.data(), serialize.size());
}
......@@ -48,7 +48,7 @@ namespace eosio {
class deferred_transaction : public transaction {
public:
uint32_t sender_id;
uint64_t sender_id;
account_name sender;
time delay_until;
......
......@@ -6,10 +6,6 @@
#include <stdint.h>
#include <wchar.h>
/*
struct checksum_base {
};
*/
#ifdef __cplusplus
extern "C" {
......
......@@ -3,6 +3,8 @@ SET(SRC_FILENAMES algorithm.cpp any.cpp bind.cpp condition_variable.cpp exceptio
regex.cpp shared_mutex.cpp stdexcept.cpp string.cpp strstream.cpp system_error.cpp
thread.cpp typeinfo.cpp utility.cpp valarray.cpp variant.cpp vector.cpp)
#SET(SRC_FILENAMES exception.cpp)
SET(SRC_FILES "")
FOREACH(FN ${SRC_FILENAMES})
LIST(APPEND SRC_FILES "upstream/src/${FN}")
......
......@@ -18,7 +18,7 @@ void apply_context::exec_one()
auto native = mutable_controller.find_apply_handler(receiver, act.account, act.name);
if (native) {
(*native)(*this);
}
}
else if (a.code.size() > 0) {
try {
mutable_controller.get_wasm_interface().apply(a.code_version, a.code, *this);
......@@ -181,14 +181,14 @@ void apply_context::require_recipient( account_name code ) {
/**
* This will execute an action after checking the authorization. Inline transactions are
* This will execute an action after checking the authorization. Inline transactions are
* implicitly authorized by the current receiver (running code). This method has significant
* security considerations and several options have been considered:
*
* 1. priviledged accounts (those marked as such by block producers) can authorize any action
* 2. all other actions are only authorized by 'receiver' which means the following:
* a. the user must set permissions on their account to allow the 'receiver' to act on their behalf
*
*
* Discarded Implemenation: at one point we allowed any account that authorized the current transaction
* to implicitly authorize an inline transaction. This approach would allow privelege escalation and
* make it unsafe for users to interact with certain contracts. We opted instead to have applications
......@@ -196,9 +196,9 @@ void apply_context::require_recipient( account_name code ) {
* can better understand the security risk.
*/
void apply_context::execute_inline( action&& a ) {
if ( !privileged ) {
if ( !privileged ) {
if( a.account != receiver ) {
controller.check_authorization({a}, flat_set<public_key_type>(), false, {receiver});
controller.check_authorization({a}, flat_set<public_key_type>(), false, {receiver});
}
}
_inline_actions.emplace_back( move(a) );
......@@ -233,7 +233,7 @@ void apply_context::execute_deferred( deferred_transaction&& trx ) {
break;
}
}
if( check_auth )
if( check_auth )
controller.check_authorization(trx.actions, flat_set<public_key_type>(), false, {receiver});
}
......@@ -245,7 +245,7 @@ void apply_context::execute_deferred( deferred_transaction&& trx ) {
} FC_CAPTURE_AND_RETHROW((trx));
}
void apply_context::cancel_deferred( uint32_t sender_id ) {
void apply_context::cancel_deferred( uint64_t sender_id ) {
results.canceled_deferred.emplace_back(receiver, sender_id);
}
......
......@@ -56,10 +56,15 @@ asset asset::from_string(const string& from)
auto fractpart = "1" + s.substr(dot_pos + 1, space_pos - dot_pos - 1);
result.amount *= int64_t(result.precision());
result.amount += int64_t(fc::to_int64(fractpart));
result.amount -= int64_t(result.precision());
if ( intpart[0] == '-' ) {
result.amount -= int64_t(fc::to_int64(fractpart));
result.amount += int64_t(result.precision());
} else {
result.amount += int64_t(fc::to_int64(fractpart));
result.amount -= int64_t(result.precision());
}
}
return result;
}
FC_CAPTURE_LOG_AND_RETHROW( (from) )
......
......@@ -331,6 +331,17 @@ transaction_trace chain_controller::_push_transaction( transaction_metadata&& da
return result;
}
block_header chain_controller::head_block_header() const
{
auto b = _fork_db.fetch_block(head_block_id());
if( b ) return b->data;
if (auto head_block = fetch_block_by_id(head_block_id()))
return *head_block;
return block_header();
}
void chain_controller::_start_pending_block()
{
FC_ASSERT( !_pending_block );
......@@ -340,6 +351,30 @@ void chain_controller::_start_pending_block()
_pending_block->regions.resize(1);
_pending_block_trace->region_traces.resize(1);
_start_pending_cycle();
_apply_on_block_transaction();
_finalize_pending_cycle();
_start_pending_cycle();
}
transaction chain_controller::_get_on_block_transaction()
{
action on_block_act;
on_block_act.account = config::system_account_name;
on_block_act.name = N(onblock);
on_block_act.authorization = vector<permission_level>{{config::system_account_name, config::active_name}};
on_block_act.data = fc::raw::pack(head_block_header());
transaction trx;
trx.actions.emplace_back(std::move(on_block_act));
trx.set_reference_block(head_block_id());
return trx;
}
void chain_controller::_apply_on_block_transaction()
{
_pending_block_trace->implicit_transactions.emplace_back(_get_on_block_transaction());
transaction_metadata mtrx(packed_transaction(_pending_block_trace->implicit_transactions.back()), get_chain_id(), head_block_time());
_push_transaction(std::move(mtrx));
}
/**
......@@ -602,18 +637,22 @@ void chain_controller::__apply_block(const signed_block& next_block)
for( uint32_t i = 1; i < next_block.regions.size(); ++i )
FC_ASSERT( next_block.regions[i-1].region < next_block.regions[i].region );
block_trace next_block_trace(next_block);
/// cache the input tranasction ids so that they can be looked up when executing the
/// summary
vector<transaction_metadata> input_metas;
input_metas.reserve(next_block.input_transactions.size());
input_metas.reserve(next_block.input_transactions.size() + 1);
{
next_block_trace.implicit_transactions.emplace_back(_get_on_block_transaction());
input_metas.emplace_back(packed_transaction(next_block_trace.implicit_transactions.back()), get_chain_id(), head_block_time());
}
map<transaction_id_type,size_t> trx_index;
for( const auto& t : next_block.input_transactions ) {
input_metas.emplace_back(t, chain_id_type(), next_block.timestamp);
trx_index[input_metas.back().id] = input_metas.size() - 1;
}
block_trace next_block_trace(next_block);
next_block_trace.region_traces.reserve(next_block.regions.size());
for( const auto& r : next_block.regions ) {
......@@ -665,10 +704,16 @@ void chain_controller::__apply_block(const signed_block& next_block)
if( itr != trx_index.end() ) {
return &input_metas.at(itr->second);
} else {
const auto& gtrx = _db.get<generated_transaction_object,by_trx_id>(receipt.id);
auto trx = fc::raw::unpack<deferred_transaction>(gtrx.packed_trx.data(), gtrx.packed_trx.size());
_temp.emplace(trx, gtrx.published, trx.sender, trx.sender_id, gtrx.packed_trx.data(), gtrx.packed_trx.size() );
return &*_temp;
const auto* gtrx = _db.find<generated_transaction_object,by_trx_id>(receipt.id);
if (gtrx != nullptr) {
auto trx = fc::raw::unpack<deferred_transaction>(gtrx->packed_trx.data(), gtrx->packed_trx.size());
_temp.emplace(trx, gtrx->published, trx.sender, trx.sender_id, gtrx->packed_trx.data(), gtrx->packed_trx.size() );
return &*_temp;
} else {
const auto& mtrx = input_metas[0];
FC_ASSERT(mtrx.id == receipt.id, "on-block transaction id mismatch");
return &input_metas[0];
}
}
};
......@@ -960,7 +1005,6 @@ void chain_controller::update_global_properties(const signed_block& b) { try {
{
FC_ASSERT( schedule == *b.new_producers, "pending producer set different than expected" );
}
const auto& gpo = get_global_properties();
if( _head_producer_schedule() != schedule ) {
......
......@@ -30,14 +30,18 @@ namespace eosio { namespace chain { namespace contracts {
template <typename T>
auto pack_unpack() {
return std::make_pair<abi_serializer::unpack_function, abi_serializer::pack_function>(
[]( fc::datastream<const char*>& stream, bool is_array) -> fc::variant {
[]( fc::datastream<const char*>& stream, bool is_array, bool is_optional) -> fc::variant {
if( is_array )
return variant_from_stream<vector<T>>(stream);
else if ( is_optional )
return variant_from_stream<optional<T>>(stream);
return variant_from_stream<T>(stream);
},
[]( const fc::variant& var, fc::datastream<char*>& ds, bool is_array ){
[]( const fc::variant& var, fc::datastream<char*>& ds, bool is_array, bool is_optional ){
if( is_array )
fc::raw::pack( ds, var.as<vector<T>>() );
else if ( is_optional )
fc::raw::pack( ds, var.as<optional<T>>() );
else
fc::raw::pack( ds, var.as<T>());
}
......@@ -87,6 +91,7 @@ namespace eosio { namespace chain { namespace contracts {
built_in_types.emplace("permission_name", pack_unpack<permission_name>());
built_in_types.emplace("action_name", pack_unpack<action_name>());
built_in_types.emplace("scope_name", pack_unpack<scope_name>());
built_in_types.emplace("producer_schedule", pack_unpack<producer_schedule_type>());
}
void abi_serializer::set_abi(const abi_def& abi) {
......@@ -146,13 +151,22 @@ namespace eosio { namespace chain { namespace contracts {
return ends_with(string(type), "[]");
}
type_name abi_serializer::array_type(const type_name& type)const {
if( !is_array(type) ) return type;
return type_name(string(type).substr(0, type.size()-2));
bool abi_serializer::is_optional(const type_name& type)const {
return ends_with(string(type), "?");
}
type_name abi_serializer::fundamental_type(const type_name& type)const {
if( is_array(type) ) {
return type_name(string(type).substr(0, type.size()-2));
} else if ( is_optional(type) ) {
return type_name(string(type).substr(0, type.size()-1));
} else {
return type;
}
}
bool abi_serializer::is_type(const type_name& rtype)const {
auto type = array_type(rtype);
auto type = fundamental_type(rtype);
if( built_in_types.find(type) != built_in_types.end() ) return true;
if( typedefs.find(type) != typedefs.end() ) return is_type(typedefs.find(type)->second);
if( structs.find(type) != structs.end() ) return true;
......@@ -223,9 +237,10 @@ namespace eosio { namespace chain { namespace contracts {
fc::variant abi_serializer::binary_to_variant(const type_name& type, fc::datastream<const char *>& stream)const
{
type_name rtype = resolve_type(type);
auto btype = built_in_types.find(array_type(rtype) );
auto ftype = fundamental_type(rtype);
auto btype = built_in_types.find(ftype );
if( btype != built_in_types.end() ) {
return btype->second.first(stream, is_array(rtype));
return btype->second.first(stream, is_array(rtype), is_optional(rtype));
}
if ( is_array(rtype) ) {
fc::unsigned_int size;
......@@ -233,9 +248,13 @@ namespace eosio { namespace chain { namespace contracts {
vector<fc::variant> vars;
vars.resize(size);
for (auto& var : vars) {
var = binary_to_variant(array_type(rtype), stream);
var = binary_to_variant(ftype, stream);
}
return fc::variant( std::move(vars) );
} else if ( is_optional(rtype) ) {
char flag;
fc::raw::unpack(stream, flag);
return flag ? binary_to_variant(ftype, stream) : fc::variant();
}
fc::mutable_variant_object mvo;
......@@ -252,14 +271,14 @@ namespace eosio { namespace chain { namespace contracts {
{ try {
auto rtype = resolve_type(type);
auto btype = built_in_types.find(array_type(rtype));
auto btype = built_in_types.find(fundamental_type(rtype));
if( btype != built_in_types.end() ) {
btype->second.second(var, ds, is_array(rtype));
btype->second.second(var, ds, is_array(rtype), is_optional(rtype));
} else if ( is_array(rtype) ) {
vector<fc::variant> vars = var.get_array();
fc::raw::pack(ds, (fc::unsigned_int)vars.size());
for (const auto& var : vars) {
variant_to_binary(array_type(rtype), var, ds);
variant_to_binary(fundamental_type(rtype), var, ds);
}
} else {
const auto& st = get_struct(rtype);
......
......@@ -72,6 +72,7 @@ abi_def chain_initializer::eos_contract_abi(const abi_def& eosio_system_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("onblock"), "onblock"} );
// ACTION PAYLOADS
......@@ -255,25 +256,6 @@ abi_def chain_initializer::eos_contract_abi(const abi_def& eosio_system_abi)
}
});
eos_abi.structs.emplace_back( struct_def {
"chain_config", "", {
{"target_block_size", "uint32"},
{"max_block_size", "uint32"},
{"target_block_acts_per_scope", "uint32"},
{"max_block_acts_per_scope", "uint32"},
{"target_block_acts", "uint32"},
{"max_block_acts", "uint32"},
{"real_threads", "uint64"},
{"max_storage_size", "uint64"},
{"max_transaction_lifetime", "uint32"},
{"max_authority_depth", "uint16"},
{"max_transaction_exec_time", "uint32"},
{"max_inline_depth", "uint16"},
{"max_inline_action_size", "uint32"},
{"max_generated_transaction_size", "uint32"}
}
});
eos_abi.structs.emplace_back( struct_def {
"type_def", "", {
{"new_type_name", "type_name"},
......@@ -307,6 +289,25 @@ abi_def chain_initializer::eos_contract_abi(const abi_def& eosio_system_abi)
}
});
eos_abi.structs.emplace_back( struct_def {
"block_header", "", {
{"previous", "checksum256"},
{"timestamp", "uint32"},
{"transaction_mroot", "checksum256"},
{"action_mroot", "checksum256"},
{"block_mroot", "checksum256"},
{"producer", "account_name"},
{"schedule_version", "uint32"},
{"new_producers", "producer_schedule?"}
}
});
eos_abi.structs.emplace_back( struct_def {
"onblock", "", {
{"header", "block_header"}
}
});
return eos_abi;
}
......
......@@ -20,7 +20,6 @@ namespace eosio { namespace chain {
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;
......
......@@ -464,7 +464,7 @@ class apply_context {
void execute_inline( action &&a );
void execute_context_free_inline( action &&a );
void execute_deferred( deferred_transaction &&trx );
void cancel_deferred( uint32_t sender_id );
void cancel_deferred( uint64_t sender_id );
/**
* @brief Require @ref account to have approved of this message
......
......@@ -147,6 +147,7 @@ namespace eosio { namespace chain {
const signed_block& block;
vector<region_trace> region_traces;
vector<transaction> implicit_transactions;
digest_type calculate_action_merkle_root()const;
};
......
......@@ -26,12 +26,10 @@ struct chain_config {
uint32_t target_block_acts; ///< regardless of the amount of parallelism, this defines target compute time per block
uint32_t max_block_acts; ///< regardless of the amount of parallelism, this maximum compute time per block
uint64_t real_threads; ///< the number of real threads the producers are using
uint64_t max_storage_size;
uint32_t max_transaction_lifetime;
uint16_t max_authority_depth;
uint32_t max_transaction_exec_time;
uint16_t max_authority_depth;
uint16_t max_inline_depth;
uint32_t max_inline_action_size;
uint32_t max_generated_transaction_size;
......@@ -41,18 +39,17 @@ struct chain_config {
template<typename Stream>
friend Stream& operator << ( Stream& out, const chain_config& c ) {
return out << "Target Block Size: " << c.target_block_size << ", "
<< "Max Block Size: " << c.max_block_size << ", "
<< "Target Block Acts Per Scope: " << c.target_block_acts_per_scope << ", "
<< "Max Block Acts Per Scope: " << c.max_block_acts_per_scope << ", "
<< "Target Block Acts: " << c.target_block_acts << ", "
<< "Max Block Acts: " << c.max_block_acts << ", "
<< "Real Threads: " << c.real_threads << ", "
<< "Max Storage Size: " << c.max_storage_size << ", "
<< "Max Transaction Lifetime: " << c.max_transaction_lifetime << ", "
<< "Max Block Size: " << c.max_block_size << ", "
<< "Target Block Acts Per Scope: " << c.target_block_acts_per_scope << ", "
<< "Max Block Acts Per Scope: " << c.max_block_acts_per_scope << ", "
<< "Target Block Acts: " << c.target_block_acts << ", "
<< "Max Block Acts: " << c.max_block_acts << ", "
<< "Max Storage Size: " << c.max_storage_size << ", "
<< "Max Transaction Lifetime: " << c.max_transaction_lifetime << ", "
<< "Max Transaction Exec Time: " << c.max_transaction_exec_time << ", "
<< "Max Authority Depth: " << c.max_authority_depth << ", "
<< "Max Transaction Exec Time: " << c.max_transaction_exec_time << ", "
<< "Max Inline Depth: " << c.max_inline_depth << ", "
<< "Max Inline Action Size: " << c.max_inline_action_size << ", "
<< "Max Inline Depth: " << c.max_inline_depth << ", "
<< "Max Inline Action Size: " << c.max_inline_action_size << ", "
<< "Max Generated Transaction Size: " << c.max_generated_transaction_size << "\n";
}
};
......@@ -62,14 +59,13 @@ inline bool operator!=(const chain_config& a, const chain_config& b) { return !(
} } // namespace eosio::chain
FC_REFLECT(eosio::chain::chain_config,
FC_REFLECT(eosio::chain::chain_config,
(target_block_size)
(max_block_size)
(target_block_acts_per_scope)
(max_block_acts_per_scope)
(target_block_acts)
(max_block_acts)
(real_threads)
(max_storage_size)
(max_transaction_lifetime)(max_authority_depth)(max_transaction_exec_time)
(max_transaction_lifetime)(max_transaction_exec_time)(max_authority_depth)
(max_inline_depth)(max_inline_action_size)(max_generated_transaction_size) )
......@@ -267,6 +267,7 @@ namespace eosio { namespace chain {
uint32_t head_block_num()const;
block_id_type head_block_id()const;
account_name head_block_producer()const;
block_header head_block_header()const;
uint32_t last_irreversible_block_num() const;
......@@ -408,6 +409,9 @@ namespace eosio { namespace chain {
void _apply_cycle_trace( const cycle_trace& trace );
void _finalize_block( const block_trace& b );
transaction _get_on_block_transaction();
void _apply_on_block_transaction();
// producer_schedule_type calculate_next_round( const signed_block& next_block );
......
......@@ -31,8 +31,8 @@ struct abi_serializer {
map<name,type_name> actions;
map<name,type_name> tables;
typedef std::function<fc::variant(fc::datastream<const char*>&, bool)> unpack_function;
typedef std::function<void(const fc::variant&, fc::datastream<char*>&, bool)> pack_function;
typedef std::function<fc::variant(fc::datastream<const char*>&, bool, bool)> unpack_function;
typedef std::function<void(const fc::variant&, fc::datastream<char*>&, bool, bool)> pack_function;
map<type_name, pair<unpack_function, pack_function>> built_in_types;
void configure_built_in_types();
......@@ -42,12 +42,13 @@ struct abi_serializer {
type_name resolve_type(const type_name& t)const;
bool is_array(const type_name& type)const;
bool is_optional(const type_name& type)const;
bool is_type(const type_name& type)const;
bool is_builtin_type(const type_name& type)const;
bool is_integer(const type_name& type) const;
int get_integer_size(const type_name& type) const;
bool is_struct(const type_name& type)const;
type_name array_type(const type_name& type)const;
type_name fundamental_type(const type_name& type)const;
const struct_def& get_struct(const type_name& type)const;
......
......@@ -23,11 +23,10 @@ struct genesis_state_type {
.max_block_acts_per_scope = config::default_max_block_acts_per_scope,
.target_block_acts = config::default_target_block_acts,
.max_block_acts = config::default_max_block_acts,
.real_threads = 0, // TODO: unused?
.max_storage_size = config::default_max_storage_size,
.max_transaction_lifetime = config::default_max_trx_lifetime,
.max_authority_depth = config::default_max_auth_depth,
.max_transaction_exec_time = 0, // TODO: unused?
.max_authority_depth = config::default_max_auth_depth,
.max_inline_depth = config::default_max_inline_depth,
.max_inline_action_size = config::default_max_inline_action_size,
.max_generated_transaction_size = config::default_max_gen_trx_size
......
#pragma once
#include <string>
#include <fc/reflect/reflect.hpp>
#include <iosfwd>
namespace eosio { namespace chain {
using std::string;
......@@ -72,8 +73,7 @@ namespace eosio { namespace chain {
return *this;
}
template<typename Stream>
friend Stream& operator << ( Stream& out, const name& n ) {
friend std::ostream& operator << ( std::ostream& out, const name& n ) {
return out << string(n);
}
......
......@@ -213,18 +213,18 @@ namespace eosio { namespace chain {
*/
struct deferred_transaction : public transaction
{
uint32_t sender_id; /// ID assigned by sender of generated, accessible via WASM api when executing normal or error
uint64_t sender_id; /// ID assigned by sender of generated, accessible via WASM api when executing normal or error
account_name sender; /// receives error handler callback
time_point_sec execute_after; /// delayed exeuction
};
struct deferred_reference {
deferred_reference( const account_name& sender, uint32_t sender_id)
deferred_reference( const account_name& sender, uint64_t sender_id)
:sender(sender),sender_id(sender_id)
{}
account_name sender;
uint32_t sender_id;
uint64_t sender_id;
};
struct data_access_info {
......
......@@ -25,7 +25,7 @@ namespace eosio { namespace chain {
bool resolve(const string& mod_name,
const string& export_name,
IR::ObjectType type,
Runtime::ObjectInstance*& out) override {
Runtime::ObjectInstance*& out) override {
try {
//protect access to "private" injected functions; so for now just simply allow "env" since injected functions
// are in a different module
......@@ -64,7 +64,6 @@ namespace eosio { namespace chain {
void apply(const digest_type& code_id, const shared_vector<char>& code, apply_context& context);
private:
wasm_interface();
unique_ptr<struct wasm_interface_impl> my;
friend class eosio::chain::webassembly::common::intrinsics_accessor;
};
......@@ -73,4 +72,4 @@ namespace eosio { namespace chain {
namespace eosio{ namespace chain {
std::istream& operator>>(std::istream& in, wasm_interface::vm_type& runtime);
}}
\ No newline at end of file
}}
......@@ -20,7 +20,13 @@ class wavm_runtime : public eosio::chain::wasm_runtime_interface {
~wavm_runtime();
std::unique_ptr<wasm_instantiated_module_interface> instantiate_module(const char* code_bytes, size_t code_size, std::vector<uint8_t> initial_memory) override;
struct runtime_guard {
runtime_guard();
~runtime_guard();
};
private:
std::shared_ptr<runtime_guard> _runtime_guard;
};
//This is a temporary hack for the single threaded implementation
......@@ -90,7 +96,7 @@ struct native_to_wasm<T *> {
/*
template<>
struct native_to_wasm<float32_t> {
using type = F32;
using type = F32;
};
template<>
struct native_to_wasm<float64_t> {
......@@ -99,7 +105,7 @@ struct native_to_wasm<float64_t> {
*/
template<>
struct native_to_wasm<float> {
using type = F32;
using type = F32;
};
template<>
struct native_to_wasm<double> {
......
此差异已折叠。
......@@ -12,6 +12,7 @@
#include "Runtime/Linker.h"
#include "Runtime/Intrinsics.h"
#include <mutex>
using namespace IR;
using namespace Runtime;
......@@ -82,14 +83,32 @@ class wavm_instantiated_module : public wasm_instantiated_module_interface {
Module* _module;
};
wavm_runtime::wavm_runtime() {
wavm_runtime::runtime_guard::runtime_guard() {
// TODO clean this up
//check_wasm_opcode_dispositions();
Runtime::init();
}
wavm_runtime::~wavm_runtime() {
wavm_runtime::runtime_guard::~runtime_guard() {
Runtime::freeUnreferencedObjects({});
}
static weak_ptr<wavm_runtime::runtime_guard> __runtime_guard_ptr;
static std::mutex __runtime_guard_lock;
wavm_runtime::wavm_runtime() {
std::lock_guard<std::mutex> l(__runtime_guard_lock);
if (__runtime_guard_ptr.use_count() == 0) {
_runtime_guard = std::make_shared<runtime_guard>();
__runtime_guard_ptr = _runtime_guard;
} else {
_runtime_guard = __runtime_guard_ptr.lock();
}
}
wavm_runtime::~wavm_runtime() {
}
std::unique_ptr<wasm_instantiated_module_interface> wavm_runtime::instantiate_module(const char* code_bytes, size_t code_size, std::vector<uint8_t> initial_memory) {
Module* module = new Module();
Serialization::MemoryInputStream stream((const U8 *)code_bytes, code_size);
......
......@@ -22,26 +22,27 @@ namespace fc {
{
public:
typedef T value_type;
typedef typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_type;
optional():_valid(false){}
~optional(){ reset(); }
optional( optional& o )
:_valid(false)
:_valid(false)
{
if( o._valid ) new (ptr()) T( *o );
_valid = o._valid;
}
optional( const optional& o )
:_valid(false)
:_valid(false)
{
if( o._valid ) new (ptr()) T( *o );
_valid = o._valid;
}
optional( optional&& o )
:_valid(false)
:_valid(false)
{
if( o._valid ) new (ptr()) T( fc::move(*o) );
_valid = o._valid;
......@@ -50,7 +51,7 @@ namespace fc {
template<typename U>
optional( const optional<U>& o )
:_valid(false)
:_valid(false)
{
if( o._valid ) new (ptr()) T( *o );
_valid = o._valid;
......@@ -58,7 +59,7 @@ namespace fc {
template<typename U>
optional( optional<U>& o )
:_valid(false)
:_valid(false)
{
if( o._valid )
{
......@@ -69,7 +70,7 @@ namespace fc {
template<typename U>
optional( optional<U>&& o )
:_valid(false)
:_valid(false)
{
if( o._valid ) new (ptr()) T( fc::move(*o) );
_valid = o._valid;
......@@ -78,13 +79,13 @@ namespace fc {
template<typename U>
optional( U&& u )
:_valid(true)
:_valid(true)
{
new ((char*)ptr()) T( fc::forward<U>(u) );
}
template<typename U>
optional& operator=( U&& u )
optional& operator=( U&& u )
{
reset();
new (ptr()) T( fc::forward<U>(u) );
......@@ -105,7 +106,7 @@ namespace fc {
template<typename U>
optional& operator=( optional<U>& o ) {
if (this != &o) {
if( _valid && o._valid ) {
if( _valid && o._valid ) {
ref() = *o;
} else if( !_valid && o._valid ) {
new (ptr()) T( *o );
......@@ -119,7 +120,7 @@ namespace fc {
template<typename U>
optional& operator=( const optional<U>& o ) {
if (this != &o) {
if( _valid && o._valid ) {
if( _valid && o._valid ) {
ref() = *o;
} else if( !_valid && o._valid ) {
new (ptr()) T( *o );
......@@ -133,7 +134,7 @@ namespace fc {
optional& operator=( optional& o ) {
if (this != &o) {
if( _valid && o._valid ) {
if( _valid && o._valid ) {
ref() = *o;
} else if( !_valid && o._valid ) {
new (ptr()) T( *o );
......@@ -147,7 +148,7 @@ namespace fc {
optional& operator=( const optional& o ) {
if (this != &o) {
if( _valid && o._valid ) {
if( _valid && o._valid ) {
ref() = *o;
} else if( !_valid && o._valid ) {
new (ptr()) T( *o );
......@@ -160,11 +161,11 @@ namespace fc {
}
template<typename U>
optional& operator=( optional<U>&& o )
optional& operator=( optional<U>&& o )
{
if (this != &o)
if (this != &o)
{
if( _valid && o._valid )
if( _valid && o._valid )
{
ref() = fc::move(*o);
o.reset();
......@@ -177,11 +178,11 @@ namespace fc {
return *this;
}
optional& operator=( optional&& o )
optional& operator=( optional&& o )
{
if (this != &o)
if (this != &o)
{
if( _valid && o._valid )
if( _valid && o._valid )
{
ref() = fc::move(*o);
o.reset();
......@@ -197,22 +198,22 @@ namespace fc {
bool valid()const { return _valid; }
bool operator!()const { return !_valid; }
// this operation is not safe and can result in unintential
// casts and comparisons, use valid() or !!
// this operation is not safe and can result in unintential
// casts and comparisons, use valid() or !!
explicit operator bool()const { return _valid; }
T& operator*() { assert(_valid); return ref(); }
const T& operator*()const { assert(_valid); return ref(); }
T* operator->()
{
T* operator->()
{
assert(_valid);
return ptr();
return ptr();
}
const T* operator->()const
{
const T* operator->()const
{
assert(_valid);
return ptr();
return ptr();
}
optional& operator=(std::nullptr_t)
......@@ -232,9 +233,9 @@ namespace fc {
return a.valid() == b.valid();
}
void reset()
{
if( _valid )
void reset()
{
if( _valid )
{
ref().~T(); // cal destructor
}
......@@ -244,12 +245,11 @@ namespace fc {
template<typename U> friend class optional;
T& ref() { return *ptr(); }
const T& ref()const { return *ptr(); }
T* ptr() { void* v = &_value[0]; return static_cast<T*>(v); }
const T* ptr()const { const void* v = &_value[0]; return static_cast<const T*>(v); }
T* ptr() { return reinterpret_cast<T*>(&_value); }
const T* ptr()const { return reinterpret_cast<const T*>(&_value); }
// force alignment... to 8 byte boundaries
double _value[((sizeof(T)+7)/8)];
bool _valid;
bool _valid;
storage_type _value;
};
template<typename T>
......@@ -274,4 +274,3 @@ namespace fc {
#endif
} // namespace fc
......@@ -633,11 +633,12 @@ namespace fc
variant operator - ( const variant& a, const variant& b );
variant operator * ( const variant& a, const variant& b );
variant operator / ( const variant& a, const variant& b );
variant operator == ( const variant& a, const variant& b );
variant operator != ( const variant& a, const variant& b );
variant operator < ( const variant& a, const variant& b );
variant operator > ( const variant& a, const variant& b );
variant operator ! ( const variant& a );
bool operator == ( const variant& a, const variant& b );
bool operator != ( const variant& a, const variant& b );
bool operator < ( const variant& a, const variant& b );
bool operator > ( const variant& a, const variant& b );
bool operator ! ( const variant& a );
} // namespace fc
#include <fc/reflect/reflect.hpp>
......
......@@ -37,6 +37,13 @@ namespace fc
void set( variant v );
variant& value();
friend bool operator == (const entry& a, const entry& b) {
return a._key == b._key && a._value == b._value;
}
friend bool operator != (const entry& a, const entry& b) {
return !(a == b);
}
private:
string _key;
......
......@@ -748,30 +748,27 @@ string format_string( const string& format, const variant_object& args )
void to_variant( unsigned long long int s, variant& v ) { v = variant( uint64_t(s)); }
#endif
variant operator == ( const variant& a, const variant& b )
bool operator == ( const variant& a, const variant& b )
{
if( a.is_string() || b.is_string() ) return a.as_string() == b.as_string();
if( a.is_double() || b.is_double() ) return a.as_double() == b.as_double();
if( a.is_int64() || b.is_int64() ) return a.as_int64() == b.as_int64();
if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() == b.as_uint64();
if( a.is_array() || b.is_array() ) return a.get_array() == b.get_array();
return false;
}
variant operator != ( const variant& a, const variant& b )
bool operator != ( const variant& a, const variant& b )
{
if( a.is_string() || b.is_string() ) return a.as_string() != b.as_string();
if( a.is_double() || b.is_double() ) return a.as_double() != b.as_double();
if( a.is_int64() || b.is_int64() ) return a.as_int64() != b.as_int64();
if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() != b.as_uint64();
return false;
return !( a == b );
}
variant operator ! ( const variant& a )
bool operator ! ( const variant& a )
{
return !a.as_bool();
}
variant operator < ( const variant& a, const variant& b )
bool operator < ( const variant& a, const variant& b )
{
if( a.is_string() || b.is_string() ) return a.as_string() < b.as_string();
if( a.is_double() || b.is_double() ) return a.as_double() < b.as_double();
......@@ -780,7 +777,7 @@ string format_string( const string& format, const variant_object& args )
FC_ASSERT( false, "Invalid operation" );
}
variant operator > ( const variant& a, const variant& b )
bool operator > ( const variant& a, const variant& b )
{
if( a.is_string() || b.is_string() ) return a.as_string() > b.as_string();
if( a.is_double() || b.is_double() ) return a.as_double() > b.as_double();
......@@ -789,7 +786,7 @@ string format_string( const string& format, const variant_object& args )
FC_ASSERT( false, "Invalid operation" );
}
variant operator <= ( const variant& a, const variant& b )
bool operator <= ( const variant& a, const variant& b )
{
if( a.is_string() || b.is_string() ) return a.as_string() <= b.as_string();
if( a.is_double() || b.is_double() ) return a.as_double() <= b.as_double();
......
......@@ -7,7 +7,7 @@ add_library( eosio_testing
${HEADERS}
)
target_link_libraries( eosio_testing eosio_chain eos_utilities fc chainbase Logging IR WAST WASM Runtime )
target_link_libraries( eosio_testing eosio_chain chain_plugin eos_utilities fc chainbase Logging IR WAST WASM Runtime )
target_include_directories( eosio_testing
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include"
......
#pragma once
#include <eosio/chain/chain_controller.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <eosio/chain/contracts/abi_serializer.hpp>
#include <fc/io/json.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/test/unit_test.hpp>
#include <iosfwd>
#define REQUIRE_EQUAL_OBJECTS(left, right) { auto a = fc::variant( left ); auto b = fc::variant( right ); BOOST_REQUIRE_EQUAL( true, a.is_object() ); \
BOOST_REQUIRE_EQUAL( true, b.is_object() ); \
BOOST_REQUIRE_EQUAL_COLLECTIONS( a.get_object().begin(), a.get_object().end(), b.get_object().begin(), b.get_object().end() ); }
#define REQUIRE_MATCHING_OBJECT(left, right) { auto a = fc::variant( left ); auto b = fc::variant( right ); BOOST_REQUIRE_EQUAL( true, a.is_object() ); \
BOOST_REQUIRE_EQUAL( true, b.is_object() ); \
auto filtered = ::eosio::testing::filter_fields( a.get_object(), b.get_object() ); \
BOOST_REQUIRE_EQUAL_COLLECTIONS( a.get_object().begin(), a.get_object().end(), filtered.begin(), filtered.end() ); }
std::ostream& operator<<( std::ostream& osm, const fc::variant& v );
#include <iostream>
std::ostream& operator<<( std::ostream& osm, const fc::variant_object& v );
std::ostream& operator<<( std::ostream& osm, const fc::variant_object::entry& e );
namespace boost { namespace test_tools { namespace tt_detail {
template<>
struct print_log_value<fc::variant> {
void operator()( std::ostream& osm, const fc::variant& v )
{
::operator<<( osm, v );
}
};
template<>
struct print_log_value<fc::variant_object> {
void operator()( std::ostream& osm, const fc::variant_object& v )
{
::operator<<( osm, v );
}
};
template<>
struct print_log_value<fc::variant_object::entry> {
void operator()( std::ostream& osm, const fc::variant_object::entry& e )
{
::operator<<( osm, e );
}
};
} } }
namespace eosio { namespace testing {
using namespace eosio::chain;
fc::variant_object filter_fields(const fc::variant_object& filter, const fc::variant_object& value);
/**
* @class tester
* @brief provides utility function to simplify the creation of unit tests
......@@ -57,6 +104,7 @@ namespace eosio { namespace testing {
transaction_trace push_dummy(account_name from, const string& v = "blah");
transaction_trace transfer( account_name from, account_name to, asset amount, string memo, account_name currency );
transaction_trace transfer( account_name from, account_name to, string amount, string memo, account_name currency );
transaction_trace issue( account_name to, string amount, account_name currency );
template<typename ObjectType>
const auto& get(const chainbase::oid< ObjectType >& key) {
......@@ -90,6 +138,8 @@ namespace eosio { namespace testing {
const symbol& asset_symbol,
const account_name& account ) const;
vector<char> get_row_by_account( uint64_t code, uint64_t scope, uint64_t table, const account_name& act );
static vector<uint8_t> to_uint8_vector(const string& s);
static vector<uint8_t> to_uint8_vector(uint64_t x);
......@@ -149,5 +199,5 @@ namespace eosio { namespace testing {
string expected;
};
} } /// eosio::testing
......@@ -5,6 +5,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_plugin/chain_plugin.hpp>
#include <eosio.bios/eosio.bios.wast.hpp>
#include <eosio.bios/eosio.bios.abi.hpp>
......@@ -19,6 +20,15 @@
namespace eosio { namespace testing {
fc::variant_object filter_fields(const fc::variant_object& filter, const fc::variant_object& value) {
fc::mutable_variant_object res;
for( auto& entry : filter ) {
auto it = value.find(entry.key());
res( it->key(), it->value() );
}
return res;
}
base_tester::base_tester(chain_controller::runtime_limits limits) {
cfg.block_log_dir = tempdir.path() / "blocklog";
cfg.shared_memory_dir = tempdir.path() / "shared";
......@@ -135,12 +145,12 @@ namespace eosio { namespace testing {
return push_transaction( ptrx, skip_flag );
}
base_tester::action_result base_tester::push_action(action&& cert_act, uint64_t authorizer) {
base_tester::action_result base_tester::push_action(action&& act, uint64_t authorizer) {
signed_transaction trx;
if (authorizer) {
cert_act.authorization = vector<permission_level>{{authorizer, config::active_name}};
act.authorization = vector<permission_level>{{authorizer, config::active_name}};
}
trx.actions.emplace_back(std::move(cert_act));
trx.actions.emplace_back(std::move(act));
set_tapos(trx);
if (authorizer) {
trx.sign(get_private_key(authorizer, "active"), chain_id_type());
......@@ -283,6 +293,32 @@ namespace eosio { namespace testing {
return push_transaction( trx );
}
transaction_trace base_tester::issue( account_name to, string amount, account_name currency ) {
variant pretty_trx = fc::mutable_variant_object()
("actions", fc::variants({
fc::mutable_variant_object()
("account", currency)
("name", "issue")
("authorization", fc::variants({
fc::mutable_variant_object()
("actor", currency )
("permission", name(config::active_name))
}))
("data", fc::mutable_variant_object()
("to", to)
("quantity", amount)
)
})
);
signed_transaction trx;
contracts::abi_serializer::from_variant(pretty_trx, trx, get_resolver());
set_tapos( trx );
trx.sign( get_private_key( currency, name(config::active_name).to_string() ), chain_id_type() );
return push_transaction( trx );
}
void base_tester::link_authority( account_name account, account_name code, permission_name req, action_name type ) {
signed_transaction trx;
......@@ -421,6 +457,26 @@ namespace eosio { namespace testing {
return asset(result, asset_symbol);
}
vector<char> base_tester::get_row_by_account( uint64_t code, uint64_t scope, uint64_t table, const account_name& act ) {
vector<char> data;
const auto& db = control->get_database();
const auto* t_id = db.find<chain::contracts::table_id_object, chain::contracts::by_code_scope_table>( boost::make_tuple( code, scope, table ) );
if ( !t_id ) {
return data;
}
//FC_ASSERT( t_id != 0, "object not found" );
const auto& idx = db.get_index<chain::contracts::key_value_index, chain::contracts::by_scope_primary>();
auto itr = idx.lower_bound( boost::make_tuple( t_id->id, act ) );
if ( itr == idx.end() || itr->t_id != t_id->id || act.value != itr->primary_key ) {
return data;
}
chain_apis::read_only::copy_inline_row( *itr, data );
return data;
}
vector<uint8_t> base_tester::to_uint8_vector(const string& s) {
vector<uint8_t> v(s.size());
copy(s.begin(), s.end(), v.begin());
......@@ -503,3 +559,19 @@ namespace eosio { namespace testing {
}
} } /// eosio::test
std::ostream& operator<<( std::ostream& osm, const fc::variant& v ) {
//fc::json::to_stream( osm, v );
osm << fc::json::to_pretty_string( v );
return osm;
}
std::ostream& operator<<( std::ostream& osm, const fc::variant_object& v ) {
osm << fc::variant(v);
return osm;
}
std::ostream& operator<<( std::ostream& osm, const fc::variant_object::entry& e ) {
osm << "{ " << e.key() << ": " << e.value() << " }";
return osm;
}
......@@ -478,7 +478,7 @@ void mongo_db_plugin_impl::_process_block(const block_trace& bt, const signed_bl
for (const auto& trx : trx_trace.deferred_transactions) {
auto doc = process_trx(trx);
doc.append(kvp("type", "deferred"),
kvp("sender_id", b_int64{trx.sender_id}),
kvp("sender_id", b_int64{static_cast<int64_t>(trx.sender_id)}),
kvp("sender", trx.sender.to_string()),
kvp("execute_after", b_date{std::chrono::milliseconds{
std::chrono::seconds{trx.execute_after.sec_since_epoch()}}}));
......@@ -522,6 +522,14 @@ void mongo_db_plugin_impl::_process_block(const block_trace& bt, const signed_bl
++trx_num;
}
for (const auto& implicit_trx : bt.implicit_transactions ){
auto doc = process_trx(implicit_trx);
doc.append(kvp("type", "implicit"));
mongocxx::model::insert_one insert_op{doc.view()};
bulk_trans.append(insert_op);
++trx_num;
}
if (actions_to_write) {
auto result = msgs.bulk_write(bulk_msgs);
if (!result) {
......
......@@ -27,7 +27,7 @@ target_link_libraries( chain_test eosio_testing eosio_chain chainbase eos_utilit
target_include_directories( chain_test PUBLIC ${CMAKE_BINARY_DIR}/contracts ${CMAKE_CURRENT_BINARY_DIR}/tests/contracts )
target_include_directories( chain_test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/wasm_tests )
target_include_directories( chain_test PUBLIC ${CMAKE_SOURCE_DIR}/plugins/net_plugin/include )
add_dependencies(chain_test asserter test_api exchange currency proxy identity identity_test stltest infinite eosio.token eosio.bios test.inline )
add_dependencies(chain_test asserter test_api exchange currency proxy identity identity_test stltest infinite eosio.system eosio.token eosio.bios test.inline )
#
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/p2p_tests/sync/test.sh ${CMAKE_CURRENT_BINARY_DIR}/p2p_tests/sync/test.sh COPYONLY)
......
......@@ -377,7 +377,7 @@ BOOST_FIXTURE_TEST_CASE(action_tests, tester) { try {
dummy_action da = { DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C };
CallAction(*this, da);
} FC_LOG_AND_RETHROW() }
/*************************************************************************************
......@@ -476,13 +476,13 @@ BOOST_FIXTURE_TEST_CASE(checktime_pass_tests, tester) { try {
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(checktime_fail_tests) {
try {
tester t( {fc::milliseconds(1), fc::milliseconds(1)} );
t.produce_blocks(2);
BOOST_AUTO_TEST_CASE(checktime_fail_tests) { try {
tester t( {fc::milliseconds(100), fc::milliseconds(100)} );
t.produce_blocks(2);
t.create_account( N(testapi) );
t.set_code( N(testapi), test_api_wast );
t.create_account( N(testapi) );
t.set_code( N(testapi), test_api_wast );
t.produce_blocks(1);
auto call_test = [](tester& test, auto ac) {
signed_transaction trx;
......@@ -501,8 +501,8 @@ BOOST_AUTO_TEST_CASE(checktime_fail_tests) {
BOOST_CHECK_EXCEPTION(call_test( t, test_api_action<TEST_METHOD("test_checktime", "checktime_failure")>{}), checktime_exceeded, is_checktime_exceeded);
} FC_LOG_AND_RETHROW();
}
} FC_LOG_AND_RETHROW() }
/*************************************************************************************
* compiler_builtins_tests test case
*************************************************************************************/
......
......@@ -10,8 +10,6 @@ using namespace eosio::testing;
BOOST_AUTO_TEST_SUITE(block_tests)
BOOST_AUTO_TEST_CASE( schedule_test ) { try {
tester test;
......@@ -204,8 +202,11 @@ BOOST_AUTO_TEST_CASE(order_dependent_transactions)
BOOST_TEST(chain.control->fetch_block_by_number(11).valid());
BOOST_TEST_REQUIRE(!chain.control->fetch_block_by_number(11)->regions.empty());
BOOST_TEST_REQUIRE(!chain.control->fetch_block_by_number(11)->regions.front().cycles_summary.empty());
BOOST_TEST_REQUIRE(chain.control->fetch_block_by_number(11)->regions.front().cycles_summary.size() >= 1);
// First cycle has only on-block transaction
BOOST_TEST(!chain.control->fetch_block_by_number(11)->regions.front().cycles_summary.front().empty());
BOOST_TEST(chain.control->fetch_block_by_number(11)->regions.front().cycles_summary.front().front().transactions.size() == 2);
BOOST_TEST(chain.control->fetch_block_by_number(11)->regions.front().cycles_summary.front().front().transactions.size() == 1);
BOOST_TEST(chain.control->fetch_block_by_number(11)->regions.front().cycles_summary.at(1).front().transactions.size() == 2);
} FC_LOG_AND_RETHROW() }
// Simple test of block production when a block is missed
......@@ -579,7 +580,6 @@ BOOST_AUTO_TEST_CASE(wipe)
}
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(irrelevant_sig_soft_check) {
try {
tester chain;
......@@ -617,4 +617,5 @@ BOOST_AUTO_TEST_CASE(irrelevant_sig_soft_check) {
} FC_LOG_AND_RETHROW()
}
BOOST_AUTO_TEST_SUITE_END()
......@@ -228,8 +228,10 @@ BOOST_FIXTURE_TEST_CASE( prove_action_in_block, tester ) { try {
if (action_leaves.size() > 0) {
process_merkle(nodes, move(action_leaves));
shard_leaves.emplace_back(nodes.size() - 1);
} else {
nodes.emplace_back(merkle_node{digest_type()});
}
shard_leaves.emplace_back(nodes.size() - 1);
}
}
}
......
......@@ -299,12 +299,6 @@ const char* my_abi = R"=====(
},{
"name": "authority_arr",
"type": "authority[]"
},{
"name": "chainconfig",
"type": "chain_config"
},{
"name": "chainconfig_arr",
"type": "chain_config[]"
},{
"name": "typedef",
"type": "type_def"
......@@ -1774,53 +1768,6 @@ BOOST_AUTO_TEST_CASE(general)
"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":"100"},{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":"200"}],
"accounts":[{"permission":{"actor":"acc1","permission":"permname1"},"weight":"1"},{"permission":{"actor":"acc2","permission":"permname2"},"weight":"2"}]
}],
"chainconfig": {
"target_block_size": "200",
"max_block_size": "300",
"target_block_acts_per_scope": "400",
"max_block_acts_per_scope": "500",
"target_block_acts": "600",
"max_block_acts": "700",
"real_threads": "800",
"max_storage_size": "900",
"max_transaction_lifetime": "1000",
"max_authority_depth": "1100",
"max_transaction_exec_time": "1200",
"max_inline_depth": "1300",
"max_inline_action_size": "1400",
"max_generated_transaction_size": "1500"
},
"chainconfig_arr": [{
"target_block_size": "200",
"max_block_size": "300",
"target_block_acts_per_scope": "400",
"max_block_acts_per_scope": "500",
"target_block_acts": "600",
"max_block_acts": "700",
"real_threads": "800",
"max_storage_size": "900",
"max_transaction_lifetime": "1000",
"max_authority_depth": "1100",
"max_transaction_exec_time": "1200",
"max_inline_depth": "1300",
"max_inline_action_size": "1400",
"max_generated_transaction_size": "1500"
},{
"target_block_size": "200",
"max_block_size": "300",
"target_block_acts_per_scope": "400",
"max_block_acts_per_scope": "500",
"target_block_acts": "600",
"max_block_acts": "700",
"real_threads": "800",
"max_storage_size": "900",
"max_transaction_lifetime": "1000",
"max_authority_depth": "1100",
"max_transaction_exec_time": "1200",
"max_inline_depth": "1300",
"max_inline_action_size": "1400",
"max_generated_transaction_size": "1500"
}],
"typedef" : {"new_type_name":"new", "type":"old"},
"typedef_arr": [{"new_type_name":"new", "type":"old"},{"new_type_name":"new", "type":"old"}],
"actiondef" : {"name":"actionname1", "type":"type1"},
......
......@@ -50,27 +50,27 @@ BOOST_AUTO_TEST_CASE(median_properties_test)
try
{
vector<chain_config> votes{
{512 , 1024 , 256, 512 , 512 , 1024 , 1000, 4096, 512 , 6, 1000 , 3, 4096, 65536},
{100 , 10000, 50 , 5000, 100 , 10000, 500 , 4096, 100 , 6, 3000 , 2, 4096, 65536},
{1500, 2048 , 750, 1024, 1500, 2048 , 300 , 1000, 1500, 6, 5000 , 9, 4096, 65536},
{25 , 100 , 12 , 50 , 25 , 100 , 1200, 1024, 25 , 6, 10000, 4, 4096, 65536},
{1000, 1024 , 500, 512 , 10 , 1024 , 1500, 100 , 1000, 6, 4000 , 1, 4096, 65536}};
{512 , 1024 , 256, 512 , 512 , 1024 , 4096, 512 , 1000 , 6, 3, 4096, 65536},
{100 , 10000, 50 , 5000, 100 , 10000, 4096, 100 , 3000 , 6, 2, 4096, 65536},
{1500, 2048 , 750, 1024, 1500, 2048 , 1000, 1500, 5000 , 6, 9, 4096, 65536},
{25 , 100 , 12 , 50 , 25 , 100 , 1024, 25 , 10000, 6, 4, 4096, 65536},
{1000, 1024 , 500, 512 , 10 , 1024 , 100 , 1000, 4000 , 6, 1, 4096, 65536}};
chain_config medians{
512, 1024, 256, 512, 100, 1024, 1000, 1024, 512, 6, 4000, 3, 4096, 65536};
512, 1024, 256, 512, 100, 1024, 1024, 512, 4000, 6, 3, 4096, 65536};
BOOST_TEST(chain_config::get_median_values(votes) == medians);
votes.emplace_back(chain_config{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1});
votes.emplace_back(chain_config{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1});
medians = chain_config{100, 1024, 50, 512, 25, 1024, 500, 1000, 100, 6, 3000, 2, 4096, 65536};
votes.emplace_back(chain_config{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1});
votes.emplace_back(chain_config{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1});
medians = chain_config{100, 1024, 50, 512, 25, 1024, 1000, 100, 3000, 6, 2, 4096, 65536};
BOOST_TEST(chain_config::get_median_values(votes) == medians);
BOOST_TEST(chain_config::get_median_values({medians}) == medians);
votes.erase(votes.begin() + 2);
votes.erase(votes.end() - 1);
medians = chain_config{100, 1024, 50, 512, 25, 1024, 1000, 1024, 100, 6, 3000, 2, 4096, 65536};
medians = chain_config{100, 1024, 50, 512, 25, 1024, 1024, 100, 3000, 6, 2, 4096, 65536};
BOOST_TEST(chain_config::get_median_values(votes) == medians);
}
FC_LOG_AND_RETHROW()
......@@ -249,7 +249,7 @@ BOOST_AUTO_TEST_CASE(authority_checker)
return authority(2, {key_weight{d, 1}}, {permission_level_weight{{"bottom", "bottom"}, 1}});
return authority{1, {{e, 1}}, {}};
};
A = authority(5, {key_weight{a, 2}, key_weight{b, 2}, key_weight{c, 2}}, {permission_level_weight{{"top", "top"}, 5}});
{
auto checker = make_auth_checker(GetAuthority, 2, {d, e});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册