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:
parent
54c66b226e
commit
0b280882af
201 changed files with 9183 additions and 3296 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -12,6 +12,8 @@ hardfork.hpp
|
|||
build_xc
|
||||
data
|
||||
|
||||
build
|
||||
|
||||
libraries/utilities/git_revision.cpp
|
||||
|
||||
libraries/wallet/Doxyfile
|
||||
|
|
@ -43,4 +45,4 @@ object_database/*
|
|||
*.pyo
|
||||
.vscode
|
||||
.DS_Store
|
||||
.idea
|
||||
.idea
|
||||
|
|
|
|||
|
|
@ -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
|
||||
tags:
|
||||
- pp-dev
|
||||
|
||||
testjob:
|
||||
- make -j$(nproc)
|
||||
artifacts:
|
||||
untracked: true
|
||||
paths:
|
||||
- libraries/
|
||||
- programs/
|
||||
- tests/
|
||||
tags:
|
||||
- builder
|
||||
|
||||
test:
|
||||
stage: test
|
||||
dependencies:
|
||||
- build
|
||||
script:
|
||||
- ./tests/betting_test
|
||||
- ./tests/chain_test
|
||||
- ./tests/tournament_test
|
||||
only:
|
||||
- master
|
||||
tags:
|
||||
- pp-dev
|
||||
- ./tests/cli_test
|
||||
tags:
|
||||
- builder
|
||||
|
||||
code_quality:
|
||||
stage: test
|
||||
image: docker:stable
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
allow_failure: true
|
||||
services:
|
||||
- docker:stable-dind
|
||||
script:
|
||||
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
|
||||
- docker run
|
||||
--env SOURCE_CODE="$PWD"
|
||||
--volume "$PWD":/code
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock
|
||||
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
|
||||
artifacts:
|
||||
paths: [gl-code-quality-report.json]
|
||||
expire_in: 1 week
|
||||
except:
|
||||
variables:
|
||||
- $CODE_QUALITY_DISABLED
|
||||
|
|
|
|||
0
.sonarcloud.properties
Normal file
0
.sonarcloud.properties
Normal 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" )
|
||||
|
|
|
|||
|
|
@ -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 && \
|
||||
|
|
|
|||
2
Doxyfile
2
Doxyfile
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ add_library( graphene_app
|
|||
database_api.cpp
|
||||
impacted.cpp
|
||||
plugin.cpp
|
||||
config_util.cpp
|
||||
${HEADERS}
|
||||
${EGENESIS_HEADERS}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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] ";
|
||||
|
|
|
|||
354
libraries/app/config_util.cpp
Normal file
354
libraries/app/config_util.cpp
Normal 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
|
||||
|
|
@ -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));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
34
libraries/app/include/graphene/app/config_util.hpp
Normal file
34
libraries/app/include/graphene/app/config_util.hpp
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
@ -348,6 +374,12 @@ class database_api
|
|||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
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)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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>); \
|
||||
}
|
||||
/// @}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <graphene/chain/balance_evaluator.hpp>
|
||||
#include <graphene/chain/pts_address.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
}
|
||||
|
||||
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -77,15 +77,7 @@ void_result committee_member_update_evaluator::do_apply( const committee_member_
|
|||
void_result committee_member_update_global_parameters_evaluator::do_evaluate(const committee_member_update_global_parameters_operation& o)
|
||||
{ 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() )
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) ) }
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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,13 +319,29 @@ 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 )
|
||||
{
|
||||
modify( del, [&]( committee_member_object& obj ){
|
||||
obj.total_votes = _vote_tally_buffer[del.vote_id];
|
||||
});
|
||||
}
|
||||
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 )
|
||||
{
|
||||
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
|
||||
if( !committee_members.empty() )
|
||||
{
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
4
libraries/chain/hardfork.d/GPOS.hf
Normal file
4
libraries/chain/hardfork.d/GPOS.hf
Normal 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
|
||||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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,11 +39,10 @@
|
|||
*/
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
class account_object;
|
||||
class database;
|
||||
class transaction_evaluation_state;
|
||||
using namespace graphene::db;
|
||||
|
||||
|
||||
/**
|
||||
* @brief tracks the asset information that changes frequently
|
||||
* @ingroup object
|
||||
|
|
@ -118,9 +118,9 @@ namespace graphene { namespace chain {
|
|||
/// Convert an asset to a textual representation with symbol, i.e. "123.45 USD"
|
||||
string amount_to_pretty_string(const asset &amount)const
|
||||
{ FC_ASSERT(amount.asset_id == id); return amount_to_pretty_string(amount.amount); }
|
||||
|
||||
|
||||
uint32_t get_issuer_num()const
|
||||
{ return issuer.instance.value; }
|
||||
{ return issuer.instance.value; }
|
||||
/// Ticker symbol for this asset, i.e. "USD"
|
||||
string symbol;
|
||||
/// Maximum number of digits after the decimal point (must be <= 12)
|
||||
|
|
@ -138,7 +138,7 @@ namespace graphene { namespace chain {
|
|||
map< account_id_type, vector< uint16_t > > distribute_winners_part( database& db );
|
||||
void distribute_sweeps_holders_part( database& db );
|
||||
void end_lottery( database& db );
|
||||
|
||||
|
||||
/// Current supply, fee pool, and collected fees are stored in a separate object as they change frequently.
|
||||
asset_dynamic_data_id_type dynamic_asset_data_id;
|
||||
/// Extra data associated with BitAssets. This field is non-null if and only if is_market_issued() returns true
|
||||
|
|
@ -150,7 +150,7 @@ namespace graphene { namespace chain {
|
|||
optional<asset_dividend_data_id_type> dividend_data_id;
|
||||
|
||||
asset_id_type get_id()const { return id; }
|
||||
|
||||
|
||||
void validate()const
|
||||
{
|
||||
// UIAs may not be prediction markets, have force settlement, or global settlements
|
||||
|
|
@ -174,7 +174,7 @@ namespace graphene { namespace chain {
|
|||
{ return db.get(dynamic_asset_data_id); }
|
||||
|
||||
/**
|
||||
* The total amount of an asset that is reserved for future issuance.
|
||||
* The total amount of an asset that is reserved for future issuance.
|
||||
*/
|
||||
template<class DB>
|
||||
share_type reserved( const DB& db )const
|
||||
|
|
@ -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;
|
||||
|
|
@ -335,7 +378,7 @@ namespace graphene { namespace chain {
|
|||
/// This field is reset any time the dividend_asset_options are updated
|
||||
fc::optional<time_point_sec> last_scheduled_payout_time;
|
||||
|
||||
/// The time payouts on this asset were last processed
|
||||
/// The time payouts on this asset were last processed
|
||||
/// (this should be the maintenance interval at or after last_scheduled_payout_time)
|
||||
/// This can be displayed for the user
|
||||
fc::optional<time_point_sec> last_payout_time;
|
||||
|
|
@ -362,7 +405,7 @@ namespace graphene { namespace chain {
|
|||
typedef generic_index<asset_dividend_data_object, asset_dividend_data_object_multi_index_type> asset_dividend_data_object_index;
|
||||
|
||||
|
||||
// This tracks the balances in a dividend distribution account at the last time
|
||||
// This tracks the balances in a dividend distribution account at the last time
|
||||
// pending dividend payouts were calculated (last maintenance interval).
|
||||
// At each maintenance interval, we will compare the current balance to the
|
||||
// balance stored here to see how much was deposited during that interval.
|
||||
|
|
@ -391,9 +434,9 @@ namespace graphene { namespace chain {
|
|||
>
|
||||
> total_distributed_dividend_balance_object_multi_index_type;
|
||||
typedef generic_index<total_distributed_dividend_balance_object, total_distributed_dividend_balance_object_multi_index_type> total_distributed_dividend_balance_object_index;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup object
|
||||
*/
|
||||
|
|
@ -402,17 +445,17 @@ namespace graphene { namespace chain {
|
|||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_lottery_balance_object_type;
|
||||
|
||||
|
||||
asset_id_type lottery_id;
|
||||
asset balance;
|
||||
|
||||
|
||||
asset get_balance()const { return balance; }
|
||||
void adjust_balance(const asset& delta);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct by_owner;
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup object_index
|
||||
*/
|
||||
|
|
@ -425,13 +468,13 @@ namespace graphene { namespace chain {
|
|||
>
|
||||
>
|
||||
> lottery_balance_index_type;
|
||||
|
||||
|
||||
/**
|
||||
* @ingroup object_index
|
||||
*/
|
||||
typedef generic_index<lottery_balance_object, lottery_balance_index_type> lottery_balance_index;
|
||||
|
||||
|
||||
|
||||
|
||||
class sweeps_vesting_balance_object : public abstract_object<sweeps_vesting_balance_object>
|
||||
{
|
||||
public:
|
||||
|
|
@ -443,7 +486,7 @@ namespace graphene { namespace chain {
|
|||
uint64_t balance;
|
||||
asset_id_type asset_id;
|
||||
time_point_sec last_claim_date;
|
||||
|
||||
|
||||
uint64_t get_balance()const { return balance; }
|
||||
void adjust_balance(const asset& delta);
|
||||
asset available_for_claim() const { return asset( balance / SWEEPS_VESTING_BALANCE_MULTIPLIER , asset_id ); }
|
||||
|
|
@ -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,11 +525,13 @@ 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),
|
||||
(options)
|
||||
(last_scheduled_payout_time)
|
||||
(last_scheduled_payout_time)
|
||||
(last_payout_time )
|
||||
(last_scheduled_distribution_time)
|
||||
(last_distribution_time)
|
||||
|
|
@ -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 )
|
||||
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
///@{
|
||||
|
|
@ -513,9 +526,13 @@ namespace graphene { namespace chain {
|
|||
void update_active_witnesses();
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@ namespace graphene { namespace chain {
|
|||
/// account's balance of core asset.
|
||||
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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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) )
|
||||
|
|
|
|||
|
|
@ -23,8 +23,21 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/protocol/base.hpp>
|
||||
#include <graphene/chain/protocol/asset.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
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
|
||||
{
|
||||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -68,3 +68,5 @@ FC_REFLECT_DERIVED(
|
|||
(graphene::db::object),
|
||||
(account)
|
||||
)
|
||||
|
||||
GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::special_authority_object )
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in a new issue