Merge pull request #246 from peerplays-network/develop

Merge GPOS feature and Graphene updates into TESTNET
This commit is contained in:
pbattu123 2019-12-16 14:10:29 -04:00 committed by GitHub
commit 9746e74885
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
189 changed files with 6831 additions and 1593 deletions

View file

@ -1,3 +1,6 @@
include:
- template: Code-Quality.gitlab-ci.yml
stages:
- build
- test
@ -5,6 +8,7 @@ stages:
build:
stage: build
script:
- git submodule sync
- git submodule update --init --recursive
- cmake .
- make -j$(nproc)
@ -24,5 +28,28 @@ test:
script:
- ./tests/betting_test
- ./tests/chain_test
- ./tests/cli_test
tags:
- builder
code_quality:
stage: test
image: docker:stable
variables:
DOCKER_DRIVER: overlay2
allow_failure: true
services:
- docker:stable-dind
script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- docker run
--env SOURCE_CODE="$PWD"
--volume "$PWD":/code
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
artifacts:
paths: [gl-code-quality-report.json]
expire_in: 1 week
except:
variables:
- $CODE_QUALITY_DISABLED

7
.gitmodules vendored
View file

@ -3,6 +3,7 @@
url = https://github.com/bitshares/bitshares-core.wiki.git
ignore = dirty
[submodule "libraries/fc"]
path = libraries/fc
url = https://github.com/PBSA/peerplays-fc.git
ignore = dirty
path = libraries/fc
url = https://github.com/peerplays-network/peerplays-fc.git
branch = latest-fc
ignore = dirty

0
.sonarcloud.properties Normal file
View file

View file

@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
PROJECT_NAME = "Graphene"
PROJECT_NAME = "Peerplays"
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version

View file

@ -7,6 +7,7 @@ add_library( graphene_app
database_api.cpp
impacted.cpp
plugin.cpp
config_util.cpp
${HEADERS}
${EGENESIS_HEADERS}
)

View file

