Merge beatrice(GPOS changes) with master (#270)

* Created unit test for #325

* remove needless find()

* issue - 154: Don't allow to vote when vesting balance is 0

* Increase block creation timeout to 2500ms

* increase delay for node connection

* remove cache from cli get_account

* add cli tests framework

* Adjust newly merged code to new API

* Merged changes from Bitshares PR 1036

* GRPH-76 - Short-cut long sequences of missed blocks

Fixes database::update_global_dynamic_data to speed up counting missed blocks.
(This also fixes a minor issue with counting - the previous algorithm would skip missed blocks for the witness who signed the first block after the gap.)

* Improved resilience of block database against corruption

* Moved reindex logic into database / chain_database, make use of additional blocks in block_database

Fixed tests wrt db.open

* Enable undo + fork database for final blocks in a replay

Dont remove blocks from block db when popping blocks, handle edge case in replay wrt fork_db, adapted unit tests

* Log starting block number of replay

* Prevent unsigned integer underflow

* Fixed lock detection

* Dont leave _data_dir empty if db is locked

* Writing the object_database is now almost atomic

* Improved consistency check for block_log

* Cut back block_log index file if inconsistent

* Fixed undo_database

* Added test case for broken merge on empty undo_db

* exclude second undo_db.enable() call in some cases

* Add missing change

* change bitshares to core in message

* Merge pull request #938 from bitshares/fix-block-storing

Store correct block ID when switching forks

* Fixed integer overflow issue

* Fix for for history ID mismatch ( Bitshares PR #875 )

* Update the FC submodule with the changes for GRPH-4

* Merged Bitshares PR #1462 and compilation fixes

* Support/gitlab (#123)

* Updated gitlab process

* Fix undefined references in cli test

* Updated GitLab CI

* Fix #436 object_database created outside of witness data directory

* supplement more comments on database::_opened variable

* prevent segfault when destructing application obj

* Fixed test failures and compilation issue

* minor performance improvement

* Added comment

* Fix compilation in debug mode

* Fixed duplicate ops returned from get_account_history

* Fixed account_history_pagination test

* Removed unrelated comment

* Update to fixed version of fc

* Skip auth check when pushing self-generated blocks

* Extract public keys before pushing a transaction

* Dereference chain_database shared_ptr

* Updated transaction::signees to mutable

and
* updated get_signature_keys() to return a const reference,
* get_signature_keys() will update signees on first call,
* modified test cases and wallet.cpp accordingly,
* no longer construct a new signed_transaction object before pushing

* Added get_asset_count API

* No longer extract public keys before pushing a trx

and removed unused new added constructor and _get_signature_keys() function from signed_transaction struct

* changes to withdraw_vesting feature(for both cdd and GPOS)

* Comments update

* update to GPOS hardfork ref

* Remove leftover comment from merge

* fix for get_vesting_balance API call

* braces update

* Allow sufficient space for new undo_session

* Throw for deep nesting

* node.cpp: Check the attacker/buggy client before updating items ids

The peer is an attacker or buggy, which means the item_hashes_received is
not correct.

Move the check before updating items ids to save some time in this case.

* Create .gitlab-ci.yml

* Added cli_test to CI

* fixing build errors (#150)

* fixing build errors

vest type correction

* fixing build errors

vest type correction

* fixes 

new Dockerfile

* vesting_balance_type correction

vesting_balance_type changed to normal

* gcc5 support to Dockerfile

gcc5 support to Dockerfile

* use random port numbers in app_test (#154)

* Changes to compiple with GCC 7(Ubuntu 18.04)

* proposal fail_reason bug fixed (#157)

* Added Sonarcloud code_quality to CI (#159)

* Added sonarcloud analysis (#158)

* changes to have separate methods and single withdrawl fee for multiple vest objects

* 163-fix, Return only non-zero vesting balances

* Support/gitlab develop (#168)

* Added code_quality to CI

* Update .gitlab-ci.yml

* Point to PBSA/peerplays-fc commit f13d063 (#167)

* [GRPH-3] Additional cli tests (#155)

* Additional cli tests

* Compatible with latest fc changes

* Fixed Spacing issues

* [GRPH-106] Added voting tests (#136)

* Added more voting tests

* Added additional option

* Adjust p2p log level (#180)

* merge gpos to develop (#186)

* issue - 154: Don't allow to vote when vesting balance is 0

* changes to withdraw_vesting feature(for both cdd and GPOS)

* Comments update

* update to GPOS hardfork ref

* fix for get_vesting_balance API call

* braces update

* Create .gitlab-ci.yml

* fixing build errors (#150)

* fixing build errors

vest type correction

* fixing build errors

vest type correction

* fixes 

new Dockerfile

* vesting_balance_type correction

vesting_balance_type changed to normal

* gcc5 support to Dockerfile

gcc5 support to Dockerfile

* Changes to compiple with GCC 7(Ubuntu 18.04)

* changes to have separate methods and single withdrawl fee for multiple vest objects

* 163-fix, Return only non-zero vesting balances

* Revert "Revert "GPOS protocol""

This reverts commit 67616417b7.

* add new line needed to gpos hardfork file

* comment temporally cli_vote_for_2_witnesses until refactor or delete

* fix gpos tests

* fix gitlab-ci conflict

* Fixed few error messages

* error message corrections at other places

* Updated FC repository to peerplays-network/peerplays-fc (#189)

Point to fc commit hash 6096e94 [latest-fc branch]

* Project name update in Doxyfile (#146)

* changes to allow user to vote in each sub-period

* Fixed GPOS vesting factor issue when proxy is set

* Added unit test for proxy voting

* Review changes

* changes to update last voting time

* resolve merge conflict

* unit test changes and also separated GPOS test suite

* delete unused variables

* removed witness check

* eliminate time gap between two consecutive vesting periods

* deleted GPOS specific test suite and updated gpos tests

* updated GPOS hf

* Fixed dividend distribution issue and added test case

* fix flag

* clean newlines gpos_tests

* adapt gpos_tests to changed flag

* Fix to roll in GPOS rules, carry votes from 6th sub-period

* check was already modified

* comments updated

* updated comments to the benefit of reviewer

* Added token symbol name in error messages

* Added token symbol name in error messages (#204)

* case 1: Fixed last voting time issue

* get_account bug fixed

* Fixed flag issue

* Fixed spelling issue

* remove non needed gcc5 changes to dockerfile

* GRPH134- High CPU Issue, websocket changes (#213)

* update submodule branch to refer to the latest commit on latest-fc branch (#214)

* Improve account maintenance performance (#130)

* Improve account maintenance performance

* merge fixes

* Fixed merge issue

* Fixed indentations and extra ';'

* Update CI for syncing gitmodules (#216)

* Added logging for the old update_expired_feeds bug

The old bug is https://github.com/cryptonomex/graphene/issues/615 .

Due to the bug, `update_median_feeds()` and `check_call_orders()`
will be called when a feed is not actually expired, normally this
should not affect consensus since calling them should not change
any data in the state.

However, the logging indicates that `check_call_orders()` did
change some data under certain circumstances, specifically, when
multiple limit order matching issue (#453) occurred at same block.
* https://github.com/bitshares/bitshares-core/issues/453

* Minor performance improvement for price::is_null()

* Use static refs in db_getter for immutable objects

* Minor performance improvement for db_maint

* Minor code updates for asset_evaluator.cpp

* changed an `assert()` to `FC_ASSERT()`
* replaced one `db.get(asset_id_type())` with `db.get_core_asset()`
* capture only required variables for lambda

* Improve update_expired_feeds performance #1093

* Change static refs to member pointers of db class

* Added getter for witness schedule object

* Added getter for core dynamic data object

* Use getters

* Removed unused variable

* Add comments for update_expired_feeds in db_block

* Minor refactory asset_create_evaluator::do_apply()

* Added FC_ASSERT for dynamic data id of core asset

* Added header inclusions in db_management.cpp

* fix global objects usage during replay

* Logging config parsing issue

* added new files

* compilation fix

* Simplified code in database::pay_workers()

* issue with withdrawl

* Added unit test for empty account history

* set extensions default values

* Update GPOS hardfork date and don't allow GPOS features before hardfork time

* refer to latest commit of latest-fc branch (#224)

* account name or id support in all database api

* asset id or name support in all asset APIs

* Fixed compilation issues

* Fixed alignment issues

* Externalized some API templates

* Externalize serialization of blocks, tx, ops

* Externalized db objects

* Externalized genesis serialization

* Externalized serialization in protocol library

* Undo superfluous change

* remove default value for extension parameter

* fix compilation issues

* GRPH-46-Quit_command_cliwallet

* removed multiple function definition

* Fixed chainparameter update proposal issue

* Move GPOS withdraw logic to have single transaction(also single fee) and update API

* Added log for authorization failure of proposal operations

* Votes consideration on GPOS activation

* bump fc version

* fix gpos tests

* Bump fc version

* Updated gpos/voting_tests

* Fixed withdraw vesting bug

* Added unit test

* Update hardfork date for TESTNET, sync fc module and update logs

* avoid wlog as it filling up space

* Beatrice hot fix(sync issue fix)

* gpos tests fix

* Set hardfork date to Jan5th on TESTNET

Co-authored-by: Peter Conrad <github.com@quisquis.de>
Co-authored-by: John M. Jones <jmjatlanta@gmail.com>
Co-authored-by: obucinac <obucinac@users.noreply.github.com>
Co-authored-by: Bobinson K B <bobinson@gmail.com>
Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>
Co-authored-by: Miha Čančula <miha@noughmad.eu>
Co-authored-by: Abit <abitmore@users.noreply.github.com>
Co-authored-by: Roshan Syed <r.syed@pbsa.info>
Co-authored-by: Sandip Patel <sandip@knackroot.com>
Co-authored-by: RichardWeiYang <richard.weiyang@gmail.com>
Co-authored-by: gladcow <jahr@yandex.ru>
Co-authored-by: satyakoneru <satyakoneru.iiith@gmail.com>
This commit is contained in:
pbattu123 2020-02-07 11:53:08 -04:00 committed by GitHub
parent 54c66b226e
commit 0b280882af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
201 changed files with 9183 additions and 3296 deletions

2
.gitignore vendored
View file

@ -12,6 +12,8 @@ hardfork.hpp
build_xc
data
build
libraries/utilities/git_revision.cpp
libraries/wallet/Doxyfile

View file

@ -1,36 +1,55 @@
include:
- template: Code-Quality.gitlab-ci.yml
stages:
- pull
- build
- test
before_script:
- cd /var/www/Projects/595.peerplays/blockchain
pulljob:
stage: pull
script:
- git pull origin master
only:
- master
tags:
- pp-dev
buildjob:
build:
stage: build
script:
- git submodule sync
- git submodule update --init --recursive
- cmake .
- make
only:
- master
- make -j$(nproc)
artifacts:
untracked: true
paths:
- libraries/
- programs/
- tests/
tags:
- pp-dev
- builder
testjob:
test:
stage: test
dependencies:
- build
script:
- ./tests/betting_test
- ./tests/chain_test
- ./tests/tournament_test
only:
- master
- ./tests/cli_test
tags:
- pp-dev
- 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

0
.sonarcloud.properties Normal file
View file

View file

@ -135,7 +135,7 @@ else( WIN32 ) # Apple AND Linux
endif( APPLE )
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-builtin-memcmp" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-builtin-memcmp -Wno-class-memaccess -Wno-parentheses -Wno-terminate -Wno-invalid-offsetof" )
elseif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
if( CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.0.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0.0 )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-partial-specialization" )

View file

@ -23,8 +23,8 @@ RUN \
libssl-dev \
libtool \
locales \
pkg-config \
ntp \
pkg-config \
wget \
&& \
apt-get clean && \
@ -34,9 +34,6 @@ RUN \
sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
locale-gen
ADD . /peerplays-core
WORKDIR /peerplays-core
# Compile Boost
RUN \
BOOST_ROOT=$HOME/boost_1_67_0 && \
@ -47,6 +44,9 @@ RUN \
./b2 install && \
cd ..
ADD . /peerplays-core
WORKDIR /peerplays-core
# Compile Peerplays
RUN \
BOOST_ROOT=$HOME/boost_1_67_0 && \

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();
database_api( *(_app.chain_database() ) ).check_transaction_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,34 +564,42 @@ 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
{
FC_ASSERT( _app.chain_database() );
const auto& db = *_app.chain_database();
FC_ASSERT( limit <= 100 );
vector<operation_history_object> 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);
if( start == operation_history_id_type() )
start = node->operation_id;
FC_ASSERT( _app.chain_database() );
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;
} catch(...) { return result; }
while(node && node->operation_id.instance.value > stop.instance.value && result.size() < limit)
{
if( node->operation_id.instance.value <= start.instance.value )
result.push_back( node->operation_id(db) );
if( node->next == account_transaction_history_id_type() )
node = nullptr;
else node = &node->next(db);
}
const auto& hist_idx = db.get_index_type<account_transaction_history_index>();
const auto& by_op_idx = hist_idx.indices().get<by_op>();
auto index_start = by_op_idx.begin();
auto itr = by_op_idx.lower_bound(boost::make_tuple(account, start));
return result;
while(itr != index_start && itr->account == account && itr->operation_id.instance.value > stop.instance.value && result.size() < limit)
{
if(itr->operation_id.instance.value <= start.instance.value)
result.push_back(itr->operation_id(db));
--itr;
}
if(stop.instance.value == 0 && result.size() < limit && itr->account == account) {
result.push_back(itr->operation_id(db));
}
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,
@ -582,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);
@ -594,16 +626,21 @@ namespace graphene { namespace app {
if(node->operation_id(db).op.which() == operation_id)
result.push_back( node->operation_id(db) );
}
}
if( node->next == account_transaction_history_id_type() )
node = nullptr;
else node = &node->next(db);
}
if( stop.instance.value == 0 && result.size() < limit ) {
auto head = db.find(account_transaction_history_id_type());
if (head != nullptr && head->account == account && head->operation_id(db).op.which() == operation_id)
result.push_back(head->operation_id(db));
}
return result;
}
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
@ -612,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;
@ -651,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);
@ -675,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(){};
@ -734,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 ) );
@ -770,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 {
@ -257,7 +257,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");
@ -323,7 +323,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>())
{
@ -331,7 +331,6 @@ namespace detail {
~application_impl()
{
fc::remove_all(_data_dir / "blockchain/dblock");
}
void set_dbg_init_key( genesis_state_type& genesis, const std::string& init_key )
@ -340,21 +339,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 {
bool clean = !fc::exists(_data_dir / "blockchain/dblock");
fc::create_directories(_data_dir / "blockchain/dblock");
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") )
{
@ -387,7 +384,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;
}
@ -403,73 +400,31 @@ 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";
// never replay if data dir is empty
if( fc::exists( _data_dir ) && fc::directory_iterator( _data_dir ) != fc::directory_iterator() )
{
if( _options->count("replay-blockchain") )
{
replay = true;
replay_reason = "replay-blockchain argument specified";
}
else if( !clean )
{
replay = true;
replay_reason = "unclean shutdown detected";
}
else if( !fc::exists( _data_dir / "db_version" ) )
{
replay = true;
replay_reason = "db_version file not found";
}
else
{
std::string version_string;
fc::read_file_contents( _data_dir / "db_version", version_string );
if( _options->count("replay-blockchain") )
_chain_db->wipe( _data_dir / "blockchain", false );
if( version_string != GRAPHENE_CURRENT_DB_VERSION )
{
replay = true;
replay_reason = "db_version file content mismatch";
}
}
try
{
_chain_db->open( _data_dir / "blockchain", initial_state, GRAPHENE_CURRENT_DB_VERSION );
}
if( !replay )
catch( const fc::exception& e )
{
try
{
_chain_db->open( _data_dir / "blockchain", initial_state );
}
catch( const fc::exception& e )
{
ilog( "Caught exception ${e} in open()", ("e", e.to_detail_string()) );
replay = true;
replay_reason = "exception in open()";
}
}
if( replay )
{
ilog( "Replaying blockchain due to: ${reason}", ("reason", replay_reason) );
fc::remove_all( _data_dir / "db_version" );
_chain_db->reindex( _data_dir / "blockchain", initial_state() );
const auto mode = std::ios::out | std::ios::binary | std::ios::trunc;
std::ofstream db_version( (_data_dir / "db_version").generic_string().c_str(), mode );
std::string version_string = GRAPHENE_CURRENT_DB_VERSION;
db_version.write( version_string.c_str(), version_string.size() );
db_version.close();
elog( "Caught exception ${e} in open(), you might want to force a replay", ("e", e.to_detail_string()) );
throw;
}
if( _options->count("force-validate") )
@ -478,9 +433,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
@ -994,6 +961,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()
@ -1022,7 +992,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,12 +26,16 @@
#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/crypto/digest.hpp>
#include <fc/rpc/api_connection.hpp>
#include <fc/uint128.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/rational.hpp>
@ -45,6 +49,7 @@
#define GET_REQUIRED_FEES_MAX_RECURSION 4
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 {
@ -87,7 +92,6 @@ namespace graphene { namespace app {
class database_api_impl;
class database_api_impl : public std::enable_shared_from_this<database_api_impl>
{
public:
@ -123,25 +127,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;
@ -165,12 +173,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;
@ -178,13 +187,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
@ -198,10 +207,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;
@ -212,8 +221,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
{
@ -256,7 +271,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) );
}
}
@ -312,7 +327,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) );
});
}
@ -596,6 +611,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());
@ -615,10 +635,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} )
@ -626,7 +642,7 @@ vector<vector<account_id_type>> database_api_impl::get_key_references( vector<pu
auto itr = refs.account_to_address_memberships.find(a);
if( itr != refs.account_to_address_memberships.end() )
{
result.reserve( itr->second.size() );
result.reserve( result.size() + itr->second.size() );
for( auto item : itr->second )
{
wdump((a)(item)(item(_db).name));
@ -635,9 +651,10 @@ 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( itr->second.size() );
result.reserve( result.size() + itr->second.size() );
for( auto item : itr->second ) result.push_back(item);
}
final_result.emplace_back( std::move(result) );
@ -670,7 +687,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();
@ -684,22 +701,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;
}
@ -711,13 +733,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>();
@ -735,7 +761,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);
@ -744,20 +769,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() )
{
@ -768,12 +784,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);
@ -837,16 +850,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;
@ -915,21 +929,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
{
@ -944,15 +961,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
@ -1002,24 +1011,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) );
}
//////////////////////////////////////////////////////////////////////
@ -1028,9 +1039,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
@ -1085,7 +1135,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);
@ -1094,6 +1144,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 //
////////////////////
@ -1277,7 +1336,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 );
}
@ -1285,12 +1344,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));
@ -1314,45 +1383,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;
@ -1362,31 +1432,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
@ -1609,9 +1685,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;
@ -1637,14 +1714,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;
@ -1712,14 +1790,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;
@ -1784,7 +1863,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;
@ -1793,7 +1872,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;
@ -1802,12 +1881,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() );
@ -1816,6 +1895,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;
@ -1924,8 +2005,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;
}
@ -1940,7 +2021,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>();
@ -1970,9 +2051,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 );
}
/**
@ -2001,7 +2082,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;
}
}
@ -2021,7 +2102,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;
}
@ -2031,7 +2112,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;
//
@ -2041,7 +2122,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,
@ -2059,16 +2140,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);
@ -2183,6 +2265,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);
@ -2200,6 +2302,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 //
@ -2283,7 +2459,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 ) );
}
}
}
@ -2327,7 +2503,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));
});
}
@ -2368,7 +2544,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.
*
@ -247,13 +257,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
@ -273,7 +291,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
@ -302,7 +320,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;
@ -312,7 +331,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
@ -323,14 +342,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
@ -349,6 +375,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 //
////////////////////
@ -426,47 +458,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
@ -525,7 +557,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
@ -555,10 +587,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
@ -572,9 +604,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;
///////////
@ -631,7 +665,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 //
@ -640,7 +674,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 //
@ -673,17 +707,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
@ -714,6 +762,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)
@ -733,6 +782,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)
@ -800,4 +851,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.
@ -119,9 +121,9 @@ set<account_id_type> account_member_index::get_account_members(const account_obj
result.insert(auth.first);
return result;
}
set<public_key_type> account_member_index::get_key_members(const account_object& a)const
set<public_key_type, account_member_index::key_compare> account_member_index::get_key_members(const account_object& a)const
{
set<public_key_type> result;
set<public_key_type, key_compare> result;
for( auto auth : a.owner.key_auths )
result.insert(auth.first);
for( auto auth : a.active.key_auths )
@ -213,7 +215,7 @@ void account_member_index::object_modified(const object& after)
{
set<public_key_type> after_key_members = get_key_members(a);
set<public_key_type, key_compare> after_key_members = get_key_members(a);
vector<public_key_type> removed; removed.reserve(before_key_members.size());
std::set_difference(before_key_members.begin(), before_key_members.end(),
@ -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

@ -134,33 +134,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;
@ -176,7 +179,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) ) }
@ -282,33 +285,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;
@ -317,7 +323,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 )
@ -328,7 +334,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) ) }
@ -355,7 +361,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;
});
@ -387,7 +393,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;
});
@ -409,7 +415,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;
});
@ -484,7 +490,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

@ -45,14 +45,15 @@ void block_database::open( const fc::path& dbdir )
_block_num_to_pos.exceptions(std::ios_base::failbit | std::ios_base::badbit);
_blocks.exceptions(std::ios_base::failbit | std::ios_base::badbit);
if( !fc::exists( dbdir/"index" ) )
_index_filename = dbdir / "index";
if( !fc::exists( _index_filename ) )
{
_block_num_to_pos.open( (dbdir/"index").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc);
_block_num_to_pos.open( _index_filename.generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc);
_blocks.open( (dbdir/"blocks").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc);
}
else
{
_block_num_to_pos.open( (dbdir/"index").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out );
_block_num_to_pos.open( _index_filename.generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out );
_blocks.open( (dbdir/"blocks").generic_string().c_str(), std::fstream::binary | std::fstream::in | std::fstream::out );
}
} FC_CAPTURE_AND_RETHROW( (dbdir) ) }
@ -121,7 +122,7 @@ bool block_database::contains( const block_id_type& id )const
index_entry e;
auto index_pos = sizeof(e)*block_header::num_from_id(id);
_block_num_to_pos.seekg( 0, _block_num_to_pos.end );
if ( _block_num_to_pos.tellg() <= index_pos )
if ( _block_num_to_pos.tellg() < index_pos + sizeof(e) )
return false;
_block_num_to_pos.seekg( index_pos );
_block_num_to_pos.read( (char*)&e, sizeof(e) );
@ -206,34 +207,47 @@ optional<signed_block> block_database::fetch_by_number( uint32_t block_num )cons
return optional<signed_block>();
}
optional<signed_block> block_database::last()const
{
optional<index_entry> block_database::last_index_entry()const {
try
{
index_entry e;
_block_num_to_pos.seekg( 0, _block_num_to_pos.end );
std::streampos pos = _block_num_to_pos.tellg();
if( pos < sizeof(index_entry) )
return optional<index_entry>();
if( _block_num_to_pos.tellp() < sizeof(index_entry) )
return optional<signed_block>();
pos -= pos % sizeof(index_entry);
_block_num_to_pos.seekg( -sizeof(index_entry), _block_num_to_pos.end );
_block_num_to_pos.read( (char*)&e, sizeof(e) );
uint64_t pos = _block_num_to_pos.tellg();
while( e.block_size == 0 && pos > 0 )
_blocks.seekg( 0, _block_num_to_pos.end );
const std::streampos blocks_size = _blocks.tellg();
while( pos > 0 )
{
pos -= sizeof(index_entry);
_block_num_to_pos.seekg( pos );
_block_num_to_pos.read( (char*)&e, sizeof(e) );
if( _block_num_to_pos.gcount() == sizeof(e) && e.block_size > 0
&& e.block_pos + e.block_size <= blocks_size )
try
{
vector<char> data( e.block_size );
_blocks.seekg( e.block_pos );
_blocks.read( data.data(), e.block_size );
if( _blocks.gcount() == e.block_size )
{
const signed_block block = fc::raw::unpack<signed_block>(data);
if( block.id() == e.block_id )
return e;
}
}
catch (const fc::exception&)
{
}
catch (const std::exception&)
{
}
fc::resize_file( _index_filename, pos );
}
if( e.block_size == 0 )
return optional<signed_block>();
vector<char> data( e.block_size );
_blocks.seekg( e.block_pos );
_blocks.read( data.data(), e.block_size );
auto result = fc::raw::unpack<signed_block>(data);
return result;
}
catch (const fc::exception&)
{
@ -241,42 +255,21 @@ optional<signed_block> block_database::last()const
catch (const std::exception&)
{
}
return optional<index_entry>();
}
optional<signed_block> block_database::last()const
{
optional<index_entry> entry = last_index_entry();
if( entry.valid() ) return fetch_by_number( block_header::num_from_id(entry->block_id) );
return optional<signed_block>();
}
optional<block_id_type> block_database::last_id()const
{
try
{
index_entry e;
_block_num_to_pos.seekg( 0, _block_num_to_pos.end );
if( _block_num_to_pos.tellp() < sizeof(index_entry) )
return optional<block_id_type>();
_block_num_to_pos.seekg( -sizeof(index_entry), _block_num_to_pos.end );
_block_num_to_pos.read( (char*)&e, sizeof(e) );
uint64_t pos = _block_num_to_pos.tellg();
while( e.block_size == 0 && pos > 0 )
{
pos -= sizeof(index_entry);
_block_num_to_pos.seekg( pos );
_block_num_to_pos.read( (char*)&e, sizeof(e) );
}
if( e.block_size == 0 )
return optional<block_id_type>();
return e.block_id;
}
catch (const fc::exception&)
{
}
catch (const std::exception&)
{
}
optional<index_entry> entry = last_index_entry();
if( entry.valid() ) return entry->block_id;
return optional<block_id_type>();
}
} }

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

@ -151,12 +151,15 @@ bool database::_push_block(const signed_block& new_block)
// pop blocks until we hit the forked block
while( head_block_id() != branches.second.back()->data.previous )
{
ilog( "popping block #${n} ${id}", ("n",head_block_num())("id",head_block_id()) );
pop_block();
}
// push all blocks on the new fork
for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr )
{
ilog( "pushing blocks from fork ${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->data.id()) );
ilog( "pushing block from fork #${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->id) );
optional<fc::exception> except;
try {
undo_database::session session = _undo_db.start_undo_session();
@ -171,21 +174,27 @@ bool database::_push_block(const signed_block& new_block)
// remove the rest of branches.first from the fork_db, those blocks are invalid
while( ritr != branches.first.rend() )
{
_fork_db.remove( (*ritr)->data.id() );
ilog( "removing block from fork_db #${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->id) );
_fork_db.remove( (*ritr)->id );
++ritr;
}
_fork_db.set_head( branches.second.front() );
// pop all blocks from the bad fork
while( head_block_id() != branches.second.back()->data.previous )
pop_block();
// restore all blocks from the good fork
for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr )
{
ilog( "popping block #${n} ${id}", ("n",head_block_num())("id",head_block_id()) );
pop_block();
}
ilog( "Switching back to fork: ${id}", ("id",branches.second.front()->data.id()) );
// restore all blocks from the good fork
for( auto ritr2 = branches.second.rbegin(); ritr2 != branches.second.rend(); ++ritr2 )
{
ilog( "pushing block #${n} ${id}", ("n",(*ritr2)->data.block_num())("id",(*ritr2)->id) );
auto session = _undo_db.start_undo_session();
apply_block( (*ritr)->data, skip );
_block_id_to_block.store( new_block.id(), (*ritr)->data );
apply_block( (*ritr2)->data, skip );
_block_id_to_block.store( (*ritr2)->id, (*ritr2)->data );
session.commit();
}
throw *except;
@ -272,6 +281,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));
@ -425,7 +436,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) ) }
@ -442,7 +453,6 @@ void database::pop_block()
GRAPHENE_ASSERT( head_block.valid(), pop_empty_chain, "there are no blocks to pop" );
_fork_db.pop_block();
_block_id_to_block.remove( head_id );
pop_undo();
_popped_tx.insert( _popped_tx.begin(), head_block->transactions.begin(), head_block->transactions.end() );
@ -518,7 +528,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;
@ -526,6 +536,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
@ -548,7 +560,8 @@ void database::_apply_block( const signed_block& next_block )
if (global_props.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SCHEDULED_ALGORITHM)
update_witness_schedule(next_block);
update_global_dynamic_data(next_block);
const uint32_t missed = update_witness_missed_blocks( next_block );
update_global_dynamic_data( next_block, missed );
update_signing_witness(signing_witness, next_block);
update_last_irreversible_block();
@ -563,7 +576,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);
@ -598,6 +612,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;
@ -607,9 +634,14 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
auto& trx_idx = get_mutable_index_type<transaction_index>();
const chain_id_type& chain_id = get_chain_id();
auto trx_id = trx.id();
FC_ASSERT( (skip & skip_transaction_dupe_check) ||
trx_idx.indices().get<by_trx_id>().find(trx_id) == trx_idx.indices().get<by_trx_id>().end() );
transaction_id_type trx_id;
if( !(skip & skip_transaction_dupe_check) )
{
trx_id = trx.id();
FC_ASSERT( trx_idx.indices().get<by_trx_id>().find(trx_id) == trx_idx.indices().get<by_trx_id>().end() );
}
transaction_evaluation_state eval_state(this);
const chain_parameters& chain_parameters = get_global_properties().parameters;
eval_state._trx = &trx;
@ -643,7 +675,7 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
//Insert transaction into unique transactions database.
if( !(skip & skip_transaction_dupe_check) )
{
create<transaction_object>([&](transaction_object& transaction) {
create<transaction_object>([&trx_id,&trx](transaction_object& transaction) {
transaction.trx_id = trx_id;
transaction.trx = trx;
});
@ -651,6 +683,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;
@ -664,9 +697,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>
@ -47,33 +50,86 @@ database::~database()
clear_pending();
}
void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation)
{ try {
ilog( "reindexing blockchain" );
wipe(data_dir, false);
open(data_dir, [&initial_allocation]{return initial_allocation;});
// Right now, we leave undo_db enabled when replaying when the bookie plugin is
// enabled. It depends on new/changed/removed object notifications, and those are
// only fired when the undo_db is enabled.
// So we use this helper object to disable undo_db only if it is not forbidden
// with _slow_replays flag.
class auto_undo_enabler
{
const bool _slow_replays;
undo_database& _undo_db;
bool _disabled;
public:
auto_undo_enabler(bool slow_replays, undo_database& undo_db) :
_slow_replays(slow_replays),
_undo_db(undo_db),
_disabled(false)
{
}
auto start = fc::time_point::now();
~auto_undo_enabler()
{
try{
enable();
} FC_CAPTURE_AND_LOG(("undo_db enabling crash"))
}
void enable()
{
if(!_disabled)
return;
_undo_db.enable();
_disabled = false;
}
void disable()
{
if(_disabled)
return;
if(_slow_replays)
return;
_undo_db.disable();
_disabled = true;
}
};
void database::reindex( fc::path data_dir )
{ try {
auto last_block = _block_id_to_block.last();
if( !last_block ) {
elog( "!no last block" );
edump((last_block));
return;
}
if( last_block->block_num() <= head_block_num()) return;
ilog( "reindexing blockchain" );
auto start = fc::time_point::now();
const auto last_block_num = last_block->block_num();
uint32_t flush_point = last_block_num < 10000 ? 0 : last_block_num - 10000;
uint32_t undo_point = last_block_num < 50 ? 0 : last_block_num - 50;
ilog( "Replaying blocks..." );
// Right now, we leave undo_db enabled when replaying when the bookie plugin is
// enabled. It depends on new/changed/removed object notifications, and those are
// only fired when the undo_db is enabled
if (!_slow_replays)
_undo_db.disable();
for( uint32_t i = 1; i <= last_block_num; ++i )
ilog( "Replaying blocks, starting at ${next}...", ("next",head_block_num() + 1) );
auto_undo_enabler undo(_slow_replays, _undo_db);
if( head_block_num() >= undo_point )
{
if( i == 1 ||
i % 10000 == 0 )
std::cerr << " " << double(i*100)/last_block_num << "% "<< i << " of " <<last_block_num<<" \n";
if( head_block_num() > 0 )
_fork_db.start_block( *fetch_block_by_number( head_block_num() ) );
}
else
{
undo.disable();
}
for( uint32_t i = head_block_num() + 1; i <= last_block_num; ++i )
{
if( i % 10000 == 0 ) std::cerr << " " << double(i*100)/last_block_num << "% "<<i << " of " <<last_block_num<<" \n";
if( i == flush_point )
{
ilog( "Writing database to disk at block ${i}", ("i",i) );
flush();
ilog( "Done" );
}
fc::optional< signed_block > block = _block_id_to_block.fetch_by_number(i);
if( !block.valid() )
{
@ -94,24 +150,27 @@ void database::reindex(fc::path data_dir, const genesis_state_type& initial_allo
wlog( "Dropped ${n} blocks from after the gap", ("n", dropped_count) );
break;
}
if (_slow_replays)
push_block(*block, skip_fork_db |
skip_witness_signature |
skip_transaction_signatures |
skip_transaction_dupe_check |
skip_tapos_check |
skip_witness_schedule_check |
skip_authority_check);
else
if( i < undo_point && !_slow_replays)
{
apply_block(*block, skip_witness_signature |
skip_transaction_signatures |
skip_transaction_dupe_check |
skip_tapos_check |
skip_witness_schedule_check |
skip_authority_check);
}
else
{
undo.enable();
push_block(*block, skip_witness_signature |
skip_transaction_signatures |
skip_transaction_dupe_check |
skip_tapos_check |
skip_witness_schedule_check |
skip_authority_check);
}
}
if (!_slow_replays)
_undo_db.enable();
undo.enable();
auto end = fc::time_point::now();
ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) );
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }
@ -119,7 +178,9 @@ void database::reindex(fc::path data_dir, const genesis_state_type& initial_allo
void database::wipe(const fc::path& data_dir, bool include_blocks)
{
ilog("Wiping database", ("include_blocks", include_blocks));
close();
if (_opened) {
close(false);
}
object_database::wipe(data_dir);
if( include_blocks )
fc::remove_all( data_dir / "database" );
@ -127,33 +188,63 @@ void database::wipe(const fc::path& data_dir, bool include_blocks)
void database::open(
const fc::path& data_dir,
std::function<genesis_state_type()> genesis_loader)
std::function<genesis_state_type()> genesis_loader,
const std::string& db_version)
{
try
{
bool wipe_object_db = false;
if( !fc::exists( data_dir / "db_version" ) )
wipe_object_db = true;
else
{
std::string version_string;
fc::read_file_contents( data_dir / "db_version", version_string );
wipe_object_db = ( version_string != db_version );
}
if( wipe_object_db ) {
ilog("Wiping object_database due to missing or wrong version");
object_database::wipe( data_dir );
std::ofstream version_file( (data_dir / "db_version").generic_string().c_str(),
std::ios::out | std::ios::binary | std::ios::trunc );
version_file.write( db_version.c_str(), db_version.size() );
version_file.close();
}
object_database::open(data_dir);
_block_id_to_block.open(data_dir / "database" / "block_num_to_block");
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<signed_block> last_block = _block_id_to_block.last();
fc::optional<block_id_type> last_block = _block_id_to_block.last_id();
if( last_block.valid() )
{
_fork_db.start_block( *last_block );
if( last_block->id() != head_block_id() )
{
FC_ASSERT( head_block_num() == 0, "last block ID does not match current chain state",
("last_block->id", last_block->id())("head_block_num",head_block_num()) );
}
FC_ASSERT( *last_block >= head_block_id(),
"last block ID does not match current chain state",
("last_block->id", last_block)("head_block_id",head_block_num()) );
reindex( data_dir );
}
_opened = true;
}
FC_CAPTURE_LOG_AND_RETHROW( (data_dir) )
}
void database::close(bool rewind)
{
if (!_opened)
return;
// TODO: Save pending tx's on close()
clear_pending();
@ -167,17 +258,9 @@ void database::close(bool rewind)
while( head_block_num() > cutoff )
{
// elog("pop");
block_id_type popped_block_id = head_block_id();
pop_block();
_fork_db.remove(popped_block_id); // doesn't throw on missing
try
{
_block_id_to_block.remove(popped_block_id);
}
catch (const fc::key_not_found_exception&)
{
}
}
}
catch ( const fc::exception& e )
@ -198,6 +281,8 @@ void database::close(bool rewind)
_block_id_to_block.close();
_fork_db.reset();
_opened = false;
}
void database::force_slow_replays()

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

@ -43,43 +43,13 @@
namespace graphene { namespace chain {
void database::update_global_dynamic_data( const signed_block& b )
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();
uint32_t missed_blocks = get_slot_at_time( b.timestamp );
//#define DIRTY_TRICK // problem with missed_blocks can occur when "maintenance_interval" set to few minutes
#ifdef DIRTY_TRICK
if (missed_blocks != 0) {
#else
assert( missed_blocks != 0 );
#endif
// bad if-condition, this code needs to execute for both shuffled and rng algorithms
// if (gpo.parameters.witness_schedule_algorithm == GRAPHENE_WITNESS_SHUFFLED_ALGORITHM)
// {
missed_blocks--;
for( uint32_t i = 0; i < missed_blocks; ++i ) {
const auto& witness_missed = get_scheduled_witness( i+1 )(*this);
if( witness_missed.id != b.witness ) {
/*
const auto& witness_account = witness_missed.witness_account(*this);
if( (fc::time_point::now() - b.timestamp) < fc::seconds(30) )
wlog( "Witness ${name} missed block ${n} around ${t}", ("name",witness_account.name)("n",b.block_num())("t",b.timestamp) );
*/
modify( witness_missed, [&]( witness_object& w ) {
w.total_missed++;
});
}
}
// }
#ifdef DIRTY_TRICK
}
#endif
// dynamic global properties updating
modify( _dgp, [&]( dynamic_global_property_object& dgp ){
modify( _dgp, [&b,this,missed_blocks]( dynamic_global_property_object& dgp ){
secret_hash_type::encoder enc;
fc::raw::pack( enc, dgp.random );
fc::raw::pack( enc, b.previous_secret );
@ -87,9 +57,10 @@ void database::update_global_dynamic_data( const signed_block& b )
_random_number_generator = fc::hash_ctr_rng<secret_hash_type, 20>(dgp.random.data());
if( BOOST_UNLIKELY( b.block_num() == 1 ) )
const uint32_t block_num = b.block_num();
if( BOOST_UNLIKELY( block_num == 1 ) )
dgp.recently_missed_count = 0;
else if( _checkpoints.size() && _checkpoints.rbegin()->first >= b.block_num() )
else if( _checkpoints.size() && _checkpoints.rbegin()->first >= block_num )
dgp.recently_missed_count = 0;
else if( missed_blocks )
dgp.recently_missed_count += GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT*missed_blocks;
@ -98,7 +69,7 @@ void database::update_global_dynamic_data( const signed_block& b )
else if( dgp.recently_missed_count > 0 )
dgp.recently_missed_count--;
dgp.head_block_number = b.block_num();
dgp.head_block_number = block_num;
dgp.head_block_id = b.id();
dgp.time = b.timestamp;
dgp.current_witness = b.witness;
@ -150,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 )
@ -266,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
@ -495,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);
@ -226,6 +226,22 @@ void database::update_witness_schedule(const signed_block& next_block)
idump( ( double(total_time/1000000.0)/calls) );
}
uint32_t database::update_witness_missed_blocks( const signed_block& b )
{
uint32_t missed_blocks = get_slot_at_time( b.timestamp );
FC_ASSERT( missed_blocks != 0, "Trying to push double-produced block onto current block?!" );
missed_blocks--;
const auto& witnesses = witness_schedule_id_type()(*this).current_shuffled_witnesses;
if( missed_blocks < witnesses.size() )
for( uint32_t i = 0; i < missed_blocks; ++i ) {
const auto& witness_missed = get_scheduled_witness( i+1 )(*this);
modify( witness_missed, []( witness_object& w ) {
w.total_missed++;
});
}
return missed_blocks;
}
uint32_t database::witness_participation_rate()const
{
const global_property_object& gpo = get_global_properties();
@ -236,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 Monday, 6 January 2020 01:00:00 GMT
#ifndef HARDFORK_GPOS_TIME
#define HARDFORK_GPOS_TIME (fc::time_point_sec( 1578272400 ))
#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);
@ -278,6 +301,25 @@ namespace graphene { namespace chain {
*/
class account_member_index : public secondary_index
{
/* std::less::operator() is less efficient so using key_compare here.
* Let assume that it has two keys key1 and key2 and we want to insert key3.
* the insert function needs to first call std::less::operator() with key1 and key3.
* Assume std::less::operator()(key1, key3) returns false.
* It has to call std::less::operator() again with the keys switched,
* std::less::operator()(key3, key1), to decide whether key1 is equal to key3 or
* key3 is greater than key1. There are two calls to std::less::operator() to make
* a decision if the first call returns false.
* std::map::insert and std::set used key_compare,
* there would be sufficient information to make the right decision using just one call.
*/
class key_compare {
public:
inline bool operator()( const public_key_type& a, const public_key_type& b )const
{
return a.key_data < b.key_data;
}
};
public:
virtual void object_inserted( const object& obj ) override;
virtual void object_removed( const object& obj ) override;
@ -287,18 +329,18 @@ namespace graphene { namespace chain {
/** given an account or key, map it to the set of accounts that reference it in an active or owner authority */
map< account_id_type, set<account_id_type> > account_to_account_memberships;
map< public_key_type, set<account_id_type> > account_to_key_memberships;
map< public_key_type, set<account_id_type>, key_compare > account_to_key_memberships;
/** some accounts use address authorities in the genesis block */
map< address, set<account_id_type> > account_to_address_memberships;
protected:
set<account_id_type> get_account_members( const account_object& a )const;
set<public_key_type> get_key_members( const account_object& a )const;
set<public_key_type, key_compare> get_key_members( const account_object& a )const;
set<address> get_address_members( const account_object& a )const;
set<account_id_type> before_account_members;
set<public_key_type> before_key_members;
set<public_key_type, key_compare> before_key_members;
set<address> before_address_members;
};
@ -344,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
*/
@ -353,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,
@ -442,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,
@ -458,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)
@ -475,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,8 +233,28 @@ 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
{ return current_feed_publication_time + options.feed_lifetime_sec; }
{
uint32_t current_feed_seconds = current_feed_publication_time.sec_since_epoch();
if( std::numeric_limits<uint32_t>::max() - current_feed_seconds <= options.feed_lifetime_sec )
return time_point_sec::maximum();
else
return current_feed_publication_time + options.feed_lifetime_sec;
}
bool feed_is_expired_before_hardfork_615(time_point_sec current_time)const
{ return feed_expiration_time() >= current_time; }
bool feed_is_expired(time_point_sec current_time)const
@ -239,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;
@ -473,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)
@ -481,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),
@ -515,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,7 +25,11 @@
#include <fstream>
#include <graphene/chain/protocol/block.hpp>
#include <fc/filesystem.hpp>
namespace graphene { namespace chain {
class index_entry;
class block_database
{
public:
@ -44,6 +48,8 @@ namespace graphene { namespace chain {
optional<signed_block> last()const;
optional<block_id_type> last_id()const;
private:
optional<index_entry> last_index_entry()const;
fc::path _index_filename;
mutable std::fstream _blocks;
mutable std::fstream _block_num_to_pos;
};

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

@ -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

@ -91,10 +91,12 @@ namespace graphene { namespace chain {
*
* @param data_dir Path to open or create database in
* @param genesis_loader A callable object which returns the genesis state to initialize new databases on
* @param db_version a version string that changes when the internal database format and/or logic is modified
*/
void open(
const fc::path& data_dir,
std::function<genesis_state_type()> genesis_loader );
std::function<genesis_state_type()> genesis_loader,
const std::string& db_version );
/**
* @brief Rebuild object graph from block history and open detabase
@ -102,7 +104,7 @@ namespace graphene { namespace chain {
* This method may be called after or instead of @ref database::open, and will rebuild the object graph by
* replaying blockchain history. When this method exits successfully, the database will be open.
*/
void reindex(fc::path data_dir, const genesis_state_type& initial_allocation = genesis_state_type());
void reindex(fc::path data_dir);
/**
* @brief wipe Delete database from disk, and potentially the raw chain as well.
@ -267,14 +269,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;
@ -432,7 +437,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 );
@ -441,7 +447,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
@ -456,6 +462,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(); }
@ -486,8 +494,11 @@ namespace graphene { namespace chain {
const witness_object& _validate_block_header( const signed_block& next_block )const;
void create_block_summary(const signed_block& next_block);
//////////////////// db_witness_schedule.cpp ////////////////////
uint32_t update_witness_missed_blocks( const signed_block& b );
//////////////////// db_update.cpp ////////////////////
void update_global_dynamic_data( const signed_block& b );
void update_global_dynamic_data( const signed_block& b, const uint32_t missed_blocks );
void update_signing_witness(const witness_object& signing_witness, const signed_block& new_block);
void update_last_irreversible_block();
void clear_expired_transactions();
@ -495,11 +506,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
///@{
@ -514,8 +527,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);
///@}
///@}
@ -554,8 +571,34 @@ 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;
/**
* Whether database is successfully opened or not.
*
* The database is considered open when there's no exception
* or assertion fail during database::open() method, and
* 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
@ -51,8 +52,10 @@ class proposal_object : public abstract_object<proposal_object>
flat_set<account_id_type> available_owner_approvals;
flat_set<public_key_type> available_key_approvals;
account_id_type proposer;
std::string fail_reason;
bool is_authorized_to_execute(database& db) const;
bool is_authorized_to_execute(database& db)const;
};
/**
@ -94,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 {
@ -92,3 +93,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
@ -112,9 +126,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))
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>
@ -33,14 +35,9 @@
#include <algorithm>
#include <boost/multi_index/composite_key.hpp>
#define offset_d(i,f) (long(&(i)->f) - long(i))
#define offset_s(t,f) offset_d((t*)1000, f)
namespace graphene { namespace chain {
using namespace graphene::db;
class vesting_balance_object;
struct vesting_policy_context
{
vesting_policy_context(
@ -143,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; }
@ -189,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) (offset_s(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 >
>
@ -228,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 )

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