@ -40,8 +40,19 @@
#include <fc/crypto/hex.hpp>
#include <fc/smart_ref_impl.hpp>
#include <fc/rpc/api_connection.hpp>
#include <fc/thread/future.hpp>
template class fc::api<graphene::app::block_api>;
template class fc::api<graphene::app::network_broadcast_api>;
template class fc::api<graphene::app::network_node_api>;
template class fc::api<graphene::app::history_api>;
template class fc::api<graphene::app::crypto_api>;
template class fc::api<graphene::app::asset_api>;
template class fc::api<graphene::debug_witness::debug_api>;
template class fc::api<graphene::app::login_api>;
namespace graphene { namespace app {
login_api::login_api(application& a)
@ -103,7 +114,7 @@ namespace graphene { namespace app {
}
else if( api_name == "asset_api" )
{
_asset_api = std::make_shared< asset_api >( std::ref( *_app.chain_database() ) );
_asset_api = std::make_shared< asset_api >( _app );
}
else if( api_name == "debug_api" )
{
@ -160,7 +171,10 @@ namespace graphene { namespace app {
{
auto block_num = b.block_num();
auto& callback = _callbacks.find(id)->second;
fc::async( [capture_this,this,id,block_num,trx_num,trx,callback](){ callback( fc::variant(transaction_confirmation{ id, block_num, trx_num, trx}) ); } );
fc::async( [capture_this,this,id,block_num,trx_num,trx,callback]() {
callback( fc::variant( transaction_confirmation{ id, block_num, trx_num, trx },
GRAPHENE_MAX_NESTED_OBJECTS ) );
} );
}
}
}
@ -171,7 +185,8 @@ namespace graphene { namespace app {
trx.validate();
_app.chain_database()->check_tansaction_for_duplicated_operations(trx);
_app.chain_database()->push_transaction(trx);
_app.p2p_node()->broadcast_transaction(trx);
if( _app.p2p_node() != nullptr )
_app.p2p_node()->broadcast_transaction(trx);
}
fc::variant network_broadcast_api::broadcast_transaction_synchronous(const signed_transaction& trx)
@ -189,7 +204,8 @@ namespace graphene { namespace app {
void network_broadcast_api::broadcast_block( const signed_block& b )
{
_app.chain_database()->push_block(b);
_app.p2p_node()->broadcast( net::block_message( b ));
if( _app.p2p_node() != nullptr )
_app.p2p_node()->broadcast( net::block_message( b ));
}
void network_broadcast_api::broadcast_transaction_with_callback(confirmation_callback cb, const signed_transaction& trx)
@ -197,7 +213,8 @@ namespace graphene { namespace app {
trx.validate();
_callbacks[trx.id()] = cb;
_app.chain_database()->push_transaction(trx);
_app.p2p_node()->broadcast_transaction(trx);
if( _app.p2p_node() != nullptr )
_app.p2p_node()->broadcast_transaction(trx);
}
network_node_api::network_node_api( application& a ) : _app( a )
@ -212,7 +229,7 @@ namespace graphene { namespace app {
if (_on_pending_transaction)
{
_on_pending_transaction(fc::variant(transaction));
_on_pending_transaction(fc::variant(transaction, GRAPHENE_MAX_NESTED_OBJECTS));
}
});
@ -520,10 +537,12 @@ namespace graphene { namespace app {
} // end get_relevant_accounts( obj )
#endif
vector<order_history_object> history_api::get_fill_order_history( asset_id_type a, asset_id_type b, uint32_t limit )const
vector<order_history_object> history_api::get_fill_order_history( std::string asset_a, std::string asset_b, uint32_t limit )const
{
FC_ASSERT(_app.chain_database());
const auto& db = *_app.chain_database();
asset_id_type a = database_api.get_asset_id_from_string( asset_a );
asset_id_type b = database_api.get_asset_id_from_string( asset_b );
if( a > b ) std::swap(a,b);
const auto& history_idx = db.get_index_type<graphene::market_history::history_index>().indices().get<by_key>();
history_key hkey;
@ -545,7 +564,7 @@ namespace graphene { namespace app {
return result;
}
vector<operation_history_object> history_api::get_account_history( account_id_type account,
vector<operation_history_object> history_api::get_account_history( const std::string account_id_or_name,
operation_history_id_type stop,
unsigned limit,
operation_history_id_type start ) const
@ -554,7 +573,9 @@ namespace graphene { namespace app {
const auto& db = *_app.chain_database();
FC_ASSERT( limit <= 100 );
vector<operation_history_object> result;
account_id_type account;
try {
account = database_api.get_account_id_from_string(account_id_or_name);
const account_transaction_history_object& node = account(db).statistics(db).most_recent_op(db);
if(start == operation_history_id_type() || start.instance.value > node.operation_id.instance.value)
start = node.operation_id;
@ -578,7 +599,7 @@ namespace graphene { namespace app {
return result;
}
vector<operation_history_object> history_api::get_account_history_operations( account_id_type account,
vector<operation_history_object> history_api::get_account_history_operations( const std::string account_id_or_name,
int operation_id,
operation_history_id_type start,
operation_history_id_type stop,
@ -588,6 +609,11 @@ namespace graphene { namespace app {
const auto& db = *_app.chain_database();
FC_ASSERT( limit <= 100 );
vector<operation_history_object> result;
account_id_type account;
try {
account = database_api.get_account_id_from_string(account_id_or_name);
} catch (...) { return result; }
const auto& stats = account(db).statistics(db);
if( stats.most_recent_op == account_transaction_history_id_type() ) return result;
const account_transaction_history_object* node = &stats.most_recent_op(db);
@ -614,7 +640,7 @@ namespace graphene { namespace app {
}
vector<operation_history_object> history_api::get_relative_account_history( account_id_type account,
vector<operation_history_object> history_api::get_relative_account_history( const std::string account_id_or_name,
uint32_t stop,
unsigned limit,
uint32_t start) const
@ -623,6 +649,10 @@ namespace graphene { namespace app {
const auto& db = *_app.chain_database();
FC_ASSERT(limit <= 100);
vector<operation_history_object> result;
account_id_type account;
try {
account = database_api.get_account_id_from_string(account_id_or_name);
} catch(...) { return result; }
const auto& stats = account(db).statistics(db);
if( start == 0 )
start = stats.total_ops;
@ -662,11 +692,13 @@ namespace graphene { namespace app {
return hist->tracked_buckets();
}
vector<bucket_object> history_api::get_market_history( asset_id_type a, asset_id_type b,
vector<bucket_object> history_api::get_market_history( std::string asset_a, std::string asset_b,
uint32_t bucket_seconds, fc::time_point_sec start, fc::time_point_sec end )const
{ try {
FC_ASSERT(_app.chain_database());
const auto& db = *_app.chain_database();
asset_id_type a = database_api.get_asset_id_from_string( asset_a );
asset_id_type b = database_api.get_asset_id_from_string( asset_b );
vector<bucket_object> result;
result.reserve(200);
@ -686,7 +718,7 @@ namespace graphene { namespace app {
++itr;
}
return result;
} FC_CAPTURE_AND_RETHROW( (a)(b)(bucket_seconds)(start)(end) ) }
} FC_CAPTURE_AND_RETHROW( (asset_a)(asset_b)(bucket_seconds)(start)(end) ) }
crypto_api::crypto_api(){};
@ -745,12 +777,16 @@ namespace graphene { namespace app {
}
// asset_api
asset_api::asset_api(graphene::chain::database& db) : _db(db) { }
asset_api::asset_api(graphene::app::application& app) :
_app(app),
_db( *app.chain_database()),
database_api( std::ref(*app.chain_database())) { }
asset_api::~asset_api() { }
vector<account_asset_balance> asset_api::get_asset_holders( asset_id_type asset_id, uint32_t start, uint32_t limit ) const {
vector<account_asset_balance> asset_api::get_asset_holders( std::string asset, uint32_t start, uint32_t limit ) const {
FC_ASSERT(limit <= 100);
asset_id_type asset_id = database_api.get_asset_id_from_string( asset );
const auto& bal_idx = _db.get_index_type< account_balance_index >().indices().get< by_asset_balance >();
auto range = bal_idx.equal_range( boost::make_tuple( asset_id ) );
@ -781,11 +817,11 @@ namespace graphene { namespace app {
return result;
}
// get number of asset holders.
int asset_api::get_asset_holders_count( asset_id_type asset_id ) const {
int asset_api::get_asset_holders_count( std::string asset ) const {
const auto& bal_idx = _db.get_index_type< account_balance_index >().indices().get< by_asset_balance >();
asset_id_type asset_id = database_api.get_asset_id_from_string( asset );
auto range = bal_idx.equal_range( boost::make_tuple( asset_id ) );
int count = boost::distance(range) - 1;
return count;

View file

@ -142,7 +142,7 @@ namespace detail {
if( _options->count("seed-nodes") )
{
auto seeds_str = _options->at("seed-nodes").as<string>();
auto seeds = fc::json::from_string(seeds_str).as<vector<string>>();
auto seeds = fc::json::from_string(seeds_str).as<vector<string>>(2);
for( const string& endpoint_string : seeds )
{
try {
@ -226,7 +226,7 @@ namespace detail {
void new_connection( const fc::http::websocket_connection_ptr& c )
{
auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(c);
auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(*c, GRAPHENE_MAX_NESTED_OBJECTS);
auto login = std::make_shared<graphene::app::login_api>( std::ref(*_self) );
login->enable_api("database_api");
@ -292,7 +292,7 @@ namespace detail {
_websocket_tls_server->start_accept();
} FC_CAPTURE_AND_RETHROW() }
application_impl(application* self)
explicit application_impl(application* self)
: _self(self),
_chain_db(std::make_shared<chain::database>())
{
@ -308,20 +308,19 @@ namespace detail {
public_key_type init_pubkey( init_key );
for( uint64_t i=0; i<genesis.initial_active_witnesses; i++ )
genesis.initial_witness_candidates[i].block_signing_key = init_pubkey;
return;
}
void startup()
{ try {
fc::create_directories(_data_dir / "blockchain");
auto initial_state = [&] {
auto initial_state = [this] {
ilog("Initializing database...");
if( _options->count("genesis-json") )
{
std::string genesis_str;
fc::read_file_contents( _options->at("genesis-json").as<boost::filesystem::path>(), genesis_str );
genesis_state_type genesis = fc::json::from_string( genesis_str ).as<genesis_state_type>();
genesis_state_type genesis = fc::json::from_string( genesis_str ).as<genesis_state_type>( 20 );
bool modified_genesis = false;
if( _options->count("genesis-timestamp") )
{
@ -354,7 +353,7 @@ namespace detail {
graphene::egenesis::compute_egenesis_json( egenesis_json );
FC_ASSERT( egenesis_json != "" );
FC_ASSERT( graphene::egenesis::get_egenesis_json_hash() == fc::sha256::hash( egenesis_json ) );
auto genesis = fc::json::from_string( egenesis_json ).as<genesis_state_type>();
auto genesis = fc::json::from_string( egenesis_json ).as<genesis_state_type>( 20 );
genesis.initial_chain_id = fc::sha256::hash( egenesis_json );
return genesis;
}
@ -370,12 +369,17 @@ namespace detail {
loaded_checkpoints.reserve( cps.size() );
for( auto cp : cps )
{
auto item = fc::json::from_string(cp).as<std::pair<uint32_t,block_id_type> >();
auto item = fc::json::from_string(cp).as<std::pair<uint32_t,block_id_type> >( 2 );
loaded_checkpoints[item.first] = item.second;
}
}
_chain_db->add_checkpoints( loaded_checkpoints );
if( _options->count("enable-standby-votes-tracking") )
{
_chain_db->enable_standby_votes_tracking( _options->at("enable-standby-votes-tracking").as<bool>() );
}
bool replay = false;
std::string replay_reason = "reason not provided";
@ -398,9 +402,21 @@ namespace detail {
_force_validate = true;
}
if( _options->count("api-access") )
_apiaccess = fc::json::from_file( _options->at("api-access").as<boost::filesystem::path>() )
.as<api_access>();
if( _options->count("api-access") ) {
if(fc::exists(_options->at("api-access").as<boost::filesystem::path>()))
{
_apiaccess = fc::json::from_file( _options->at("api-access").as<boost::filesystem::path>() ).as<api_access>( 20 );
ilog( "Using api access file from ${path}",
("path", _options->at("api-access").as<boost::filesystem::path>().string()) );
}
else
{
elog("Failed to load file from ${path}",
("path", _options->at("api-access").as<boost::filesystem::path>().string()));
std::exit(EXIT_FAILURE);
}
}
else
{
// TODO: Remove this generous default access policy
@ -914,6 +930,9 @@ void application::set_program_options(boost::program_options::options_descriptio
("genesis-json", bpo::value<boost::filesystem::path>(), "File to read Genesis State from")
("dbg-init-key", bpo::value<string>(), "Block signing key to use for init witnesses, overrides genesis file")
("api-access", bpo::value<boost::filesystem::path>(), "JSON file specifying API permissions")
("enable-standby-votes-tracking", bpo::value<bool>()->implicit_value(true),
"Whether to enable tracking of votes of standby witnesses and committee members. "
"Set it to true to provide accurate data to API clients, set to false for slightly better performance.")
;
command_line_options.add(configuration_file_options);
command_line_options.add_options()
@ -942,7 +961,7 @@ void application::initialize(const fc::path& data_dir, const boost::program_opti
if( fc::exists(genesis_out) )
{
try {
genesis_state = fc::json::from_file(genesis_out).as<genesis_state_type>();
genesis_state = fc::json::from_file(genesis_out).as<genesis_state_type>( 20 );
} catch(const fc::exception& e) {
std::cerr << "Unable to parse existing genesis file:\n" << e.to_string()
<< "\nWould you like to replace it? [y/N] ";

View file

@ -0,0 +1,354 @@
/*
* Copyright (c) 2018 Lubos Ilcik, and contributors.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <graphene/app/config_util.hpp>
#include <graphene/chain/config.hpp>
#include <fc/reflect/variant.hpp>
#include <fc/string.hpp>
#include <fc/exception/exception.hpp>
#include <fc/log/console_appender.hpp>
#include <fc/log/file_appender.hpp>
#include <fc/log/logger_config.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string.hpp>
#include <fstream>
namespace bpo = boost::program_options;
class deduplicator
{
public:
deduplicator() : modifier(nullptr) {}
deduplicator(const boost::shared_ptr<bpo::option_description> (*mod_fn)(const boost::shared_ptr<bpo::option_description>&))
: modifier(mod_fn) {}
const boost::shared_ptr<bpo::option_description> next(const boost::shared_ptr<bpo::option_description>& o)
{
const std::string name = o->long_name();
if( seen.find( name ) != seen.end() )
return nullptr;
seen.insert(name);
return modifier ? modifier(o) : o;
}
private:
boost::container::flat_set<std::string> seen;
const boost::shared_ptr<bpo::option_description> (*modifier)(const boost::shared_ptr<bpo::option_description>&);
};
// Currently, you can only specify the filenames and logging levels, which
// are all most users would want to change. At a later time, options can
// be added to control rotation intervals, compression, and other seldom-
// used features
static void write_default_logging_config_to_stream(std::ostream& out)
{
out << "# declare an appender named \"stderr\" that writes messages to the console\n"
"[log.console_appender.stderr]\n"
"stream=std_error\n\n"
"# declare an appender named \"default\" that writes messages to default.log\n"
"[log.file_appender.default]\n"
"# filename can be absolute or relative to this config file\n"
"filename=logs/default/default.log\n"
"# Rotate log every ? minutes, if leave out default to 60\n"
"rotation_interval=60\n"
"# how long will logs be kept (in days), if leave out default to 1\n"
"rotation_limit=7\n\n"
"# declare an appender named \"p2p\" that writes messages to p2p.log\n"
"[log.file_appender.p2p]\n"
"# filename can be absolute or relative to this config file\n"
"filename=logs/p2p/p2p.log\n"
"# Rotate log every ? minutes, if leave out default to 60\n"
"rotation_interval=60\n"
"# how long will logs be kept (in days), if leave out default to 1\n"
"rotation_limit=7\n\n"
"# declare an appender named \"rpc\" that writes messages to rpc.log\n"
"[log.file_appender.rpc]\n"
"# filename can be absolute or relative to this config file\n"
"filename=logs/rpc/rpc.log\n"
"# Rotate log every ? minutes, if leave out default to 60\n"
"rotation_interval=60\n"
"# how long will logs be kept (in days), if leave out default to 1\n"
"rotation_limit=7\n\n"
"# route any messages logged to the default logger to the \"stderr\" appender and\n"
"# \"default\" appender we declared above, if they are info level or higher\n"
"[logger.default]\n"
"level=info\n"
"appenders=stderr,default\n\n"
"# route messages sent to the \"p2p\" logger to the \"p2p\" appender declared above\n"
"[logger.p2p]\n"
"level=warn\n"
"appenders=p2p\n\n"
"# route messages sent to the \"rpc\" logger to the \"rpc\" appender declared above\n"
"[logger.rpc]\n"
"level=error\n"
"appenders=rpc\n\n";
}
// logging config is too complicated to be parsed by boost::program_options,
// so we do it by hand
static fc::optional<fc::logging_config> load_logging_config_from_ini_file(const fc::path& config_ini_filename)
{
try
{
fc::logging_config logging_config;
bool found_logging_config = false;
boost::property_tree::ptree config_ini_tree;
boost::property_tree::ini_parser::read_ini(config_ini_filename.preferred_string().c_str(), config_ini_tree);
for (const auto& section : config_ini_tree)
{
const std::string& section_name = section.first;
const boost::property_tree::ptree& section_tree = section.second;
const std::string console_appender_section_prefix = "log.console_appender.";
const std::string file_appender_section_prefix = "log.file_appender.";
const std::string logger_section_prefix = "logger.";
if (boost::starts_with(section_name, console_appender_section_prefix))
{
std::string console_appender_name = section_name.substr(console_appender_section_prefix.length());
std::string stream_name = section_tree.get<std::string>("stream");
// construct a default console appender config here
// stdout/stderr will be taken from ini file, everything else hard-coded here
fc::console_appender::config console_appender_config;
console_appender_config.level_colors.emplace_back(
fc::console_appender::level_color(fc::log_level::debug,
fc::console_appender::color::green));
console_appender_config.level_colors.emplace_back(
fc::console_appender::level_color(fc::log_level::warn,
fc::console_appender::color::brown));
console_appender_config.level_colors.emplace_back(
fc::console_appender::level_color(fc::log_level::error,
fc::console_appender::color::cyan));
console_appender_config.stream = fc::variant(stream_name).as<fc::console_appender::stream::type>(GRAPHENE_MAX_NESTED_OBJECTS);
logging_config.appenders.push_back(fc::appender_config(console_appender_name, "console", fc::variant(console_appender_config, GRAPHENE_MAX_NESTED_OBJECTS)));
found_logging_config = true;
}
else if (boost::starts_with(section_name, file_appender_section_prefix))
{
std::string file_appender_name = section_name.substr(file_appender_section_prefix.length());
fc::path file_name = section_tree.get<std::string>("filename");
if (file_name.is_relative())
file_name = fc::absolute(config_ini_filename).parent_path() / file_name;
int interval = section_tree.get_optional<int>("rotation_interval").get_value_or(60);
int limit = section_tree.get_optional<int>("rotation_limit").get_value_or(1);
// construct a default file appender config here
// filename will be taken from ini file, everything else hard-coded here
fc::file_appender::config file_appender_config;
file_appender_config.filename = file_name;
file_appender_config.flush = true;
file_appender_config.rotate = true;
file_appender_config.rotation_interval = fc::minutes(interval);
file_appender_config.rotation_limit = fc::days(limit);
logging_config.appenders.push_back(fc::appender_config(file_appender_name, "file", fc::variant(file_appender_config, GRAPHENE_MAX_NESTED_OBJECTS)));
found_logging_config = true;
}
else if (boost::starts_with(section_name, logger_section_prefix))
{
std::string logger_name = section_name.substr(logger_section_prefix.length());
std::string level_string = section_tree.get<std::string>("level");
std::string appenders_string = section_tree.get<std::string>("appenders");
fc::logger_config logger_config(logger_name);
logger_config.level = fc::variant(level_string).as<fc::log_level>(5);
boost::split(logger_config.appenders, appenders_string,
boost::is_any_of(" ,"),
boost::token_compress_on);
logging_config.loggers.push_back(logger_config);
found_logging_config = true;
}
}
if (found_logging_config)
return logging_config;
else
return fc::optional<fc::logging_config>();
}
FC_RETHROW_EXCEPTIONS(warn, "")
}
static const boost::shared_ptr<bpo::option_description> new_option_description( const std::string& name, const bpo::value_semantic* value, const std::string& description )
{
bpo::options_description helper("");
helper.add_options()( name.c_str(), value, description.c_str() );
return helper.options()[0];
}
static void load_config_file(const fc::path& config_ini_path, const bpo::options_description& cfg_options,
bpo::variables_map& options )
{
deduplicator dedup;
bpo::options_description unique_options("Graphene Witness Node");
for( const boost::shared_ptr<bpo::option_description> opt : cfg_options.options() )
{
const boost::shared_ptr<bpo::option_description> od = dedup.next(opt);
if( !od ) continue;
unique_options.add( od );
}
// get the basic options
bpo::store(bpo::parse_config_file<char>(config_ini_path.preferred_string().c_str(),
unique_options, true), options);
}
static bool load_logging_config_file(const fc::path& config_ini_path)
{
// try to get logging options from the config file.
try
{
fc::optional<fc::logging_config> logging_config = load_logging_config_from_ini_file(config_ini_path);
if (logging_config)
{
fc::configure_logging(*logging_config);
return true;
}
}
catch (const fc::exception& ex)
{
wlog("Error parsing logging config from logging config file ${config}, using default config", ("config", config_ini_path.preferred_string()));
}
return false;
}
static void create_new_config_file(const fc::path& config_ini_path, const fc::path& data_dir,
const bpo::options_description& cfg_options )
{
ilog("Writing new config file at ${path}", ("path", config_ini_path));
if( !fc::exists(data_dir) )
fc::create_directories(data_dir);
auto modify_option_defaults = [](const boost::shared_ptr<bpo::option_description>& o) -> const boost::shared_ptr<bpo::option_description> {
const std::string& name = o->long_name();
if( name == "partial-operations" )
return new_option_description(name, bpo::value<bool>()->default_value(true), o->description() );
if( name == "max-ops-per-account" )
return new_option_description(name, bpo::value<int>()->default_value(100), o->description() );
return o;
};
deduplicator dedup(modify_option_defaults);
std::ofstream out_cfg(config_ini_path.preferred_string());
std::string plugin_header_surrounding( 78, '=' );
for( const boost::shared_ptr<bpo::option_description> opt : cfg_options.options() )
{
const boost::shared_ptr<bpo::option_description> od = dedup.next(opt);
if( !od ) continue;
if( od->long_name().find("plugin-cfg-header-") == 0 ) // it's a plugin header
{
out_cfg << "\n";
out_cfg << "# " << plugin_header_surrounding << "\n";
out_cfg << "# " << od->description() << "\n";
out_cfg << "# " << plugin_header_surrounding << "\n";
out_cfg << "\n";
continue;
}
if( !od->description().empty() )
out_cfg << "# " << od->description() << "\n";
boost::any store;
if( !od->semantic()->apply_default(store) )
out_cfg << "# " << od->long_name() << " = \n";
else {
auto example = od->format_parameter();
if( example.empty() )
// This is a boolean switch
out_cfg << od->long_name() << " = " << "false\n";
else {
// The string is formatted "arg (=<interesting part>)"
example.erase(0, 6);
example.erase(example.length()-1);
out_cfg << od->long_name() << " = " << example << "\n";
}
}
out_cfg << "\n";
}
out_cfg << "\n"
<< "# " << plugin_header_surrounding << "\n"
<< "# logging options\n"
<< "# " << plugin_header_surrounding << "\n"
<< "#\n"
<< "# Logging configuration is loaded from logging.ini by default.\n"
<< "# If logging.ini exists, logging configuration added in this file will be ignored.\n";
out_cfg.close();
}
static void create_logging_config_file(const fc::path& config_ini_path, const fc::path& data_dir)
{
ilog("Writing new config file at ${path}", ("path", config_ini_path));
if (!exists(data_dir))
{
create_directories(data_dir);
}
std::ofstream out_cfg(config_ini_path.preferred_string());
write_default_logging_config_to_stream(out_cfg);
out_cfg.close();
}
namespace graphene { namespace app {
void load_configuration_options(const fc::path& data_dir, const bpo::options_description& cfg_options, bpo::variables_map& options)
{
const auto config_ini_path = data_dir / "config.ini";
const auto logging_ini_path = data_dir / "logging.ini";
if(!exists(config_ini_path) && fc::exists(logging_ini_path))
{
// this is an uncommon case
create_new_config_file(config_ini_path, data_dir, cfg_options);
}
else if(!exists(config_ini_path))
{
// create default config.ini and logging.ini
create_new_config_file(config_ini_path, data_dir, cfg_options);
create_logging_config_file(logging_ini_path, data_dir);
}
// load witness node configuration
load_config_file(config_ini_path, cfg_options, options);
// load logging configuration
if (fc::exists(logging_ini_path))
{
load_logging_config_file(logging_ini_path);
}
else
{
// this is the legacy config.ini case
load_logging_config_file(config_ini_path);
}
}
} } // graphene::app

View file

@ -26,11 +26,15 @@
#include <graphene/chain/get_config.hpp>
#include <graphene/chain/tournament_object.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/protocol/address.hpp>
#include <graphene/chain/pts_address.hpp>
#include <fc/bloom_filter.hpp>
#include <fc/smart_ref_impl.hpp>
#include <fc/crypto/hex.hpp>
#include <fc/rpc/api_connection.hpp>
#include <fc/uint128.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/rational.hpp>
@ -45,11 +49,10 @@
typedef std::map< std::pair<graphene::chain::asset_id_type, graphene::chain::asset_id_type>, std::vector<fc::variant> > market_queue_type;
template class fc::api<graphene::app::database_api>;
namespace graphene { namespace app {
class database_api_impl;
class database_api_impl : public std::enable_shared_from_this<database_api_impl>
{
public:
@ -84,25 +87,29 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
bool is_public_key_registered(string public_key) const;
// Accounts
vector<optional<account_object>> get_accounts(const vector<account_id_type>& account_ids)const;
account_id_type get_account_id_from_string(const std::string& name_or_id)const;
vector<optional<account_object>> get_accounts(const vector<std::string>& account_names_or_ids)const;
std::map<string,full_account> get_full_accounts( const vector<string>& names_or_ids, bool subscribe );
optional<account_object> get_account_by_name( string name )const;
vector<account_id_type> get_account_references( account_id_type account_id )const;
vector<account_id_type> get_account_references( const std::string account_id_or_name )const;
vector<optional<account_object>> lookup_account_names(const vector<string>& account_names)const;
map<string,account_id_type> lookup_accounts(const string& lower_bound_name, uint32_t limit)const;
uint64_t get_account_count()const;
// Balances
vector<asset> get_account_balances(account_id_type id, const flat_set<asset_id_type>& assets)const;
vector<asset> get_named_account_balances(const std::string& name, const flat_set<asset_id_type>& assets)const;
vector<asset> get_account_balances(const std::string& account_name_or_id, const flat_set<asset_id_type>& assets)const;
vector<balance_object> get_balance_objects( const vector<address>& addrs )const;
vector<asset> get_vested_balances( const vector<balance_id_type>& objs )const;
vector<vesting_balance_object> get_vesting_balances( account_id_type account_id )const;
vector<vesting_balance_object> get_vesting_balances( const std::string account_id_or_name )const;
// Assets
vector<optional<asset_object>> get_assets(const vector<asset_id_type>& asset_ids)const;
asset_id_type get_asset_id_from_string(const std::string& symbol_or_id)const;
vector<optional<asset_object>> get_assets(const vector<std::string>& asset_symbols_or_ids)const;
// helper function
vector<optional<asset_object>> get_assets( const vector<asset_id_type>& asset_ids )const;
vector<asset_object> list_assets(const string& lower_bound_symbol, uint32_t limit)const;
vector<optional<asset_object>> lookup_asset_symbols(const vector<string>& symbols_or_ids)const;
uint64_t get_asset_count()const;
// Peerplays
vector<sport_object> list_sports() const;
@ -126,12 +133,13 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
asset get_sweeps_vesting_balance_available_for_claim( account_id_type account )const;
// Markets / feeds
vector<limit_order_object> get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const;
vector<call_order_object> get_call_orders(asset_id_type a, uint32_t limit)const;
vector<force_settlement_object> get_settle_orders(asset_id_type a, uint32_t limit)const;
vector<call_order_object> get_margin_positions( const account_id_type& id )const;
void subscribe_to_market(std::function<void(const variant&)> callback, asset_id_type a, asset_id_type b);
void unsubscribe_from_market(asset_id_type a, asset_id_type b);
vector<limit_order_object> get_limit_orders( const asset_id_type a, const asset_id_type b, const uint32_t limit )const;
vector<limit_order_object> get_limit_orders( const std::string& a, const std::string& b, const uint32_t limit)const;
vector<call_order_object> get_call_orders(const std::string& a, uint32_t limit)const;
vector<force_settlement_object> get_settle_orders(const std::string& a, uint32_t limit)const;
vector<call_order_object> get_margin_positions( const std::string account_id_or_name )const;
void subscribe_to_market(std::function<void(const variant&)> callback, const std::string& a, const std::string& b);
void unsubscribe_from_market(const std::string& a, const std::string& b);
market_ticker get_ticker( const string& base, const string& quote )const;
market_volume get_24_volume( const string& base, const string& quote )const;
order_book get_order_book( const string& base, const string& quote, unsigned limit = 50 )const;
@ -139,13 +147,13 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
// Witnesses
vector<optional<witness_object>> get_witnesses(const vector<witness_id_type>& witness_ids)const;
fc::optional<witness_object> get_witness_by_account(account_id_type account)const;
fc::optional<witness_object> get_witness_by_account(const std::string account_id_or_name)const;
map<string, witness_id_type> lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const;
uint64_t get_witness_count()const;
// Committee members
vector<optional<committee_member_object>> get_committee_members(const vector<committee_member_id_type>& committee_member_ids)const;
fc::optional<committee_member_object> get_committee_member_by_account(account_id_type account)const;
fc::optional<committee_member_object> get_committee_member_by_account(const std::string account_id_or_name)const;
map<string, committee_member_id_type> lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const;
// Votes
@ -159,10 +167,10 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
bool verify_authority( const signed_transaction& trx )const;
bool verify_account_authority( const string& name_or_id, const flat_set<public_key_type>& signers )const;
processed_transaction validate_transaction( const signed_transaction& trx )const;
vector< fc::variant > get_required_fees( const vector<operation>& ops, asset_id_type id )const;
vector< fc::variant > get_required_fees( const vector<operation>& ops, const std::string& asset_id_or_symbol )const;
// Proposed transactions
vector<proposal_object> get_proposed_transactions( account_id_type id )const;
vector<proposal_object> get_proposed_transactions( const std::string account_id_or_name )const;
// Blinded balances
vector<blinded_balance_object> get_blinded_balances( const flat_set<commitment_type>& commitments )const;
@ -173,8 +181,14 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
vector<tournament_object> get_tournaments_by_state(tournament_id_type stop, unsigned limit, tournament_id_type start, tournament_state state);
vector<tournament_id_type> get_registered_tournaments(account_id_type account_filter, uint32_t limit) const;
// gpos
gpos_info get_gpos_info(const account_id_type account) const;
//private:
const account_object* get_account_from_string( const std::string& name_or_id,
bool throw_if_not_found = true ) const;
const asset_object* get_asset_from_string( const std::string& symbol_or_id,
bool throw_if_not_found = true ) const;
template<typename T>
void subscribe_to_item( const T& i )const
{
@ -217,7 +231,7 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
auto sub = _market_subscriptions.find( market );
if( sub != _market_subscriptions.end() ) {
queue[market].emplace_back( full_object ? obj->to_variant() : fc::variant(obj->id) );
queue[market].emplace_back( full_object ? obj->to_variant() : fc::variant(obj->id, 1) );
}
}
@ -273,7 +287,7 @@ database_api_impl::database_api_impl( graphene::chain::database& db ):_db(db)
_applied_block_connection = _db.applied_block.connect([this](const signed_block&){ on_applied_block(); });
_pending_trx_connection = _db.on_pending_transaction.connect([this](const signed_transaction& trx ){
if( _pending_trx_callback ) _pending_trx_callback( fc::variant(trx) );
if( _pending_trx_callback ) _pending_trx_callback( fc::variant(trx, GRAPHENE_MAX_NESTED_OBJECTS) );
});
}
@ -524,6 +538,11 @@ vector<vector<account_id_type>> database_api::get_key_references( vector<public_
vector<vector<account_id_type>> database_api_impl::get_key_references( vector<public_key_type> keys )const
{
wdump( (keys) );
const auto& idx = _db.get_index_type<account_index>();
const auto& aidx = dynamic_cast<const base_primary_index&>(idx);
const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
vector< vector<account_id_type> > final_result;
final_result.reserve(keys.size());
@ -543,10 +562,6 @@ vector<vector<account_id_type>> database_api_impl::get_key_references( vector<pu
subscribe_to_item( a4 );
subscribe_to_item( a5 );
const auto& idx = _db.get_index_type<account_index>();
const auto& aidx = dynamic_cast<const primary_index<account_index>&>(idx);
const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
auto itr = refs.account_to_key_memberships.find(key);
vector<account_id_type> result;
for( auto& a : {a1,a2,a3,a4,a5} )
@ -563,6 +578,7 @@ vector<vector<account_id_type>> database_api_impl::get_key_references( vector<pu
}
}
auto itr = refs.account_to_key_memberships.find(key);
if( itr != refs.account_to_key_memberships.end() )
{
result.reserve( result.size() + itr->second.size() );
@ -598,7 +614,7 @@ bool database_api_impl::is_public_key_registered(string public_key) const
return false;
}
const auto& idx = _db.get_index_type<account_index>();
const auto& aidx = dynamic_cast<const primary_index<account_index>&>(idx);
const auto& aidx = dynamic_cast<const base_primary_index&>(idx);
const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
auto itr = refs.account_to_key_memberships.find(key);
bool is_known = itr != refs.account_to_key_memberships.end();
@ -612,22 +628,27 @@ bool database_api_impl::is_public_key_registered(string public_key) const
// //
//////////////////////////////////////////////////////////////////////
vector<optional<account_object>> database_api::get_accounts(const vector<account_id_type>& account_ids)const
account_id_type database_api::get_account_id_from_string(const std::string& name_or_id)const
{
return my->get_accounts( account_ids );
return my->get_account_from_string( name_or_id )->id;
}
vector<optional<account_object>> database_api_impl::get_accounts(const vector<account_id_type>& account_ids)const
vector<optional<account_object>> database_api::get_accounts(const vector<std::string>& account_names_or_ids)const
{
vector<optional<account_object>> result; result.reserve(account_ids.size());
std::transform(account_ids.begin(), account_ids.end(), std::back_inserter(result),
[this](account_id_type id) -> optional<account_object> {
if(auto o = _db.find(id))
{
subscribe_to_item( id );
return *o;
}
return {};
return my->get_accounts( account_names_or_ids );
}
vector<optional<account_object>> database_api_impl::get_accounts(const vector<std::string>& account_names_or_ids)const
{
vector<optional<account_object>> result; result.reserve(account_names_or_ids.size());
std::transform(account_names_or_ids.begin(), account_names_or_ids.end(), std::back_inserter(result),
[this](std::string id_or_name) -> optional<account_object> {
const account_object *account = get_account_from_string(id_or_name, false);
if(account == nullptr)
return {};
subscribe_to_item( account->id );
return *account;
});
return result;
}
@ -639,13 +660,17 @@ std::map<string,full_account> database_api::get_full_accounts( const vector<stri
std::map<std::string, full_account> database_api_impl::get_full_accounts( const vector<std::string>& names_or_ids, bool subscribe)
{
const auto& proposal_idx = _db.get_index_type<proposal_index>();
const auto& pidx = dynamic_cast<const base_primary_index&>(proposal_idx);
const auto& proposals_by_account = pidx.get_secondary_index<graphene::chain::required_approval_index>();
std::map<std::string, full_account> results;
for (const std::string& account_name_or_id : names_or_ids)
{
const account_object* account = nullptr;
if (std::isdigit(account_name_or_id[0]))
account = _db.find(fc::variant(account_name_or_id).as<account_id_type>());
account = _db.find(fc::variant(account_name_or_id, 1).as<account_id_type>(1));
else
{
const auto& idx = _db.get_index_type<account_index>().indices().get<by_name>();
@ -663,7 +688,6 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
subscribe_to_item( account->id );
}
// fc::mutable_variant_object full_account;
full_account acnt;
acnt.account = *account;
acnt.statistics = account->statistics(_db);
@ -672,20 +696,11 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
acnt.lifetime_referrer_name = account->lifetime_referrer(_db).name;
acnt.votes = lookup_vote_ids( vector<vote_id_type>(account->options.votes.begin(),account->options.votes.end()) );
// Add the account itself, its statistics object, cashback balance, and referral account names
/*
full_account("account", *account)("statistics", account->statistics(_db))
("registrar_name", account->registrar(_db).name)("referrer_name", account->referrer(_db).name)
("lifetime_referrer_name", account->lifetime_referrer(_db).name);
*/
if (account->cashback_vb)
{
acnt.cashback_balance = account->cashback_balance(_db);
}
// Add the account's proposals
const auto& proposal_idx = _db.get_index_type<proposal_index>();
const auto& pidx = dynamic_cast<const primary_index<proposal_index>&>(proposal_idx);
const auto& proposals_by_account = pidx.get_secondary_index<graphene::chain::required_approval_index>();
auto required_approvals_itr = proposals_by_account._account_to_proposals.find( account->id );
if( required_approvals_itr != proposals_by_account._account_to_proposals.end() )
{
@ -696,12 +711,9 @@ std::map<std::string, full_account> database_api_impl::get_full_accounts( const
// Add the account's balances
auto balance_range = _db.get_index_type<account_balance_index>().indices().get<by_account_asset>().equal_range(boost::make_tuple(account->id));
//vector<account_balance_object> balances;
std::for_each(balance_range.first, balance_range.second,
[&acnt](const account_balance_object& balance) {
acnt.balances.emplace_back(balance);
});
const auto& balances = _db.get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >().get_account_balances( account->id );
for( const auto balance : balances )
acnt.balances.emplace_back( *balance.second );
// Add the account's vesting balances
auto vesting_range = _db.get_index_type<vesting_balance_index>().indices().get<by_account>().equal_range(account->id);
@ -765,16 +777,17 @@ optional<account_object> database_api_impl::get_account_by_name( string name )co
return optional<account_object>();
}
vector<account_id_type> database_api::get_account_references( account_id_type account_id )const
vector<account_id_type> database_api::get_account_references( const std::string account_id_or_name )const
{
return my->get_account_references( account_id );
return my->get_account_references( account_id_or_name );
}
vector<account_id_type> database_api_impl::get_account_references( account_id_type account_id )const
vector<account_id_type> database_api_impl::get_account_references( const std::string account_id_or_name )const
{
const auto& idx = _db.get_index_type<account_index>();
const auto& aidx = dynamic_cast<const primary_index<account_index>&>(idx);
const auto& aidx = dynamic_cast<const base_primary_index&>(idx);
const auto& refs = aidx.get_secondary_index<graphene::chain::account_member_index>();
const account_id_type account_id = get_account_from_string(account_id_or_name)->id;
auto itr = refs.account_to_account_memberships.find(account_id);
vector<account_id_type> result;
@ -843,21 +856,24 @@ uint64_t database_api_impl::get_account_count()const
// //
//////////////////////////////////////////////////////////////////////
vector<asset> database_api::get_account_balances(account_id_type id, const flat_set<asset_id_type>& assets)const
vector<asset> database_api::get_account_balances(const std::string& account_name_or_id, const flat_set<asset_id_type>& assets)const
{
return my->get_account_balances( id, assets );
return my->get_account_balances( account_name_or_id, assets );
}
vector<asset> database_api_impl::get_account_balances(account_id_type acnt, const flat_set<asset_id_type>& assets)const
vector<asset> database_api_impl::get_account_balances( const std::string& account_name_or_id,
const flat_set<asset_id_type>& assets)const
{
const account_object* account = get_account_from_string(account_name_or_id);
account_id_type acnt = account->id;
vector<asset> result;
if (assets.empty())
{
// if the caller passes in an empty list of assets, return balances for all assets the account owns
const account_balance_index& balance_index = _db.get_index_type<account_balance_index>();
auto range = balance_index.indices().get<by_account_asset>().equal_range(boost::make_tuple(acnt));
for (const account_balance_object& balance : boost::make_iterator_range(range.first, range.second))
result.push_back(asset(balance.get_balance()));
const auto& balance_index = _db.get_index_type< primary_index< account_balance_index > >();
const auto& balances = balance_index.get_secondary_index< balances_by_account_index >().get_account_balances( acnt );
for( const auto balance : balances )
result.push_back( balance.second->get_balance() );
}
else
{
@ -872,15 +888,7 @@ vector<asset> database_api_impl::get_account_balances(account_id_type acnt, cons
vector<asset> database_api::get_named_account_balances(const std::string& name, const flat_set<asset_id_type>& assets)const
{
return my->get_named_account_balances( name, assets );
}
vector<asset> database_api_impl::get_named_account_balances(const std::string& name, const flat_set<asset_id_type>& assets) const
{
const auto& accounts_by_name = _db.get_index_type<account_index>().indices().get<by_name>();
auto itr = accounts_by_name.find(name);
FC_ASSERT( itr != accounts_by_name.end() );
return get_account_balances(itr->get_id(), assets);
return my->get_account_balances( name, assets );
}
vector<balance_object> database_api::get_balance_objects( const vector<address>& addrs )const
@ -930,24 +938,26 @@ vector<asset> database_api_impl::get_vested_balances( const vector<balance_id_ty
} FC_CAPTURE_AND_RETHROW( (objs) )
}
vector<vesting_balance_object> database_api::get_vesting_balances( account_id_type account_id )const
vector<vesting_balance_object> database_api::get_vesting_balances( const std::string account_id_or_name )const
{
return my->get_vesting_balances( account_id );
return my->get_vesting_balances( account_id_or_name );
}
vector<vesting_balance_object> database_api_impl::get_vesting_balances( account_id_type account_id )const
vector<vesting_balance_object> database_api_impl::get_vesting_balances( const std::string account_id_or_name )const
{
try
{
const account_id_type account_id = get_account_from_string(account_id_or_name)->id;
vector<vesting_balance_object> result;
auto vesting_range = _db.get_index_type<vesting_balance_index>().indices().get<by_account>().equal_range(account_id);
std::for_each(vesting_range.first, vesting_range.second,
[&result](const vesting_balance_object& balance) {
result.emplace_back(balance);
if(balance.balance.amount > 0)
result.emplace_back(balance);
});
return result;
}
FC_CAPTURE_AND_RETHROW( (account_id) );
FC_CAPTURE_AND_RETHROW( (account_id_or_name) );
}
//////////////////////////////////////////////////////////////////////
@ -956,9 +966,48 @@ vector<vesting_balance_object> database_api_impl::get_vesting_balances( account_
// //
//////////////////////////////////////////////////////////////////////
vector<optional<asset_object>> database_api::get_assets(const vector<asset_id_type>& asset_ids)const
asset_id_type database_api::get_asset_id_from_string(const std::string& symbol_or_id)const
{
return my->get_assets( asset_ids );
return my->get_asset_from_string( symbol_or_id )->id;
}
const asset_object* database_api_impl::get_asset_from_string( const std::string& symbol_or_id,
bool throw_if_not_found ) const
{
// TODO cache the result to avoid repeatly fetching from db
FC_ASSERT( symbol_or_id.size() > 0);
const asset_object* asset = nullptr;
if (std::isdigit(symbol_or_id[0]))
asset = _db.find(fc::variant(symbol_or_id, 1).as<asset_id_type>(1));
else
{
const auto& idx = _db.get_index_type<asset_index>().indices().get<by_symbol>();
auto itr = idx.find(symbol_or_id);
if (itr != idx.end())
asset = &*itr;
}
if(throw_if_not_found)
FC_ASSERT( asset, "no such asset" );
return asset;
}
vector<optional<asset_object>> database_api::get_assets(const vector<std::string>& asset_symbols_or_ids)const
{
return my->get_assets( asset_symbols_or_ids );
}
vector<optional<asset_object>> database_api_impl::get_assets(const vector<std::string>& asset_symbols_or_ids)const
{
vector<optional<asset_object>> result; result.reserve(asset_symbols_or_ids.size());
std::transform(asset_symbols_or_ids.begin(), asset_symbols_or_ids.end(), std::back_inserter(result),
[this](std::string id_or_name) -> optional<asset_object> {
const asset_object* asset_obj = get_asset_from_string( id_or_name, false );
if( asset_obj == nullptr )
return {};
subscribe_to_item(asset_obj->id );
return asset_object( *asset_obj );
});
return result;
}
vector<optional<asset_object>> database_api_impl::get_assets(const vector<asset_id_type>& asset_ids)const
@ -1013,7 +1062,7 @@ vector<optional<asset_object>> database_api_impl::lookup_asset_symbols(const vec
[this, &assets_by_symbol](const string& symbol_or_id) -> optional<asset_object> {
if( !symbol_or_id.empty() && std::isdigit(symbol_or_id[0]) )
{
auto ptr = _db.find(variant(symbol_or_id).as<asset_id_type>());
auto ptr = _db.find(variant(symbol_or_id, 1).as<asset_id_type>(1));
return ptr == nullptr? optional<asset_object>() : *ptr;
}
auto itr = assets_by_symbol.find(symbol_or_id);
@ -1022,6 +1071,15 @@ vector<optional<asset_object>> database_api_impl::lookup_asset_symbols(const vec
return result;
}
uint64_t database_api::get_asset_count()const
{
return my->get_asset_count();
}
uint64_t database_api_impl::get_asset_count()const
{
return _db.get_index_type<asset_index>().indices().size();
}
////////////////////
// Lottery Assets //
////////////////////
@ -1205,7 +1263,7 @@ vector<bet_object> database_api_impl::get_all_unmatched_bets_for_bettor(account_
// //
//////////////////////////////////////////////////////////////////////
vector<limit_order_object> database_api::get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const
vector<limit_order_object> database_api::get_limit_orders(const std::string& a, const std::string& b, const uint32_t limit)const
{
return my->get_limit_orders( a, b, limit );
}
@ -1213,12 +1271,22 @@ vector<limit_order_object> database_api::get_limit_orders(asset_id_type a, asset
/**
* @return the limit orders for both sides of the book for the two assets specified up to limit number on each side.
*/
vector<limit_order_object> database_api_impl::get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const
vector<limit_order_object> database_api_impl::get_limit_orders(const std::string& a, const std::string& b, const uint32_t limit)const
{
const asset_id_type asset_a_id = get_asset_from_string(a)->id;
const asset_id_type asset_b_id = get_asset_from_string(b)->id;
return get_limit_orders(asset_a_id, asset_b_id, limit);
}
vector<limit_order_object> database_api_impl::get_limit_orders( const asset_id_type a, const asset_id_type b,
const uint32_t limit )const
{
const auto& limit_order_idx = _db.get_index_type<limit_order_index>();
const auto& limit_price_idx = limit_order_idx.indices().get<by_price>();
vector<limit_order_object> result;
result.reserve(limit*2);
uint32_t count = 0;
auto limit_itr = limit_price_idx.lower_bound(price::max(a,b));
@ -1242,45 +1310,46 @@ vector<limit_order_object> database_api_impl::get_limit_orders(asset_id_type a,
return result;
}
vector<call_order_object> database_api::get_call_orders(asset_id_type a, uint32_t limit)const
vector<call_order_object> database_api::get_call_orders(const std::string& a, uint32_t limit)const
{
return my->get_call_orders( a, limit );
}
vector<call_order_object> database_api_impl::get_call_orders(asset_id_type a, uint32_t limit)const
vector<call_order_object> database_api_impl::get_call_orders(const std::string& a, uint32_t limit)const
{
const auto& call_index = _db.get_index_type<call_order_index>().indices().get<by_price>();
const asset_object& mia = _db.get(a);
price index_price = price::min(mia.bitasset_data(_db).options.short_backing_asset, mia.get_id());
const asset_object* mia = get_asset_from_string(a);
price index_price = price::min(mia->bitasset_data(_db).options.short_backing_asset, mia->get_id());
return vector<call_order_object>(call_index.lower_bound(index_price.min()),
call_index.lower_bound(index_price.max()));
}
vector<force_settlement_object> database_api::get_settle_orders(asset_id_type a, uint32_t limit)const
vector<force_settlement_object> database_api::get_settle_orders(const std::string& a, uint32_t limit)const
{
return my->get_settle_orders( a, limit );
}
vector<force_settlement_object> database_api_impl::get_settle_orders(asset_id_type a, uint32_t limit)const
vector<force_settlement_object> database_api_impl::get_settle_orders(const std::string& a, uint32_t limit)const
{
const auto& settle_index = _db.get_index_type<force_settlement_index>().indices().get<by_expiration>();
const asset_object& mia = _db.get(a);
return vector<force_settlement_object>(settle_index.lower_bound(mia.get_id()),
settle_index.upper_bound(mia.get_id()));
const asset_object* mia = get_asset_from_string(a);
return vector<force_settlement_object>(settle_index.lower_bound(mia->get_id()),
settle_index.upper_bound(mia->get_id()));
}
vector<call_order_object> database_api::get_margin_positions( const account_id_type& id )const
vector<call_order_object> database_api::get_margin_positions( const std::string account_id_or_name )const
{
return my->get_margin_positions( id );
return my->get_margin_positions( account_id_or_name );
}
vector<call_order_object> database_api_impl::get_margin_positions( const account_id_type& id )const
vector<call_order_object> database_api_impl::get_margin_positions( const std::string account_id_or_name )const
{
try
{
const auto& idx = _db.get_index_type<call_order_index>();
const auto& aidx = idx.indices().get<by_account>();
const account_id_type id = get_account_from_string(account_id_or_name)->id;
auto start = aidx.lower_bound( boost::make_tuple( id, asset_id_type(0) ) );
auto end = aidx.lower_bound( boost::make_tuple( id+1, asset_id_type(0) ) );
vector<call_order_object> result;
@ -1290,31 +1359,37 @@ vector<call_order_object> database_api_impl::get_margin_positions( const account
++start;
}
return result;
} FC_CAPTURE_AND_RETHROW( (id) )
} FC_CAPTURE_AND_RETHROW( (account_id_or_name) )
}
void database_api::subscribe_to_market(std::function<void(const variant&)> callback, asset_id_type a, asset_id_type b)
void database_api::subscribe_to_market(std::function<void(const variant&)> callback, const std::string& a, const std::string& b)
{
my->subscribe_to_market( callback, a, b );
}
void database_api_impl::subscribe_to_market(std::function<void(const variant&)> callback, asset_id_type a, asset_id_type b)
void database_api_impl::subscribe_to_market(std::function<void(const variant&)> callback, const std::string& a, const std::string& b)
{
if(a > b) std::swap(a,b);
FC_ASSERT(a != b);
_market_subscriptions[ std::make_pair(a,b) ] = callback;
auto asset_a_id = get_asset_from_string(a)->id;
auto asset_b_id = get_asset_from_string(b)->id;
if(asset_a_id > asset_b_id) std::swap(asset_a_id,asset_b_id);
FC_ASSERT(asset_a_id != asset_b_id);
_market_subscriptions[ std::make_pair(asset_a_id,asset_b_id) ] = callback;
}
void database_api::unsubscribe_from_market(asset_id_type a, asset_id_type b)
void database_api::unsubscribe_from_market(const std::string& a, const std::string& b)
{
my->unsubscribe_from_market( a, b );
}
void database_api_impl::unsubscribe_from_market(asset_id_type a, asset_id_type b)
void database_api_impl::unsubscribe_from_market(const std::string& a, const std::string& b)
{
if(a > b) std::swap(a,b);
FC_ASSERT(a != b);
_market_subscriptions.erase(std::make_pair(a,b));
auto asset_a_id = get_asset_from_string(a)->id;
auto asset_b_id = get_asset_from_string(b)->id;
if(asset_a_id > asset_b_id) std::swap(asset_a_id,asset_b_id);
FC_ASSERT(asset_a_id != asset_b_id);
_market_subscriptions.erase(std::make_pair(asset_a_id,asset_b_id));
}
market_ticker database_api::get_ticker( const string& base, const string& quote )const
@ -1537,9 +1612,10 @@ vector<optional<witness_object>> database_api::get_witnesses(const vector<witnes
return my->get_witnesses( witness_ids );
}
vector<worker_object> database_api::get_workers_by_account(account_id_type account)const
vector<worker_object> database_api::get_workers_by_account(const std::string account_id_or_name)const
{
const auto& idx = my->_db.get_index_type<worker_index>().indices().get<by_account>();
const account_id_type account = my->get_account_from_string(account_id_or_name)->id;
auto itr = idx.find(account);
vector<worker_object> result;
@ -1565,14 +1641,15 @@ vector<optional<witness_object>> database_api_impl::get_witnesses(const vector<w
return result;
}
fc::optional<witness_object> database_api::get_witness_by_account(account_id_type account)const
fc::optional<witness_object> database_api::get_witness_by_account(const std::string account_id_or_name)const
{
return my->get_witness_by_account( account );
return my->get_witness_by_account( account_id_or_name );
}
fc::optional<witness_object> database_api_impl::get_witness_by_account(account_id_type account) const
fc::optional<witness_object> database_api_impl::get_witness_by_account(const std::string account_id_or_name) const
{
const auto& idx = _db.get_index_type<witness_index>().indices().get<by_account>();
const account_id_type account = get_account_from_string(account_id_or_name)->id;
auto itr = idx.find(account);
if( itr != idx.end() )
return *itr;
@ -1640,14 +1717,15 @@ vector<optional<committee_member_object>> database_api_impl::get_committee_membe
return result;
}
fc::optional<committee_member_object> database_api::get_committee_member_by_account(account_id_type account)const
fc::optional<committee_member_object> database_api::get_committee_member_by_account(const std::string account_id_or_name)const
{
return my->get_committee_member_by_account( account );
return my->get_committee_member_by_account( account_id_or_name );
}
fc::optional<committee_member_object> database_api_impl::get_committee_member_by_account(account_id_type account) const
fc::optional<committee_member_object> database_api_impl::get_committee_member_by_account(const std::string account_id_or_name) const
{
const auto& idx = _db.get_index_type<committee_member_index>().indices().get<by_account>();
const account_id_type account = get_account_from_string(account_id_or_name)->id;
auto itr = idx.find(account);
if( itr != idx.end() )
return *itr;
@ -1712,7 +1790,7 @@ vector<variant> database_api_impl::lookup_vote_ids( const vector<vote_id_type>&
{
auto itr = committee_idx.find( id );
if( itr != committee_idx.end() )
result.emplace_back( variant( *itr ) );
result.emplace_back( variant( *itr, 1 ) );
else
result.emplace_back( variant() );
break;
@ -1721,7 +1799,7 @@ vector<variant> database_api_impl::lookup_vote_ids( const vector<vote_id_type>&
{
auto itr = witness_idx.find( id );
if( itr != witness_idx.end() )
result.emplace_back( variant( *itr ) );
result.emplace_back( variant( *itr, 1 ) );
else
result.emplace_back( variant() );
break;
@ -1730,12 +1808,12 @@ vector<variant> database_api_impl::lookup_vote_ids( const vector<vote_id_type>&
{
auto itr = for_worker_idx.find( id );
if( itr != for_worker_idx.end() ) {
result.emplace_back( variant( *itr ) );
result.emplace_back( variant( *itr, 1 ) );
}
else {
auto itr = against_worker_idx.find( id );
if( itr != against_worker_idx.end() ) {
result.emplace_back( variant( *itr ) );
result.emplace_back( variant( *itr, 1 ) );
}
else {
result.emplace_back( variant() );
@ -1744,6 +1822,8 @@ vector<variant> database_api_impl::lookup_vote_ids( const vector<vote_id_type>&
break;
}
case vote_id_type::VOTE_TYPE_COUNT: break; // supress unused enum value warnings
default:
FC_CAPTURE_AND_THROW( fc::out_of_range_exception, (id) );
}
}
return result;
@ -1852,8 +1932,8 @@ bool database_api::verify_authority( const signed_transaction& trx )const
bool database_api_impl::verify_authority( const signed_transaction& trx )const
{
trx.verify_authority( _db.get_chain_id(),
[&]( account_id_type id ){ return &id(_db).active; },
[&]( account_id_type id ){ return &id(_db).owner; },
[this]( account_id_type id ){ return &id(_db).active; },
[this]( account_id_type id ){ return &id(_db).owner; },
_db.get_global_properties().parameters.max_authority_depth );
return true;
}
@ -1868,7 +1948,7 @@ bool database_api_impl::verify_account_authority( const string& name_or_id, cons
FC_ASSERT( name_or_id.size() > 0);
const account_object* account = nullptr;
if (std::isdigit(name_or_id[0]))
account = _db.find(fc::variant(name_or_id).as<account_id_type>());
account = _db.find(fc::variant(name_or_id, 1).as<account_id_type>(1));
else
{
const auto& idx = _db.get_index_type<account_index>().indices().get<by_name>();
@ -1898,9 +1978,9 @@ processed_transaction database_api_impl::validate_transaction( const signed_tran
return _db.validate_transaction(trx);
}
vector< fc::variant > database_api::get_required_fees( const vector<operation>& ops, asset_id_type id )const
vector< fc::variant > database_api::get_required_fees( const vector<operation>& ops, const std::string& asset_id_or_symbol )const
{
return my->get_required_fees( ops, id );
return my->get_required_fees( ops, asset_id_or_symbol );
}
/**
@ -1929,7 +2009,7 @@ struct get_required_fees_helper
{
asset fee = current_fee_schedule.set_fee( op, core_exchange_rate );
fc::variant result;
fc::to_variant( fee, result );
fc::to_variant( fee, result, GRAPHENE_NET_MAX_NESTED_OBJECTS );
return result;
}
}
@ -1949,7 +2029,7 @@ struct get_required_fees_helper
// two mutually recursive functions instead of a visitor
result.first = current_fee_schedule.set_fee( proposal_create_op, core_exchange_rate );
fc::variant vresult;
fc::to_variant( result, vresult );
fc::to_variant( result, vresult, GRAPHENE_NET_MAX_NESTED_OBJECTS );
return vresult;
}
@ -1959,7 +2039,7 @@ struct get_required_fees_helper
uint32_t current_recursion = 0;
};
vector< fc::variant > database_api_impl::get_required_fees( const vector<operation>& ops, asset_id_type id )const
vector< fc::variant > database_api_impl::get_required_fees( const vector<operation>& ops, const std::string& asset_id_or_symbol )const
{
vector< operation > _ops = ops;
//
@ -1969,7 +2049,7 @@ vector< fc::variant > database_api_impl::get_required_fees( const vector<operati
vector< fc::variant > result;
result.reserve(ops.size());
const asset_object& a = id(_db);
const asset_object& a = *get_asset_from_string(asset_id_or_symbol);
get_required_fees_helper helper(
_db.current_fee_schedule(),
a.options.core_exchange_rate,
@ -1987,16 +2067,17 @@ vector< fc::variant > database_api_impl::get_required_fees( const vector<operati
// //
//////////////////////////////////////////////////////////////////////
vector<proposal_object> database_api::get_proposed_transactions( account_id_type id )const
vector<proposal_object> database_api::get_proposed_transactions( const std::string account_id_or_name )const
{
return my->get_proposed_transactions( id );
return my->get_proposed_transactions( account_id_or_name );
}
/** TODO: add secondary index that will accelerate this process */
vector<proposal_object> database_api_impl::get_proposed_transactions( account_id_type id )const
vector<proposal_object> database_api_impl::get_proposed_transactions( const std::string account_id_or_name )const
{
const auto& idx = _db.get_index_type<proposal_index>();
vector<proposal_object> result;
const account_id_type id = get_account_from_string(account_id_or_name)->id;
idx.inspect_all_objects( [&](const object& obj){
const proposal_object& p = static_cast<const proposal_object&>(obj);
@ -2111,6 +2192,26 @@ vector<tournament_object> database_api_impl::get_tournaments_by_state(tournament
return result;
}
const account_object* database_api_impl::get_account_from_string( const std::string& name_or_id,
bool throw_if_not_found ) const
{
// TODO cache the result to avoid repeatly fetching from db
FC_ASSERT( name_or_id.size() > 0);
const account_object* account = nullptr;
if (std::isdigit(name_or_id[0]))
account = _db.find(fc::variant(name_or_id, 1).as<account_id_type>(1));
else
{
const auto& idx = _db.get_index_type<account_index>().indices().get<by_name>();
auto itr = idx.find(name_or_id);
if (itr != idx.end())
account = &*itr;
}
if(throw_if_not_found)
FC_ASSERT( account, "no such account" );
return account;
}
vector<tournament_id_type> database_api::get_registered_tournaments(account_id_type account_filter, uint32_t limit) const
{
return my->get_registered_tournaments(account_filter, limit);
@ -2128,6 +2229,80 @@ vector<tournament_id_type> database_api_impl::get_registered_tournaments(account
return tournament_ids;
}
//////////////////////////////////////////////////////////////////////
// //
// GPOS methods //
// //
//////////////////////////////////////////////////////////////////////
graphene::app::gpos_info database_api::get_gpos_info(const account_id_type account) const
{
return my->get_gpos_info(account);
}
graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type account) const
{
FC_ASSERT( _db.head_block_time() > HARDFORK_GPOS_TIME); //Can be deleted after GPOS hardfork time
gpos_info result;
result.vesting_factor = _db.calculate_vesting_factor(account(_db));
result.current_subperiod = _db.get_gpos_current_subperiod();
result.last_voted_time = account(_db).statistics(_db).last_vote_time;
const auto& dividend_data = asset_id_type()(_db).dividend_data(_db);
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(_db);
result.award = _db.get_balance(dividend_distribution_account, asset_id_type()(_db));
share_type total_amount;
auto balance_type = vesting_balance_type::gpos;
#ifdef USE_VESTING_OBJECT_BY_ASSET_BALANCE_INDEX
// get only once a collection of accounts that hold nonzero vesting balances of the dividend asset
auto vesting_balances_begin =
vesting_index.indices().get<by_asset_balance>().lower_bound(boost::make_tuple(asset_id_type(), balance_type));
auto vesting_balances_end =
vesting_index.indices().get<by_asset_balance>().upper_bound(boost::make_tuple(asset_id_type(), balance_type, share_type()));
for (const vesting_balance_object& vesting_balance_obj : boost::make_iterator_range(vesting_balances_begin, vesting_balances_end))
{
total_amount += vesting_balance_obj.balance.amount;
}
#else
const vesting_balance_index& vesting_index = _db.get_index_type<vesting_balance_index>();
const auto& vesting_balances = vesting_index.indices().get<by_id>();
for (const vesting_balance_object& vesting_balance_obj : vesting_balances)
{
if (vesting_balance_obj.balance.asset_id == asset_id_type() && vesting_balance_obj.balance_type == balance_type)
{
total_amount += vesting_balance_obj.balance.amount;
}
}
#endif
vector<vesting_balance_object> account_vbos;
const time_point_sec now = _db.head_block_time();
auto vesting_range = _db.get_index_type<vesting_balance_index>().indices().get<by_account>().equal_range(account);
std::for_each(vesting_range.first, vesting_range.second,
[&account_vbos, now](const vesting_balance_object& balance) {
if(balance.balance.amount > 0 && balance.balance_type == vesting_balance_type::gpos
&& balance.balance.asset_id == asset_id_type())
account_vbos.emplace_back(balance);
});
share_type allowed_withdraw_amount = 0, account_vested_balance = 0;
for (const vesting_balance_object& vesting_balance_obj : account_vbos)
{
account_vested_balance += vesting_balance_obj.balance.amount;
if(vesting_balance_obj.is_withdraw_allowed(_db.head_block_time(), vesting_balance_obj.balance.amount))
allowed_withdraw_amount += vesting_balance_obj.balance.amount;
}
result.total_amount = total_amount;
result.allowed_withdraw_amount = allowed_withdraw_amount;
result.account_vested_balance = account_vested_balance;
return result;
}
//////////////////////////////////////////////////////////////////////
// //
// Private methods //
@ -2211,7 +2386,7 @@ void database_api_impl::handle_object_changed(bool force_notify, bool full_objec
}
else
{
updates.emplace_back( id );
updates.emplace_back( fc::variant( id, 1 ) );
}
}
}
@ -2255,7 +2430,7 @@ void database_api_impl::on_applied_block()
auto capture_this = shared_from_this();
block_id_type block_id = _db.head_block_id();
fc::async([this,capture_this,block_id](){
_block_applied_callback(fc::variant(block_id));
_block_applied_callback(fc::variant(block_id, 1));
});
}
@ -2296,7 +2471,7 @@ void database_api_impl::on_applied_block()
{
auto itr = _market_subscriptions.find(item.first);
if(itr != _market_subscriptions.end())
itr->second(fc::variant(item.second));
itr->second(fc::variant(item.second, GRAPHENE_NET_MAX_NESTED_OBJECTS));
}
});
}

View file

@ -95,31 +95,32 @@ namespace graphene { namespace app {
class history_api
{
public:
history_api(application& app):_app(app){}
history_api(application& app)
:_app(app), database_api( std::ref(*app.chain_database())) {}
/**
* @brief Get operations relevant to the specificed account
* @param account The account whose history should be queried
* @param account_id_or_name The account ID or name whose history should be queried
* @param stop ID of the earliest operation to retrieve
* @param limit Maximum number of operations to retrieve (must not exceed 100)
* @param start ID of the most recent operation to retrieve
* @return A list of operations performed by account, ordered from most recent to oldest.
*/
vector<operation_history_object> get_account_history(account_id_type account,
vector<operation_history_object> get_account_history(const std::string account_id_or_name,
operation_history_id_type stop = operation_history_id_type(),
unsigned limit = 100,
operation_history_id_type start = operation_history_id_type())const;
/**
* @brief Get only asked operations relevant to the specified account
* @param account The account whose history should be queried
* @param account_id_or_name The account ID or name whose history should be queried
* @param operation_id The ID of the operation we want to get operations in the account( 0 = transfer , 1 = limit order create, ...)
* @param stop ID of the earliest operation to retrieve
* @param limit Maximum number of operations to retrieve (must not exceed 100)
* @param start ID of the most recent operation to retrieve
* @return A list of operations performed by account, ordered from most recent to oldest.
*/
vector<operation_history_object> get_account_history_operations(account_id_type account,
vector<operation_history_object> get_account_history_operations(const std::string account_id_or_name,
int operation_id,
operation_history_id_type start = operation_history_id_type(),
operation_history_id_type stop = operation_history_id_type(),
@ -129,7 +130,7 @@ namespace graphene { namespace app {
* @breif Get operations relevant to the specified account referenced
* by an event numbering specific to the account. The current number of operations
* for the account can be found in the account statistics (or use 0 for start).
* @param account The account whose history should be queried
* @param account_id_or_name The account ID or name whose history should be queried
* @param stop Sequence number of earliest operation. 0 is default and will
* query 'limit' number of operations.
* @param limit Maximum number of operations to retrieve (must not exceed 100)
@ -137,18 +138,19 @@ namespace graphene { namespace app {
* 0 is default, which will start querying from the most recent operation.
* @return A list of operations performed by account, ordered from most recent to oldest.
*/
vector<operation_history_object> get_relative_account_history( account_id_type account,
vector<operation_history_object> get_relative_account_history( const std::string account_id_or_name,
uint32_t stop = 0,
unsigned limit = 100,
uint32_t start = 0) const;
vector<order_history_object> get_fill_order_history( asset_id_type a, asset_id_type b, uint32_t limit )const;
vector<bucket_object> get_market_history( asset_id_type a, asset_id_type b, uint32_t bucket_seconds,
vector<order_history_object> get_fill_order_history( std::string asset_a, std::string asset_b, uint32_t limit )const;
vector<bucket_object> get_market_history( std::string asset_a, std::string asset_b, uint32_t bucket_seconds,
fc::time_point_sec start, fc::time_point_sec end )const;
vector<account_balance_object> list_core_accounts()const;
flat_set<uint32_t> get_market_history_buckets()const;
private:
application& _app;
graphene::app::database_api database_api;
};
/**
@ -325,17 +327,47 @@ namespace graphene { namespace app {
class asset_api
{
public:
asset_api(graphene::chain::database& db);
asset_api(graphene::app::application& app);
~asset_api();
vector<account_asset_balance> get_asset_holders( asset_id_type asset_id, uint32_t start, uint32_t limit )const;
int get_asset_holders_count( asset_id_type asset_id )const;
/**
* @brief Get asset holders for a specific asset
* @param asset The specific asset id or symbol
* @param start The start index
* @param limit Maximum limit must not exceed 100
* @return A list of asset holders for the specified asset
*/
vector<account_asset_balance> get_asset_holders( std::string asset, uint32_t start, uint32_t limit )const;
/**
* @brief Get asset holders count for a specific asset
* @param asset The specific asset id or symbol
* @return Holders count for the specified asset
*/
int get_asset_holders_count( std::string asset )const;
/**
* @brief Get all asset holders
* @return A list of all asset holders
*/
vector<asset_holders> get_all_asset_holders() const;
private:
graphene::app::application& _app;
graphene::chain::database& _db;
graphene::app::database_api database_api;
};
} } // graphene::app
extern template class fc::api<graphene::app::block_api>;
extern template class fc::api<graphene::app::network_broadcast_api>;
extern template class fc::api<graphene::app::network_node_api>;
extern template class fc::api<graphene::app::history_api>;
extern template class fc::api<graphene::app::crypto_api>;
extern template class fc::api<graphene::app::asset_api>;
extern template class fc::api<graphene::debug_witness::debug_api>;
namespace graphene { namespace app {
/**
* @brief The login_api class implements the bottom layer of the RPC API
*
@ -397,6 +429,8 @@ namespace graphene { namespace app {
}} // graphene::app
extern template class fc::api<graphene::app::login_api>;
FC_REFLECT( graphene::app::network_broadcast_api::transaction_confirmation,
(id)(block_num)(trx_num)(trx) )
FC_REFLECT( graphene::app::verify_range_result,

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2018 Lubos Ilcik, and contributors.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#pragma once
#include <fc/filesystem.hpp>
#include <boost/program_options.hpp>
namespace graphene { namespace app {
void load_configuration_options(const fc::path &data_dir, const boost::program_options::options_description &cfg_options,
boost::program_options::variables_map &options);
} } // graphene::app

View file

@ -114,6 +114,16 @@ struct market_trade
double value;
};
struct gpos_info {
double vesting_factor;
asset award;
share_type total_amount;
uint32_t current_subperiod;
fc::time_point_sec last_voted_time;
share_type allowed_withdraw_amount;
share_type account_vested_balance;
};
/**
* @brief The database_api class implements the RPC API for the chain database.
*
@ -241,13 +251,21 @@ class database_api
//////////////
/**
* @brief Get a list of accounts by ID
* @brief Get account object from a name or ID
* @param name_or_id name or ID of the account
* @return Account ID
*
*/
account_id_type get_account_id_from_string(const std::string& name_or_id)const;
/**
* @brief Get a list of accounts by ID or Name
* @param account_ids IDs of the accounts to retrieve
* @return The accounts corresponding to the provided IDs
*
* This function has semantics identical to @ref get_objects
*/
vector<optional<account_object>> get_accounts(const vector<account_id_type>& account_ids)const;
vector<optional<account_object>> get_accounts(const vector<std::string>& account_names_or_ids)const;
/**
* @brief Fetch all objects relevant to the specified accounts and subscribe to updates
@ -267,7 +285,7 @@ class database_api
/**
* @return all accounts that referr to the key or account id in their owner or active authorities.
*/
vector<account_id_type> get_account_references( account_id_type account_id )const;
vector<account_id_type> get_account_references( const std::string account_name_or_id )const;
/**
* @brief Get a list of accounts by name
@ -296,7 +314,8 @@ class database_api
* @param assets IDs of the assets to get balances of; if empty, get all assets account has a balance in
* @return Balances of the account
*/
vector<asset> get_account_balances(account_id_type id, const flat_set<asset_id_type>& assets)const;
vector<asset> get_account_balances( const std::string& account_name_or_id,
const flat_set<asset_id_type>& assets )const;
/// Semantically equivalent to @ref get_account_balances, but takes a name instead of an ID.
vector<asset> get_named_account_balances(const std::string& name, const flat_set<asset_id_type>& assets)const;
@ -306,7 +325,7 @@ class database_api
vector<asset> get_vested_balances( const vector<balance_id_type>& objs )const;
vector<vesting_balance_object> get_vesting_balances( account_id_type account_id )const;
vector<vesting_balance_object> get_vesting_balances( const std::string account_id_or_name )const;
/**
* @brief Get the total number of accounts registered with the blockchain
@ -317,14 +336,21 @@ class database_api
// Assets //
////////////
/**
* @brief Get asset ID from an asset symbol or ID
* @param symbol_or_id symbol name or ID of the asset
* @return asset ID
*/
asset_id_type get_asset_id_from_string(const std::string& symbol_or_id) const;
/**
* @brief Get a list of assets by ID
* @param asset_ids IDs of the assets to retrieve
* @param asset_symbols_or_ids IDs or names of the assets to retrieve
* @return The assets corresponding to the provided IDs
*
* This function has semantics identical to @ref get_objects
*/
vector<optional<asset_object>> get_assets(const vector<asset_id_type>& asset_ids)const;
vector<optional<asset_object>> get_assets(const vector<std::string>& asset_symbols_or_ids)const;
/**
* @brief Get assets alphabetically by symbol name
@ -343,6 +369,12 @@ class database_api
*/
vector<optional<asset_object>> lookup_asset_symbols(const vector<string>& symbols_or_ids)const;
/**
* @brief Get assets count
* @return The assets count
*/
uint64_t get_asset_count()const;
////////////////////
// Lottery Assets //
////////////////////
@ -420,47 +452,47 @@ class database_api
* @param limit Maximum number of orders to retrieve
* @return The limit orders, ordered from least price to greatest
*/
vector<limit_order_object> get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const;
vector<limit_order_object> get_limit_orders(const std::string& a, const std::string& b, uint32_t limit)const;
/**
* @brief Get call orders in a given asset
* @param a ID of asset being called
* @param a ID or name of asset being called
* @param limit Maximum number of orders to retrieve
* @return The call orders, ordered from earliest to be called to latest
*/
vector<call_order_object> get_call_orders(asset_id_type a, uint32_t limit)const;
vector<call_order_object> get_call_orders(const std::string& a, uint32_t limit)const;
/**
* @brief Get forced settlement orders in a given asset
* @param a ID of asset being settled
* @param a ID or name of asset being settled
* @param limit Maximum number of orders to retrieve
* @return The settle orders, ordered from earliest settlement date to latest
*/
vector<force_settlement_object> get_settle_orders(asset_id_type a, uint32_t limit)const;
vector<force_settlement_object> get_settle_orders(const std::string& a, uint32_t limit)const;
/**
* @return all open margin positions for a given account id.
*/
vector<call_order_object> get_margin_positions( const account_id_type& id )const;
vector<call_order_object> get_margin_positions( const std::string account_id_or_name )const;
/**
* @brief Request notification when the active orders in the market between two assets changes
* @param callback Callback method which is called when the market changes
* @param a First asset ID
* @param b Second asset ID
* @param a First asset ID or name
* @param b Second asset ID or name
*
* Callback will be passed a variant containing a vector<pair<operation, operation_result>>. The vector will
* contain, in order, the operations which changed the market, and their results.
*/
void subscribe_to_market(std::function<void(const variant&)> callback,
asset_id_type a, asset_id_type b);
const std::string& a, const std::string& b);
/**
* @brief Unsubscribe from updates to a given market
* @param a First asset ID
* @param b Second asset ID
* @param a First asset ID or name
* @param b Second asset ID or name
*/
void unsubscribe_from_market( asset_id_type a, asset_id_type b );
void unsubscribe_from_market( const std::string& a, const std::string& b );
/**
* @brief Returns the ticker for the market assetA:assetB
@ -519,7 +551,7 @@ class database_api
* @param account The ID of the account whose witness should be retrieved
* @return The witness object, or null if the account does not have a witness
*/
fc::optional<witness_object> get_witness_by_account(account_id_type account)const;
fc::optional<witness_object> get_witness_by_account(const std::string account_name_or_id)const;
/**
* @brief Get names and IDs for registered witnesses
@ -549,10 +581,10 @@ class database_api
/**
* @brief Get the committee_member owned by a given account
* @param account The ID of the account whose committee_member should be retrieved
* @param account_id_or_name The ID or name of the account whose committee_member should be retrieved
* @return The committee_member object, or null if the account does not have a committee_member
*/
fc::optional<committee_member_object> get_committee_member_by_account(account_id_type account)const;
fc::optional<committee_member_object> get_committee_member_by_account(const std::string account_id_or_name)const;
/**
* @brief Get names and IDs for registered committee_members
@ -566,9 +598,11 @@ class database_api
/// WORKERS
/**
* Return the worker objects associated with this account.
* @brief Return the worker objects associated with this account.
* @param account_id_or_name The ID or name of the account whose worker should be retrieved
* @return The worker object or null if the account does not have a worker
*/
vector<worker_object> get_workers_by_account(account_id_type account)const;
vector<worker_object> get_workers_by_account(const std::string account_id_or_name)const;
///////////
@ -625,7 +659,7 @@ class database_api
* For each operation calculate the required fee in the specified asset type. If the asset type does
* not have a valid core_exchange_rate
*/
vector< fc::variant > get_required_fees( const vector<operation>& ops, asset_id_type id )const;
vector< fc::variant > get_required_fees( const vector<operation>& ops, const std::string& asset_id_or_symbol )const;
///////////////////////////
// Proposed transactions //
@ -634,7 +668,7 @@ class database_api
/**
* @return the set of proposed transactions relevant to the specified account id.
*/
vector<proposal_object> get_proposed_transactions( account_id_type id )const;
vector<proposal_object> get_proposed_transactions( const std::string account_id_or_name )const;
//////////////////////
// Blinded balances //
@ -667,17 +701,31 @@ class database_api
*/
vector<tournament_id_type> get_registered_tournaments(account_id_type account_filter, uint32_t limit) const;
private:
//////////
// GPOS //
//////////
/**
* @return account and network GPOS information
*/
gpos_info get_gpos_info(const account_id_type account) const;
private:
std::shared_ptr< database_api_impl > my;
};
} }
extern template class fc::api<graphene::app::database_api>;
FC_REFLECT( graphene::app::order, (price)(quote)(base) );
FC_REFLECT( graphene::app::order_book, (base)(quote)(bids)(asks) );
FC_REFLECT( graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highest_bid)(percent_change)(base_volume)(quote_volume) );
FC_REFLECT( graphene::app::market_volume, (base)(quote)(base_volume)(quote_volume) );
FC_REFLECT( graphene::app::market_trade, (date)(price)(amount)(value) );
FC_REFLECT( graphene::app::gpos_info, (vesting_factor)(award)(total_amount)(current_subperiod)(last_voted_time)(allowed_withdraw_amount)(account_vested_balance) );
FC_API(graphene::app::database_api,
// Objects
@ -708,6 +756,7 @@ FC_API(graphene::app::database_api,
(is_public_key_registered)
// Accounts
(get_account_id_from_string)
(get_accounts)
(get_full_accounts)
(get_account_by_name)
@ -727,6 +776,8 @@ FC_API(graphene::app::database_api,
(get_assets)
(list_assets)
(lookup_asset_symbols)
(get_asset_count)
(get_asset_id_from_string)
// Peerplays
(list_sports)
@ -794,4 +845,7 @@ FC_API(graphene::app::database_api,
(get_tournaments_by_state)
(get_tournaments )
(get_registered_tournaments)
// gpos
(get_gpos_info)
)

View file

@ -121,16 +121,24 @@ class plugin : public abstract_plugin
/// @group Some useful tools for boost::program_options arguments using vectors of JSON strings
/// @{
template<typename T>
T dejsonify(const string& s)
T dejsonify(const string& s, uint32_t max_depth)
{
return fc::json::from_string(s).as<T>();
return fc::json::from_string(s).as<T>(max_depth);
}
namespace impl {
template<typename T>
T dejsonify( const string& s )
{
return graphene::app::dejsonify<T>( s, GRAPHENE_MAX_NESTED_OBJECTS );
}
}
#define DEFAULT_VALUE_VECTOR(value) default_value({fc::json::to_string(value)}, fc::json::to_string(value))
#define LOAD_VALUE_SET(options, name, container, type) \
if( options.count(name) ) { \
const std::vector<std::string>& ops = options[name].as<std::vector<std::string>>(); \
std::transform(ops.begin(), ops.end(), std::inserter(container, container.end()), &graphene::app::dejsonify<type>); \
std::transform(ops.begin(), ops.end(), std::inserter(container, container.end()), &graphene::app::impl::dejsonify<type>); \
}
/// @}

View file

@ -60,6 +60,7 @@ add_library( graphene_chain
protocol/confidential.cpp
protocol/vote.cpp
protocol/tournament.cpp
protocol/small_ops.cpp
genesis_state.cpp
get_config.cpp
@ -93,6 +94,7 @@ add_library( graphene_chain
fba_object.cpp
proposal_object.cpp
vesting_balance_object.cpp
small_objects.cpp
block_database.cpp

View file

@ -162,33 +162,39 @@ object_id_type account_create_evaluator::do_apply( const account_create_operatio
if( referrer_percent > GRAPHENE_100_PERCENT )
referrer_percent = GRAPHENE_100_PERCENT;
}
const auto& global_properties = d.get_global_properties();
const auto& new_acnt_object = db().create<account_object>( [&]( account_object& obj ){
obj.registrar = o.registrar;
obj.referrer = o.referrer;
obj.lifetime_referrer = o.referrer(db()).lifetime_referrer;
const auto& new_acnt_object = d.create<account_object>( [&o,&d,&global_properties,referrer_percent]( account_object& obj )
{
obj.registrar = o.registrar;
obj.referrer = o.referrer;
obj.lifetime_referrer = o.referrer(d).lifetime_referrer;
auto& params = db().get_global_properties().parameters;
obj.network_fee_percentage = params.network_percent_of_fee;
obj.lifetime_referrer_fee_percentage = params.lifetime_referrer_percent_of_fee;
obj.referrer_rewards_percentage = referrer_percent;
const auto& params = global_properties.parameters;
obj.network_fee_percentage = params.network_percent_of_fee;
obj.lifetime_referrer_fee_percentage = params.lifetime_referrer_percent_of_fee;
obj.referrer_rewards_percentage = referrer_percent;
obj.name = o.name;
obj.owner = o.owner;
obj.active = o.active;
obj.options = o.options;
obj.statistics = db().create<account_statistics_object>([&](account_statistics_object& s){s.owner = obj.id;}).id;
obj.name = o.name;
obj.owner = o.owner;
obj.active = o.active;
obj.options = o.options;
obj.statistics = d.create<account_statistics_object>([&obj](account_statistics_object& s){
s.owner = obj.id;
s.name = obj.name;
s.is_voting = obj.options.is_voting();
}).id;
if( o.extensions.value.owner_special_authority.valid() )
obj.owner_special_authority = *(o.extensions.value.owner_special_authority);
if( o.extensions.value.active_special_authority.valid() )
obj.active_special_authority = *(o.extensions.value.active_special_authority);
if( o.extensions.value.buyback_options.valid() )
{
obj.allowed_assets = o.extensions.value.buyback_options->markets;
obj.allowed_assets->emplace( o.extensions.value.buyback_options->asset_to_buy );
}
obj.affiliate_distributions = o.extensions.value.affiliate_distributions;
if( o.extensions.value.owner_special_authority.valid() )
obj.owner_special_authority = *(o.extensions.value.owner_special_authority);
if( o.extensions.value.active_special_authority.valid() )
obj.active_special_authority = *(o.extensions.value.active_special_authority);
if( o.extensions.value.buyback_options.valid() )
{
obj.allowed_assets = o.extensions.value.buyback_options->markets;
obj.allowed_assets->emplace( o.extensions.value.buyback_options->asset_to_buy );
}
obj.affiliate_distributions = o.extensions.value.affiliate_distributions;
});
if( has_small_percent )
@ -200,17 +206,18 @@ object_id_type account_create_evaluator::do_apply( const account_create_operatio
wlog( "Affected account object is ${o}", ("o", new_acnt_object) );
}
const auto& dynamic_properties = db().get_dynamic_global_properties();
db().modify(dynamic_properties, [](dynamic_global_property_object& p) {
const auto& dynamic_properties = d.get_dynamic_global_properties();
d.modify(dynamic_properties, [](dynamic_global_property_object& p) {
++p.accounts_registered_this_interval;
});
const auto& global_properties = db().get_global_properties();
if( dynamic_properties.accounts_registered_this_interval %
global_properties.parameters.accounts_per_fee_scale == 0 )
db().modify(global_properties, [&dynamic_properties](global_property_object& p) {
if( dynamic_properties.accounts_registered_this_interval % global_properties.parameters.accounts_per_fee_scale == 0
&& global_properties.parameters.account_fee_scale_bitshifts != 0 )
{
d.modify(global_properties, [&dynamic_properties](global_property_object& p) {
p.parameters.current_fees->get<account_create_operation>().basic_fee <<= p.parameters.account_fee_scale_bitshifts;
});
}
if( o.extensions.value.owner_special_authority.valid()
|| o.extensions.value.active_special_authority.valid() )
@ -280,18 +287,26 @@ void_result account_update_evaluator::do_apply( const account_update_operation&
{ try {
database& d = db();
bool sa_before = acnt->has_special_authority();
// update account statistics
if( o.new_options.valid() )
{
d.modify( acnt->statistics( d ), [&]( account_statistics_object& aso )
{
fc::optional< bool > flag = o.extensions.value.update_last_voting_time;
if((o.new_options->votes != acnt->options.votes ||
o.new_options->voting_account != acnt->options.voting_account))
o.new_options->voting_account != acnt->options.voting_account) ||
(flag.valid() && *flag))
aso.last_vote_time = d.head_block_time();
if(o.new_options->is_voting() != acnt->options.is_voting())
aso.is_voting = !aso.is_voting;
} );
}
bool sa_before, sa_after;
d.modify( *acnt, [&](account_object& a){
// update account object
d.modify( *acnt, [&o](account_object& a){
if( o.owner )
{
a.owner = *o.owner;
@ -303,7 +318,6 @@ void_result account_update_evaluator::do_apply( const account_update_operation&
a.top_n_control_flags = 0;
}
if( o.new_options ) a.options = *o.new_options;
sa_before = a.has_special_authority();
if( o.extensions.value.owner_special_authority.valid() )
{
a.owner_special_authority = *(o.extensions.value.owner_special_authority);
@ -314,9 +328,10 @@ void_result account_update_evaluator::do_apply( const account_update_operation&
a.active_special_authority = *(o.extensions.value.active_special_authority);
a.top_n_control_flags = 0;
}
sa_after = a.has_special_authority();
});
bool sa_after = acnt->has_special_authority();
if( sa_before & (!sa_after) )
{
const auto& sa_idx = d.get_index_type< special_authority_index >().indices().get<by_account>();

View file

@ -22,9 +22,9 @@
* THE SOFTWARE.
*/
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/hardfork.hpp>
#include <fc/io/raw.hpp>
#include <fc/uint128.hpp>
namespace graphene { namespace chain {
@ -46,6 +46,8 @@ void account_balance_object::adjust_balance(const asset& delta)
{
assert(delta.asset_id == asset_type);
balance += delta.amount;
if( asset_type == asset_id_type() ) // CORE asset
maintenance_flag = true;
}
void account_statistics_object::process_fees(const account_object& a, database& d) const
@ -57,8 +59,8 @@ void account_statistics_object::process_fees(const account_object& a, database&
// Check the referrer -- if he's no longer a member, pay to the lifetime referrer instead.
// No need to check the registrar; registrars are required to be lifetime members.
if( account.referrer(d).is_basic_account(d.head_block_time()) )
d.modify(account, [](account_object& a) {
a.referrer = a.lifetime_referrer;
d.modify( account, [](account_object& acc) {
acc.referrer = acc.lifetime_referrer;
});
share_type network_cut = cut_fee(core_fee_total, account.network_fee_percentage);
@ -74,8 +76,8 @@ void account_statistics_object::process_fees(const account_object& a, database&
share_type lifetime_cut = cut_fee(core_fee_total, account.lifetime_referrer_fee_percentage);
share_type referral = core_fee_total - network_cut - lifetime_cut;
d.modify(asset_dynamic_data_id_type()(d), [network_cut](asset_dynamic_data_object& d) {
d.accumulated_fees += network_cut;
d.modify( d.get_core_dynamic_data(), [network_cut](asset_dynamic_data_object& addo) {
addo.accumulated_fees += network_cut;
});
// Potential optimization: Skip some of this math and object lookups by special casing on the account type.
@ -267,4 +269,59 @@ void account_referrer_index::object_modified( const object& after )
{
}
const uint8_t balances_by_account_index::bits = 20;
const uint64_t balances_by_account_index::mask = (1ULL << balances_by_account_index::bits) - 1;
void balances_by_account_index::object_inserted( const object& obj )
{
const auto& abo = dynamic_cast< const account_balance_object& >( obj );
while( balances.size() < (abo.owner.instance.value >> bits) + 1 )
{
balances.reserve( (abo.owner.instance.value >> bits) + 1 );
balances.resize( balances.size() + 1 );
balances.back().resize( 1ULL << bits );
}
balances[abo.owner.instance.value >> bits][abo.owner.instance.value & mask][abo.asset_type] = &abo;
}
void balances_by_account_index::object_removed( const object& obj )
{
const auto& abo = dynamic_cast< const account_balance_object& >( obj );
if( balances.size() < (abo.owner.instance.value >> bits) + 1 ) return;
balances[abo.owner.instance.value >> bits][abo.owner.instance.value & mask].erase( abo.asset_type );
}
void balances_by_account_index::about_to_modify( const object& before )
{
ids_being_modified.emplace( before.id );
}
void balances_by_account_index::object_modified( const object& after )
{
FC_ASSERT( ids_being_modified.top() == after.id, "Modification of ID is not supported!");
ids_being_modified.pop();
}
const map< asset_id_type, const account_balance_object* >& balances_by_account_index::get_account_balances( const account_id_type& acct )const
{
static const map< asset_id_type, const account_balance_object* > _empty;
if( balances.size() < (acct.instance.value >> bits) + 1 ) return _empty;
return balances[acct.instance.value >> bits][acct.instance.value & mask];
}
const account_balance_object* balances_by_account_index::get_account_balance( const account_id_type& acct, const asset_id_type& asset )const
{
if( balances.size() < (acct.instance.value >> bits) + 1 ) return nullptr;
const auto& mine = balances[acct.instance.value >> bits][acct.instance.value & mask];
const auto itr = mine.find( asset );
if( mine.end() == itr ) return nullptr;
return itr->second;
}
} } // graphene::chain
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_object )
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_balance_object )
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_statistics_object )
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::pending_dividend_payout_balance_for_holder_object )

View file

@ -133,33 +133,36 @@ void asset_create_evaluator::pay_fee()
object_id_type asset_create_evaluator::do_apply( const asset_create_operation& op )
{ try {
database& d = db();
// includes changes from bitshares. (https://github.com/bitshares/bitshares-core/issues/429)
bool hf_429 = fee_is_odd && db().head_block_time() > HARDFORK_CORE_429_TIME;
const asset_dynamic_data_object& dyn_asset =
db().create<asset_dynamic_data_object>( [&]( asset_dynamic_data_object& a ) {
d.create<asset_dynamic_data_object>( [hf_429,this]( asset_dynamic_data_object& a ) {
a.current_supply = 0;
a.fee_pool = core_fee_paid - (hf_429 ? 1 : 0);
});
if( fee_is_odd && !hf_429 )
{
const auto& core_dd = db().get<asset_object>( asset_id_type() ).dynamic_data( db() );
db().modify( core_dd, [=]( asset_dynamic_data_object& dd ) {
if( fee_is_odd && !hf_429 )
{
const auto& core_dd = d.get_core_asset().dynamic_data( d );
d.modify( core_dd, []( asset_dynamic_data_object& dd ) {
dd.current_supply++;
});
}
});
}
auto next_asset_id = d.get_index_type<asset_index>().get_next_id();
asset_bitasset_data_id_type bit_asset_id;
if( op.bitasset_opts.valid() )
bit_asset_id = db().create<asset_bitasset_data_object>( [&]( asset_bitasset_data_object& a ) {
bit_asset_id = d.create<asset_bitasset_data_object>( [&]( asset_bitasset_data_object& a ) {
a.options = *op.bitasset_opts;
a.is_prediction_market = op.is_prediction_market;
a.asset_id = next_asset_id;
}).id;
auto next_asset_id = db().get_index_type<asset_index>().get_next_id();
const asset_object& new_asset =
db().create<asset_object>( [&]( asset_object& a ) {
d.create<asset_object>( [&]( asset_object& a ) {
a.issuer = op.issuer;
a.symbol = op.symbol;
a.precision = op.precision;
@ -175,7 +178,7 @@ object_id_type asset_create_evaluator::do_apply( const asset_create_operation& o
if( op.bitasset_opts.valid() )
a.bitasset_data_id = bit_asset_id;
});
assert( new_asset.id == next_asset_id );
FC_ASSERT( new_asset.id == next_asset_id );
return new_asset.id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
@ -281,33 +284,36 @@ void lottery_asset_create_evaluator::pay_fee()
object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_create_operation& op )
{ try {
database& d = db();
// includes changes from bitshares. (https://github.com/bitshares/bitshares-core/issues/429)
bool hf_429 = fee_is_odd && db().head_block_time() > HARDFORK_CORE_429_TIME;
bool hf_429 = fee_is_odd && d.head_block_time() > HARDFORK_CORE_429_TIME;
const asset_dynamic_data_object& dyn_asset =
db().create<asset_dynamic_data_object>( [&]( asset_dynamic_data_object& a ) {
d.create<asset_dynamic_data_object>( [&]( asset_dynamic_data_object& a ) {
a.current_supply = 0;
a.fee_pool = core_fee_paid - (hf_429 ? 1 : 0);
});
if( fee_is_odd && !hf_429 )
{
const auto& core_dd = db().get<asset_object>( asset_id_type() ).dynamic_data( db() );
db().modify( core_dd, [=]( asset_dynamic_data_object& dd ) {
const auto& core_dd = d.get<asset_object>( asset_id_type() ).dynamic_data( db() );
d.modify( core_dd, [=]( asset_dynamic_data_object& dd ) {
dd.current_supply++;
});
}
auto next_asset_id = d.get_index_type<asset_index>().get_next_id();
asset_bitasset_data_id_type bit_asset_id;
if( op.bitasset_opts.valid() )
bit_asset_id = db().create<asset_bitasset_data_object>( [&]( asset_bitasset_data_object& a ) {
bit_asset_id = d.create<asset_bitasset_data_object>( [&op,next_asset_id]( asset_bitasset_data_object& a ) {
a.options = *op.bitasset_opts;
a.is_prediction_market = op.is_prediction_market;
a.asset_id = next_asset_id;
}).id;
auto next_asset_id = db().get_index_type<asset_index>().get_next_id();
const asset_object& new_asset =
db().create<asset_object>( [&]( asset_object& a ) {
d.create<asset_object>( [&op,next_asset_id,&dyn_asset,bit_asset_id,&d]( asset_object& a ) {
a.issuer = op.issuer;
a.symbol = op.symbol;
a.precision = op.precision;
@ -316,7 +322,7 @@ object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_cre
a.lottery_options = op.extensions;
//a.lottery_options->balance = asset( 0, a.lottery_options->ticket_price.asset_id );
a.lottery_options->owner = a.id;
db().create<lottery_balance_object>([&](lottery_balance_object& lbo) {
d.create<lottery_balance_object>([&a](lottery_balance_object& lbo) {
lbo.lottery_id = a.id;
});
if( a.options.core_exchange_rate.base.asset_id.instance.value == 0 )
@ -327,7 +333,7 @@ object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_cre
if( op.bitasset_opts.valid() )
a.bitasset_data_id = bit_asset_id;
});
assert( new_asset.id == next_asset_id );
FC_ASSERT( new_asset.id == next_asset_id, "Unexpected object database error, object id mismatch" );
return new_asset.id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
@ -354,7 +360,7 @@ void_result asset_issue_evaluator::do_apply( const asset_issue_operation& o )
{ try {
db().adjust_balance( o.issue_to_account, o.asset_to_issue );
db().modify( *asset_dyn_data, [&]( asset_dynamic_data_object& data ){
db().modify( *asset_dyn_data, [&o]( asset_dynamic_data_object& data ){
data.current_supply += o.asset_to_issue.amount;
});
@ -386,7 +392,7 @@ void_result asset_reserve_evaluator::do_apply( const asset_reserve_operation& o
{ try {
db().adjust_balance( o.payer, -o.amount_to_reserve );
db().modify( *asset_dyn_data, [&]( asset_dynamic_data_object& data ){
db().modify( *asset_dyn_data, [&o]( asset_dynamic_data_object& data ){
data.current_supply -= o.amount_to_reserve.amount;
});
@ -408,7 +414,7 @@ void_result asset_fund_fee_pool_evaluator::do_apply(const asset_fund_fee_pool_op
{ try {
db().adjust_balance(o.from_account, -o.amount);
db().modify( *asset_dyn_data, [&]( asset_dynamic_data_object& data ) {
db().modify( *asset_dyn_data, [&o]( asset_dynamic_data_object& data ) {
data.fee_pool += o.amount;
});
@ -483,7 +489,21 @@ void_result asset_update_evaluator::do_apply(const asset_update_operation& o)
d.cancel_order(*itr);
}
d.modify(*asset_to_update, [&](asset_object& a) {
// For market-issued assets, if core change rate changed, update flag in bitasset data
if( asset_to_update->is_market_issued()
&& asset_to_update->options.core_exchange_rate != o.new_options.core_exchange_rate )
{
const auto& bitasset = asset_to_update->bitasset_data(d);
if( !bitasset.asset_cer_updated )
{
d.modify( bitasset, [](asset_bitasset_data_object& b)
{
b.asset_cer_updated = true;
});
}
}
d.modify(*asset_to_update, [&o](asset_object& a) {
if( o.new_issuer )
a.issuer = *o.new_issuer;
a.options = o.new_options;

View file

@ -24,10 +24,9 @@
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/database.hpp>
#include <fc/io/raw.hpp>
#include <fc/uint128.hpp>
#include <cmath>
using namespace graphene::chain;
share_type asset_bitasset_data_object::max_force_settlement_volume(share_type current_supply) const
@ -61,12 +60,15 @@ void asset_bitasset_data_object::update_median_feeds(time_point_sec current_time
if( current_feeds.size() < options.minimum_feeds )
{
//... don't calculate a median, and set a null feed
feed_cer_updated = false; // new median cer is null, won't update asset_object anyway, set to false for better performance
current_feed_publication_time = current_time;
current_feed = price_feed();
return;
}
if( current_feeds.size() == 1 )
{
if( current_feed.core_exchange_rate != current_feeds.front().get().core_exchange_rate )
feed_cer_updated = true;
current_feed = std::move(current_feeds.front());
return;
}
@ -85,6 +87,8 @@ void asset_bitasset_data_object::update_median_feeds(time_point_sec current_time
#undef CALCULATE_MEDIAN_VALUE
// *** End Median Calculations ***
if( current_feed.core_exchange_rate != median_feed.core_exchange_rate )
feed_cer_updated = true;
current_feed = median_feed;
}
@ -291,3 +295,11 @@ void sweeps_vesting_balance_object::adjust_balance( const asset& delta )
FC_ASSERT( delta.asset_id == asset_id );
balance += delta.amount.value;
}
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_dynamic_data_object )
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_bitasset_data_object )
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_dividend_data_object )
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::total_distributed_dividend_balance_object )
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_object )
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::lottery_balance_object )
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::sweeps_vesting_balance_object )

View file

@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include <graphene/chain/balance_evaluator.hpp>
#include <graphene/chain/pts_address.hpp>
namespace graphene { namespace chain {

View file

@ -543,35 +543,35 @@ void betting_market_group_object::dispatch_new_status(database& db, betting_mark
namespace fc {
// Manually reflect betting_market_group_object to variant to properly reflect "state"
void to_variant(const graphene::chain::betting_market_group_object& betting_market_group_obj, fc::variant& v)
void to_variant(const graphene::chain::betting_market_group_object& betting_market_group_obj, fc::variant& v, uint32_t max_depth)
{
fc::mutable_variant_object o;
o("id", betting_market_group_obj.id)
("description", betting_market_group_obj.description)
("event_id", betting_market_group_obj.event_id)
("rules_id", betting_market_group_obj.rules_id)
("asset_id", betting_market_group_obj.asset_id)
("total_matched_bets_amount", betting_market_group_obj.total_matched_bets_amount)
("never_in_play", betting_market_group_obj.never_in_play)
("delay_before_settling", betting_market_group_obj.delay_before_settling)
("settling_time", betting_market_group_obj.settling_time)
("status", betting_market_group_obj.get_status());
o("id", fc::variant(betting_market_group_obj.id, max_depth))
("description", fc::variant(betting_market_group_obj.description, max_depth))
("event_id", fc::variant(betting_market_group_obj.event_id, max_depth))
("rules_id", fc::variant(betting_market_group_obj.rules_id, max_depth))
("asset_id", fc::variant(betting_market_group_obj.asset_id, max_depth))
("total_matched_bets_amount", fc::variant(betting_market_group_obj.total_matched_bets_amount, max_depth))
("never_in_play", fc::variant(betting_market_group_obj.never_in_play, max_depth))
("delay_before_settling", fc::variant(betting_market_group_obj.delay_before_settling, max_depth))
("settling_time", fc::variant(betting_market_group_obj.settling_time, max_depth))
("status", fc::variant(betting_market_group_obj.get_status(), max_depth));
v = o;
}
// Manually reflect betting_market_group_object to variant to properly reflect "state"
void from_variant(const fc::variant& v, graphene::chain::betting_market_group_object& betting_market_group_obj)
void from_variant(const fc::variant& v, graphene::chain::betting_market_group_object& betting_market_group_obj, uint32_t max_depth)
{
betting_market_group_obj.id = v["id"].as<graphene::chain::betting_market_group_id_type>();
betting_market_group_obj.description = v["description"].as<graphene::chain::internationalized_string_type>();
betting_market_group_obj.event_id = v["event_id"].as<graphene::chain::event_id_type>();
betting_market_group_obj.asset_id = v["asset_id"].as<graphene::chain::asset_id_type>();
betting_market_group_obj.total_matched_bets_amount = v["total_matched_bets_amount"].as<graphene::chain::share_type>();
betting_market_group_obj.never_in_play = v["never_in_play"].as<bool>();
betting_market_group_obj.delay_before_settling = v["delay_before_settling"].as<uint32_t>();
betting_market_group_obj.settling_time = v["settling_time"].as<fc::optional<fc::time_point_sec>>();
graphene::chain::betting_market_group_status status = v["status"].as<graphene::chain::betting_market_group_status>();
betting_market_group_obj.id = v["id"].as<graphene::chain::betting_market_group_id_type>( max_depth );
betting_market_group_obj.description = v["description"].as<graphene::chain::internationalized_string_type>( max_depth );
betting_market_group_obj.event_id = v["event_id"].as<graphene::chain::event_id_type>( max_depth );
betting_market_group_obj.asset_id = v["asset_id"].as<graphene::chain::asset_id_type>( max_depth );
betting_market_group_obj.total_matched_bets_amount = v["total_matched_bets_amount"].as<graphene::chain::share_type>( max_depth );
betting_market_group_obj.never_in_play = v["never_in_play"].as<bool>( max_depth );
betting_market_group_obj.delay_before_settling = v["delay_before_settling"].as<uint32_t>( max_depth );
betting_market_group_obj.settling_time = v["settling_time"].as<fc::optional<fc::time_point_sec>>( max_depth );
graphene::chain::betting_market_group_status status = v["status"].as<graphene::chain::betting_market_group_status>( max_depth );
const_cast<int*>(betting_market_group_obj.my->state_machine.current_state())[0] = (int)status;
}
} //end namespace fc

View file

@ -468,28 +468,28 @@ void betting_market_object::on_canceled_event(database& db)
namespace fc {
// Manually reflect betting_market_object to variant to properly reflect "state"
void to_variant(const graphene::chain::betting_market_object& event_obj, fc::variant& v)
void to_variant(const graphene::chain::betting_market_object& event_obj, fc::variant& v, uint32_t max_depth)
{
fc::mutable_variant_object o;
o("id", event_obj.id)
("group_id", event_obj.group_id)
("description", event_obj.description)
("payout_condition", event_obj.payout_condition)
("resolution", event_obj.resolution)
("status", event_obj.get_status());
o("id", fc::variant(event_obj.id, max_depth) )
("group_id", fc::variant(event_obj.group_id, max_depth))
("description", fc::variant(event_obj.description, max_depth))
("payout_condition", fc::variant(event_obj.payout_condition, max_depth))
("resolution", fc::variant(event_obj.resolution, max_depth))
("status", fc::variant(event_obj.get_status(), max_depth));
v = o;
}
// Manually reflect betting_market_object to variant to properly reflect "state"
void from_variant(const fc::variant& v, graphene::chain::betting_market_object& event_obj)
void from_variant(const fc::variant& v, graphene::chain::betting_market_object& event_obj, uint32_t max_depth)
{
event_obj.id = v["id"].as<graphene::chain::betting_market_id_type>();
event_obj.group_id = v["name"].as<graphene::chain::betting_market_group_id_type>();
event_obj.description = v["description"].as<graphene::chain::internationalized_string_type>();
event_obj.payout_condition = v["payout_condition"].as<graphene::chain::internationalized_string_type>();
event_obj.resolution = v["resolution"].as<fc::optional<graphene::chain::betting_market_resolution_type>>();
graphene::chain::betting_market_status status = v["status"].as<graphene::chain::betting_market_status>();
event_obj.id = v["id"].as<graphene::chain::betting_market_id_type>( max_depth );
event_obj.group_id = v["name"].as<graphene::chain::betting_market_group_id_type>( max_depth );
event_obj.description = v["description"].as<graphene::chain::internationalized_string_type>( max_depth );
event_obj.payout_condition = v["payout_condition"].as<graphene::chain::internationalized_string_type>( max_depth );
event_obj.resolution = v["resolution"].as<fc::optional<graphene::chain::betting_market_resolution_type>>( max_depth );
graphene::chain::betting_market_status status = v["status"].as<graphene::chain::betting_market_status>( max_depth );
const_cast<int*>(event_obj.my->state_machine.current_state())[0] = (int)status;
}
} //end namespace fc

View file

@ -78,14 +78,6 @@ void_result committee_member_update_global_parameters_evaluator::do_evaluate(con
{ try {
FC_ASSERT(trx_state->_is_proposed_trx);
if( db().head_block_time() < HARDFORK_1000_TIME ) // TODO: remove after hf
FC_ASSERT( !o.new_parameters.extensions.value.min_bet_multiplier.valid()
&& !o.new_parameters.extensions.value.max_bet_multiplier.valid()
&& !o.new_parameters.extensions.value.betting_rake_fee_percentage.valid()
&& !o.new_parameters.extensions.value.permitted_betting_odds_increments.valid()
&& !o.new_parameters.extensions.value.live_betting_delay_time.valid(),
"Parameter extensions are not allowed yet!" );
dgpo = &db().get_global_properties();
if( o.new_parameters.extensions.value.min_bet_multiplier.valid()
&& !o.new_parameters.extensions.value.max_bet_multiplier.valid() )

View file

@ -34,11 +34,11 @@ namespace graphene { namespace chain {
asset database::get_balance(account_id_type owner, asset_id_type asset_id) const
{
auto& index = get_index_type<account_balance_index>().indices().get<by_account_asset>();
auto itr = index.find(boost::make_tuple(owner, asset_id));
if( itr == index.end() )
auto& index = get_index_type< primary_index< account_balance_index > >().get_secondary_index<balances_by_account_index>();
auto abo = index.get_account_balance( owner, asset_id );
if( !abo )
return asset(0, asset_id);
return itr->get_balance();
return abo->get_balance();
}
asset database::get_balance(const account_object& owner, const asset_object& asset_obj) const
@ -65,9 +65,9 @@ void database::adjust_balance(account_id_type account, asset delta )
if( delta.amount == 0 )
return;
auto& index = get_index_type<account_balance_index>().indices().get<by_account_asset>();
auto itr = index.find(boost::make_tuple(account, delta.asset_id));
if(itr == index.end())
auto& index = get_index_type< primary_index< account_balance_index > >().get_secondary_index<balances_by_account_index>();
auto abo = index.get_account_balance( account, delta.asset_id );
if( !abo )
{
FC_ASSERT( delta.amount > 0, "Insufficient Balance: ${a}'s balance of ${b} is less than required ${r}",
("a",account(*this).name)
@ -77,11 +77,14 @@ void database::adjust_balance(account_id_type account, asset delta )
b.owner = account;
b.asset_type = delta.asset_id;
b.balance = delta.amount.value;
if( b.asset_type == asset_id_type() ) // CORE asset
b.maintenance_flag = true;
});
} else {
if( delta.amount < 0 )
FC_ASSERT( itr->get_balance() >= -delta, "Insufficient Balance: ${a}'s balance of ${b} is less than required ${r}", ("a",account(*this).name)("b",to_pretty_string(itr->get_balance()))("r",to_pretty_string(-delta)));
modify(*itr, [delta](account_balance_object& b) {
FC_ASSERT( abo->get_balance() >= -delta, "Insufficient Balance: ${a}'s balance of ${b} is less than required ${r}",
("a",account(*this).name)("b",to_pretty_string(abo->get_balance()))("r",to_pretty_string(-delta)));
modify(*abo, [delta](account_balance_object& b) {
b.adjust_balance(delta);
});
}
@ -207,7 +210,7 @@ void database::deposit_cashback(const account_object& acct, share_type amount, b
acct.get_id() == GRAPHENE_TEMP_ACCOUNT )
{
// The blockchain's accounts do not get cashback; it simply goes to the reserve pool.
modify(get(asset_id_type()).dynamic_asset_data_id(*this), [amount](asset_dynamic_data_object& d) {
modify( get_core_dynamic_data(), [amount](asset_dynamic_data_object& d) {
d.current_supply -= amount;
});
return;
@ -222,10 +225,15 @@ void database::deposit_cashback(const account_object& acct, share_type amount, b
if( new_vbid.valid() )
{
modify( acct, [&]( account_object& _acct )
modify( acct, [&new_vbid]( account_object& _acct )
{
_acct.cashback_vb = *new_vbid;
} );
modify( acct.statistics( *this ), []( account_statistics_object& aso )
{
aso.has_cashback_vb = true;
} );
}
return;

View file

@ -345,6 +345,8 @@ processed_transaction database::push_proposal(const proposal_object& proposal)
size_t old_applied_ops_size = _applied_ops.size();
try {
if( _undo_db.size() >= _undo_db.max_size() )
_undo_db.set_max_size( _undo_db.size() + 1 );
auto session = _undo_db.start_undo_session(true);
for( auto& op : proposal.proposed_transaction.operations )
eval_state.operation_results.emplace_back(apply_operation(eval_state, op));
@ -498,7 +500,7 @@ signed_block database::_generate_block(
FC_ASSERT( fc::raw::pack_size(pending_block) <= get_global_properties().parameters.maximum_block_size );
}
push_block( pending_block, skip );
push_block( pending_block, skip | skip_transaction_signatures ); // skip authority check when pushing self-generated blocks
return pending_block;
} FC_CAPTURE_AND_RETHROW( (witness_id) ) }
@ -590,7 +592,7 @@ void database::_apply_block( const signed_block& next_block )
const witness_object& signing_witness = validate_block_header(skip, next_block);
const auto& global_props = get_global_properties();
const auto& dynamic_global_props = get<dynamic_global_property_object>(dynamic_global_property_id_type());
const auto& dynamic_global_props = get_dynamic_global_properties();
bool maint_needed = (dynamic_global_props.next_maintenance_time <= next_block.timestamp);
_current_block_num = next_block_num;
@ -598,6 +600,8 @@ void database::_apply_block( const signed_block& next_block )
_current_op_in_trx = 0;
_current_virtual_op = 0;
_issue_453_affected_assets.clear();
for( const auto& trx : next_block.transactions )
{
/* We do not need to push the undo state for each transaction
@ -636,7 +640,8 @@ void database::_apply_block( const signed_block& next_block )
clear_expired_transactions();
clear_expired_proposals();
clear_expired_orders();
update_expired_feeds();
update_expired_feeds(); // this will update expired feeds and some core exchange rates
update_core_exchange_rates(); // this will update remaining core exchange rates
update_withdraw_permissions();
update_tournaments();
update_betting_markets(next_block.timestamp);
@ -671,6 +676,19 @@ processed_transaction database::apply_transaction(const signed_transaction& trx,
return result;
}
class undo_size_restorer {
public:
undo_size_restorer( undo_database& db ) : _db( db ), old_max( db.max_size() ) {
_db.set_max_size( old_max * 2 );
}
~undo_size_restorer() {
_db.set_max_size( old_max );
}
private:
undo_database& _db;
size_t old_max;
};
processed_transaction database::_apply_transaction(const signed_transaction& trx)
{ try {
uint32_t skip = get_node_properties().skip_flags;
@ -729,6 +747,7 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
eval_state.operation_results.reserve(trx.operations.size());
const undo_size_restorer undo_guard( _undo_db );
//Finally process the operations
processed_transaction ptrx(trx);
_current_op_in_trx = 0;
@ -742,9 +761,9 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
ptrx.operation_results = std::move(eval_state.operation_results);
//Make sure the temp account has no non-zero balances
const auto& index = get_index_type<account_balance_index>().indices().get<by_account_asset>();
auto range = index.equal_range( boost::make_tuple( GRAPHENE_TEMP_ACCOUNT ) );
std::for_each(range.first, range.second, [](const account_balance_object& b) { FC_ASSERT(b.balance == 0); });
const auto& balances = get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >().get_account_balances( GRAPHENE_TEMP_ACCOUNT );
for( const auto b : balances )
FC_ASSERT(b.second->balance == 0);
return ptrx;
} FC_CAPTURE_AND_RETHROW( (trx) ) }

View file

@ -42,7 +42,7 @@ void database::debug_dump()
const asset_dynamic_data_object& core_asset_data = db.get_core_asset().dynamic_asset_data_id(db);
const auto& balance_index = db.get_index_type<account_balance_index>().indices();
const simple_index<account_statistics_object>& statistics_index = db.get_index_type<simple_index<account_statistics_object>>();
const auto& statistics_index = db.get_index_type<account_stats_index>().indices();
map<asset_id_type,share_type> total_balances;
map<asset_id_type,share_type> total_debts;
share_type core_in_orders;
@ -118,10 +118,10 @@ void debug_apply_update( database& db, const fc::variant_object& vo )
auto it_id = vo.find("id");
FC_ASSERT( it_id != vo.end() );
from_variant( it_id->value(), oid );
from_variant( it_id->value(), oid, GRAPHENE_MAX_NESTED_OBJECTS );
action = ( vo.size() == 1 ) ? db_action_delete : db_action_write;
from_variant( vo["id"], oid );
from_variant( vo["id"], oid, GRAPHENE_MAX_NESTED_OBJECTS );
if( vo.size() == 1 )
action = db_action_delete;
auto it_action = vo.find("_action" );
@ -143,25 +143,19 @@ void debug_apply_update( database& db, const fc::variant_object& vo )
switch( action )
{
case db_action_create:
/*
idx.create( [&]( object& obj )
{
idx.object_from_variant( vo, obj );
} );
*/
FC_ASSERT( false );
break;
case db_action_write:
db.modify( db.get_object( oid ), [&]( object& obj )
{
idx.object_default( obj );
idx.object_from_variant( vo, obj );
idx.object_from_variant( vo, obj, GRAPHENE_MAX_NESTED_OBJECTS );
} );
break;
case db_action_update:
db.modify( db.get_object( oid ), [&]( object& obj )
{
idx.object_from_variant( vo, obj );
idx.object_from_variant( vo, obj, GRAPHENE_MAX_NESTED_OBJECTS );
} );
break;
case db_action_delete:

View file

@ -37,22 +37,27 @@ namespace graphene { namespace chain {
const asset_object& database::get_core_asset() const
{
return get(asset_id_type());
return *_p_core_asset_obj;
}
const asset_dynamic_data_object& database::get_core_dynamic_data() const
{
return *_p_core_dynamic_data_obj;
}
const global_property_object& database::get_global_properties()const
{
return get( global_property_id_type() );
return *_p_global_prop_obj;
}
const chain_property_object& database::get_chain_properties()const
{
return get( chain_property_id_type() );
return *_p_chain_property_obj;
}
const dynamic_global_property_object& database::get_dynamic_global_properties() const
{
return get( dynamic_global_property_id_type() );
return *_p_dyn_global_prop_obj;
}
const fee_schedule& database::current_fee_schedule()const
@ -62,17 +67,17 @@ const fee_schedule& database::current_fee_schedule()const
time_point_sec database::head_block_time()const
{
return get( dynamic_global_property_id_type() ).time;
return get_dynamic_global_properties().time;
}
uint32_t database::head_block_num()const
{
return get( dynamic_global_property_id_type() ).head_block_number;
return get_dynamic_global_properties().head_block_number;
}
block_id_type database::head_block_id()const
{
return get( dynamic_global_property_id_type() ).head_block_id;
return get_dynamic_global_properties().head_block_id;
}
decltype( chain_parameters::block_interval ) database::block_interval( )const
@ -141,4 +146,17 @@ const std::vector<uint32_t> database::get_winner_numbers( asset_id_type for_asse
return result;
}
const account_statistics_object& database::get_account_stats_by_owner( account_id_type owner )const
{
auto& idx = get_index_type<account_stats_index>().indices().get<by_owner>();
auto itr = idx.find( owner );
FC_ASSERT( itr != idx.end(), "Can not find account statistics object for owner ${a}", ("a",owner) );
return *itr;
}
const witness_schedule_object& database::get_witness_schedule_object()const
{
return *_p_witness_schedule_obj;
}
} }

View file

@ -251,15 +251,15 @@ void database::initialize_indexes()
_undo_db.set_max_size( GRAPHENE_MIN_UNDO_HISTORY );
//Protocol object indexes
add_index< primary_index<asset_index> >();
add_index< primary_index<asset_index, 13> >(); // 8192 assets per chunk
add_index< primary_index<force_settlement_index> >();
auto acnt_index = add_index< primary_index<account_index> >();
auto acnt_index = add_index< primary_index<account_index, 20> >(); // ~1 million accounts per chunk
acnt_index->add_secondary_index<account_member_index>();
acnt_index->add_secondary_index<account_referrer_index>();
add_index< primary_index<committee_member_index> >();
add_index< primary_index<witness_index> >();
add_index< primary_index<committee_member_index, 8> >(); // 256 members per chunk
add_index< primary_index<witness_index, 10> >(); // 1024 witnesses per chunk
add_index< primary_index<limit_order_index > >();
add_index< primary_index<call_order_index > >();
@ -287,12 +287,15 @@ void database::initialize_indexes()
//Implementation object indexes
add_index< primary_index<transaction_index > >();
add_index< primary_index<account_balance_index > >();
add_index< primary_index<asset_bitasset_data_index > >();
auto bal_idx = add_index< primary_index<account_balance_index > >();
bal_idx->add_secondary_index<balances_by_account_index>();
add_index< primary_index<asset_bitasset_data_index, 13 > >(); // 8192
add_index< primary_index<asset_dividend_data_object_index > >();
add_index< primary_index<simple_index<global_property_object >> >();
add_index< primary_index<simple_index<dynamic_global_property_object >> >();
add_index< primary_index<simple_index<account_statistics_object >> >();
add_index< primary_index<account_stats_index > >();
add_index< primary_index<simple_index<asset_dynamic_data_object >> >();
add_index< primary_index<flat_index< block_summary_object >> >();
add_index< primary_index<simple_index<chain_property_object > > >();
@ -352,12 +355,19 @@ void database::init_genesis(const genesis_state_type& genesis_state)
n.owner.weight_threshold = 1;
n.active.weight_threshold = 1;
n.name = "committee-account";
n.statistics = create<account_statistics_object>( [&](account_statistics_object& s){ s.owner = n.id; }).id;
n.statistics = create<account_statistics_object>( [&n](account_statistics_object& s){
s.owner = n.id;
s.name = n.name;
s.core_in_balance = GRAPHENE_MAX_SHARE_SUPPLY;
}).id;
});
FC_ASSERT(committee_account.get_id() == GRAPHENE_COMMITTEE_ACCOUNT);
FC_ASSERT(create<account_object>([this](account_object& a) {
a.name = "witness-account";
a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).id;
a.statistics = create<account_statistics_object>([&a](account_statistics_object& s){
s.owner = a.id;
s.name = a.name;
}).id;
a.owner.weight_threshold = 1;
a.active.weight_threshold = 1;
a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_WITNESS_ACCOUNT;
@ -367,7 +377,10 @@ void database::init_genesis(const genesis_state_type& genesis_state)
}).get_id() == GRAPHENE_WITNESS_ACCOUNT);
FC_ASSERT(create<account_object>([this](account_object& a) {
a.name = "relaxed-committee-account";
a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).id;
a.statistics = create<account_statistics_object>([&a](account_statistics_object& s){
s.owner = a.id;
s.name = a.name;
}).id;
a.owner.weight_threshold = 1;
a.active.weight_threshold = 1;
a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_RELAXED_COMMITTEE_ACCOUNT;
@ -377,7 +390,10 @@ void database::init_genesis(const genesis_state_type& genesis_state)
}).get_id() == GRAPHENE_RELAXED_COMMITTEE_ACCOUNT);
FC_ASSERT(create<account_object>([this](account_object& a) {
a.name = "null-account";
a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).id;
a.statistics = create<account_statistics_object>([&a](account_statistics_object& s){
s.owner = a.id;
s.name = a.name;
}).id;
a.owner.weight_threshold = 1;
a.active.weight_threshold = 1;
a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_NULL_ACCOUNT;
@ -387,7 +403,10 @@ void database::init_genesis(const genesis_state_type& genesis_state)
}).get_id() == GRAPHENE_NULL_ACCOUNT);
FC_ASSERT(create<account_object>([this](account_object& a) {
a.name = "temp-account";
a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).id;
a.statistics = create<account_statistics_object>([&a](account_statistics_object& s){
s.owner = a.id;
s.name = a.name;
}).id;
a.owner.weight_threshold = 0;
a.active.weight_threshold = 0;
a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_TEMP_ACCOUNT;
@ -397,7 +416,10 @@ void database::init_genesis(const genesis_state_type& genesis_state)
}).get_id() == GRAPHENE_TEMP_ACCOUNT);
FC_ASSERT(create<account_object>([this](account_object& a) {
a.name = "proxy-to-self";
a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).id;
a.statistics = create<account_statistics_object>([&a](account_statistics_object& s){
s.owner = a.id;
s.name = a.name;
}).id;
a.owner.weight_threshold = 1;
a.active.weight_threshold = 1;
a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_NULL_ACCOUNT;
@ -407,7 +429,10 @@ void database::init_genesis(const genesis_state_type& genesis_state)
}).get_id() == GRAPHENE_PROXY_TO_SELF_ACCOUNT);
FC_ASSERT(create<account_object>([this](account_object& a) {
a.name = "default-dividend-distribution";
a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).id;
a.statistics = create<account_statistics_object>([&a](account_statistics_object& s){
s.owner = a.id;
s.name = a.name;
}).id;
a.owner.weight_threshold = 1;
a.active.weight_threshold = 1;
a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_PROXY_TO_SELF_ACCOUNT;
@ -421,9 +446,12 @@ void database::init_genesis(const genesis_state_type& genesis_state)
uint64_t id = get_index<account_object>().get_next_id().instance();
if( id >= genesis_state.immutable_parameters.num_special_accounts )
break;
const account_object& acct = create<account_object>([&](account_object& a) {
const account_object& acct = create<account_object>([this,id](account_object& a) {
a.name = "special-account-" + std::to_string(id);
a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).id;
a.statistics = create<account_statistics_object>([&a](account_statistics_object& s){
s.owner = a.id;
s.name = a.name;
}).id;
a.owner.weight_threshold = 1;
a.active.weight_threshold = 1;
a.registrar = a.lifetime_referrer = a.referrer = account_id_type(id);
@ -437,12 +465,12 @@ void database::init_genesis(const genesis_state_type& genesis_state)
// Create core asset
const asset_dynamic_data_object& dyn_asset =
create<asset_dynamic_data_object>([&](asset_dynamic_data_object& a) {
create<asset_dynamic_data_object>([](asset_dynamic_data_object& a) {
a.current_supply = GRAPHENE_MAX_SHARE_SUPPLY;
});
const asset_dividend_data_object& div_asset =
create<asset_dividend_data_object>([&](asset_dividend_data_object& a) {
create<asset_dividend_data_object>([&genesis_state](asset_dividend_data_object& a) {
a.options.minimum_distribution_interval = 3*24*60*60;
a.options.minimum_fee_percentage = 10*GRAPHENE_1_PERCENT;
a.options.next_payout_time = genesis_state.initial_timestamp + fc::days(1);
@ -451,7 +479,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
});
const asset_object& core_asset =
create<asset_object>( [&]( asset_object& a ) {
create<asset_object>( [&genesis_state,&div_asset,&dyn_asset]( asset_object& a ) {
a.symbol = GRAPHENE_SYMBOL;
a.options.max_supply = genesis_state.max_core_supply;
a.precision = GRAPHENE_BLOCKCHAIN_PRECISION_DIGITS;
@ -464,9 +492,12 @@ void database::init_genesis(const genesis_state_type& genesis_state)
a.options.core_exchange_rate.quote.asset_id = asset_id_type(0);
a.dynamic_asset_data_id = dyn_asset.id;
a.dividend_data_id = div_asset.id;
});
assert( asset_id_type(core_asset.id) == asset().asset_id );
assert( get_balance(account_id_type(), asset_id_type()) == asset(dyn_asset.current_supply) );
});
FC_ASSERT( dyn_asset.id == asset_dynamic_data_id_type() );
FC_ASSERT( asset_id_type(core_asset.id) == asset().asset_id );
FC_ASSERT( get_balance(account_id_type(), asset_id_type()) == asset(dyn_asset.current_supply) );
_p_core_asset_obj = &core_asset;
_p_core_dynamic_data_obj = &dyn_asset;
#ifdef _DEFAULT_DIVIDEND_ASSET
// Create default dividend asset
@ -499,7 +530,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
a.dynamic_asset_data_id = dyn_asset1.id;
a.dividend_data_id = div_asset1.id;
});
assert( default_asset.id == asset_id_type(1) );
FC_ASSERT( default_asset.id == asset_id_type(1) );
#endif
// Create more special assets
@ -509,10 +540,10 @@ void database::init_genesis(const genesis_state_type& genesis_state)
if( id >= genesis_state.immutable_parameters.num_special_assets )
break;
const asset_dynamic_data_object& dyn_asset =
create<asset_dynamic_data_object>([&](asset_dynamic_data_object& a) {
create<asset_dynamic_data_object>([](asset_dynamic_data_object& a) {
a.current_supply = 0;
});
const asset_object& asset_obj = create<asset_object>( [&]( asset_object& a ) {
const asset_object& asset_obj = create<asset_object>( [id,&dyn_asset]( asset_object& a ) {
a.symbol = "SPECIAL" + std::to_string( id );
a.options.max_supply = 0;
a.precision = GRAPHENE_BLOCKCHAIN_PRECISION_DIGITS;
@ -532,14 +563,14 @@ void database::init_genesis(const genesis_state_type& genesis_state)
chain_id_type chain_id = genesis_state.compute_chain_id();
// Create global properties
create<global_property_object>([&](global_property_object& p) {
_p_global_prop_obj = & create<global_property_object>([&genesis_state](global_property_object& p) {
p.parameters = genesis_state.initial_parameters;
// Set fees to zero initially, so that genesis initialization needs not pay them
// We'll fix it at the end of the function
p.parameters.current_fees->zero_all_fees();
});
create<dynamic_global_property_object>([&](dynamic_global_property_object& p) {
_p_dyn_global_prop_obj = & create<dynamic_global_property_object>([&genesis_state](dynamic_global_property_object& p) {
p.time = genesis_state.initial_timestamp;
p.dynamic_flags = 0;
p.witness_budget = 0;
@ -552,7 +583,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
FC_ASSERT( (genesis_state.immutable_parameters.min_witness_count & 1) == 1, "min_witness_count must be odd" );
FC_ASSERT( (genesis_state.immutable_parameters.min_committee_member_count & 1) == 1, "min_committee_member_count must be odd" );
create<chain_property_object>([&](chain_property_object& p)
_p_chain_property_obj = & create<chain_property_object>([chain_id,&genesis_state](chain_property_object& p)
{
p.chain_id = chain_id;
p.immutable_parameters = genesis_state.immutable_parameters;
@ -676,7 +707,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
cop.active = cop.owner;
account_id_type owner_account_id = apply_operation(genesis_eval_state, cop).get<object_id_type>();
modify( owner_account_id(*this).statistics(*this), [&]( account_statistics_object& o ) {
modify( owner_account_id(*this).statistics(*this), [&collateral_rec]( account_statistics_object& o ) {
o.total_core_in_orders = collateral_rec.collateral;
});
@ -739,7 +770,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
vbo.owner = get_account_id(account.name);
vbo.balance = asset(vesting_balance.amount, get_asset_id(vesting_balance.asset_symbol));
if (vesting_balance.policy_type == "linear") {
auto initial_linear_vesting_policy = vesting_balance.policy.as<genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy>();
auto initial_linear_vesting_policy = vesting_balance.policy.as<genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy>( 20 );
linear_vesting_policy new_vesting_policy;
new_vesting_policy.begin_timestamp = initial_linear_vesting_policy.begin_timestamp;
new_vesting_policy.vesting_cliff_seconds = initial_linear_vesting_policy.vesting_cliff_seconds;
@ -747,7 +778,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
new_vesting_policy.begin_balance = initial_linear_vesting_policy.begin_balance;
vbo.policy = new_vesting_policy;
} else if (vesting_balance.policy_type == "cdd") {
auto initial_cdd_vesting_policy = vesting_balance.policy.as<genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy>();
auto initial_cdd_vesting_policy = vesting_balance.policy.as<genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy>( 20 );
cdd_vesting_policy new_vesting_policy;
new_vesting_policy.vesting_seconds = initial_cdd_vesting_policy.vesting_seconds;
new_vesting_policy.coin_seconds_earned = initial_cdd_vesting_policy.coin_seconds_earned;
@ -892,7 +923,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
});
// Set active witnesses
modify(get_global_properties(), [&](global_property_object& p) {
modify(get_global_properties(), [&genesis_state](global_property_object& p) {
for( uint32_t i = 1; i <= genesis_state.initial_active_witnesses; ++i )
{
p.active_witnesses.insert(witness_id_type(i));
@ -900,10 +931,7 @@ void database::init_genesis(const genesis_state_type& genesis_state)
});
// Initialize witness schedule
#ifndef NDEBUG
const witness_schedule_object& wso =
#endif
create<witness_schedule_object>([&](witness_schedule_object& _wso)
_p_witness_schedule_obj = & create<witness_schedule_object>([this](witness_schedule_object& _wso)
{
// for scheduled
memset(_wso.rng_seed.begin(), 0, _wso.rng_seed.size());
@ -927,19 +955,13 @@ void database::init_genesis(const genesis_state_type& genesis_state)
for( const witness_id_type& wid : get_global_properties().active_witnesses )
_wso.current_shuffled_witnesses.push_back( wid );
});
assert( wso.id == witness_schedule_id_type() );
FC_ASSERT( _p_witness_schedule_obj->id == witness_schedule_id_type() );
// Enable fees
modify(get_global_properties(), [&genesis_state](global_property_object& p) {
p.parameters.current_fees = genesis_state.initial_parameters.current_fees;
});
// Create witness scheduler
//create<witness_schedule_object>([&]( witness_schedule_object& wso )
//{
// for( const witness_id_type& wid : get_global_properties().active_witnesses )
// wso.current_shuffled_witnesses.push_back( wid );
//});
// Create FBA counters
create<fba_accumulator_object>([&]( fba_accumulator_object& acc )

View file

@ -76,12 +76,44 @@ vector<std::reference_wrapper<const typename Index::object_type>> database::sort
return refs;
}
template<class... Types>
void database::perform_account_maintenance(std::tuple<Types...> helpers)
template<class Type>
void database::perform_account_maintenance(Type tally_helper)
{
const auto& idx = get_index_type<account_index>().indices().get<by_name>();
for( const account_object& a : idx )
detail::for_each(helpers, a, detail::gen_seq<sizeof...(Types)>());
const auto& bal_idx = get_index_type< account_balance_index >().indices().get< by_maintenance_flag >();
if( bal_idx.begin() != bal_idx.end() )
{
auto bal_itr = bal_idx.rbegin();
while( bal_itr->maintenance_flag )
{
const account_balance_object& bal_obj = *bal_itr;
modify( get_account_stats_by_owner( bal_obj.owner ), [&bal_obj](account_statistics_object& aso) {
aso.core_in_balance = bal_obj.balance;
});
modify( bal_obj, []( account_balance_object& abo ) {
abo.maintenance_flag = false;
});
bal_itr = bal_idx.rbegin();
}
}
const auto& stats_idx = get_index_type< account_stats_index >().indices().get< by_maintenance_seq >();
auto stats_itr = stats_idx.lower_bound( true );
while( stats_itr != stats_idx.end() )
{
const account_statistics_object& acc_stat = *stats_itr;
const account_object& acc_obj = acc_stat.owner( *this );
++stats_itr;
if( acc_stat.has_some_core_voting() )
tally_helper( acc_obj, acc_stat );
if( acc_stat.has_pending_fees() )
acc_stat.process_fees( acc_obj, *this );
}
}
/// @brief A visitor for @ref worker_type which calls pay_worker on the worker within
@ -119,12 +151,13 @@ void database::update_worker_votes()
void database::pay_workers( share_type& budget )
{
const auto head_time = head_block_time();
// ilog("Processing payroll! Available budget is ${b}", ("b", budget));
vector<std::reference_wrapper<const worker_object>> active_workers;
get_index_type<worker_index>().inspect_all_objects([this, &active_workers](const object& o) {
// TODO optimization: add by_expiration index to avoid iterating through all objects
get_index_type<worker_index>().inspect_all_objects([head_time, &active_workers](const object& o) {
const worker_object& w = static_cast<const worker_object&>(o);
auto now = head_block_time();
if( w.is_active(now) && w.approving_stake() > 0 )
if( w.is_active(head_time) && w.approving_stake() > 0 )
active_workers.emplace_back(w);
});
@ -138,17 +171,22 @@ void database::pay_workers( share_type& budget )
return wa.id < wb.id;
});
const auto last_budget_time = get_dynamic_global_properties().last_budget_time;
const auto passed_time_ms = head_time - last_budget_time;
const auto passed_time_count = passed_time_ms.count();
const auto day_count = fc::days(1).count();
for( uint32_t i = 0; i < active_workers.size() && budget > 0; ++i )
{
const worker_object& active_worker = active_workers[i];
share_type requested_pay = active_worker.daily_pay;
if( head_block_time() - get_dynamic_global_properties().last_budget_time != fc::days(1) )
{
fc::uint128 pay(requested_pay.value);
pay *= (head_block_time() - get_dynamic_global_properties().last_budget_time).count();
pay /= fc::days(1).count();
requested_pay = pay.to_uint64();
}
// Note: if there is a good chance that passed_time_count == day_count,
// for better performance, can avoid the 128 bit calculation by adding a check.
// Since it's not the case on BitShares mainnet, we're not using a check here.
fc::uint128 pay(requested_pay.value);
pay *= passed_time_count;
pay /= day_count;
requested_pay = pay.to_uint64();
share_type actual_pay = std::min(budget, requested_pay);
//ilog(" ==> Paying ${a} to worker ${w}", ("w", active_worker.id)("a", actual_pay));
@ -185,13 +223,27 @@ void database::update_active_witnesses()
const global_property_object& gpo = get_global_properties();
const auto& all_witnesses = get_index_type<witness_index>().indices();
auto update_witness_total_votes = [this]( const witness_object& wit ) {
modify( wit, [this]( witness_object& obj )
{
obj.total_votes = _vote_tally_buffer[obj.vote_id];
});
};
for( const witness_object& wit : all_witnesses )
if( _track_standby_votes )
{
modify( wit, [&]( witness_object& obj ){
obj.total_votes = _vote_tally_buffer[wit.vote_id];
});
const auto& all_witnesses = get_index_type<witness_index>().indices();
for( const witness_object& wit : all_witnesses )
{
update_witness_total_votes( wit );
}
}
else
{
for( const witness_object& wit : wits )
{
update_witness_total_votes( wit );
}
}
// Update witness authority
@ -267,11 +319,27 @@ void database::update_active_committee_members()
const chain_property_object& cpo = get_chain_properties();
auto committee_members = sort_votable_objects<committee_member_index>(std::max(committee_member_count*2+1, (size_t)cpo.immutable_parameters.min_committee_member_count));
for( const committee_member_object& del : committee_members )
auto update_committee_member_total_votes = [this]( const committee_member_object& cm ) {
modify( cm, [this]( committee_member_object& obj )
{
obj.total_votes = _vote_tally_buffer[obj.vote_id];
});
};
if( _track_standby_votes )
{
modify( del, [&]( committee_member_object& obj ){
obj.total_votes = _vote_tally_buffer[del.vote_id];
});
const auto& all_committee_members = get_index_type<committee_member_index>().indices();
for( const committee_member_object& cm : all_committee_members )
{
update_committee_member_total_votes( cm );
}
}
else
{
for( const committee_member_object& cm : committee_members )
{
update_committee_member_total_votes( cm );
}
}
// Update committee authorities
@ -329,8 +397,8 @@ void database::update_active_committee_members()
void database::initialize_budget_record( fc::time_point_sec now, budget_record& rec )const
{
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
const asset_object& core = asset_id_type(0)(*this);
const asset_dynamic_data_object& core_dd = core.dynamic_asset_data_id(*this);
const asset_object& core = get_core_asset();
const asset_dynamic_data_object& core_dd = get_core_dynamic_data();
rec.from_initial_reserve = core.reserved(*this);
rec.from_accumulated_fees = core_dd.accumulated_fees;
@ -383,8 +451,7 @@ void database::process_budget()
{
const global_property_object& gpo = get_global_properties();
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
const asset_dynamic_data_object& core =
asset_id_type(0)(*this).dynamic_asset_data_id(*this);
const asset_dynamic_data_object& core = get_core_dynamic_data();
fc::time_point_sec now = head_block_time();
int64_t time_to_maint = (dpo.next_maintenance_time - now).to_seconds();
@ -544,8 +611,7 @@ void split_fba_balance(
if( fba.accumulated_fba_fees == 0 )
return;
const asset_object& core = asset_id_type(0)(db);
const asset_dynamic_data_object& core_dd = core.dynamic_asset_data_id(db);
const asset_dynamic_data_object& core_dd = db.get_core_dynamic_data();
if( !fba.is_configured(db) )
{
@ -621,7 +687,7 @@ void distribute_fba_balances( database& db )
void create_buyback_orders( database& db )
{
const auto& bbo_idx = db.get_index_type< buyback_index >().indices().get<by_id>();
const auto& bal_idx = db.get_index_type< account_balance_index >().indices().get< by_account_asset >();
const auto& bal_idx = db.get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >();
for( const buyback_object& bbo : bbo_idx )
{
@ -629,7 +695,6 @@ void create_buyback_orders( database& db )
assert( asset_to_buy.buyback_account.valid() );
const account_object& buyback_account = (*(asset_to_buy.buyback_account))(db);
asset_id_type next_asset = asset_id_type();
if( !buyback_account.allowed_assets.valid() )
{
@ -637,16 +702,11 @@ void create_buyback_orders( database& db )
continue;
}
while( true )
for( const auto& entry : bal_idx.get_account_balances( buyback_account.id ) )
{
auto it = bal_idx.lower_bound( boost::make_tuple( buyback_account.id, next_asset ) );
if( it == bal_idx.end() )
break;
if( it->owner != buyback_account.id )
break;
const auto* it = entry.second;
asset_id_type asset_to_sell = it->asset_type;
share_type amount_to_sell = it->balance;
next_asset = asset_to_sell + 1;
if( asset_to_sell == asset_to_buy.id )
continue;
if( amount_to_sell == 0 )
@ -725,6 +785,154 @@ void deprecate_annual_members( database& db )
return;
}
uint32_t database::get_gpos_current_subperiod()
{
if(this->head_block_time() < HARDFORK_GPOS_TIME) //Can be deleted after GPOS hardfork time
return 0;
fc::time_point_sec last_date_voted;
const auto &gpo = this->get_global_properties();
const auto vesting_period = gpo.parameters.gpos_period();
const auto vesting_subperiod = gpo.parameters.gpos_subperiod();
const auto period_start = fc::time_point_sec(gpo.parameters.gpos_period_start());
// variables needed
const fc::time_point_sec period_end = period_start + vesting_period;
const auto number_of_subperiods = vesting_period / vesting_subperiod;
const auto now = this->head_block_time();
auto seconds_since_period_start = now.sec_since_epoch() - period_start.sec_since_epoch();
FC_ASSERT(period_start <= now && now <= period_end);
// get in what sub period we are
uint32_t current_subperiod = 0;
std::list<uint32_t> period_list(number_of_subperiods);
std::iota(period_list.begin(), period_list.end(), 1);
std::for_each(period_list.begin(), period_list.end(),[&](uint32_t period) {
if(seconds_since_period_start >= vesting_subperiod * (period - 1) &&
seconds_since_period_start < vesting_subperiod * period)
current_subperiod = period;
});
return current_subperiod;
}
double database::calculate_vesting_factor(const account_object& stake_account)
{
fc::time_point_sec last_date_voted;
// get last time voted form account stats
// check last_vote_time of proxy voting account if proxy is set
if (stake_account.options.voting_account == GRAPHENE_PROXY_TO_SELF_ACCOUNT)
last_date_voted = stake_account.statistics(*this).last_vote_time;
else
last_date_voted = stake_account.options.voting_account(*this).statistics(*this).last_vote_time;
// get global data related to gpos
const auto &gpo = this->get_global_properties();
const auto vesting_period = gpo.parameters.gpos_period();
const auto vesting_subperiod = gpo.parameters.gpos_subperiod();
const auto period_start = fc::time_point_sec(gpo.parameters.gpos_period_start());
// variables needed
const auto number_of_subperiods = vesting_period / vesting_subperiod;
double vesting_factor;
// get in what sub period we are
uint32_t current_subperiod = get_gpos_current_subperiod();
if(current_subperiod == 0 || current_subperiod > number_of_subperiods) return 0;
// On starting new vesting period, all votes become zero until someone votes, To avoid a situation of zero votes,
// changes were done to roll in GPOS rules, the vesting factor will be 1 for whoever votes in 6th sub-period of last vesting period
// BLOCKBACK-174 fix
if(current_subperiod == 1 && this->head_block_time() >= HARDFORK_GPOS_TIME + vesting_period) //Applicable only from 2nd vesting period
{
if(last_date_voted > period_start - vesting_subperiod)
return 1;
}
if(last_date_voted < period_start) return 0;
double numerator = number_of_subperiods;
if(current_subperiod > 1) {
std::list<uint32_t> subperiod_list(current_subperiod - 1);
std::iota(subperiod_list.begin(), subperiod_list.end(), 2);
subperiod_list.reverse();
for(auto subperiod: subperiod_list)
{
numerator--;
auto last_period_start = period_start + fc::seconds(vesting_subperiod * (subperiod - 1));
auto last_period_end = period_start + fc::seconds(vesting_subperiod * (subperiod));
if (last_date_voted > last_period_start && last_date_voted <= last_period_end) {
numerator++;
break;
}
}
}
vesting_factor = numerator / number_of_subperiods;
return vesting_factor;
}
share_type credit_account(database& db, const account_id_type owner_id, const std::string owner_name,
share_type remaining_amount_to_distribute,
const share_type shares_to_credit, const asset_id_type payout_asset_type,
const pending_dividend_payout_balance_for_holder_object_index& pending_payout_balance_index,
const asset_id_type dividend_id) {
//wdump((delta_balance.value)(holder_balance)(total_balance_of_dividend_asset));
if (shares_to_credit.value) {
remaining_amount_to_distribute -= shares_to_credit;
dlog("Crediting account ${account} with ${amount}",
("account", owner_name)
("amount", asset(shares_to_credit, payout_asset_type)));
auto pending_payout_iter =
pending_payout_balance_index.indices().get<by_dividend_payout_account>().find(
boost::make_tuple(dividend_id, payout_asset_type,
owner_id));
if (pending_payout_iter ==
pending_payout_balance_index.indices().get<by_dividend_payout_account>().end())
db.create<pending_dividend_payout_balance_for_holder_object>(
[&](pending_dividend_payout_balance_for_holder_object &obj) {
obj.owner = owner_id;
obj.dividend_holder_asset_type = dividend_id;
obj.dividend_payout_asset_type = payout_asset_type;
obj.pending_balance = shares_to_credit;
});
else
db.modify(*pending_payout_iter,
[&](pending_dividend_payout_balance_for_holder_object &pending_balance) {
pending_balance.pending_balance += shares_to_credit;
});
}
return remaining_amount_to_distribute;
}
void rolling_period_start(database& db)
{
if(db.head_block_time() >= HARDFORK_GPOS_TIME)
{
auto gpo = db.get_global_properties();
auto period_start = db.get_global_properties().parameters.gpos_period_start();
auto vesting_period = db.get_global_properties().parameters.gpos_period();
auto now = db.head_block_time();
if(now.sec_since_epoch() >= (period_start + vesting_period))
{
// roll
db.modify(db.get_global_properties(), [now](global_property_object& p) {
p.parameters.extensions.value.gpos_period_start = now.sec_since_epoch();
});
}
}
}
// Schedules payouts from a dividend distribution account to the current holders of the
// dividend-paying asset. This takes any deposits made to the dividend distribution account
// since the last time it was called, and distributes them to the current owners of the
@ -740,8 +948,10 @@ void schedule_pending_dividend_balances(database& db,
{ try {
dlog("Processing dividend payments for dividend holder asset type ${holder_asset} at time ${t}",
("holder_asset", dividend_holder_asset_obj.symbol)("t", db.head_block_time()));
auto balance_by_acc_index = db.get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >();
auto current_distribution_account_balance_range =
balance_index.indices().get<by_account_asset>().equal_range(boost::make_tuple(dividend_data.dividend_distribution_account));
//balance_index.indices().get<by_account_asset>().equal_range(boost::make_tuple(dividend_data.dividend_distribution_account));
balance_by_acc_index.get_account_balances(dividend_data.dividend_distribution_account);
auto previous_distribution_account_balance_range =
distributed_dividend_balance_index.indices().get<by_dividend_payout_asset>().equal_range(boost::make_tuple(dividend_holder_asset_obj.id));
// the current range is now all current balances for the distribution account, sorted by asset_type
@ -754,34 +964,42 @@ void schedule_pending_dividend_balances(database& db,
balance_index.indices().get<by_asset_balance>().lower_bound(boost::make_tuple(dividend_holder_asset_obj.id));
auto holder_balances_end =
balance_index.indices().get<by_asset_balance>().upper_bound(boost::make_tuple(dividend_holder_asset_obj.id, share_type()));
uint32_t holder_account_count = std::distance(holder_balances_begin, holder_balances_end);
uint64_t distribution_base_fee = gpo.parameters.current_fees->get<asset_dividend_distribution_operation>().distribution_base_fee;
uint32_t distribution_fee_per_holder = gpo.parameters.current_fees->get<asset_dividend_distribution_operation>().distribution_fee_per_holder;
// the fee, in BTS, for distributing each asset in the account
uint64_t total_fee_per_asset_in_core = distribution_base_fee + holder_account_count * (uint64_t)distribution_fee_per_holder;
std::map<account_id_type, share_type> vesting_amounts;
auto balance_type = vesting_balance_type::normal;
if(db.head_block_time() >= HARDFORK_GPOS_TIME)
balance_type = vesting_balance_type::gpos;
uint32_t holder_account_count = 0;
#ifdef USE_VESTING_OBJECT_BY_ASSET_BALANCE_INDEX
// get only once a collection of accounts that hold nonzero vesting balances of the dividend asset
auto vesting_balances_begin =
vesting_index.indices().get<by_asset_balance>().lower_bound(boost::make_tuple(dividend_holder_asset_obj.id));
vesting_index.indices().get<by_asset_balance>().lower_bound(boost::make_tuple(dividend_holder_asset_obj.id, balance_type));
auto vesting_balances_end =
vesting_index.indices().get<by_asset_balance>().upper_bound(boost::make_tuple(dividend_holder_asset_obj.id, share_type()));
vesting_index.indices().get<by_asset_balance>().upper_bound(boost::make_tuple(dividend_holder_asset_obj.id, balance_type, share_type()));
for (const vesting_balance_object& vesting_balance_obj : boost::make_iterator_range(vesting_balances_begin, vesting_balances_end))
{
vesting_amounts[vesting_balance_obj.owner] += vesting_balance_obj.balance.amount;
//dlog("Vesting balance for account: ${owner}, amount: ${amount}",
// ("owner", vesting_balance_obj.owner(db).name)
// ("amount", vesting_balance_obj.balance.amount));
++holder_account_count;
dlog("Vesting balance for account: ${owner}, amount: ${amount}",
("owner", vesting_balance_obj.owner(db).name)
("amount", vesting_balance_obj.balance.amount));
}
#else
// get only once a collection of accounts that hold nonzero vesting balances of the dividend asset
const auto& vesting_balances = vesting_index.indices().get<by_id>();
for (const vesting_balance_object& vesting_balance_obj : vesting_balances)
{
if (vesting_balance_obj.balance.asset_id == dividend_holder_asset_obj.id && vesting_balance_obj.balance.amount)
if (vesting_balance_obj.balance.asset_id == dividend_holder_asset_obj.id && vesting_balance_obj.balance.amount &&
vesting_balance_object.balance_type == balance_type)
{
vesting_amounts[vesting_balance_obj.owner] += vesting_balance_obj.balance.amount;
++gpos_holder_account_count;
dlog("Vesting balance for account: ${owner}, amount: ${amount}",
("owner", vesting_balance_obj.owner(db).name)
("amount", vesting_balance_obj.balance.amount));
@ -789,26 +1007,41 @@ void schedule_pending_dividend_balances(database& db,
}
#endif
auto current_distribution_account_balance_iter = current_distribution_account_balance_range.first;
auto current_distribution_account_balance_iter = current_distribution_account_balance_range.begin();
if(db.head_block_time() < HARDFORK_GPOS_TIME)
holder_account_count = std::distance(holder_balances_begin, holder_balances_end);
// the fee, in BTS, for distributing each asset in the account
uint64_t total_fee_per_asset_in_core = distribution_base_fee + holder_account_count * (uint64_t)distribution_fee_per_holder;
//auto current_distribution_account_balance_iter = current_distribution_account_balance_range.first;
auto previous_distribution_account_balance_iter = previous_distribution_account_balance_range.first;
dlog("Current balances in distribution account: ${current}, Previous balances: ${previous}",
("current", (int64_t)std::distance(current_distribution_account_balance_range.first, current_distribution_account_balance_range.second))
("current", (int64_t)std::distance(current_distribution_account_balance_range.begin(), current_distribution_account_balance_range.end()))
("previous", (int64_t)std::distance(previous_distribution_account_balance_range.first, previous_distribution_account_balance_range.second)));
// when we pay out the dividends to the holders, we need to know the total balance of the dividend asset in all
// accounts other than the distribution account (it would be silly to distribute dividends back to
// the distribution account)
share_type total_balance_of_dividend_asset;
for (const account_balance_object& holder_balance_object : boost::make_iterator_range(holder_balances_begin, holder_balances_end))
if (holder_balance_object.owner != dividend_data.dividend_distribution_account)
{
total_balance_of_dividend_asset += holder_balance_object.balance;
auto itr = vesting_amounts.find(holder_balance_object.owner);
if (itr != vesting_amounts.end())
total_balance_of_dividend_asset += itr->second;
}
if(db.head_block_time() >= HARDFORK_GPOS_TIME && dividend_holder_asset_obj.symbol == GRAPHENE_SYMBOL) { // only core
for (const vesting_balance_object &holder_balance_object : boost::make_iterator_range(vesting_balances_begin,
vesting_balances_end))
if (holder_balance_object.owner != dividend_data.dividend_distribution_account) {
total_balance_of_dividend_asset += holder_balance_object.balance.amount;
}
}
else {
for (const account_balance_object &holder_balance_object : boost::make_iterator_range(holder_balances_begin,
holder_balances_end))
if (holder_balance_object.owner != dividend_data.dividend_distribution_account) {
total_balance_of_dividend_asset += holder_balance_object.balance;
auto itr = vesting_amounts.find(holder_balance_object.owner);
if (itr != vesting_amounts.end())
total_balance_of_dividend_asset += itr->second;
}
}
// loop through all of the assets currently or previously held in the distribution account
while (current_distribution_account_balance_iter != current_distribution_account_balance_range.second ||
while (current_distribution_account_balance_iter != current_distribution_account_balance_range.end() ||
previous_distribution_account_balance_iter != previous_distribution_account_balance_range.second)
{
try
@ -819,15 +1052,15 @@ void schedule_pending_dividend_balances(database& db,
asset_id_type payout_asset_type;
if (previous_distribution_account_balance_iter == previous_distribution_account_balance_range.second ||
current_distribution_account_balance_iter->asset_type < previous_distribution_account_balance_iter->dividend_payout_asset_type)
current_distribution_account_balance_iter->second->asset_type < previous_distribution_account_balance_iter->dividend_payout_asset_type)
{
// there are no more previous balances or there is no previous balance for this particular asset type
payout_asset_type = current_distribution_account_balance_iter->asset_type;
current_balance = current_distribution_account_balance_iter->balance;
payout_asset_type = current_distribution_account_balance_iter->second->asset_type;
current_balance = current_distribution_account_balance_iter->second->balance;
idump((payout_asset_type)(current_balance));
}
else if (current_distribution_account_balance_iter == current_distribution_account_balance_range.second ||
previous_distribution_account_balance_iter->dividend_payout_asset_type < current_distribution_account_balance_iter->asset_type)
else if (current_distribution_account_balance_iter == current_distribution_account_balance_range.end() ||
previous_distribution_account_balance_iter->dividend_payout_asset_type < current_distribution_account_balance_iter->second->asset_type)
{
// there are no more current balances or there is no current balance for this particular previous asset type
payout_asset_type = previous_distribution_account_balance_iter->dividend_payout_asset_type;
@ -837,8 +1070,8 @@ void schedule_pending_dividend_balances(database& db,
else
{
// we have both a previous and a current balance for this asset type
payout_asset_type = current_distribution_account_balance_iter->asset_type;
current_balance = current_distribution_account_balance_iter->balance;
payout_asset_type = current_distribution_account_balance_iter->second->asset_type;
current_balance = current_distribution_account_balance_iter->second->balance;
previous_balance = previous_distribution_account_balance_iter->balance_at_last_maintenance_interval;
idump((payout_asset_type)(current_balance)(previous_balance));
}
@ -930,46 +1163,68 @@ void schedule_pending_dividend_balances(database& db,
("total", total_balance_of_dividend_asset));
share_type remaining_amount_to_distribute = delta_balance;
// credit each account with their portion, don't send any back to the dividend distribution account
for (const account_balance_object& holder_balance_object : boost::make_iterator_range(holder_balances_begin, holder_balances_end))
{
if (holder_balance_object.owner == dividend_data.dividend_distribution_account) continue;
if(db.head_block_time() >= HARDFORK_GPOS_TIME && dividend_holder_asset_obj.symbol == GRAPHENE_SYMBOL) { // core only
// credit each account with their portion, don't send any back to the dividend distribution account
for (const vesting_balance_object &holder_balance_object : boost::make_iterator_range(
vesting_balances_begin, vesting_balances_end)) {
if (holder_balance_object.owner == dividend_data.dividend_distribution_account) continue;
auto holder_balance = holder_balance_object.balance;
auto vesting_factor = db.calculate_vesting_factor(holder_balance_object.owner(db));
auto itr = vesting_amounts.find(holder_balance_object.owner);
if (itr != vesting_amounts.end())
holder_balance += itr->second;
auto holder_balance = holder_balance_object.balance;
fc::uint128_t amount_to_credit(delta_balance.value);
amount_to_credit *= holder_balance.value;
amount_to_credit /= total_balance_of_dividend_asset.value;
share_type shares_to_credit((int64_t)amount_to_credit.to_uint64());
if (shares_to_credit.value)
{
wdump((delta_balance.value)(holder_balance)(total_balance_of_dividend_asset));
fc::uint128_t amount_to_credit(delta_balance.value);
amount_to_credit *= holder_balance.amount.value;
amount_to_credit /= total_balance_of_dividend_asset.value;
share_type full_shares_to_credit((int64_t) amount_to_credit.to_uint64());
share_type shares_to_credit = (uint64_t) floor(full_shares_to_credit.value * vesting_factor);
remaining_amount_to_distribute -= shares_to_credit;
if (shares_to_credit < full_shares_to_credit) {
// Todo: sending results of decay to committee account, need to change to specified account
dlog("Crediting committee_account with ${amount}",
("amount", asset(full_shares_to_credit - shares_to_credit, payout_asset_type)));
db.adjust_balance(dividend_data.dividend_distribution_account,
-asset(full_shares_to_credit - shares_to_credit, payout_asset_type));
db.adjust_balance(account_id_type(0), asset(full_shares_to_credit - shares_to_credit, payout_asset_type));
}
dlog("Crediting account ${account} with ${amount}",
("account", holder_balance_object.owner(db).name)
("amount", asset(shares_to_credit, payout_asset_type)));
auto pending_payout_iter =
pending_payout_balance_index.indices().get<by_dividend_payout_account>().find(boost::make_tuple(dividend_holder_asset_obj.id, payout_asset_type, holder_balance_object.owner));
if (pending_payout_iter == pending_payout_balance_index.indices().get<by_dividend_payout_account>().end())
db.create<pending_dividend_payout_balance_for_holder_object>( [&]( pending_dividend_payout_balance_for_holder_object& obj ){
obj.owner = holder_balance_object.owner;
obj.dividend_holder_asset_type = dividend_holder_asset_obj.id;
obj.dividend_payout_asset_type = payout_asset_type;
obj.pending_balance = shares_to_credit;
});
else
db.modify(*pending_payout_iter, [&]( pending_dividend_payout_balance_for_holder_object& pending_balance ){
pending_balance.pending_balance += shares_to_credit;
});
remaining_amount_to_distribute = credit_account(db,
holder_balance_object.owner,
holder_balance_object.owner(db).name,
remaining_amount_to_distribute,
shares_to_credit,
payout_asset_type,
pending_payout_balance_index,
dividend_holder_asset_obj.id);
}
}
else {
// credit each account with their portion, don't send any back to the dividend distribution account
for (const account_balance_object &holder_balance_object : boost::make_iterator_range(
holder_balances_begin, holder_balances_end)) {
if (holder_balance_object.owner == dividend_data.dividend_distribution_account) continue;
auto holder_balance = holder_balance_object.balance;
auto itr = vesting_amounts.find(holder_balance_object.owner);
if (itr != vesting_amounts.end())
holder_balance += itr->second;
fc::uint128_t amount_to_credit(delta_balance.value);
amount_to_credit *= holder_balance.value;
amount_to_credit /= total_balance_of_dividend_asset.value;
share_type shares_to_credit((int64_t) amount_to_credit.to_uint64());
remaining_amount_to_distribute = credit_account(db,
holder_balance_object.owner,
holder_balance_object.owner(db).name,
remaining_amount_to_distribute,
shares_to_credit,
payout_asset_type,
pending_payout_balance_index,
dividend_holder_asset_obj.id);
}
}
for (const auto& pending_payout : pending_payout_balance_index.indices())
if (pending_payout.pending_balance.value)
dlog("Pending payout: ${account_name} -> ${amount}",
@ -1043,10 +1298,10 @@ void schedule_pending_dividend_balances(database& db,
// iterate
if (previous_distribution_account_balance_iter == previous_distribution_account_balance_range.second ||
current_distribution_account_balance_iter->asset_type < previous_distribution_account_balance_iter->dividend_payout_asset_type)
current_distribution_account_balance_iter->second->asset_type < previous_distribution_account_balance_iter->dividend_payout_asset_type)
++current_distribution_account_balance_iter;
else if (current_distribution_account_balance_iter == current_distribution_account_balance_range.second ||
previous_distribution_account_balance_iter->dividend_payout_asset_type < current_distribution_account_balance_iter->asset_type)
else if (current_distribution_account_balance_iter == current_distribution_account_balance_range.end() ||
previous_distribution_account_balance_iter->dividend_payout_asset_type < current_distribution_account_balance_iter->second->asset_type)
++previous_distribution_account_balance_iter;
else
{
@ -1066,6 +1321,7 @@ void process_dividend_assets(database& db)
ilog("In process_dividend_assets time ${time}", ("time", db.head_block_time()));
const account_balance_index& balance_index = db.get_index_type<account_balance_index>();
//const auto& balance_index = db.get_index_type< primary_index< account_balance_index > >().get_secondary_index< balances_by_account_index >();
const vesting_balance_index& vbalance_index = db.get_index_type<vesting_balance_index>();
const total_distributed_dividend_balance_object_index& distributed_dividend_balance_index = db.get_index_type<total_distributed_dividend_balance_object_index>();
const pending_dividend_payout_balance_for_holder_object_index& pending_payout_balance_index = db.get_index_type<pending_dividend_payout_balance_for_holder_object_index>();
@ -1090,10 +1346,10 @@ void process_dividend_assets(database& db)
("holder_asset", dividend_holder_asset_obj.symbol));
#ifndef NDEBUG
// dump balances before the payouts for debugging
const auto& balance_idx = db.get_index_type<account_balance_index>().indices().get<by_account_asset>();
auto holder_account_balance_range = balance_idx.equal_range(boost::make_tuple(dividend_data.dividend_distribution_account));
for (const account_balance_object& holder_balance_object : boost::make_iterator_range(holder_account_balance_range.first, holder_account_balance_range.second))
ilog(" Current balance: ${asset}", ("asset", asset(holder_balance_object.balance, holder_balance_object.asset_type)));
const auto& balance_index = db.get_index_type< primary_index< account_balance_index > >();
const auto& balances = balance_index.get_secondary_index< balances_by_account_index >().get_account_balances( dividend_data.dividend_distribution_account );
for( const auto balance : balances )
ilog(" Current balance: ${asset}", ("asset", asset(balance.second->balance, balance.second->asset_type)));
#endif
// when we do the payouts, we first increase the balances in all of the receiving accounts
@ -1231,6 +1487,8 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
process_dividend_assets(*this);
rolling_period_start(*this);
struct vote_tally_helper {
database& d;
const global_property_object& props;
@ -1244,24 +1502,28 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
d._committee_count_histogram_buffer.resize(props.parameters.maximum_committee_count / 2 + 1);
d._total_voting_stake = 0;
auto balance_type = vesting_balance_type::normal;
if(d.head_block_time() >= HARDFORK_GPOS_TIME)
balance_type = vesting_balance_type::gpos;
const vesting_balance_index& vesting_index = d.get_index_type<vesting_balance_index>();
#ifdef USE_VESTING_OBJECT_BY_ASSET_BALANCE_INDEX
auto vesting_balances_begin =
vesting_index.indices().get<by_asset_balance>().lower_bound(boost::make_tuple(asset_id_type()));
vesting_index.indices().get<by_asset_balance>().lower_bound(boost::make_tuple(asset_id_type(), balance_type));
auto vesting_balances_end =
vesting_index.indices().get<by_asset_balance>().upper_bound(boost::make_tuple(asset_id_type(), share_type()));
vesting_index.indices().get<by_asset_balance>().upper_bound(boost::make_tuple(asset_id_type(), balance_type, share_type()));
for (const vesting_balance_object& vesting_balance_obj : boost::make_iterator_range(vesting_balances_begin, vesting_balances_end))
{
vesting_amounts[vesting_balance_obj.owner] += vesting_balance_obj.balance.amount;
//dlog("Vesting balance for account: ${owner}, amount: ${amount}",
// ("owner", vesting_balance_obj.owner(d).name)
// ("amount", vesting_balance_obj.balance.amount));
dlog("Vesting balance for account: ${owner}, amount: ${amount}",
("owner", vesting_balance_obj.owner(d).name)
("amount", vesting_balance_obj.balance.amount));
}
#else
const auto& vesting_balances = vesting_index.indices().get<by_id>();
for (const vesting_balance_object& vesting_balance_obj : vesting_balances)
{
if (vesting_balance_obj.balance.asset_id == asset_id_type() && vesting_balance_obj.balance.amount)
if (vesting_balance_obj.balance.asset_id == asset_id_type() && vesting_balance_obj.balance.amount && vesting_balance_obj.balance_type == balance_type)
{
vesting_amounts[vesting_balance_obj.owner] += vesting_balance_obj.balance.amount;
dlog("Vesting balance for account: ${owner}, amount: ${amount}",
@ -1272,7 +1534,8 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
#endif
}
void operator()(const account_object& stake_account) {
void operator()( const account_object& stake_account, const account_statistics_object& stats )
{
if( props.parameters.count_non_member_votes || stake_account.is_member(d.head_block_time()) )
{
// There may be a difference between the account whose stake is voting and the one specifying opinions.
@ -1289,13 +1552,35 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
const account_object& opinion_account = *opinion_account_ptr;
const auto& stats = stake_account.statistics(d);
uint64_t voting_stake = stats.total_core_in_orders.value
+ (stake_account.cashback_vb.valid() ? (*stake_account.cashback_vb)(d).balance.amount.value: 0)
+ d.get_balance(stake_account.get_id(), asset_id_type()).amount.value;
uint64_t voting_stake = 0;
auto itr = vesting_amounts.find(stake_account.id);
if (itr != vesting_amounts.end())
voting_stake += itr->second.value;
if(d.head_block_time() >= HARDFORK_GPOS_TIME)
{
if (itr == vesting_amounts.end() && d.head_block_time() >= (HARDFORK_GPOS_TIME + props.parameters.gpos_subperiod()/2))
return;
auto vesting_factor = d.calculate_vesting_factor(stake_account);
voting_stake = (uint64_t)floor(voting_stake * vesting_factor);
//Include votes(based on stake) for the period of gpos_subperiod()/2 as system has zero votes on GPOS activation
if(d.head_block_time() < (HARDFORK_GPOS_TIME + props.parameters.gpos_subperiod()/2))
{
voting_stake += stats.total_core_in_orders.value
+ (stake_account.cashback_vb.valid() ? (*stake_account.cashback_vb)(d).balance.amount.value : 0)
+ d.get_balance(stake_account.get_id(), asset_id_type()).amount.value;
}
}
else
{
voting_stake += stats.total_core_in_orders.value
+ (stake_account.cashback_vb.valid() ? (*stake_account.cashback_vb)(d).balance.amount.value : 0)
+ d.get_balance(stake_account.get_id(), asset_id_type()).amount.value;
}
for( vote_id_type id : opinion_account.options.votes )
{
uint32_t offset = id.instance();
@ -1331,23 +1616,8 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
}
}
} tally_helper(*this, gpo);
struct process_fees_helper {
database& d;
const global_property_object& props;
process_fees_helper(database& d, const global_property_object& gpo)
: d(d), props(gpo) {}
void operator()(const account_object& a) {
a.statistics(d).process_fees(a, d);
}
} fee_helper(*this, gpo);
perform_account_maintenance(std::tie(
tally_helper,
fee_helper
));
perform_account_maintenance( tally_helper );
struct clear_canary {
clear_canary(vector<uint64_t>& target): target(target){}
~clear_canary() { target.clear(); }
@ -1363,9 +1633,10 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
update_active_committee_members();
update_worker_votes();
modify(gpo, [this](global_property_object& p) {
const dynamic_global_property_object& dgpo = get_dynamic_global_properties();
modify(gpo, [&dgpo](global_property_object& p) {
// Remove scaling of account registration fee
const auto& dgpo = get_dynamic_global_properties();
p.parameters.current_fees->get<account_create_operation>().basic_fee >>= p.parameters.account_fee_scale_bitshifts *
(dgpo.accounts_registered_this_interval / p.parameters.accounts_per_fee_scale);
@ -1381,12 +1652,20 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
p.pending_parameters->extensions.value.permitted_betting_odds_increments = p.parameters.extensions.value.permitted_betting_odds_increments;
if( !p.pending_parameters->extensions.value.live_betting_delay_time.valid() )
p.pending_parameters->extensions.value.live_betting_delay_time = p.parameters.extensions.value.live_betting_delay_time;
if( !p.pending_parameters->extensions.value.gpos_period_start.valid() )
p.pending_parameters->extensions.value.gpos_period_start = p.parameters.extensions.value.gpos_period_start;
if( !p.pending_parameters->extensions.value.gpos_period.valid() )
p.pending_parameters->extensions.value.gpos_period = p.parameters.extensions.value.gpos_period;
if( !p.pending_parameters->extensions.value.gpos_subperiod.valid() )
p.pending_parameters->extensions.value.gpos_subperiod = p.parameters.extensions.value.gpos_subperiod;
if( !p.pending_parameters->extensions.value.gpos_vesting_lockin_period.valid() )
p.pending_parameters->extensions.value.gpos_vesting_lockin_period = p.parameters.extensions.value.gpos_vesting_lockin_period;
p.parameters = std::move(*p.pending_parameters);
p.pending_parameters.reset();
}
});
auto next_maintenance_time = get<dynamic_global_property_object>(dynamic_global_property_id_type()).next_maintenance_time;
auto next_maintenance_time = dgpo.next_maintenance_time;
auto maintenance_interval = gpo.parameters.maintenance_interval;
if( next_maintenance_time <= next_block.timestamp )
@ -1416,8 +1695,6 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
}
}
const dynamic_global_property_object& dgpo = get_dynamic_global_properties();
if( (dgpo.next_maintenance_time < HARDFORK_613_TIME) && (next_maintenance_time >= HARDFORK_613_TIME) )
deprecate_annual_members(*this);

View file

@ -24,6 +24,9 @@
#include <graphene/chain/database.hpp>
#include <graphene/chain/chain_property_object.hpp>
#include <graphene/chain/witness_schedule_object.hpp>
#include <graphene/chain/special_authority_object.hpp>
#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>
@ -176,7 +179,7 @@ void database::wipe(const fc::path& data_dir, bool include_blocks)
{
ilog("Wiping database", ("include_blocks", include_blocks));
if (_opened) {
close();
close(false);
}
object_database::wipe(data_dir);
if( include_blocks )
@ -214,6 +217,15 @@ void database::open(
if( !find(global_property_id_type()) )
init_genesis(genesis_loader());
else
{
_p_core_asset_obj = &get( asset_id_type() );
_p_core_dynamic_data_obj = &get( asset_dynamic_data_id_type() );
_p_global_prop_obj = &get( global_property_id_type() );
_p_chain_property_obj = &get( chain_property_id_type() );
_p_dyn_global_prop_obj = &get( dynamic_global_property_id_type() );
_p_witness_schedule_obj = &get( witness_schedule_id_type() );
}
fc::optional<block_id_type> last_block = _block_id_to_block.last_id();
if( last_block.valid() )

View file

@ -426,14 +426,16 @@ bool database::fill_order(const force_settlement_object& settle, const asset& pa
*
* @return true if a margin call was executed.
*/
bool database::check_call_orders(const asset_object& mia, bool enable_black_swan)
bool database::check_call_orders( const asset_object& mia, bool enable_black_swan, bool for_new_limit_order,
const asset_bitasset_data_object* bitasset_ptr )
{ try {
if( !mia.is_market_issued() ) return false;
if( check_for_blackswan( mia, enable_black_swan ) )
const asset_bitasset_data_object& bitasset = ( bitasset_ptr ? *bitasset_ptr : mia.bitasset_data(*this) );
if( check_for_blackswan( mia, enable_black_swan, &bitasset ) )
return false;
const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this);
if( bitasset.is_prediction_market ) return false;
if( bitasset.current_feed.settlement_price.is_null() ) return false;
@ -464,7 +466,12 @@ bool database::check_call_orders(const asset_object& mia, bool enable_black_swan
bool filled_limit = false;
bool margin_called = false;
while( !check_for_blackswan( mia, enable_black_swan ) && call_itr != call_end )
auto head_time = head_block_time();
auto head_num = head_block_num();
bool after_hardfork_436 = ( head_time > HARDFORK_436_TIME );
while( !check_for_blackswan( mia, enable_black_swan, &bitasset ) && call_itr != call_end )
{
bool filled_call = false;
price match_price;
@ -481,7 +488,7 @@ bool database::check_call_orders(const asset_object& mia, bool enable_black_swan
// would be margin called, but there is no matching order #436
bool feed_protected = ( bitasset.current_feed.settlement_price > ~call_itr->call_price );
if( feed_protected && (head_block_time() > HARDFORK_436_TIME) )
if( feed_protected && after_hardfork_436 )
return margin_called;
// would be margin called, but there is no matching order
@ -506,7 +513,8 @@ bool database::check_call_orders(const asset_object& mia, bool enable_black_swan
if( usd_to_buy * match_price > call_itr->get_collateral() )
{
elog( "black swan detected" );
elog( "black swan detected on asset ${symbol} (${id}) at block ${b}",
("id",mia.id)("symbol",mia.symbol)("b",head_num) );
edump((enable_black_swan));
FC_ASSERT( enable_black_swan );
globally_settle_asset(mia, bitasset.current_feed.settlement_price );

View file

@ -45,7 +45,7 @@ namespace graphene { namespace chain {
void database::update_global_dynamic_data( const signed_block& b, const uint32_t missed_blocks )
{
const dynamic_global_property_object& _dgp = dynamic_global_property_id_type(0)(*this);
const dynamic_global_property_object& _dgp = get_dynamic_global_properties();
const global_property_object& gpo = get_global_properties();
// dynamic global properties updating
@ -121,6 +121,7 @@ void database::update_last_irreversible_block()
const global_property_object& gpo = get_global_properties();
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
// TODO for better performance, move this to db_maint, because only need to do it once per maintenance interval
vector< const witness_object* > wit_objs;
wit_objs.reserve( gpo.active_witnesses.size() );
for( const witness_id_type& wid : gpo.active_witnesses )
@ -237,11 +238,12 @@ void database::clear_expired_proposals()
*
* A black swan occurs if MAX(HB,SP) <= LC
*/
bool database::check_for_blackswan( const asset_object& mia, bool enable_black_swan )
bool database::check_for_blackswan( const asset_object& mia, bool enable_black_swan,
const asset_bitasset_data_object* bitasset_ptr )
{
if( !mia.is_market_issued() ) return false;
const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this);
const asset_bitasset_data_object& bitasset = ( bitasset_ptr ? *bitasset_ptr : mia.bitasset_data(*this) );
if( bitasset.has_settlement() ) return true; // already force settled
auto settle_price = bitasset.current_feed.settlement_price;
if( settle_price.is_null() ) return false; // no feed
@ -466,32 +468,84 @@ void database::clear_expired_orders()
void database::update_expired_feeds()
{
auto& asset_idx = get_index_type<asset_index>().indices().get<by_type>();
auto itr = asset_idx.lower_bound( true /** market issued */ );
while( itr != asset_idx.end() )
{
const asset_object& a = *itr;
++itr;
assert( a.is_market_issued() );
const auto head_time = head_block_time();
bool after_hardfork_615 = ( head_time >= HARDFORK_615_TIME );
const asset_bitasset_data_object& b = a.bitasset_data(*this);
bool feed_is_expired;
if( head_block_time() < HARDFORK_615_TIME )
feed_is_expired = b.feed_is_expired_before_hardfork_615( head_block_time() );
else
feed_is_expired = b.feed_is_expired( head_block_time() );
if( feed_is_expired )
const auto& idx = get_index_type<asset_bitasset_data_index>().indices().get<by_feed_expiration>();
auto itr = idx.begin();
while( itr != idx.end() && itr->feed_is_expired( head_time ) )
{
const asset_bitasset_data_object& b = *itr;
++itr; // not always process begin() because old code skipped updating some assets before hf 615
bool update_cer = false; // for better performance, to only update bitasset once, also check CER in this function
const asset_object* asset_ptr = nullptr;
// update feeds, check margin calls
if( after_hardfork_615 || b.feed_is_expired_before_hardfork_615( head_time ) )
{
modify(b, [this](asset_bitasset_data_object& a) {
a.update_median_feeds(head_block_time());
auto old_median_feed = b.current_feed;
modify( b, [head_time,&update_cer]( asset_bitasset_data_object& abdo )
{
abdo.update_median_feeds( head_time );
if( abdo.need_to_update_cer() )
{
update_cer = true;
abdo.asset_cer_updated = false;
abdo.feed_cer_updated = false;
}
});
check_call_orders(b.current_feed.settlement_price.base.asset_id(*this));
if( !b.current_feed.settlement_price.is_null() && !( b.current_feed == old_median_feed ) ) // `==` check is safe here
{
asset_ptr = &b.asset_id( *this );
check_call_orders( *asset_ptr, true, false, &b );
}
}
if( !b.current_feed.core_exchange_rate.is_null() &&
a.options.core_exchange_rate != b.current_feed.core_exchange_rate )
modify(a, [&b](asset_object& a) {
a.options.core_exchange_rate = b.current_feed.core_exchange_rate;
// update CER
if( update_cer )
{
if( !asset_ptr )
asset_ptr = &b.asset_id( *this );
if( asset_ptr->options.core_exchange_rate != b.current_feed.core_exchange_rate )
{
modify( *asset_ptr, [&b]( asset_object& ao )
{
ao.options.core_exchange_rate = b.current_feed.core_exchange_rate;
});
}
}
} // for each asset whose feed is expired
// process assets affected by bitshares-core issue 453 before hard fork 615
if( !after_hardfork_615 )
{
for( asset_id_type a : _issue_453_affected_assets )
{
check_call_orders( a(*this) );
}
}
}
void database::update_core_exchange_rates()
{
const auto& idx = get_index_type<asset_bitasset_data_index>().indices().get<by_cer_update>();
if( idx.begin() != idx.end() )
{
for( auto itr = idx.rbegin(); itr->need_to_update_cer(); itr = idx.rbegin() )
{
const asset_bitasset_data_object& b = *itr;
const asset_object& a = b.asset_id( *this );
if( a.options.core_exchange_rate != b.current_feed.core_exchange_rate )
{
modify( a, [&b]( asset_object& ao )
{
ao.options.core_exchange_rate = b.current_feed.core_exchange_rate;
});
}
modify( b, []( asset_bitasset_data_object& abdo )
{
abdo.asset_cer_updated = false;
abdo.feed_cer_updated = false;
});
}
}
}

View file

@ -38,14 +38,14 @@ witness_id_type database::get_scheduled_witness( uint32_t slot_num )const
if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM)
{
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
const witness_schedule_object& wso = witness_schedule_id_type()(*this);
const witness_schedule_object& wso = get_witness_schedule_object();;
uint64_t current_aslot = dpo.current_aslot + slot_num;
return wso.current_shuffled_witnesses[ current_aslot % wso.current_shuffled_witnesses.size() ];
}
if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM &&
slot_num != 0 )
{
const witness_schedule_object& wso = witness_schedule_id_type()(*this);
const witness_schedule_object& wso = get_witness_schedule_object();;
// ask the near scheduler who goes in the given slot
bool slot_is_near = wso.scheduler.get_slot(slot_num-1, wid);
if(! slot_is_near)
@ -113,7 +113,7 @@ uint32_t database::get_slot_at_time(fc::time_point_sec when)const
void database::update_witness_schedule()
{
const witness_schedule_object& wso = witness_schedule_id_type()(*this);
const witness_schedule_object& wso = get_witness_schedule_object();
const global_property_object& gpo = get_global_properties();
if( head_block_num() % gpo.active_witnesses.size() == 0 )
@ -148,7 +148,7 @@ void database::update_witness_schedule()
vector<witness_id_type> database::get_near_witness_schedule()const
{
const witness_schedule_object& wso = witness_schedule_id_type()(*this);
const witness_schedule_object& wso = get_witness_schedule_object();
vector<witness_id_type> result;
result.reserve(wso.scheduler.size());
@ -165,7 +165,7 @@ void database::update_witness_schedule(const signed_block& next_block)
{
auto start = fc::time_point::now();
const global_property_object& gpo = get_global_properties();
const witness_schedule_object& wso = get(witness_schedule_id_type());
const witness_schedule_object& wso = get_witness_schedule_object();
uint32_t schedule_needs_filled = gpo.active_witnesses.size();
uint32_t schedule_slot = get_slot_at_time(next_block.timestamp);
@ -252,7 +252,7 @@ uint32_t database::witness_participation_rate()const
}
if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM)
{
const witness_schedule_object& wso = get(witness_schedule_id_type());
const witness_schedule_object& wso = get_witness_schedule_object();
return uint64_t(GRAPHENE_100_PERCENT) * wso.recent_slots_filled.popcount() / 128;
}
return 0;

View file

@ -553,30 +553,30 @@ namespace graphene { namespace chain {
namespace fc {
// Manually reflect event_object to variant to properly reflect "state"
void to_variant(const graphene::chain::event_object& event_obj, fc::variant& v)
void to_variant(const graphene::chain::event_object& event_obj, fc::variant& v, uint32_t max_depth)
{
fc::mutable_variant_object o;
o("id", event_obj.id)
("name", event_obj.name)
("season", event_obj.season)
("start_time", event_obj.start_time)
("event_group_id", event_obj.event_group_id)
("scores", event_obj.scores)
("status", event_obj.get_status());
o("id", fc::variant(event_obj.id, max_depth))
("name", fc::variant(event_obj.name, max_depth))
("season", fc::variant(event_obj.season, max_depth))
("start_time", fc::variant(event_obj.start_time, max_depth))
("event_group_id", fc::variant(event_obj.event_group_id, max_depth))
("scores", fc::variant(event_obj.scores, max_depth))
("status", fc::variant(event_obj.get_status(), max_depth));
v = o;
}
// Manually reflect event_object to variant to properly reflect "state"
void from_variant(const fc::variant& v, graphene::chain::event_object& event_obj)
void from_variant(const fc::variant& v, graphene::chain::event_object& event_obj, uint32_t max_depth)
{
event_obj.id = v["id"].as<graphene::chain::event_id_type>();
event_obj.name = v["name"].as<graphene::chain::internationalized_string_type>();
event_obj.season = v["season"].as<graphene::chain::internationalized_string_type>();
event_obj.start_time = v["start_time"].as<optional<time_point_sec> >();
event_obj.event_group_id = v["event_group_id"].as<graphene::chain::event_group_id_type>();
event_obj.scores = v["scores"].as<std::vector<std::string>>();
graphene::chain::event_status status = v["status"].as<graphene::chain::event_status>();
event_obj.id = v["id"].as<graphene::chain::event_id_type>( max_depth );
event_obj.name = v["name"].as<graphene::chain::internationalized_string_type>( max_depth );
event_obj.season = v["season"].as<graphene::chain::internationalized_string_type>( max_depth );
event_obj.start_time = v["start_time"].as<optional<time_point_sec> >( max_depth );
event_obj.event_group_id = v["event_group_id"].as<graphene::chain::event_group_id_type>( max_depth );
event_obj.scores = v["scores"].as<std::vector<std::string>>( max_depth );
graphene::chain::event_status status = v["status"].as<graphene::chain::event_status>( max_depth );
const_cast<int*>(event_obj.my->state_machine.current_state())[0] = (int)status;
}
} //end namespace fc

View file

@ -549,33 +549,33 @@ namespace graphene { namespace chain {
namespace fc {
// Manually reflect game_object to variant to properly reflect "state"
void to_variant(const graphene::chain::game_object& game_obj, fc::variant& v)
void to_variant(const graphene::chain::game_object& game_obj, fc::variant& v, uint32_t max_depth)
{
fc_elog(fc::logger::get("tournament"), "In game_obj to_variant");
elog("In game_obj to_variant");
fc::mutable_variant_object o;
o("id", game_obj.id)
("match_id", game_obj.match_id)
("players", game_obj.players)
("winners", game_obj.winners)
("game_details", game_obj.game_details)
("next_timeout", game_obj.next_timeout)
("state", game_obj.get_state());
o("id", fc::variant(game_obj.id, max_depth ))
("match_id", fc::variant(game_obj.match_id, max_depth ))
("players", fc::variant(game_obj.players, max_depth ))
("winners", fc::variant(game_obj.winners, max_depth ))
("game_details", fc::variant(game_obj.game_details, max_depth ))
("next_timeout", fc::variant(game_obj.next_timeout, max_depth ))
("state", fc::variant(game_obj.get_state(), max_depth ));
v = o;
}
// Manually reflect game_object to variant to properly reflect "state"
void from_variant(const fc::variant& v, graphene::chain::game_object& game_obj)
void from_variant(const fc::variant& v, graphene::chain::game_object& game_obj, uint32_t max_depth)
{
fc_elog(fc::logger::get("tournament"), "In game_obj from_variant");
game_obj.id = v["id"].as<graphene::chain::game_id_type>();
game_obj.match_id = v["match_id"].as<graphene::chain::match_id_type>();
game_obj.players = v["players"].as<std::vector<graphene::chain::account_id_type> >();
game_obj.winners = v["winners"].as<flat_set<graphene::chain::account_id_type> >();
game_obj.game_details = v["game_details"].as<graphene::chain::game_specific_details>();
game_obj.next_timeout = v["next_timeout"].as<fc::optional<time_point_sec> >();
graphene::chain::game_state state = v["state"].as<graphene::chain::game_state>();
game_obj.id = v["id"].as<graphene::chain::game_id_type>( max_depth );
game_obj.match_id = v["match_id"].as<graphene::chain::match_id_type>( max_depth );
game_obj.players = v["players"].as<std::vector<graphene::chain::account_id_type> >( max_depth );
game_obj.winners = v["winners"].as<flat_set<graphene::chain::account_id_type> >( max_depth );
game_obj.game_details = v["game_details"].as<graphene::chain::game_specific_details>( max_depth );
game_obj.next_timeout = v["next_timeout"].as<fc::optional<time_point_sec> >( max_depth );
graphene::chain::game_state state = v["state"].as<graphene::chain::game_state>( max_depth );
const_cast<int*>(game_obj.my->state_machine.current_state())[0] = (int)state;
}
} //end namespace fc

View file

@ -36,3 +36,72 @@ chain_id_type genesis_state_type::compute_chain_id() const
}
} } // graphene::chain
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_account_type, BOOST_PP_SEQ_NIL, (name)(owner_key)(active_key)(is_lifetime_member))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_asset_type, BOOST_PP_SEQ_NIL,
(symbol)(issuer_name)(description)(precision)(max_supply)(accumulated_fees)(is_bitasset)(collateral_records))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_asset_type::initial_collateral_position, BOOST_PP_SEQ_NIL,
(owner)(collateral)(debt))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_balance_type, BOOST_PP_SEQ_NIL,
(owner)(asset_symbol)(amount))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_vesting_balance_type, BOOST_PP_SEQ_NIL,
(owner)(asset_symbol)(amount)(begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds)(begin_balance))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_witness_type, BOOST_PP_SEQ_NIL, (owner_name)(block_signing_key))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_committee_member_type, BOOST_PP_SEQ_NIL, (owner_name))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_worker_type, BOOST_PP_SEQ_NIL, (owner_name)(daily_pay))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority, BOOST_PP_SEQ_NIL,
(weight_threshold)
(account_auths)
(key_auths)
(address_auths))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy, BOOST_PP_SEQ_NIL,
(vesting_seconds)
(coin_seconds_earned)
(start_claim)
(coin_seconds_earned_last_update))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy, BOOST_PP_SEQ_NIL,
(begin_timestamp)
(vesting_cliff_seconds)
(vesting_duration_seconds)
(begin_balance))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_vesting_balance, BOOST_PP_SEQ_NIL,
(asset_symbol)
(amount)
(policy_type)
(policy))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type, BOOST_PP_SEQ_NIL,
(name)
(owner_authority)
(active_authority)
(core_balance)
(vesting_balances))
FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type, BOOST_PP_SEQ_NIL,
(initial_timestamp)(max_core_supply)(initial_parameters)(initial_bts_accounts)(initial_accounts)(initial_assets)(initial_balances)
(initial_vesting_balances)(initial_active_witnesses)(initial_witness_candidates)
(initial_committee_candidates)(initial_worker_candidates)
(initial_chain_id)
(immutable_parameters))
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_account_type)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_asset_type)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_asset_type::initial_collateral_position)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_balance_type)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_vesting_balance_type)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_witness_type)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_committee_member_type)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_worker_type)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_bts_account_type::initial_vesting_balance)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_bts_account_type)
GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type)

View file

@ -103,11 +103,11 @@ fc::variant_object get_config()
result[ "GRAPHENE_DEFAULT_WITNESS_PAY_VESTING_SECONDS" ] = GRAPHENE_DEFAULT_WITNESS_PAY_VESTING_SECONDS;
result[ "GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY" ] = GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY;
result[ "GRAPHENE_MAX_INTEREST_APR" ] = GRAPHENE_MAX_INTEREST_APR;
result[ "GRAPHENE_COMMITTEE_ACCOUNT" ] = GRAPHENE_COMMITTEE_ACCOUNT;
result[ "GRAPHENE_WITNESS_ACCOUNT" ] = GRAPHENE_WITNESS_ACCOUNT;
result[ "GRAPHENE_RELAXED_COMMITTEE_ACCOUNT" ] = GRAPHENE_RELAXED_COMMITTEE_ACCOUNT;
result[ "GRAPHENE_NULL_ACCOUNT" ] = GRAPHENE_NULL_ACCOUNT;
result[ "GRAPHENE_TEMP_ACCOUNT" ] = GRAPHENE_TEMP_ACCOUNT;
result[ "GRAPHENE_COMMITTEE_ACCOUNT" ] = fc::variant(GRAPHENE_COMMITTEE_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
result[ "GRAPHENE_WITNESS_ACCOUNT" ] = fc::variant(GRAPHENE_WITNESS_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
result[ "GRAPHENE_RELAXED_COMMITTEE_ACCOUNT" ] = fc::variant(GRAPHENE_RELAXED_COMMITTEE_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
result[ "GRAPHENE_NULL_ACCOUNT" ] = fc::variant(GRAPHENE_NULL_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
result[ "GRAPHENE_TEMP_ACCOUNT" ] = fc::variant(GRAPHENE_TEMP_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS);
return result;
}

View file

@ -0,0 +1,4 @@
// GPOS HARDFORK Thursday, October 1, 2020 05:00:00 AM GMT
#ifndef HARDFORK_GPOS_TIME
#define HARDFORK_GPOS_TIME (fc::time_point_sec( 1601528400 ))
#endif

View file

@ -22,8 +22,9 @@
* THE SOFTWARE.
*/
#pragma once
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/db/generic_index.hpp>
#include <graphene/chain/protocol/account.hpp>
#include <boost/multi_index/composite_key.hpp>
namespace graphene { namespace chain {
@ -46,6 +47,8 @@ namespace graphene { namespace chain {
account_id_type owner;
string name; ///< redundantly store account name here for better maintenance performance
/**
* Keep the most recent operation as a root pointer to a linked list of the transaction history.
*/
@ -62,6 +65,19 @@ namespace graphene { namespace chain {
*/
share_type total_core_in_orders;
share_type core_in_balance = 0; ///< redundantly store core balance here for better maintenance performance
bool has_cashback_vb = false; ///< redundantly store this for better maintenance performance
bool is_voting = false; ///< redundately store whether this account is voting for better maintenance performance
/// Whether this account owns some CORE asset and is voting
inline bool has_some_core_voting() const
{
return is_voting && ( total_core_in_orders > 0 || core_in_balance > 0 || has_cashback_vb );
}
/**
* Tracks the total fees paid by this account for the purpose of calculating bulk discounts.
*/
@ -87,6 +103,12 @@ namespace graphene { namespace chain {
*/
time_point_sec last_vote_time;
/// Whether this account has pending fees, no matter vested or not
inline bool has_pending_fees() const { return pending_fees > 0 || pending_vested_fees > 0; }
/// Whether need to process this account during the maintenance interval
inline bool need_maintenance() const { return has_some_core_voting() || has_pending_fees(); }
/// @brief Split up and pay out @ref pending_fees and @ref pending_vested_fees
void process_fees(const account_object& a, database& d) const;
@ -112,6 +134,7 @@ namespace graphene { namespace chain {
account_id_type owner;
asset_id_type asset_type;
share_type balance;
bool maintenance_flag = false; ///< Whether need to process this balance object in maintenance interval
asset get_balance()const { return asset(balance, asset_type); }
void adjust_balance(const asset& delta);
@ -363,8 +386,34 @@ namespace graphene { namespace chain {
};
struct by_account_asset;
/**
* @brief This secondary index will allow fast access to the balance objects
* that belonging to an account.
*/
class balances_by_account_index : public secondary_index
{
public:
virtual void object_inserted( const object& obj ) override;
virtual void object_removed( const object& obj ) override;
virtual void about_to_modify( const object& before ) override;
virtual void object_modified( const object& after ) override;
const map< asset_id_type, const account_balance_object* >& get_account_balances( const account_id_type& acct )const;
const account_balance_object* get_account_balance( const account_id_type& acct, const asset_id_type& asset )const;
private:
static const uint8_t bits;
static const uint64_t mask;
/** Maps each account to its balance objects */
vector< vector< map< asset_id_type, const account_balance_object* > > > balances;
std::stack< object_id_type > ids_being_modified;
};
struct by_asset_balance;
struct by_maintenance_flag;
struct by_account_asset;
/**
* @ingroup object_index
*/
@ -372,6 +421,8 @@ namespace graphene { namespace chain {
account_balance_object,
indexed_by<
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
ordered_non_unique< tag<by_maintenance_flag>,
member< account_balance_object, bool, &account_balance_object::maintenance_flag > >,
ordered_unique< tag<by_account_asset>,
composite_key<
account_balance_object,
@ -461,6 +512,33 @@ namespace graphene { namespace chain {
*/
typedef generic_index<pending_dividend_payout_balance_for_holder_object, pending_dividend_payout_balance_for_holder_object_multi_index_type> pending_dividend_payout_balance_for_holder_object_index;
struct by_owner;
struct by_maintenance_seq;
/**
* @ingroup object_index
*/
typedef multi_index_container<
account_statistics_object,
indexed_by<
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
ordered_unique< tag<by_owner>,
member< account_statistics_object, account_id_type, &account_statistics_object::owner > >,
ordered_unique< tag<by_maintenance_seq>,
composite_key<
account_statistics_object,
const_mem_fun<account_statistics_object, bool, &account_statistics_object::need_maintenance>,
member<account_statistics_object, string, &account_statistics_object::name>
>
>
>
> account_stats_multi_index_type;
/**
* @ingroup object_index
*/
typedef generic_index<account_statistics_object, account_stats_multi_index_type> account_stats_index;
}}
FC_REFLECT_DERIVED( graphene::chain::account_object,
@ -477,14 +555,17 @@ FC_REFLECT_DERIVED( graphene::chain::account_object,
FC_REFLECT_DERIVED( graphene::chain::account_balance_object,
(graphene::db::object),
(owner)(asset_type)(balance) )
(owner)(asset_type)(balance)(maintenance_flag) )
FC_REFLECT_DERIVED( graphene::chain::account_statistics_object,
(graphene::chain::object),
(owner)
(owner)(name)
(most_recent_op)
(total_ops)(removed_ops)
(total_core_in_orders)
(core_in_balance)
(has_cashback_vb)
(is_voting)
(lifetime_fees_paid)
(pending_fees)(pending_vested_fees)
(last_vote_time)
@ -494,4 +575,7 @@ FC_REFLECT_DERIVED( graphene::chain::pending_dividend_payout_balance_for_holder_
(graphene::db::object),
(owner)(dividend_holder_asset_type)(dividend_payout_asset_type)(pending_balance) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_balance_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_statistics_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::pending_dividend_payout_balance_for_holder_object )

View file

@ -22,10 +22,11 @@
* THE SOFTWARE.
*/
#pragma once
#include <graphene/chain/protocol/types.hpp>
#include <graphene/db/generic_index.hpp>
#include <graphene/db/flat_index.hpp>
#include <graphene/chain/protocol/asset_ops.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <graphene/db/flat_index.hpp>
#include <graphene/db/generic_index.hpp>
/**
* @defgroup prediction_market Prediction Market
@ -38,7 +39,6 @@
*/
namespace graphene { namespace chain {
class account_object;
class database;
class transaction_evaluation_state;
using namespace graphene::db;
@ -193,6 +193,9 @@ namespace graphene { namespace chain {
static const uint8_t space_id = implementation_ids;
static const uint8_t type_id = impl_asset_bitasset_data_type;
/// The asset this object belong to
asset_id_type asset_id;
/// The tunable options for BitAssets are stored in this field.
bitasset_options options;
@ -230,6 +233,18 @@ namespace graphene { namespace chain {
share_type settlement_fund;
///@}
/// Track whether core_exchange_rate in corresponding asset_object has updated
bool asset_cer_updated = false;
/// Track whether core exchange rate in current feed has updated
bool feed_cer_updated = false;
/// Whether need to update core_exchange_rate in asset_object
bool need_to_update_cer() const
{
return ( ( feed_cer_updated || asset_cer_updated ) && !current_feed.core_exchange_rate.is_null() );
}
/// The time when @ref current_feed would expire
time_point_sec feed_expiration_time()const
{
@ -247,14 +262,34 @@ namespace graphene { namespace chain {
void update_median_feeds(time_point_sec current_time);
};
// key extractor for short backing asset
struct bitasset_short_backing_asset_extractor
{
typedef asset_id_type result_type;
result_type operator() (const asset_bitasset_data_object& obj) const
{
return obj.options.short_backing_asset;
}
};
struct by_short_backing_asset;
struct by_feed_expiration;
struct by_cer_update;
typedef multi_index_container<
asset_bitasset_data_object,
indexed_by<
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
ordered_non_unique< tag<by_feed_expiration>,
const_mem_fun< asset_bitasset_data_object, time_point_sec, &asset_bitasset_data_object::feed_expiration_time >
>
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
ordered_non_unique< tag<by_short_backing_asset>, bitasset_short_backing_asset_extractor >,
ordered_unique< tag<by_feed_expiration>,
composite_key< asset_bitasset_data_object,
const_mem_fun< asset_bitasset_data_object, time_point_sec, &asset_bitasset_data_object::feed_expiration_time >,
member< asset_bitasset_data_object, asset_id_type, &asset_bitasset_data_object::asset_id >
>
>,
ordered_non_unique< tag<by_cer_update>,
const_mem_fun< asset_bitasset_data_object, bool, &asset_bitasset_data_object::need_to_update_cer >
>
>
> asset_bitasset_data_object_multi_index_type;
//typedef flat_index<asset_bitasset_data_object> asset_bitasset_data_index;
@ -481,6 +516,7 @@ FC_REFLECT_DERIVED( graphene::chain::asset_dynamic_data_object, (graphene::db::o
(current_supply)(sweeps_tickets_sold)(confidential_supply)(accumulated_fees)(fee_pool) )
FC_REFLECT_DERIVED( graphene::chain::asset_bitasset_data_object, (graphene::db::object),
(asset_id)
(feeds)
(current_feed)
(current_feed_publication_time)
@ -489,6 +525,8 @@ FC_REFLECT_DERIVED( graphene::chain::asset_bitasset_data_object, (graphene::db::
(is_prediction_market)
(settlement_price)
(settlement_fund)
(asset_cer_updated)
(feed_cer_updated)
)
FC_REFLECT_DERIVED( graphene::chain::asset_dividend_data_object, (graphene::db::object),
@ -523,3 +561,13 @@ FC_REFLECT_DERIVED( graphene::chain::lottery_balance_object, (graphene::db::obje
FC_REFLECT_DERIVED( graphene::chain::sweeps_vesting_balance_object, (graphene::db::object),
(owner)(balance)(asset_id)(last_claim_date) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_dynamic_data_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_bitasset_data_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_dividend_data_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::total_distributed_dividend_balance_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::lottery_balance_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::sweeps_vesting_balance_object )

View file

@ -73,3 +73,5 @@ namespace graphene { namespace chain {
FC_REFLECT_DERIVED( graphene::chain::balance_object, (graphene::db::object),
(owner)(balance)(vesting_policy)(last_claim_date) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::balance_object )

View file

@ -37,10 +37,10 @@ namespace graphene { namespace chain {
} }
namespace fc {
void to_variant(const graphene::chain::betting_market_object& betting_market_obj, fc::variant& v);
void from_variant(const fc::variant& v, graphene::chain::betting_market_object& betting_market_obj);
void to_variant(const graphene::chain::betting_market_group_object& betting_market_group_obj, fc::variant& v);
void from_variant(const fc::variant& v, graphene::chain::betting_market_group_object& betting_market_group_obj);
void to_variant(const graphene::chain::betting_market_object& betting_market_obj, fc::variant& v, uint32_t max_depth = 1);
void from_variant(const fc::variant& v, graphene::chain::betting_market_object& betting_market_obj, uint32_t max_depth = 1);
void to_variant(const graphene::chain::betting_market_group_object& betting_market_group_obj, fc::variant& v, uint32_t max_depth = 1);
void from_variant(const fc::variant& v, graphene::chain::betting_market_group_object& betting_market_group_obj, uint32_t max_depth = 1);
} //end namespace fc
namespace graphene { namespace chain {
@ -110,8 +110,8 @@ class betting_market_group_object : public graphene::db::abstract_object< bettin
template<typename Stream>
friend Stream& operator>>( Stream& s, betting_market_group_object& betting_market_group_obj );
friend void ::fc::to_variant(const graphene::chain::betting_market_group_object& betting_market_group_obj, fc::variant& v);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::betting_market_group_object& betting_market_group_obj);
friend void ::fc::to_variant(const graphene::chain::betting_market_group_object& betting_market_group_obj, fc::variant& v, uint32_t max_depth);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::betting_market_group_object& betting_market_group_obj, uint32_t max_depth);
void pack_impl(std::ostream& stream) const;
void unpack_impl(std::istream& stream);
@ -166,8 +166,8 @@ class betting_market_object : public graphene::db::abstract_object< betting_mark
template<typename Stream>
friend Stream& operator>>( Stream& s, betting_market_object& betting_market_obj );
friend void ::fc::to_variant(const graphene::chain::betting_market_object& betting_market_obj, fc::variant& v);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::betting_market_object& betting_market_obj);
friend void ::fc::to_variant(const graphene::chain::betting_market_object& betting_market_obj, fc::variant& v, uint32_t max_depth);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::betting_market_object& betting_market_obj, uint32_t max_depth);
void pack_impl(std::ostream& stream) const;
void unpack_impl(std::istream& stream);

View file

@ -25,6 +25,8 @@
#include <fstream>
#include <graphene/chain/protocol/block.hpp>
#include <fc/filesystem.hpp>
namespace graphene { namespace chain {
class index_entry;

View file

@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#pragma once
#include <graphene/chain/protocol/types.hpp>
#include <graphene/db/object.hpp>
namespace graphene { namespace chain {
@ -47,4 +48,7 @@ namespace graphene { namespace chain {
} }
FC_REFLECT_DERIVED( graphene::chain::block_summary_object, (graphene::db::object), (block_id) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::block_summary_object )

View file

@ -23,7 +23,6 @@
*/
#pragma once
#include <graphene/chain/protocol/types.hpp>
#include <graphene/db/object.hpp>
#include <graphene/db/generic_index.hpp>
namespace graphene { namespace chain {
@ -54,8 +53,6 @@ struct budget_record
share_type supply_delta = 0;
};
class budget_record_object;
class budget_record_object : public graphene::db::abstract_object<budget_record_object>
{
public:
@ -68,8 +65,7 @@ class budget_record_object : public graphene::db::abstract_object<budget_record_
} }
FC_REFLECT(
graphene::chain::budget_record,
FC_REFLECT(graphene::chain::budget_record,
(time_since_last_budget)
(from_initial_reserve)
(from_accumulated_fees)
@ -82,9 +78,8 @@ FC_REFLECT(
(supply_delta)
)
FC_REFLECT_DERIVED(
graphene::chain::budget_record_object,
(graphene::db::object),
(time)
(record)
)
FC_REFLECT_DERIVED(graphene::chain::budget_record_object,
(graphene::db::object), (time)(record) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::budget_record )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::budget_record_object )

View file

@ -65,3 +65,5 @@ typedef generic_index< buyback_object, buyback_multi_index_type > buyback_index;
} } // graphene::chain
FC_REFLECT_DERIVED( graphene::chain::buyback_object, (graphene::db::object), (asset_to_buy) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::buyback_object )

View file

@ -27,8 +27,6 @@
namespace graphene { namespace chain {
class chain_property_object;
/**
* Contains invariants which are set at genesis and never changed.
*/
@ -48,3 +46,5 @@ FC_REFLECT_DERIVED( graphene::chain::chain_property_object, (graphene::db::objec
(chain_id)
(immutable_parameters)
)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::chain_property_object )

View file

@ -29,8 +29,6 @@
namespace graphene { namespace chain {
using namespace graphene::db;
class account_object;
/**
* @brief tracks information about a committee_member account.
* @ingroup object
@ -73,5 +71,8 @@ namespace graphene { namespace chain {
using committee_member_index = generic_index<committee_member_object, committee_member_multi_index_type>;
} } // graphene::chain
FC_REFLECT_DERIVED( graphene::chain::committee_member_object, (graphene::db::object),
(committee_member_account)(vote_id)(total_votes)(url) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_object )

View file

@ -26,7 +26,6 @@
#include <graphene/chain/protocol/authority.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/db/object.hpp>
#include <graphene/db/generic_index.hpp>
#include <fc/crypto/elliptic.hpp>
@ -50,8 +49,6 @@ class blinded_balance_object : public graphene::db::abstract_object<blinded_bala
authority owner;
};
struct by_asset;
struct by_owner;
struct by_commitment;
/**
@ -68,4 +65,8 @@ typedef generic_index<blinded_balance_object, blinded_balance_object_multi_index
} } // graphene::chain
FC_REFLECT_DERIVED( graphene::chain::blinded_balance_object, (graphene::db::object), (commitment)(asset_id)(owner) )
FC_REFLECT_DERIVED( graphene::chain::blinded_balance_object, (graphene::db::object),
(commitment)(asset_id)(owner) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::blinded_balance_object )

View file

@ -151,7 +151,7 @@
#define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4
#define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3
#define GRAPHENE_CURRENT_DB_VERSION "PPY2.2"
#define GRAPHENE_CURRENT_DB_VERSION "PPY2.3"
#define GRAPHENE_IRREVERSIBLE_THRESHOLD (70 * GRAPHENE_1_PERCENT)
@ -211,6 +211,7 @@
{ 10000000, 100000} } /* <= 1000: 10.00 */
#define GRAPHENE_DEFAULT_BETTING_PERCENT_FEE (2 * GRAPHENE_1_PERCENT)
#define GRAPHENE_DEFAULT_LIVE_BETTING_DELAY_TIME 5 // seconds
#define GRAPHENE_MAX_NESTED_OBJECTS (200)
#define TOURNAMENT_MIN_ROUND_DELAY 0
#define TOURNAMENT_MAX_ROUND_DELAY 600
#define TOURNAMENT_MIN_TIME_PER_COMMIT_MOVE 0
@ -226,8 +227,10 @@
#define TOURNAMENT_MAX_WHITELIST_LENGTH 1000
#define TOURNAMENT_MAX_START_TIME_IN_FUTURE (60*60*24*7*4) // 1 month
#define TOURNAMENT_MAX_START_DELAY (60*60*24*7) // 1 week
#define SWEEPS_DEFAULT_DISTRIBUTION_PERCENTAGE (2*GRAPHENE_1_PERCENT)
#define SWEEPS_DEFAULT_DISTRIBUTION_ASSET (graphene::chain::asset_id_type(0))
#define SWEEPS_VESTING_BALANCE_MULTIPLIER 100000000
#define SWEEPS_ACCUMULATOR_ACCOUNT (graphene::chain::account_id_type(0))
#define GPOS_PERIOD (60*60*24*30*6) // 6 months
#define GPOS_SUBPERIOD (60*60*24*30) // 1 month
#define GPOS_VESTING_LOCKIN_PERIOD (60*60*24*30) // 1 month

View file

@ -271,14 +271,17 @@ namespace graphene { namespace chain {
const chain_id_type& get_chain_id()const;
const asset_object& get_core_asset()const;
const asset_dynamic_data_object& get_core_dynamic_data()const;
const chain_property_object& get_chain_properties()const;
const global_property_object& get_global_properties()const;
const dynamic_global_property_object& get_dynamic_global_properties()const;
const node_property_object& get_node_properties()const;
const fee_schedule& current_fee_schedule()const;
const account_statistics_object& get_account_stats_by_owner( account_id_type owner )const;
const std::vector<uint32_t> get_winner_numbers( asset_id_type for_asset, uint32_t count_members, uint8_t count_winners ) const;
std::vector<uint32_t> get_seeds( asset_id_type for_asset, uint8_t count_winners )const;
uint64_t get_random_bits( uint64_t bound );
const witness_schedule_object& get_witness_schedule_object()const;
time_point_sec head_block_time()const;
uint32_t head_block_num()const;
@ -436,7 +439,8 @@ namespace graphene { namespace chain {
bool fill_order( const call_order_object& order, const asset& pays, const asset& receives );
bool fill_order( const force_settlement_object& settle, const asset& pays, const asset& receives );
bool check_call_orders( const asset_object& mia, bool enable_black_swan = true );
bool check_call_orders( const asset_object& mia, bool enable_black_swan = true, bool for_new_limit_order = false,
const asset_bitasset_data_object* bitasset_ptr = nullptr );
// helpers to fill_order
void pay_order( const account_object& receiver, const asset& receives, const asset& pays );
@ -445,7 +449,7 @@ namespace graphene { namespace chain {
asset pay_market_fees( const asset_object& recv_asset, const asset& receives );
///@}
///@{
/**
* This method validates transactions without adding it to the pending state.
* @return true if the transaction would validate
@ -460,6 +464,8 @@ namespace graphene { namespace chain {
/**
* @}
*/
/// Enable or disable tracking of votes of standby witnesses and committee members
inline void enable_standby_votes_tracking(bool enable) { _track_standby_votes = enable; }
protected:
//Mark pop_undo() as protected -- we do not want outside calling pop_undo(); it should call pop_block() instead
void pop_undo() { object_database::pop_undo(); }
@ -502,11 +508,13 @@ namespace graphene { namespace chain {
void clear_expired_proposals();
void clear_expired_orders();
void update_expired_feeds();
void update_core_exchange_rates();
void update_maintenance_flag( bool new_maintenance_flag );
void update_withdraw_permissions();
void update_tournaments();
void update_betting_markets(fc::time_point_sec current_block_time);
bool check_for_blackswan( const asset_object& mia, bool enable_black_swan = true );
bool check_for_blackswan( const asset_object& mia, bool enable_black_swan = true,
const asset_bitasset_data_object* bitasset_ptr = nullptr );
///Steps performed only at maintenance intervals
///@{
@ -521,8 +529,12 @@ namespace graphene { namespace chain {
void update_active_committee_members();
void update_worker_votes();
template<class... Types>
void perform_account_maintenance(std::tuple<Types...> helpers);
public:
double calculate_vesting_factor(const account_object& stake_account);
uint32_t get_gpos_current_subperiod();
template<class Type>
void perform_account_maintenance(Type tally_helper);
///@}
///@}
@ -561,6 +573,11 @@ namespace graphene { namespace chain {
flat_map<uint32_t,block_id_type> _checkpoints;
node_property_object _node_property_object;
/// Whether to update votes of standby witnesses and committee members when performing chain maintenance.
/// Set it to true to provide accurate data to API clients, set to false to have better performance.
bool _track_standby_votes = true;
fc::hash_ctr_rng<secret_hash_type, 20> _random_number_generator;
bool _slow_replays = false;
@ -572,6 +589,18 @@ namespace graphene { namespace chain {
* database::close() has not been called, or failed during execution.
*/
bool _opened = false;
/// Tracks assets affected by bitshares-core issue #453 before hard fork #615 in one block
flat_set<asset_id_type> _issue_453_affected_assets;
/// Pointers to core asset object and global objects who will have immutable addresses after created
///@{
const asset_object* _p_core_asset_obj = nullptr;
const asset_dynamic_data_object* _p_core_dynamic_data_obj = nullptr;
const global_property_object* _p_global_prop_obj = nullptr;
const dynamic_global_property_object* _p_dyn_global_prop_obj = nullptr;
const chain_property_object* _p_chain_property_obj = nullptr;
const witness_schedule_object* _p_witness_schedule_obj = nullptr;
///@}
};
namespace detail

View file

@ -36,8 +36,8 @@ namespace graphene { namespace chain {
} }
namespace fc {
void to_variant(const graphene::chain::event_object& event_obj, fc::variant& v);
void from_variant(const fc::variant& v, graphene::chain::event_object& event_obj);
void to_variant(const graphene::chain::event_object& event_obj, fc::variant& v, uint32_t max_depth = 1);
void from_variant(const fc::variant& v, graphene::chain::event_object& event_obj, uint32_t max_depth = 1);
} //end namespace fc
namespace graphene { namespace chain {
@ -77,8 +77,8 @@ class event_object : public graphene::db::abstract_object< event_object >
template<typename Stream>
friend Stream& operator>>( Stream& s, event_object& event_obj );
friend void ::fc::to_variant(const graphene::chain::event_object& event_obj, fc::variant& v);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::event_object& event_obj);
friend void ::fc::to_variant(const graphene::chain::event_object& event_obj, fc::variant& v, uint32_t max_depth);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::event_object& event_obj, uint32_t max_depth);
void pack_impl(std::ostream& stream) const;
void unpack_impl(std::istream& stream);

View file

@ -49,4 +49,7 @@ class fba_accumulator_object : public graphene::db::abstract_object< fba_accumul
} } // graphene::chain
FC_REFLECT_DERIVED( graphene::chain::fba_accumulator_object, (graphene::db::object), (accumulated_fba_fees)(designated_asset) )
FC_REFLECT_DERIVED( graphene::chain::fba_accumulator_object, (graphene::db::object),
(accumulated_fba_fees)(designated_asset) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::fba_accumulator_object )

View file

@ -36,8 +36,8 @@ namespace graphene { namespace chain {
} }
namespace fc {
void to_variant(const graphene::chain::game_object& game_obj, fc::variant& v);
void from_variant(const fc::variant& v, graphene::chain::game_object& game_obj);
void to_variant(const graphene::chain::game_object& game_obj, fc::variant& v, uint32_t max_depth = 1);
void from_variant(const fc::variant& v, graphene::chain::game_object& game_obj, uint32_t max_depth = 1);
} //end namespace fc
namespace graphene { namespace chain {
@ -92,8 +92,8 @@ namespace graphene { namespace chain {
template<typename Stream>
friend Stream& operator>>( Stream& s, game_object& game_obj );
friend void ::fc::to_variant(const graphene::chain::game_object& game_obj, fc::variant& v);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::game_object& game_obj);
friend void ::fc::to_variant(const graphene::chain::game_object& game_obj, fc::variant& v, uint32_t max_depth);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::game_object& game_obj, uint32_t max_depth);
void pack_impl(std::ostream& stream) const;
void unpack_impl(std::istream& stream);

View file

@ -23,6 +23,7 @@
*/
#pragma once
#include <graphene/chain/protocol/address.hpp>
#include <graphene/chain/protocol/chain_parameters.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/immutable_chain_parameters.hpp>
@ -169,56 +170,32 @@ struct genesis_state_type {
} } // namespace graphene::chain
FC_REFLECT(graphene::chain::genesis_state_type::initial_account_type, (name)(owner_key)(active_key)(is_lifetime_member))
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_account_type)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_asset_type)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_asset_type::initial_collateral_position)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_balance_type)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_vesting_balance_type)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_witness_type)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_committee_member_type)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_worker_type)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_vesting_balance)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type)
FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type)
FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type,
(symbol)(issuer_name)(description)(precision)(max_supply)(accumulated_fees)(is_bitasset)(collateral_records))
FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type::initial_collateral_position,
(owner)(collateral)(debt))
FC_REFLECT(graphene::chain::genesis_state_type::initial_balance_type,
(owner)(asset_symbol)(amount))
FC_REFLECT(graphene::chain::genesis_state_type::initial_vesting_balance_type,
(owner)(asset_symbol)(amount)(begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds)(begin_balance))
FC_REFLECT(graphene::chain::genesis_state_type::initial_witness_type, (owner_name)(block_signing_key))
FC_REFLECT(graphene::chain::genesis_state_type::initial_committee_member_type, (owner_name))
FC_REFLECT(graphene::chain::genesis_state_type::initial_worker_type, (owner_name)(daily_pay))
FC_REFLECT(graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority,
(weight_threshold)
(account_auths)
(key_auths)
(address_auths))
FC_REFLECT(graphene::chain::genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy,
(vesting_seconds)
(coin_seconds_earned)
(start_claim)
(coin_seconds_earned_last_update))
FC_REFLECT(graphene::chain::genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy,
(begin_timestamp)
(vesting_cliff_seconds)
(vesting_duration_seconds)
(begin_balance))
FC_REFLECT(graphene::chain::genesis_state_type::initial_bts_account_type::initial_vesting_balance,
(asset_symbol)
(amount)
(policy_type)
(policy))
FC_REFLECT(graphene::chain::genesis_state_type::initial_bts_account_type,
(name)
(owner_authority)
(active_authority)
(core_balance)
(vesting_balances))
FC_REFLECT(graphene::chain::genesis_state_type,
(initial_timestamp)(max_core_supply)(initial_parameters)(initial_bts_accounts)(initial_accounts)(initial_assets)(initial_balances)
(initial_vesting_balances)(initial_active_witnesses)(initial_witness_candidates)
(initial_committee_candidates)(initial_worker_candidates)
(initial_chain_id)
(immutable_parameters))
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_account_type)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_asset_type)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_asset_type::initial_collateral_position)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_balance_type)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_vesting_balance_type)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_witness_type)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_committee_member_type)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_worker_type)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_bts_account_type::initial_vesting_balance)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_bts_account_type)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type)

View file

@ -126,7 +126,6 @@ namespace graphene { namespace chain {
}}
FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene::db::object),
(random)
(head_block_number)
(head_block_id)
(time)
@ -149,3 +148,6 @@ FC_REFLECT_DERIVED( graphene::chain::global_property_object, (graphene::db::obje
(active_committee_members)
(active_witnesses)
)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::dynamic_global_property_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::global_property_object )

View file

@ -23,11 +23,8 @@
*/
#pragma once
#include <fc/reflect/reflect.hpp>
#include <cstdint>
#include <graphene/chain/config.hpp>
#include <graphene/chain/protocol/types.hpp>
namespace graphene { namespace chain {
@ -47,3 +44,5 @@ FC_REFLECT( graphene::chain::immutable_chain_parameters,
(num_special_accounts)
(num_special_assets)
)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::immutable_chain_parameters )

View file

@ -217,3 +217,7 @@ FC_REFLECT_DERIVED( graphene::chain::force_settlement_object,
(graphene::db::object),
(owner)(balance)(settlement_date)
)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::limit_order_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::call_order_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::force_settlement_object )

View file

@ -12,8 +12,8 @@ namespace graphene { namespace chain {
} }
namespace fc {
void to_variant(const graphene::chain::match_object& match_obj, fc::variant& v);
void from_variant(const fc::variant& v, graphene::chain::match_object& match_obj);
void to_variant(const graphene::chain::match_object& match_obj, fc::variant& v, uint32_t max_depth = 1);
void from_variant(const fc::variant& v, graphene::chain::match_object& match_obj, uint32_t max_depth = 1);
} //end namespace fc
namespace graphene { namespace chain {
@ -84,8 +84,8 @@ namespace graphene { namespace chain {
template<typename Stream>
friend Stream& operator>>( Stream& s, match_object& match_obj );
friend void ::fc::to_variant(const graphene::chain::match_object& match_obj, fc::variant& v);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::match_object& match_obj);
friend void ::fc::to_variant(const graphene::chain::match_object& match_obj, fc::variant& v, uint32_t max_depth);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::match_object& match_obj, uint32_t max_depth);
void pack_impl(std::ostream& stream) const;
void unpack_impl(std::istream& stream);

View file

@ -22,8 +22,10 @@
* THE SOFTWARE.
*/
#pragma once
#include <graphene/chain/protocol/operations.hpp>
#include <graphene/db/object.hpp>
#include <boost/multi_index/composite_key.hpp>
namespace graphene { namespace chain {
@ -94,9 +96,6 @@ namespace graphene { namespace chain {
operation_history_id_type operation_id;
uint32_t sequence = 0; /// the operation position within the given account
account_transaction_history_id_type next;
//std::pair<account_id_type,operation_history_id_type> account_op()const { return std::tie( account, operation_id ); }
//std::pair<account_id_type,uint32_t> account_seq()const { return std::tie( account, sequence ); }
};
struct by_id;
@ -132,6 +131,8 @@ typedef generic_index<account_transaction_history_object, account_transaction_hi
FC_REFLECT_DERIVED( graphene::chain::operation_history_object, (graphene::chain::object),
(op)(result)(block_num)(trx_in_block)(op_in_trx)(virtual_op) )
FC_REFLECT_DERIVED( graphene::chain::account_transaction_history_object, (graphene::chain::object),
(account)(operation_id)(sequence)(next) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::operation_history_object )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_transaction_history_object )

View file

@ -27,9 +27,10 @@
#include <graphene/chain/transaction_evaluation_state.hpp>
#include <graphene/db/generic_index.hpp>
#include <boost/multi_index/composite_key.hpp>
namespace graphene { namespace chain {
class database;
/**
* @brief tracks the approval of a partially approved transaction
@ -96,4 +97,6 @@ typedef generic_index<proposal_object, proposal_multi_index_container> proposal_
FC_REFLECT_DERIVED( graphene::chain::proposal_object, (graphene::chain::object),
(expiration_time)(review_period_time)(proposed_transaction)(required_active_approvals)
(available_active_approvals)(required_owner_approvals)(available_owner_approvals)
(available_key_approvals)(proposer) )
(available_key_approvals)(proposer)(fail_reason))
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_object )

View file

@ -57,6 +57,12 @@ namespace graphene { namespace chain {
flat_set<vote_id_type> votes;
extensions_type extensions;
/// Whether this account is voting
inline bool is_voting() const
{
return ( voting_account != GRAPHENE_PROXY_TO_SELF_ACCOUNT || !votes.empty() );
}
void validate()const;
};
@ -140,6 +146,7 @@ namespace graphene { namespace chain {
optional< void_t > null_ext;
optional< special_authority > owner_special_authority;
optional< special_authority > active_special_authority;
optional< bool > update_last_voting_time;
};
struct fee_parameters_type
@ -295,7 +302,7 @@ FC_REFLECT( graphene::chain::account_create_operation,
(name)(owner)(active)(options)(extensions)
)
FC_REFLECT(graphene::chain::account_update_operation::ext, (null_ext)(owner_special_authority)(active_special_authority) )
FC_REFLECT(graphene::chain::account_update_operation::ext, (null_ext)(owner_special_authority)(active_special_authority)(update_last_voting_time) )
FC_REFLECT( graphene::chain::account_update_operation,
(fee)(account)(owner)(active)(new_options)(extensions)
)
@ -310,5 +317,16 @@ FC_REFLECT( graphene::chain::account_whitelist_operation::fee_parameters_type, (
FC_REFLECT( graphene::chain::account_update_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::account_upgrade_operation::fee_parameters_type, (membership_annual_fee)(membership_lifetime_fee) )
FC_REFLECT( graphene::chain::account_transfer_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::account_transfer_operation, (fee)(account_id)(new_owner)(extensions) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_options )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_create_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_whitelist_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_update_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_upgrade_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_transfer_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_create_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_whitelist_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_update_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_upgrade_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_transfer_operation )

View file

@ -25,14 +25,10 @@
#include <graphene/chain/config.hpp>
#include <graphene/chain/pts_address.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <fc/array.hpp>
#include <fc/crypto/ripemd160.hpp>
namespace fc { namespace ecc {
class public_key;
typedef fc::array<char,33> public_key_data;
} } // fc::ecc
#include <fc/reflect/typename.hpp>
namespace graphene { namespace chain {
@ -51,7 +47,7 @@ namespace graphene { namespace chain {
class address
{
public:
address(); ///< constructs empty / null address
address(){} ///< constructs empty / null address
explicit address( const std::string& base58str ); ///< converts to binary, validates checksum
address( const fc::ecc::public_key& pub ); ///< converts to binary
explicit address( const fc::ecc::public_key_data& pub ); ///< converts to binary
@ -78,8 +74,8 @@ namespace graphene { namespace chain {
namespace fc
{
void to_variant( const graphene::chain::address& var, fc::variant& vo );
void from_variant( const fc::variant& var, graphene::chain::address& vo );
void to_variant( const graphene::chain::address& var, fc::variant& vo, uint32_t max_depth = 1 );
void from_variant( const fc::variant& var, graphene::chain::address& vo, uint32_t max_depth = 1 );
}
namespace std
@ -97,3 +93,5 @@ namespace std
#include <fc/reflect/reflect.hpp>
FC_REFLECT( graphene::chain::address, (addr) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::address )

View file

@ -23,6 +23,7 @@
*/
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/asset.hpp>
namespace graphene { namespace chain {
@ -112,3 +113,5 @@ FC_REFLECT( graphene::chain::block_id_predicate, (id) )
FC_REFLECT_TYPENAME( graphene::chain::predicate )
FC_REFLECT( graphene::chain::assert_operation, (fee)(fee_paying_account)(predicates)(required_auths)(extensions) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::assert_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::assert_operation )

View file

@ -218,3 +218,7 @@ FC_REFLECT( graphene::chain::price, (base)(quote) )
(core_exchange_rate)
FC_REFLECT( graphene::chain::price_feed, GRAPHENE_PRICE_FEED_FIELDS )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::price )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::price_feed )

View file

@ -764,3 +764,30 @@ FC_REFLECT( graphene::chain::asset_reserve_operation,
FC_REFLECT( graphene::chain::asset_fund_fee_pool_operation, (fee)(from_account)(asset_id)(amount)(extensions) );
FC_REFLECT( graphene::chain::asset_dividend_distribution_operation, (fee)(dividend_asset_id)(account_id)(amounts)(extensions) );
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_options )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::bitasset_options )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_create_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_global_settle_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_settle_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_fund_fee_pool_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_dividend_distribution_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_claim_fees_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_bitasset_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_feed_producers_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_publish_feed_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_issue_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_reserve_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_create_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_global_settle_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_settle_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_settle_cancel_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_fund_fee_pool_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_claim_fees_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_bitasset_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_feed_producers_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_publish_feed_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_issue_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_reserve_operation )

View file

@ -23,6 +23,7 @@
*/
#pragma once
#include <graphene/chain/protocol/types.hpp>
#include <graphene/chain/protocol/address.hpp>
namespace graphene { namespace chain {
@ -134,3 +135,5 @@ void add_authority_accounts(
FC_REFLECT( graphene::chain::authority, (weight_threshold)(account_auths)(key_auths)(address_auths) )
// FC_REFLECT_TYPENAME( graphene::chain::authority::classification )
FC_REFLECT_ENUM( graphene::chain::authority::classification, (owner)(active)(key) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::authority )

View file

@ -23,6 +23,8 @@
*/
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/asset.hpp>
#include <graphene/chain/protocol/authority.hpp>
namespace graphene { namespace chain {
@ -57,3 +59,5 @@ namespace graphene { namespace chain {
FC_REFLECT( graphene::chain::balance_claim_operation::fee_parameters_type, )
FC_REFLECT( graphene::chain::balance_claim_operation,
(fee)(deposit_to_account)(balance_to_claim)(balance_owner_key)(total_claimed) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::balance_claim_operation )

View file

@ -27,8 +27,13 @@
#include <graphene/chain/protocol/asset.hpp>
#include <graphene/chain/protocol/authority.hpp>
#include <fc/thread/future.hpp>
namespace graphene { namespace chain {
struct asset;
struct authority;
/**
* @defgroup operations Operations
* @ingroup transactions Transactions

View file

@ -69,3 +69,8 @@ FC_REFLECT( graphene::chain::block_header,
(extensions) )
FC_REFLECT_DERIVED( graphene::chain::signed_block_header, (graphene::chain::block_header), (witness_signature) )
FC_REFLECT_DERIVED( graphene::chain::signed_block, (graphene::chain::signed_block_header), (transactions) )
GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::block_header)
GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::signed_block_header)
GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::signed_block)

View file

@ -50,3 +50,5 @@ struct buyback_account_options
} }
FC_REFLECT( graphene::chain::buyback_account_options, (asset_to_buy)(asset_to_buy_issuer)(markets) );
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::buyback_account_options )

View file

@ -27,19 +27,28 @@
#include <graphene/chain/protocol/types.hpp>
#include <fc/smart_ref_fwd.hpp>
#include <../hardfork.d/GPOS.hf>
#include <memory>
namespace graphene { namespace chain { struct fee_schedule; } }
namespace graphene { namespace chain {
struct parameter_extension
{
optional< bet_multiplier_type > min_bet_multiplier;
optional< bet_multiplier_type > max_bet_multiplier;
optional< uint16_t > betting_rake_fee_percentage;
optional< flat_map<bet_multiplier_type, bet_multiplier_type> > permitted_betting_odds_increments;
optional< uint16_t > live_betting_delay_time;
optional< uint16_t > sweeps_distribution_percentage;
optional< asset_id_type > sweeps_distribution_asset;
optional< account_id_type > sweeps_vesting_accumulator_account;
optional< bet_multiplier_type > min_bet_multiplier = GRAPHENE_DEFAULT_MIN_BET_MULTIPLIER;
optional< bet_multiplier_type > max_bet_multiplier = GRAPHENE_DEFAULT_MAX_BET_MULTIPLIER;
optional< uint16_t > betting_rake_fee_percentage = GRAPHENE_DEFAULT_RAKE_FEE_PERCENTAGE;
optional< flat_map<bet_multiplier_type, bet_multiplier_type> >
permitted_betting_odds_increments = flat_map<bet_multiplier_type, bet_multiplier_type>(GRAPHENE_DEFAULT_PERMITTED_BETTING_ODDS_INCREMENTS);
optional< uint16_t > live_betting_delay_time = GRAPHENE_DEFAULT_LIVE_BETTING_DELAY_TIME;
optional< uint16_t > sweeps_distribution_percentage = SWEEPS_DEFAULT_DISTRIBUTION_PERCENTAGE;
optional< asset_id_type > sweeps_distribution_asset = SWEEPS_DEFAULT_DISTRIBUTION_ASSET;
optional< account_id_type > sweeps_vesting_accumulator_account= SWEEPS_ACCUMULATOR_ACCOUNT;
/* gpos parameters */
optional < uint32_t > gpos_period = GPOS_PERIOD;
optional < uint32_t > gpos_subperiod = GPOS_SUBPERIOD;
optional < uint32_t > gpos_period_start = HARDFORK_GPOS_TIME.sec_since_epoch();
optional < uint32_t > gpos_vesting_lockin_period = GPOS_VESTING_LOCKIN_PERIOD;
};
struct chain_parameters
@ -119,6 +128,18 @@ namespace graphene { namespace chain {
inline account_id_type sweeps_vesting_accumulator_account()const {
return extensions.value.sweeps_vesting_accumulator_account.valid() ? *extensions.value.sweeps_vesting_accumulator_account : SWEEPS_ACCUMULATOR_ACCOUNT;
}
inline uint32_t gpos_period()const {
return extensions.value.gpos_period.valid() ? *extensions.value.gpos_period : GPOS_PERIOD; /// total seconds of current gpos period
}
inline uint32_t gpos_subperiod()const {
return extensions.value.gpos_subperiod.valid() ? *extensions.value.gpos_subperiod : GPOS_SUBPERIOD; /// gpos_period % gpos_subperiod = 0
}
inline uint32_t gpos_period_start()const {
return extensions.value.gpos_period_start.valid() ? *extensions.value.gpos_period_start : HARDFORK_GPOS_TIME.sec_since_epoch(); /// current period start date
}
inline uint32_t gpos_vesting_lockin_period()const {
return extensions.value.gpos_vesting_lockin_period.valid() ? *extensions.value.gpos_vesting_lockin_period : GPOS_VESTING_LOCKIN_PERIOD; /// GPOS vesting lockin period
}
};
} } // graphene::chain
@ -127,11 +148,14 @@ FC_REFLECT( graphene::chain::parameter_extension,
(min_bet_multiplier)
(max_bet_multiplier)
(betting_rake_fee_percentage)
(permitted_betting_odds_increments)
(live_betting_delay_time)
(sweeps_distribution_percentage)
(sweeps_distribution_asset)
(sweeps_vesting_accumulator_account)
(gpos_period)
(gpos_subperiod)
(gpos_period_start)
(gpos_vesting_lockin_period)
)
FC_REFLECT( graphene::chain::chain_parameters,
@ -179,3 +203,5 @@ FC_REFLECT( graphene::chain::chain_parameters,
(maximum_tournament_number_of_wins)
(extensions)
)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::chain_parameters )

View file

@ -104,3 +104,10 @@ FC_REFLECT( graphene::chain::committee_member_create_operation,
FC_REFLECT( graphene::chain::committee_member_update_operation,
(fee)(committee_member)(committee_member_account)(new_url) )
FC_REFLECT( graphene::chain::committee_member_update_global_parameters_operation, (fee)(new_parameters) );
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_create_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_update_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_update_global_parameters_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_create_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_update_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_update_global_parameters_operation )

View file

@ -281,3 +281,10 @@ FC_REFLECT( graphene::chain::blind_transfer_operation,
FC_REFLECT( graphene::chain::transfer_to_blind_operation::fee_parameters_type, (fee)(price_per_output) )
FC_REFLECT( graphene::chain::transfer_from_blind_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::blind_transfer_operation::fee_parameters_type, (fee)(price_per_output) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_to_blind_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_from_blind_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::blind_transfer_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_to_blind_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_from_blind_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::blind_transfer_operation )

View file

@ -56,3 +56,6 @@ namespace graphene { namespace chain {
FC_REFLECT( graphene::chain::custom_operation::fee_parameters_type, (fee)(price_per_kbyte) )
FC_REFLECT( graphene::chain::custom_operation, (fee)(payer)(required_auths)(id)(data) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::custom_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::custom_operation )

View file

@ -24,6 +24,7 @@
#pragma once
#include <fc/io/varint.hpp>
#include <fc/io/raw_fwd.hpp>
#include <fc/reflect/reflect.hpp>
namespace graphene { namespace chain {
@ -145,9 +146,10 @@ namespace fc {
template< typename T >
struct graphene_extension_from_variant_visitor
{
graphene_extension_from_variant_visitor( const variant_object& v, T& val )
: vo( v ), value( val )
graphene_extension_from_variant_visitor( const variant_object& v, T& val, uint32_t max_depth )
: vo( v ), value( val ), _max_depth(max_depth - 1)
{
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
count_left = vo.size();
}
@ -157,7 +159,7 @@ struct graphene_extension_from_variant_visitor
auto it = vo.find(name);
if( it != vo.end() )
{
from_variant( it->value(), (value.*member) );
from_variant( it->value(), (value.*member), _max_depth );
assert( count_left > 0 ); // x.find(k) returns true for n distinct values of k only if x.size() >= n
--count_left;
}
@ -165,11 +167,12 @@ struct graphene_extension_from_variant_visitor
const variant_object& vo;
T& value;
const uint32_t _max_depth;
mutable uint32_t count_left = 0;
};
template< typename T >
void from_variant( const fc::variant& var, graphene::chain::extension<T>& value )
void from_variant( const fc::variant& var, graphene::chain::extension<T>& value, uint32_t max_depth )
{
value = graphene::chain::extension<T>();
if( var.is_null() )
@ -180,7 +183,7 @@ void from_variant( const fc::variant& var, graphene::chain::extension<T>& value
return;
}
graphene_extension_from_variant_visitor<T> vtor( var.get_object(), value.value );
graphene_extension_from_variant_visitor<T> vtor( var.get_object(), value.value, max_depth );
fc::reflector<T>::visit( vtor );
FC_ASSERT( vtor.count_left == 0 ); // unrecognized extension throws here
}
@ -188,23 +191,23 @@ void from_variant( const fc::variant& var, graphene::chain::extension<T>& value
template< typename T >
struct graphene_extension_to_variant_visitor
{
graphene_extension_to_variant_visitor( const T& v ) : value(v) {}
graphene_extension_to_variant_visitor( const T& v, uint32_t max_depth ) : value(v), mvo(max_depth) {}
template<typename Member, class Class, Member (Class::*member)>
void operator()( const char* name )const
{
if( (value.*member).valid() )
mvo[ name ] = (value.*member);
mvo( name, value.*member );
}
const T& value;
mutable mutable_variant_object mvo;
mutable limited_mutable_variant_object mvo;
};
template< typename T >
void to_variant( const graphene::chain::extension<T>& value, fc::variant& var )
void to_variant( const graphene::chain::extension<T>& value, fc::variant& var, uint32_t max_depth )
{
graphene_extension_to_variant_visitor<T> vtor( value.value );
graphene_extension_to_variant_visitor<T> vtor( value.value, max_depth );
fc::reflector<T>::visit( vtor );
var = vtor.mvo;
}

View file

@ -23,6 +23,7 @@
*/
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/asset.hpp>
namespace graphene { namespace chain {
@ -45,3 +46,5 @@ struct fba_distribute_operation : public base_operation
FC_REFLECT( graphene::chain::fba_distribute_operation::fee_parameters_type, )
FC_REFLECT( graphene::chain::fba_distribute_operation, (fee)(account_id)(fba_id)(amount) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::fba_distribute_operation )

View file

@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#pragma once
#include <fc/smart_ref_fwd.hpp>
#include <graphene/chain/protocol/operations.hpp>
namespace graphene { namespace chain {
@ -85,3 +86,5 @@ namespace graphene { namespace chain {
FC_REFLECT_TYPENAME( graphene::chain::fee_parameters )
FC_REFLECT( graphene::chain::fee_schedule, (parameters)(scale) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::fee_schedule )

View file

@ -23,6 +23,7 @@
*/
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/asset.hpp>
namespace graphene { namespace chain {
@ -165,9 +166,15 @@ FC_REFLECT( graphene::chain::limit_order_cancel_operation::fee_parameters_type,
FC_REFLECT( graphene::chain::call_order_update_operation::fee_parameters_type, (fee) )
/// THIS IS THE ONLY VIRTUAL OPERATION THUS FAR...
FC_REFLECT( graphene::chain::fill_order_operation::fee_parameters_type, )
FC_REFLECT( graphene::chain::limit_order_create_operation,(fee)(seller)(amount_to_sell)(min_to_receive)(expiration)(fill_or_kill)(extensions))
FC_REFLECT( graphene::chain::limit_order_cancel_operation,(fee)(fee_paying_account)(order)(extensions) )
FC_REFLECT( graphene::chain::call_order_update_operation, (fee)(funding_account)(delta_collateral)(delta_debt)(extensions) )
FC_REFLECT( graphene::chain::fill_order_operation, (fee)(order_id)(account_id)(pays)(receives) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::limit_order_create_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::limit_order_cancel_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::call_order_update_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::limit_order_create_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::limit_order_cancel_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::call_order_update_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::fill_order_operation )

View file

@ -89,3 +89,6 @@ namespace graphene { namespace chain {
FC_REFLECT( graphene::chain::memo_message, (checksum)(text) )
FC_REFLECT( graphene::chain::memo_data, (from)(to)(nonce)(message) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::memo_message )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::memo_data )

View file

@ -167,3 +167,5 @@ namespace graphene { namespace chain {
FC_REFLECT_TYPENAME( graphene::chain::operation )
FC_REFLECT( graphene::chain::op_wrapper, (op) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::op_wrapper )

View file

@ -23,6 +23,7 @@
*/
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/asset.hpp>
namespace graphene { namespace chain {
/**
@ -179,3 +180,10 @@ FC_REFLECT( graphene::chain::proposal_update_operation, (fee)(fee_paying_account
(active_approvals_to_add)(active_approvals_to_remove)(owner_approvals_to_add)(owner_approvals_to_remove)
(key_approvals_to_add)(key_approvals_to_remove)(extensions) )
FC_REFLECT( graphene::chain::proposal_delete_operation, (fee)(fee_paying_account)(using_owner_authority)(proposal)(extensions) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_create_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_update_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_delete_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_create_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_update_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_delete_operation )

View file

@ -48,3 +48,5 @@ void validate_special_authority( const special_authority& auth );
FC_REFLECT( graphene::chain::no_special_authority, )
FC_REFLECT( graphene::chain::top_holders_special_authority, (asset)(num_top_holders) )
FC_REFLECT_TYPENAME( graphene::chain::special_authority )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::top_holders_special_authority )

View file

@ -165,12 +165,30 @@ namespace graphene { namespace chain {
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH
) const;
flat_set<public_key_type> get_signature_keys( const chain_id_type& chain_id )const;
/**
* @brief Extract public keys from signatures with given chain ID.
* @param chain_id A chain ID
* @return Public keys
* @note If @ref signees is empty, E.G. when it's the first time calling
* this function for the signed transaction, public keys will be
* extracted with given chain ID, and be stored into the mutable
* @ref signees field, then @ref signees will be returned;
* otherwise, the @ref chain_id parameter will be ignored, and
* @ref signees will be returned directly.
*/
const flat_set<public_key_type>& get_signature_keys( const chain_id_type& chain_id )const;
/** Signatures */
vector<signature_type> signatures;
/// Removes all operations and signatures
void clear() { operations.clear(); signatures.clear(); }
/** Public keys extracted from signatures */
mutable flat_set<public_key_type> signees;
/// Removes all operations, signatures and signees
void clear() { operations.clear(); signatures.clear(); signees.clear(); }
/// Removes all signatures and signees
void clear_signatures() { signatures.clear(); signees.clear(); }
};
void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
@ -209,5 +227,11 @@ namespace graphene { namespace chain {
} } // graphene::chain
FC_REFLECT( graphene::chain::transaction, (ref_block_num)(ref_block_prefix)(expiration)(operations)(extensions) )
// Note: not reflecting signees field for backward compatibility; in addition, it should not be in p2p messages
FC_REFLECT_DERIVED( graphene::chain::signed_transaction, (graphene::chain::transaction), (signatures) )
FC_REFLECT_DERIVED( graphene::chain::processed_transaction, (graphene::chain::signed_transaction), (operation_results) )
GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::transaction)
GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::signed_transaction)
GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::processed_transaction)

View file

@ -24,6 +24,7 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/memo.hpp>
#include <graphene/chain/protocol/asset.hpp>
namespace graphene { namespace chain {
@ -105,3 +106,8 @@ FC_REFLECT( graphene::chain::override_transfer_operation::fee_parameters_type, (
FC_REFLECT( graphene::chain::override_transfer_operation, (fee)(issuer)(from)(to)(amount)(memo)(extensions) )
FC_REFLECT( graphene::chain::transfer_operation, (fee)(from)(to)(amount)(memo)(extensions) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::override_transfer_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::override_transfer_operation )

View file

@ -27,13 +27,15 @@
#include <fc/io/enum_type.hpp>
#include <fc/crypto/sha224.hpp>
#include <fc/crypto/elliptic.hpp>
#include <fc/crypto/ripemd160.hpp>
#include <fc/reflect/reflect.hpp>
#include <fc/reflect/variant.hpp>
#include <fc/optional.hpp>
#include <fc/safe.hpp>
#include <fc/container/flat.hpp>
#include <fc/string.hpp>
#include <fc/io/raw.hpp>
#include <fc/io/datastream.hpp>
#include <fc/io/raw_fwd.hpp>
#include <fc/uint128.hpp>
#include <fc/static_variant.hpp>
#include <fc/smart_ref_fwd.hpp>
@ -42,10 +44,34 @@
#include <vector>
#include <deque>
#include <cstdint>
#include <graphene/chain/protocol/address.hpp>
#include <graphene/db/object_id.hpp>
#include <graphene/chain/protocol/config.hpp>
#define GRAPHENE_EXTERNAL_SERIALIZATION(ext, type) \
namespace fc { \
ext template void from_variant( const variant& v, type& vo, uint32_t max_depth ); \
ext template void to_variant( const type& v, variant& vo, uint32_t max_depth ); \
namespace raw { \
ext template void pack< datastream<size_t>, type >( datastream<size_t>& s, const type& tx, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); \
ext template void pack< datastream<char*>, type >( datastream<char*>& s, const type& tx, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); \
ext template void unpack< datastream<const char*>, type >( datastream<const char*>& s, type& tx, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); \
} } // fc::raw
#define FC_REFLECT_DERIVED_NO_TYPENAME( TYPE, INHERITS, MEMBERS ) \
namespace fc { \
template<> struct reflector<TYPE> {\
typedef TYPE type; \
typedef fc::true_type is_defined; \
typedef fc::false_type is_enum; \
enum member_count_enum { \
local_member_count = 0 BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_MEMBER_COUNT, +, MEMBERS ),\
total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\
}; \
FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \
}; \
} // fc
namespace graphene { namespace chain {
using namespace graphene::db;
@ -367,12 +393,12 @@ namespace graphene { namespace chain {
namespace fc
{
void to_variant( const graphene::chain::public_key_type& var, fc::variant& vo );
void from_variant( const fc::variant& var, graphene::chain::public_key_type& vo );
void to_variant( const graphene::chain::extended_public_key_type& var, fc::variant& vo );
void from_variant( const fc::variant& var, graphene::chain::extended_public_key_type& vo );
void to_variant( const graphene::chain::extended_private_key_type& var, fc::variant& vo );
void from_variant( const fc::variant& var, graphene::chain::extended_private_key_type& vo );
void to_variant( const graphene::chain::public_key_type& var, fc::variant& vo, uint32_t max_depth = 2 );
void from_variant( const fc::variant& var, graphene::chain::public_key_type& vo, uint32_t max_depth = 2 );
void to_variant( const graphene::chain::extended_public_key_type& var, fc::variant& vo, uint32_t max_depth = 2 );
void from_variant( const fc::variant& var, graphene::chain::extended_public_key_type& vo, uint32_t max_depth = 2 );
void to_variant( const graphene::chain::extended_private_key_type& var, fc::variant& vo, uint32_t max_depth = 2 );
void from_variant( const fc::variant& var, graphene::chain::extended_private_key_type& vo, uint32_t max_depth = 2 );
}
FC_REFLECT( graphene::chain::public_key_type, (key_data) )

View file

@ -23,9 +23,22 @@
*/
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/asset.hpp>
namespace graphene { namespace chain {
enum class vesting_balance_type { normal, gpos };
inline std::string get_vesting_balance_type(vesting_balance_type type) {
switch (type) {
case vesting_balance_type::normal:
return "NORMAL";
case vesting_balance_type::gpos:
default:
return "GPOS";
}
}
struct linear_vesting_policy_initializer
{
/** while vesting begins on begin_timestamp, none may be claimed before vesting_cliff_seconds have passed */
@ -72,6 +85,7 @@ namespace graphene { namespace chain {
account_id_type owner; ///< Who is able to withdraw the balance
asset amount;
vesting_policy_initializer policy;
vesting_balance_type balance_type;
account_id_type fee_payer()const { return creator; }
void validate()const
@ -98,6 +112,7 @@ namespace graphene { namespace chain {
vesting_balance_id_type vesting_balance;
account_id_type owner; ///< Must be vesting_balance.owner
asset amount;
vesting_balance_type balance_type;
account_id_type fee_payer()const { return owner; }
void validate()const
@ -112,9 +127,16 @@ namespace graphene { namespace chain {
FC_REFLECT( graphene::chain::vesting_balance_create_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::vesting_balance_create_operation, (fee)(creator)(owner)(amount)(policy) )
FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation, (fee)(vesting_balance)(owner)(amount) )
FC_REFLECT( graphene::chain::vesting_balance_create_operation, (fee)(creator)(owner)(amount)(policy)(balance_type) )
FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation, (fee)(vesting_balance)(owner)(amount)(balance_type) )
FC_REFLECT(graphene::chain::linear_vesting_policy_initializer, (begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds) )
FC_REFLECT(graphene::chain::cdd_vesting_policy_initializer, (start_claim)(vesting_seconds) )
FC_REFLECT_TYPENAME( graphene::chain::vesting_policy_initializer )
FC_REFLECT_ENUM( graphene::chain::vesting_balance_type, (normal)(gpos) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vesting_balance_create_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vesting_balance_withdraw_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vesting_balance_create_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vesting_balance_withdraw_operation )

View file

@ -24,12 +24,7 @@
#pragma once
#include <cassert>
#include <cstdint>
#include <string>
#include <fc/container/flat.hpp>
#include <fc/reflect/reflect.hpp>
#include <graphene/chain/protocol/types.hpp>
namespace graphene { namespace chain {
@ -141,8 +136,8 @@ namespace fc
class variant;
void to_variant( const graphene::chain::vote_id_type& var, fc::variant& vo );
void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo );
void to_variant( const graphene::chain::vote_id_type& var, fc::variant& vo, uint32_t max_depth = 1 );
void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo, uint32_t max_depth = 1 );
} // fc
@ -150,3 +145,5 @@ FC_REFLECT_TYPENAME( fc::flat_set<graphene::chain::vote_id_type> )
FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(VOTE_TYPE_COUNT) )
FC_REFLECT( graphene::chain::vote_id_type, (content) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vote_id_type )

View file

@ -24,6 +24,7 @@
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/memo.hpp>
#include <graphene/chain/protocol/asset.hpp>
namespace graphene { namespace chain {
@ -179,3 +180,12 @@ FC_REFLECT( graphene::chain::withdraw_permission_update_operation, (fee)(withdra
FC_REFLECT( graphene::chain::withdraw_permission_claim_operation, (fee)(withdraw_permission)(withdraw_from_account)(withdraw_to_account)(amount_to_withdraw)(memo) );
FC_REFLECT( graphene::chain::withdraw_permission_delete_operation, (fee)(withdraw_from_account)(authorized_account)
(withdrawal_permission) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_create_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_update_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_claim_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_delete_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_create_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_update_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_claim_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_delete_operation )

View file

@ -23,6 +23,7 @@
*/
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/asset.hpp>
namespace graphene { namespace chain {
@ -84,3 +85,8 @@ FC_REFLECT( graphene::chain::witness_create_operation, (fee)(witness_account)(ur
FC_REFLECT( graphene::chain::witness_update_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::witness_update_operation, (fee)(witness)(witness_account)(new_url)(new_signing_key)(new_initial_secret) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_create_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_update_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_create_operation )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_update_operation )

View file

@ -23,6 +23,7 @@
*/
#pragma once
#include <graphene/chain/protocol/base.hpp>
#include <graphene/chain/protocol/asset.hpp>
namespace graphene { namespace chain {
@ -104,3 +105,5 @@ FC_REFLECT( graphene::chain::worker_create_operation::fee_parameters_type, (fee)
FC_REFLECT( graphene::chain::worker_create_operation,
(fee)(owner)(work_begin_date)(work_end_date)(daily_pay)(name)(url)(initializer) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::worker_create_operation::fee_parameters_type )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::worker_create_operation )

View file

@ -24,6 +24,8 @@
#pragma once
#include <fc/array.hpp>
#include <fc/io/datastream.hpp>
#include <fc/io/raw_fwd.hpp>
#include <string>
namespace fc { namespace ecc { class public_key; } }
@ -73,6 +75,13 @@ FC_REFLECT( graphene::chain::pts_address, (addr) )
namespace fc
{
void to_variant( const graphene::chain::pts_address& var, fc::variant& vo );
void from_variant( const fc::variant& var, graphene::chain::pts_address& vo );
}
void to_variant( const graphene::chain::pts_address& var, fc::variant& vo, uint32_t max_depth = 1 );
void from_variant( const fc::variant& var, graphene::chain::pts_address& vo, uint32_t max_depth = 1 );
namespace raw {
extern template void pack( datastream<size_t>& s, const graphene::chain::pts_address& tx,
uint32_t _max_depth=FC_PACK_MAX_DEPTH );
extern template void pack( datastream<char*>& s, const graphene::chain::pts_address& tx,
uint32_t _max_depth=FC_PACK_MAX_DEPTH );
extern template void unpack( datastream<const char*>& s, graphene::chain::pts_address& tx,
uint32_t _max_depth=FC_PACK_MAX_DEPTH );
} } // fc::raw

View file

@ -68,3 +68,5 @@ FC_REFLECT_DERIVED(
(graphene::db::object),
(account)
)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::special_authority_object )

View file

@ -12,8 +12,8 @@ namespace graphene { namespace chain {
} }
namespace fc {
void to_variant(const graphene::chain::tournament_object& tournament_obj, fc::variant& v);
void from_variant(const fc::variant& v, graphene::chain::tournament_object& tournament_obj);
void to_variant(const graphene::chain::tournament_object& tournament_obj, fc::variant& v, uint32_t max_depth = 1);
void from_variant(const fc::variant& v, graphene::chain::tournament_object& tournament_obj, uint32_t max_depth = 1);
} //end namespace fc
namespace graphene { namespace chain {
@ -108,8 +108,8 @@ namespace graphene { namespace chain {
template<typename Stream>
friend Stream& operator>>( Stream& s, tournament_object& tournament_obj );
friend void ::fc::to_variant(const graphene::chain::tournament_object& tournament_obj, fc::variant& v);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::tournament_object& tournament_obj);
friend void ::fc::to_variant(const graphene::chain::tournament_object& tournament_obj, fc::variant& v, uint32_t max_depth);
friend void ::fc::from_variant(const fc::variant& v, graphene::chain::tournament_object& tournament_obj, uint32_t max_depth);
void pack_impl(std::ostream& stream) const;
void unpack_impl(std::istream& stream);

View file

@ -22,12 +22,10 @@
* THE SOFTWARE.
*/
#pragma once
#include <fc/io/raw.hpp>
#include <graphene/chain/protocol/transaction.hpp>
#include <graphene/db/index.hpp>
#include <graphene/db/generic_index.hpp>
#include <fc/uint128.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
@ -72,3 +70,5 @@ namespace graphene { namespace chain {
} }
FC_REFLECT_DERIVED( graphene::chain::transaction_object, (graphene::db::object), (trx)(trx_id) )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transaction_object )

View file

@ -46,6 +46,7 @@ class vesting_balance_withdraw_evaluator : public evaluator<vesting_balance_with
void_result do_evaluate( const vesting_balance_withdraw_operation& op );
void_result do_apply( const vesting_balance_withdraw_operation& op );
virtual operation_result start_evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply);
};
} } // graphene::chain

View file

@ -24,6 +24,8 @@
#pragma once
#include <graphene/chain/protocol/asset.hpp>
#include <graphene/chain/protocol/vesting.hpp>
#include <graphene/db/object.hpp>
#include <graphene/db/generic_index.hpp>
@ -36,8 +38,6 @@
namespace graphene { namespace chain {
using namespace graphene::db;
class vesting_balance_object;
struct vesting_policy_context
{
vesting_policy_context(
@ -140,6 +140,9 @@ namespace graphene { namespace chain {
/// The vesting policy stores details on when funds vest, and controls when they may be withdrawn
vesting_policy policy;
/// We can have 2 types of vesting, gpos and all the rest
vesting_balance_type balance_type = vesting_balance_type::normal;
vesting_balance_object() {}
asset_id_type get_asset_id() const { return balance.asset_id; }
@ -186,12 +189,14 @@ namespace graphene { namespace chain {
composite_key<
vesting_balance_object,
member_offset<vesting_balance_object, asset_id_type, (size_t) (offsetof(vesting_balance_object,balance) + offsetof(asset,asset_id))>,
member<vesting_balance_object, vesting_balance_type, &vesting_balance_object::balance_type>,
member_offset<vesting_balance_object, share_type, (size_t) (offsetof(vesting_balance_object,balance) + offsetof(asset,amount))>
//member<vesting_balance_object, account_id_type, &vesting_balance_object::owner>
//member_offset<vesting_balance_object, account_id_type, (size_t) (offsetof(vesting_balance_object,owner))>
>,
composite_key_compare<
std::less< asset_id_type >,
std::less< vesting_balance_type >,
std::greater< share_type >
//std::less< account_id_type >
>
@ -225,4 +230,9 @@ FC_REFLECT_DERIVED(graphene::chain::vesting_balance_object, (graphene::db::objec
(owner)
(balance)
(policy)
(balance_type)
)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::linear_vesting_policy )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::cdd_vesting_policy )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vesting_balance_object )

View file

@ -114,3 +114,5 @@ FC_REFLECT_DERIVED( graphene::chain::withdraw_permission_object, (graphene::db::
(expiration)
(claimed_this_period)
)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_object )

View file

@ -29,8 +29,6 @@
namespace graphene { namespace chain {
using namespace graphene::db;
class witness_object;
class witness_object : public abstract_object<witness_object>
{
public:
@ -85,3 +83,5 @@ FC_REFLECT_DERIVED( graphene::chain::witness_object, (graphene::db::object),
(total_missed)
(last_confirmed_block_num)
)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_object )

View file

@ -30,8 +30,6 @@
namespace graphene { namespace chain {
class witness_schedule_object;
typedef hash_ctr_rng<
/* HashClass = */ fc::sha256,
/* SeedLength = */ GRAPHENE_RNG_SEED_LENGTH
@ -96,3 +94,6 @@ FC_REFLECT_DERIVED(
(recent_slots_filled)
(current_shuffled_witnesses)
)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_scheduler )
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_schedule_object )

View file

@ -22,8 +22,9 @@
* THE SOFTWARE.
*/
#pragma once
#include <graphene/db/object.hpp>
#include <graphene/chain/protocol/types.hpp>
#include <graphene/db/generic_index.hpp>
#include <graphene/chain/protocol/vote.hpp>
namespace graphene { namespace chain {
@ -175,3 +176,5 @@ FC_REFLECT_DERIVED( graphene::chain::worker_object, (graphene::db::object),
(name)
(url)
)
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::worker_object )

Some files were not shown because too many files have changed in this diff Show more