From c88827484616fdd5e70123dec73da9598684de5c Mon Sep 17 00:00:00 2001 From: serkixenos Date: Wed, 15 Dec 2021 16:36:40 +0000 Subject: [PATCH] Merge beatrice to master 2021-12 --- .gitignore | 1 + .gitlab-ci.yml | 13 +- CMakeLists.txt | 89 +- Dockerfile | 134 +- README.md | 4 +- bkup_CMakeCache.txt | 794 -- clang-format.sh | 5 + docker/default_config.ini | 61 - docker/peerplaysentry.sh | 87 - genesis.json => genesis-mainnet.json | 0 genesis-testnet.json | 10438 ++++++++++++++++ libraries/CMakeLists.txt | 10 +- libraries/app/CMakeLists.txt | 29 +- libraries/app/api.cpp | 1361 +- libraries/app/application.cpp | 1148 +- libraries/app/config_util.cpp | 205 +- libraries/app/database_api.cpp | 3121 +++-- libraries/app/include/graphene/app/api.hpp | 602 +- .../app/include/graphene/app/api_access.hpp | 26 +- .../app/include/graphene/app/application.hpp | 125 +- .../app/include/graphene/app/config_util.hpp | 8 +- .../app/include/graphene/app/database_api.hpp | 1642 ++- .../app/include/graphene/app/full_account.hpp | 84 +- libraries/app/include/graphene/app/plugin.hpp | 175 +- libraries/app/plugin.cpp | 32 +- libraries/chain/CMakeLists.txt | 142 +- libraries/chain/asset_evaluator.cpp | 1 - libraries/chain/asset_object.cpp | 2 +- libraries/chain/block_database.cpp | 54 +- libraries/chain/database.cpp | 2 +- libraries/chain/db_balance.cpp | 6 +- libraries/chain/db_bet.cpp | 4 - libraries/chain/db_block.cpp | 3 +- libraries/chain/db_getter.cpp | 34 +- libraries/chain/db_init.cpp | 21 +- libraries/chain/db_maint.cpp | 160 +- libraries/chain/db_management.cpp | 32 +- libraries/chain/db_notify.cpp | 22 + libraries/chain/db_update.cpp | 9 +- libraries/chain/hardfork.d/1000.hf | 6 +- libraries/chain/hardfork.d/1001.hf | 6 +- libraries/chain/hardfork.d/357.hf | 6 +- libraries/chain/hardfork.d/359.hf | 6 +- libraries/chain/hardfork.d/385.hf | 6 +- libraries/chain/hardfork.d/409.hf | 6 +- libraries/chain/hardfork.d/413.hf | 6 +- libraries/chain/hardfork.d/415.hf | 6 +- libraries/chain/hardfork.d/416.hf | 6 +- libraries/chain/hardfork.d/419.hf | 6 +- libraries/chain/hardfork.d/436.hf | 6 +- libraries/chain/hardfork.d/445.hf | 6 +- libraries/chain/hardfork.d/453.hf | 6 +- libraries/chain/hardfork.d/480.hf | 6 +- libraries/chain/hardfork.d/483.hf | 6 +- libraries/chain/hardfork.d/5050-1.hf | 7 +- libraries/chain/hardfork.d/516.hf | 6 +- libraries/chain/hardfork.d/533.hf | 6 +- libraries/chain/hardfork.d/538.hf | 6 +- libraries/chain/hardfork.d/555.hf | 6 +- libraries/chain/hardfork.d/563.hf | 6 +- libraries/chain/hardfork.d/572.hf | 6 +- libraries/chain/hardfork.d/599.hf | 6 +- libraries/chain/hardfork.d/607.hf | 6 +- libraries/chain/hardfork.d/613.hf | 6 +- libraries/chain/hardfork.d/615.hf | 6 +- libraries/chain/hardfork.d/999.hf | 6 +- libraries/chain/hardfork.d/CORE-429.hf | 6 +- libraries/chain/hardfork.d/CORE_210.hf | 6 +- libraries/chain/hardfork.d/GPOS.hf | 7 +- libraries/chain/hardfork.d/NFT.hf | 7 +- libraries/chain/hardfork.d/SON.hf | 7 +- libraries/chain/hardfork.d/SON2.hf | 7 +- libraries/chain/hardfork.d/SON_FOR_HIVE.hf | 7 + libraries/chain/hardfork.d/SWEEPS.hf | 6 +- .../graphene/chain/account_role_object.hpp | 2 +- .../include/graphene/chain/block_database.hpp | 4 + .../chain/include/graphene/chain/config.hpp | 5 + .../chain/include/graphene/chain/database.hpp | 2 + .../global_betting_statistics_object.hpp | 2 +- .../chain/include/graphene/chain/impacted.hpp | 2 +- .../graphene/chain/nft_lottery_evaluator.hpp | 39 + .../include/graphene/chain/nft_object.hpp | 100 +- .../chain/protocol/chain_parameters.hpp | 10 + .../graphene/chain/protocol/nft_lottery.hpp | 86 + .../graphene/chain/protocol/nft_ops.hpp | 32 +- .../graphene/chain/protocol/operations.hpp | 8 +- .../graphene/chain/protocol/random_number.hpp | 25 + .../include/graphene/chain/protocol/son.hpp | 4 +- .../include/graphene/chain/protocol/types.hpp | 13 +- .../chain/random_number_evaluator.hpp | 19 + .../graphene/chain/random_number_object.hpp | 41 + .../graphene/chain/rbac_hardfork_visitor.hpp | 3 + .../include/graphene/chain/sidechain_defs.hpp | 4 +- .../chain/sidechain_transaction_object.hpp | 6 +- .../include/graphene/chain/son_object.hpp | 9 +- .../graphene/chain/vesting_balance_object.hpp | 20 +- libraries/chain/index.cpp | 43 - libraries/chain/nft_evaluator.cpp | 41 + libraries/chain/nft_lottery_evaluator.cpp | 145 + libraries/chain/nft_lottery_object.cpp | 171 + libraries/chain/proposal_evaluator.cpp | 12 + libraries/chain/protocol/competitor.cpp | 35 - libraries/chain/protocol/memo.cpp | 8 +- libraries/chain/protocol/nft.cpp | 4 + libraries/chain/protocol/nft_lottery.cpp | 38 + libraries/chain/random_number_evaluator.cpp | 24 + .../chain/sidechain_address_evaluator.cpp | 8 +- .../chain/sidechain_transaction_evaluator.cpp | 11 +- libraries/chain/son_evaluator.cpp | 4 + libraries/chain/son_object.cpp | 12 + .../chain/son_wallet_deposit_evaluator.cpp | 16 +- .../chain/son_wallet_withdraw_evaluator.cpp | 16 +- libraries/chain/tournament_object.cpp | 5 +- libraries/chain/transaction_object.cpp | 95 - .../db/include/graphene/db/undo_database.hpp | 12 +- libraries/db/undo_database.cpp | 12 + libraries/egenesis/CMakeLists.txt | 8 +- libraries/net/CMakeLists.txt | 8 +- libraries/net/node.cpp | 2 + libraries/plugins/CMakeLists.txt | 14 +- .../plugins/account_history/CMakeLists.txt | 2 +- .../plugins/accounts_list/CMakeLists.txt | 2 +- .../plugins/affiliate_stats/CMakeLists.txt | 2 +- libraries/plugins/bookie/CMakeLists.txt | 2 +- .../plugins/debug_witness/CMakeLists.txt | 2 +- libraries/plugins/delayed_node/CMakeLists.txt | 2 +- .../plugins/elasticsearch/CMakeLists.txt | 14 +- .../elasticsearch/elasticsearch_plugin.cpp | 109 +- .../elasticsearch/elasticsearch_plugin.hpp | 35 +- libraries/plugins/es_objects/CMakeLists.txt | 14 +- libraries/plugins/es_objects/es_objects.cpp | 416 +- .../plugins/generate_genesis/CMakeLists.txt | 2 +- .../CMakeLists.txt | 2 +- .../grouped_orders/grouped_orders_plugin.cpp | 303 - .../plugins/market_history/CMakeLists.txt | 2 +- .../peerplays_sidechain/CMakeLists.txt | 9 +- .../bitcoin/bitcoin_script.cpp | 1 + .../bitcoin/bitcoin_transaction.cpp | 1 + .../bitcoin/sign_bitcoin_transaction.cpp | 3 + .../peerplays_sidechain/common/rpc_client.cpp | 1017 ++ .../peerplays_sidechain/common/utils.cpp | 8 + .../peerplays_sidechain/hive/asset.cpp | 69 + .../peerplays_sidechain/hive/operations.cpp | 101 + .../peerplays_sidechain/hive/transaction.cpp | 57 + .../peerplays_sidechain/hive/types.cpp | 73 + .../peerplays_sidechain/common/rpc_client.hpp | 136 + .../peerplays_sidechain/common/utils.hpp | 5 + .../peerplays_sidechain/hive/asset.hpp | 41 + .../peerplays_sidechain/hive/authority.hpp | 33 + .../hive/hive_operations.hpp | 123 + .../peerplays_sidechain/hive/operations.hpp | 69 + .../peerplays_sidechain/hive/transaction.hpp | 44 + .../peerplays_sidechain/hive/types.hpp | 72 + .../peerplays_sidechain_plugin.hpp | 1 + .../sidechain_net_handler.hpp | 7 +- .../sidechain_net_handler_bitcoin.hpp | 19 +- .../sidechain_net_handler_hive.hpp | 67 + .../sidechain_net_handler_peerplays.hpp | 5 +- .../sidechain_net_manager.hpp | 2 + .../peerplays_sidechain_plugin.cpp | 96 +- .../sidechain_net_handler.cpp | 150 +- .../sidechain_net_handler_bitcoin.cpp | 225 +- .../sidechain_net_handler_hive.cpp | 943 ++ .../sidechain_net_handler_peerplays.cpp | 107 +- .../sidechain_net_manager.cpp | 14 + libraries/plugins/snapshot/CMakeLists.txt | 2 +- libraries/plugins/witness/CMakeLists.txt | 2 +- libraries/plugins/witness/witness.cpp | 6 +- libraries/wallet/CMakeLists.txt | 2 +- .../wallet/include/graphene/wallet/wallet.hpp | 266 +- libraries/wallet/wallet.cpp | 318 +- programs/CMakeLists.txt | 4 +- programs/build_helpers/CMakeLists.txt | 4 +- programs/cli_wallet/CMakeLists.txt | 2 +- programs/debug_node/CMakeLists.txt | 2 +- programs/delayed_node/CMakeLists.txt | 2 +- programs/genesis_util/CMakeLists.txt | 6 +- .../js_operation_serializer/CMakeLists.txt | 2 +- programs/size_checker/CMakeLists.txt | 2 +- programs/witness_node/CMakeLists.txt | 2 +- programs/witness_node/genesis.json | 2 +- programs/witness_node/main.cpp | 5 +- tests/CMakeLists.txt | 47 +- tests/betting/betting_tests.cpp | 1138 +- tests/cli/son.cpp | 17 +- tests/common/betting_test_markets.hpp | 141 +- tests/common/database_fixture.cpp | 43 +- tests/common/database_fixture.hpp | 4 +- tests/generate_empty_blocks/CMakeLists.txt | 2 +- .../bitcoin_transaction_tests.cpp | 1 + tests/tests/affiliate_tests.cpp | 48 +- tests/tests/basic_tests.cpp | 197 +- tests/tests/block_tests.cpp | 2 +- tests/tests/confidential_tests.cpp | 1 - tests/tests/database_tests.cpp | 2 +- tests/tests/dividend_tests.cpp | 37 - tests/tests/gpos_tests.cpp | 230 +- tests/tests/history_api_tests.cpp | 8 + tests/tests/lottery_tests.cpp | 5 +- tests/tests/nft_lottery_tests.cpp | 842 ++ tests/tests/operation_tests.cpp | 1 - tests/tests/son_operations_tests.cpp | 44 +- tests/tests/voting_tests.cpp | 2 +- tests/tournament/tournament_tests.cpp | 6 +- 204 files changed, 22157 insertions(+), 7779 deletions(-) delete mode 100644 bkup_CMakeCache.txt create mode 100755 clang-format.sh delete mode 100644 docker/default_config.ini delete mode 100644 docker/peerplaysentry.sh rename genesis.json => genesis-mainnet.json (100%) create mode 100644 genesis-testnet.json create mode 100644 libraries/chain/hardfork.d/SON_FOR_HIVE.hf create mode 100644 libraries/chain/include/graphene/chain/nft_lottery_evaluator.hpp create mode 100644 libraries/chain/include/graphene/chain/protocol/nft_lottery.hpp create mode 100644 libraries/chain/include/graphene/chain/protocol/random_number.hpp create mode 100644 libraries/chain/include/graphene/chain/random_number_evaluator.hpp create mode 100644 libraries/chain/include/graphene/chain/random_number_object.hpp delete mode 100644 libraries/chain/index.cpp create mode 100644 libraries/chain/nft_lottery_evaluator.cpp create mode 100644 libraries/chain/nft_lottery_object.cpp delete mode 100644 libraries/chain/protocol/competitor.cpp create mode 100644 libraries/chain/protocol/nft_lottery.cpp create mode 100644 libraries/chain/random_number_evaluator.cpp delete mode 100644 libraries/chain/transaction_object.cpp delete mode 100644 libraries/plugins/grouped_orders/grouped_orders_plugin.cpp create mode 100644 libraries/plugins/peerplays_sidechain/common/rpc_client.cpp create mode 100644 libraries/plugins/peerplays_sidechain/common/utils.cpp create mode 100644 libraries/plugins/peerplays_sidechain/hive/asset.cpp create mode 100644 libraries/plugins/peerplays_sidechain/hive/operations.cpp create mode 100644 libraries/plugins/peerplays_sidechain/hive/transaction.cpp create mode 100644 libraries/plugins/peerplays_sidechain/hive/types.cpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/utils.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/authority.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/hive_operations.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/operations.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/transaction.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types.hpp create mode 100644 libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp create mode 100644 libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp create mode 100644 tests/tests/nft_lottery_tests.cpp diff --git a/.gitignore b/.gitignore index 39b23163..1a84b559 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ data CMakeDoxyfile.in build +build__* libraries/utilities/git_revision.cpp diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 97f01d3f..369dcf8a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,7 +19,7 @@ build: - mkdir build - cd build - cmake -DCMAKE_BUILD_TYPE=Release .. - - make -j$(nproc) + - make -j4 artifacts: untracked: true paths: @@ -31,11 +31,14 @@ build: dockerize: stage: build + variables: + IMAGE: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA + before_script: + - docker info + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY script: - - docker build . -t $DOCKER_REPO:$CI_COMMIT_REF_NAME - - docker login -u $DOCKER_USER -p $DOCKER_PASS - - docker push $DOCKER_REPO:$CI_COMMIT_REF_NAME - - docker logout + - docker build -t $IMAGE . + - docker push $IMAGE tags: - builder when: manual diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c6be0bc..2f006aa0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,11 @@ -# Defines BitShares library target. -project( BitShares ) +# Defines Peerplays library target. +project( Peerplays ) cmake_minimum_required( VERSION 2.8.12 ) -set( BLOCKCHAIN_NAME "BitShares" ) +set( BLOCKCHAIN_NAME "Peerplays" ) set( CLI_CLIENT_EXECUTABLE_NAME graphene_client ) -set( GUI_CLIENT_EXECUTABLE_NAME BitShares ) +set( GUI_CLIENT_EXECUTABLE_NAME Peerplays ) set( CUSTOM_URL_SCHEME "gcs" ) set( INSTALLER_APP_ID "68ad7005-8eee-49c9-95ce-9eed97e5b347" ) @@ -22,8 +22,45 @@ endif() list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules" ) +# function to help with cUrl +macro(FIND_CURL) + if (NOT WIN32 AND NOT APPLE AND CURL_STATICLIB) + find_package(OpenSSL REQUIRED) + set (OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set (CMAKE_FIND_LIBRARY_SUFFIXES .a) + find_package(CURL REQUIRED) + list(APPEND CURL_LIBRARIES ${OPENSSL_LIBRARIES} ${BOOST_THREAD_LIBRARY} ${CMAKE_DL_LIBS}) + set (CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES}) + else (NOT WIN32 AND NOT APPLE AND CURL_STATICLIB) + find_package(CURL REQUIRED) + endif (NOT WIN32 AND NOT APPLE AND CURL_STATICLIB) + + if( WIN32 ) + if ( MSVC ) + list( APPEND CURL_LIBRARIES Wldap32 ) + endif( MSVC ) + + if( MINGW ) + # MinGW requires a specific order of included libraries ( CURL before ZLib ) + find_package( ZLIB REQUIRED ) + list( APPEND CURL_LIBRARIES ${ZLIB_LIBRARY} pthread ) + endif( MINGW ) + + list( APPEND CURL_LIBRARIES ${PLATFORM_SPECIFIC_LIBS} ) + endif( WIN32 ) +endmacro() + set(CMAKE_EXPORT_COMPILE_COMMANDS "ON") -set(GRAPHENE_EGENESIS_JSON "${CMAKE_CURRENT_SOURCE_DIR}/genesis.json" CACHE PATH "location of the genesis.json to embed in the executable" ) + +if (BUILD_PEERPLAYS_TESTNET) + set(GRAPHENE_EGENESIS_JSON "${CMAKE_CURRENT_SOURCE_DIR}/genesis-testnet.json" CACHE PATH "location of the genesis.json to embed in the executable" ) + #add_compile_definitions(BUILD_PEERPLAYS_TESTNET=1) + add_definitions(-DBUILD_PEERPLAYS_TESTNET=1) + message ("\n====================\nBuilding for Testnet\n====================\n") +else (BUILD_PEERPLAYS_TESTNET) + set(GRAPHENE_EGENESIS_JSON "${CMAKE_CURRENT_SOURCE_DIR}/genesis-mainnet.json" CACHE PATH "location of the genesis.json to embed in the executable" ) + message ("\n====================\nBuilding for Mainnet\n====================\n") +endif (BUILD_PEERPLAYS_TESTNET) #set (ENABLE_INSTALLER 1) #set (USE_PCH 1) @@ -71,7 +108,7 @@ ENDIF() if( WIN32 ) - message( STATUS "Configuring BitShares on WIN32") + message( STATUS "Configuring Peerplays on WIN32") set( DB_VERSION 60 ) set( BDB_STATIC_LIBS 1 ) @@ -103,20 +140,13 @@ if( WIN32 ) SET(TCL_LIBRARY ${TCL_LIBS}) else( WIN32 ) # Apple AND Linux - - find_library(READLINE_LIBRARIES NAMES readline) - find_path(READLINE_INCLUDE_DIR readline/readline.h) - #if(NOT READLINE_INCLUDE_DIR OR NOT READLINE_LIBRARIES) - # MESSAGE(FATAL_ERROR "Could not find lib readline.") - #endif() - if( APPLE ) # Apple Specific Options Here - message( STATUS "Configuring BitShares on OS X" ) + message( STATUS "Configuring Peerplays on OS X" ) set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -stdlib=libc++ -Wall" ) else( APPLE ) # Linux Specific Options Here - message( STATUS "Configuring BitShares on Linux" ) + message( STATUS "Configuring Peerplays on Linux" ) set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -Wall" ) set( rt_library rt ) #set( pthread_library pthread) @@ -135,7 +165,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 -Wno-parentheses -Wno-terminate -Wno-invalid-offsetof -Wno-sign-compare" ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" ) 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" ) @@ -154,7 +184,7 @@ else( WIN32 ) # Apple AND Linux endif( WIN32 ) -set(ENABLE_COVERAGE_TESTING FALSE CACHE BOOL "Build BitShares for code coverage analysis") +set(ENABLE_COVERAGE_TESTING FALSE CACHE BOOL "Build Peerplays for code coverage analysis") if(ENABLE_COVERAGE_TESTING) SET(CMAKE_CXX_FLAGS "--coverage ${CMAKE_CXX_FLAGS}") @@ -163,13 +193,13 @@ endif() add_subdirectory( libraries ) -set(BUILD_BITSHARES_PROGRAMS TRUE CACHE BOOL "Build bitshares executables (witness node, cli wallet, etc)") +set(BUILD_PEERPLAYS_PROGRAMS TRUE CACHE BOOL "Build peerplays executables (witness node, cli wallet, etc)") add_subdirectory( programs ) -set(BUILD_BITSHARES_TESTS TRUE CACHE BOOL "Build bitshares unit tests") -if( BUILD_BITSHARES_TESTS ) +set(BUILD_PEERPLAYS_TESTS TRUE CACHE BOOL "Build peerplays unit tests") +if( BUILD_PEERPLAYS_TESTS ) add_subdirectory( tests ) -endif( BUILD_BITSHARES_TESTS ) +endif( BUILD_PEERPLAYS_TESTS ) if (ENABLE_INSTALLER) @@ -191,18 +221,18 @@ set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}") set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") -set(CPACK_PACKAGE_DESCRIPTION "A client for the BitShares network") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A client for the BitShares network") +set(CPACK_PACKAGE_DESCRIPTION "A client for the Peerplays network") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A client for the Peerplays network") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.md") -set(CPACK_PACKAGE_INSTALL_DIRECTORY "BitShares ${CPACK_PACKAGE_VERSION}") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "Peerplays ${CPACK_PACKAGE_VERSION}") if(WIN32) SET(CPACK_GENERATOR "ZIP;NSIS") - set(CPACK_PACKAGE_NAME "BitShares") # override above + set(CPACK_PACKAGE_NAME "Peerplays") # override above set(CPACK_NSIS_EXECUTABLES_DIRECTORY .) - set(CPACK_NSIS_PACKAGE_NAME "BitShares v${CPACK_PACKAGE_VERSION}") + set(CPACK_NSIS_PACKAGE_NAME "Peerplays v${CPACK_PACKAGE_VERSION}") set(CPACK_NSIS_DISPLAY_NAME "${CPACK_NSIS_PACKAGE_NAME}") - set(CPACK_NSIS_DEFINES " !define MUI_STARTMENUPAGE_DEFAULTFOLDER \\\"BitShares\\\"") + set(CPACK_NSIS_DEFINES " !define MUI_STARTMENUPAGE_DEFAULTFOLDER \\\"Peerplays\\\"") # it seems like windows zip files usually don't have a single directory inside them, unix tgz frequently do SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0) @@ -220,3 +250,8 @@ endif(LINUX) include(CPack) endif(ENABLE_INSTALLER) + +unset(GRAPHENE_EGENESIS_JSON) +unset(GRAPHENE_EGENESIS_JSON CACHE) +unset(BUILD_PEERPLAYS_TESTNET) +unset(BUILD_PEERPLAYS_TESTNET CACHE) diff --git a/Dockerfile b/Dockerfile index 5f63bd77..38c96a3c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,14 @@ -FROM ubuntu:18.04 +FROM ubuntu:20.04 MAINTAINER PeerPlays Blockchain Standards Association -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US.UTF-8 -ENV LC_ALL en_US.UTF-8 +#=============================================================================== +# Ubuntu setup +#=============================================================================== RUN \ apt-get update -y && \ DEBIAN_FRONTEND=noninteractive apt-get install -y \ + apt-utils \ autoconf \ bash \ build-essential \ @@ -15,82 +16,89 @@ RUN \ cmake \ dnsutils \ doxygen \ + expect \ git \ graphviz \ + libboost1.67-all-dev \ libbz2-dev \ libcurl4-openssl-dev \ libncurses-dev \ libreadline-dev \ + libsnappy-dev \ libssl-dev \ libtool \ + libzip-dev \ libzmq3-dev \ locales \ + mc \ + nano \ + net-tools \ ntp \ + openssh-server \ pkg-config \ - wget \ - && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + perl \ + python3 \ + python3-jinja2 \ + sudo \ + wget +ENV HOME /home/peerplays +RUN useradd -rm -d /home/peerplays -s /bin/bash -g root -G sudo -u 1000 peerplays +RUN echo "peerplays ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/peerplays +RUN chmod 440 /etc/sudoers.d/peerplays + +RUN service ssh start +RUN echo 'peerplays:peerplays' | chpasswd + +# SSH +EXPOSE 22 + +#=============================================================================== +# Peerplays setup +#=============================================================================== + +WORKDIR /home/peerplays/ + +## Clone Peerplays +#RUN \ +# git clone https://gitlab.com/PBSA/peerplays.git && \ +# cd peerplays && \ +# git checkout develop && \ +# git submodule update --init --recursive && \ +# git branch --show-current && \ +# git log --oneline -n 5 + +# Add local source +ADD . peerplays + +# Configure Peerplays RUN \ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \ - locale-gen - -# Compile Boost -RUN \ - BOOST_ROOT=$HOME/boost_1_67_0 && \ - wget -c 'http://sourceforge.net/projects/boost/files/boost/1.67.0/boost_1_67_0.tar.gz/download' -O boost_1_67_0.tar.gz &&\ - tar -zxvf boost_1_67_0.tar.gz && \ - cd boost_1_67_0/ && \ - ./bootstrap.sh "--prefix=$BOOST_ROOT" && \ - ./b2 install && \ - cd .. - -ADD . /peerplays-core -WORKDIR /peerplays-core - -# Compile Peerplays -RUN \ - BOOST_ROOT=$HOME/boost_1_67_0 && \ - git submodule sync --recursive && \ - git submodule update --init --recursive && \ + cd peerplays && \ mkdir build && \ - mkdir build/release && \ - cd build/release && \ - cmake \ - -DBOOST_ROOT="$BOOST_ROOT" \ - -DCMAKE_BUILD_TYPE=Debug \ - ../.. && \ - make witness_node cli_wallet && \ - install -s programs/witness_node/witness_node programs/cli_wallet/cli_wallet /usr/local/bin && \ - # - # Obtain version - mkdir /etc/peerplays && \ - git rev-parse --short HEAD > /etc/peerplays/version && \ - cd / && \ - rm -rf /peerplays-core + cd build && \ + cmake -DCMAKE_BUILD_TYPE=Release .. -# Home directory $HOME -WORKDIR / -RUN useradd -s /bin/bash -m -d /var/lib/peerplays peerplays -ENV HOME /var/lib/peerplays -RUN chown peerplays:peerplays -R /var/lib/peerplays +# Build Peerplays +RUN \ + cd peerplays/build && \ + make -j$(nproc) cli_wallet witness_node -# Volume -VOLUME ["/var/lib/peerplays", "/etc/peerplays"] +WORKDIR /home/peerplays/peerplays-network -# rpc service: +# Setup Peerplays runimage +RUN \ + ln -s /home/peerplays/peerplays/build/programs/cli_wallet/cli_wallet ./ && \ + ln -s /home/peerplays/peerplays/build/programs/witness_node/witness_node ./ + +RUN ./witness_node --create-genesis-json genesis.json && \ + rm genesis.json + +RUN chown peerplays:root -R /home/peerplays/peerplays-network + +# Peerplays RPC EXPOSE 8090 -# p2p service: -EXPOSE 1776 +# Peerplays P2P: +EXPOSE 9777 -# default exec/config files -ADD docker/default_config.ini /etc/peerplays/config.ini -ADD docker/peerplaysentry.sh /usr/local/bin/peerplaysentry.sh -RUN chmod a+x /usr/local/bin/peerplaysentry.sh - -# Make Docker send SIGINT instead of SIGTERM to the daemon -STOPSIGNAL SIGINT - -# default execute entry -CMD ["/usr/local/bin/peerplaysentry.sh"] +# Peerplays +CMD ["./witness_node", "-d", "./witness_node_data_dir"] diff --git a/README.md b/README.md index 7173bcb1..bc37f091 100644 --- a/README.md +++ b/README.md @@ -38,13 +38,15 @@ export BOOST_ROOT=$HOME/src/boost_1_67_0 git clone https://github.com/peerplays-network/peerplays.git cd peerplays git submodule update --init --recursive +# If you want to build Mainnet node cmake -DBOOST_ROOT="$BOOST_ROOT" -DCMAKE_BUILD_TYPE=Release +# If you want to build Testnet node +cmake -DBOOST_ROOT="$BOOST_ROOT" -DCMAKE_BUILD_TYPE=Release -DBUILD_PEERPLAYS_TESTNET=1 make -j$(nproc) make install # this can install the executable files under /usr/local ``` -docker build -t peerplays . ## Docker image diff --git a/bkup_CMakeCache.txt b/bkup_CMakeCache.txt deleted file mode 100644 index daa267e9..00000000 --- a/bkup_CMakeCache.txt +++ /dev/null @@ -1,794 +0,0 @@ -# This is the CMakeCache file. -# For build in directory: /home/pbattu/git/18.04/peerplays -# It was generated by CMake: /usr/bin/cmake -# You can edit this file to change values found and used by cmake. -# If you do not want to change any of the values, simply exit the editor. -# If you do want to change a value, simply edit, save, and exit the editor. -# The syntax for the file is as follows: -# KEY:TYPE=VALUE -# KEY is the name of a variable in the cache. -# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. -# VALUE is the current value for the KEY. - -######################## -# EXTERNAL cache entries -######################## - -//No help, variable specified on the command line. -BOOST_ROOT:PATH=/home/pbattu/git/18.04/boost_1_67_0 - -//The threading library used by boost-thread -BOOST_THREAD_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpthread.so - -//Build bitshares executables (witness node, cli wallet, etc) -BUILD_BITSHARES_PROGRAMS:BOOL=TRUE - -//Build bitshares unit tests -BUILD_BITSHARES_TESTS:BOOL=TRUE - -//Build websocketpp examples. -BUILD_EXAMPLES:BOOL=OFF - -//Build websocketpp tests. -BUILD_TESTS:BOOL=OFF - -//Value Computed by CMake -BitShares_BINARY_DIR:STATIC=/home/pbattu/git/18.04/peerplays - -//Value Computed by CMake -BitShares_SOURCE_DIR:STATIC=/home/pbattu/git/18.04/peerplays - -//Boost chrono library (debug) -Boost_CHRONO_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_chrono.a - -//Boost chrono library (release) -Boost_CHRONO_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_chrono.a - -//Boost context library (debug) -Boost_CONTEXT_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_context.a - -//Boost context library (release) -Boost_CONTEXT_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_context.a - -//Boost coroutine library (debug) -Boost_COROUTINE_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_coroutine.a - -//Boost coroutine library (release) -Boost_COROUTINE_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_coroutine.a - -//Boost date_time library (debug) -Boost_DATE_TIME_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_date_time.a - -//Boost date_time library (release) -Boost_DATE_TIME_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_date_time.a - -//The directory containing a CMake configuration file for Boost. -Boost_DIR:PATH=Boost_DIR-NOTFOUND - -//Boost filesystem library (debug) -Boost_FILESYSTEM_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_filesystem.a - -//Boost filesystem library (release) -Boost_FILESYSTEM_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_filesystem.a - -//Path to a file. -Boost_INCLUDE_DIR:PATH=/home/pbattu/git/18.04/boost_1_67_0/include - -//Boost iostreams library (debug) -Boost_IOSTREAMS_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_iostreams.a - -//Boost iostreams library (release) -Boost_IOSTREAMS_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_iostreams.a - -//Boost library directory -Boost_LIBRARY_DIR:PATH=/home/pbattu/git/18.04/boost_1_67_0/lib - -//Boost library directory DEBUG -Boost_LIBRARY_DIR_DEBUG:PATH=/home/pbattu/git/18.04/boost_1_67_0/lib - -//Boost library directory RELEASE -Boost_LIBRARY_DIR_RELEASE:PATH=/home/pbattu/git/18.04/boost_1_67_0/lib - -//Boost locale library (debug) -Boost_LOCALE_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_locale.a - -//Boost locale library (release) -Boost_LOCALE_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_locale.a - -//Boost program_options library (debug) -Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_program_options.a - -//Boost program_options library (release) -Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_program_options.a - -//Boost serialization library (debug) -Boost_SERIALIZATION_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_serialization.a - -//Boost serialization library (release) -Boost_SERIALIZATION_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_serialization.a - -//Boost signals library (debug) -Boost_SIGNALS_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_signals.a - -//Boost signals library (release) -Boost_SIGNALS_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_signals.a - -//Boost system library (debug) -Boost_SYSTEM_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_system.a - -//Boost system library (release) -Boost_SYSTEM_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_system.a - -//Boost thread library (debug) -Boost_THREAD_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_thread.a - -//Boost thread library (release) -Boost_THREAD_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_thread.a - -//Boost unit_test_framework library (debug) -Boost_UNIT_TEST_FRAMEWORK_LIBRARY_DEBUG:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_unit_test_framework.a - -//Boost unit_test_framework library (release) -Boost_UNIT_TEST_FRAMEWORK_LIBRARY_RELEASE:FILEPATH=/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_unit_test_framework.a - -//ON or OFF -Boost_USE_STATIC_LIBS:STRING=ON - -//Path to a program. -CMAKE_AR:FILEPATH=/usr/bin/ar - -//Choose the type of build, options are: None(CMAKE_CXX_FLAGS or -// CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel. -CMAKE_BUILD_TYPE:STRING=Debug - -//Enable/Disable color output during build. -CMAKE_COLOR_MAKEFILE:BOOL=ON - -//Configurations -CMAKE_CONFIGURATION_TYPES:STRING=Release;RelWithDebInfo;Debug - -//CXX compiler -CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++-5 - -//A wrapper around 'ar' adding the appropriate '--plugin' option -// for the GCC compiler -CMAKE_CXX_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-5 - -//A wrapper around 'ranlib' adding the appropriate '--plugin' option -// for the GCC compiler -CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-5 - -//Flags used by the compiler during all build types. -CMAKE_CXX_FLAGS:STRING= - -//Flags used by the compiler during debug builds. -CMAKE_CXX_FLAGS_DEBUG:STRING=-g - -//Flags used by the compiler during release builds for minimum -// size. -CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG - -//Flags used by the compiler during release builds. -CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG - -//Flags used by the compiler during release builds with debug info. -CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG - -//C compiler -CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc-5 - -//A wrapper around 'ar' adding the appropriate '--plugin' option -// for the GCC compiler -CMAKE_C_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-5 - -//A wrapper around 'ranlib' adding the appropriate '--plugin' option -// for the GCC compiler -CMAKE_C_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-5 - -//Flags used by the compiler during all build types. -CMAKE_C_FLAGS:STRING= - -//Flags used by the compiler during debug builds. -CMAKE_C_FLAGS_DEBUG:STRING=-g - -//Flags used by the compiler during release builds for minimum -// size. -CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG - -//Flags used by the compiler during release builds. -CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG - -//Flags used by the compiler during release builds with debug info. -CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG - -//Flags used by the linker. -CMAKE_EXE_LINKER_FLAGS:STRING= - -//Flags used by the linker during debug builds. -CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Enable/Disable output of compile commands during generation. -CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=OFF - -//Install path prefix, prepended onto install directories. -CMAKE_INSTALL_PREFIX:PATH=/usr/local - -//Path to a program. -CMAKE_LINKER:FILEPATH=/usr/bin/ld - -//Path to a program. -CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/make - -//Flags used by the linker during the creation of modules. -CMAKE_MODULE_LINKER_FLAGS:STRING= - -//Flags used by the linker during debug builds. -CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Path to a program. -CMAKE_NM:FILEPATH=/usr/bin/nm - -//Path to a program. -CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy - -//Path to a program. -CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump - -//Value Computed by CMake -CMAKE_PROJECT_NAME:STATIC=BitShares - -//Path to a program. -CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib - -//Flags used by the linker during the creation of dll's. -CMAKE_SHARED_LINKER_FLAGS:STRING= - -//Flags used by the linker during debug builds. -CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//If set, runtime paths are not added when installing shared libraries, -// but are added when building. -CMAKE_SKIP_INSTALL_RPATH:BOOL=NO - -//If set, runtime paths are not added when using shared libraries. -CMAKE_SKIP_RPATH:BOOL=NO - -//Flags used by the linker during the creation of static libraries. -CMAKE_STATIC_LINKER_FLAGS:STRING= - -//Flags used by the linker during debug builds. -CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during release minsize builds. -CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during release builds. -CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during Release with Debug Info builds. -CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Path to a program. -CMAKE_STRIP:FILEPATH=/usr/bin/strip - -//If this value is on, makefiles will be generated without the -// .SILENT directive, and all commands will be echoed to the console -// during the make. This is useful for debugging only. With Visual -// Studio IDE projects all commands are done without /nologo. -CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE - -//Path to a library. -CURSES_CURSES_LIBRARY:FILEPATH=CURSES_CURSES_LIBRARY-NOTFOUND - -//Path to a library. -CURSES_FORM_LIBRARY:FILEPATH=CURSES_FORM_LIBRARY-NOTFOUND - -//Path to a file. -CURSES_INCLUDE_PATH:PATH=CURSES_INCLUDE_PATH-NOTFOUND - -//Path to a library. -CURSES_NCURSES_LIBRARY:FILEPATH=CURSES_NCURSES_LIBRARY-NOTFOUND - -//Dot tool for use with Doxygen -DOXYGEN_DOT_EXECUTABLE:FILEPATH=DOXYGEN_DOT_EXECUTABLE-NOTFOUND - -//Doxygen documentation generation tool (http://www.doxygen.org) -DOXYGEN_EXECUTABLE:FILEPATH=DOXYGEN_EXECUTABLE-NOTFOUND - -//secp256k1 or openssl or mixed -ECC_IMPL:STRING=secp256k1 - -//Build BitShares for code coverage analysis -ENABLE_COVERAGE_TESTING:BOOL=FALSE - -//Build websocketpp with CPP11 features enabled. -ENABLE_CPP11:BOOL=ON - -//TRUE to try to use full zlib for compression, FALSE to use miniz.c -FC_USE_FULL_ZLIB:BOOL=FALSE - -//Git command line client -GIT_EXECUTABLE:FILEPATH=/usr/bin/git - -//location of the genesis.json to embed in the executable -GRAPHENE_EGENESIS_JSON:PATH=/home/pbattu/git/18.04/peerplays/genesis.json - -//The directory containing a CMake configuration file for Gperftools. -Gperftools_DIR:PATH=Gperftools_DIR-NOTFOUND - -//Installation directory for CMake files -INSTALL_CMAKE_DIR:PATH=lib/cmake/websocketpp - -//Installation directory for header files -INSTALL_INCLUDE_DIR:PATH=include - -//Log long API calls over websocket (ON OR OFF) -LOG_LONG_API:BOOL=ON - -//Max API execution time in ms -LOG_LONG_API_MAX_MS:STRING=1000 - -//API execution time in ms at which to warn -LOG_LONG_API_WARN_MS:STRING=750 - -//Path to a library. -OPENSSL_CRYPTO_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcrypto.a - -//Path to a file. -OPENSSL_INCLUDE_DIR:PATH=/usr/include - -//Path to a library. -OPENSSL_SSL_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libssl.a - -//Path to a program. -PERL_EXECUTABLE:FILEPATH=/usr/bin/perl - -//pkg-config executable -PKG_CONFIG_EXECUTABLE:FILEPATH=/usr/bin/pkg-config - -//Path to a file. -READLINE_INCLUDE_DIR:PATH=/usr/include - -//Path to a library. -READLINE_LIBRARIES:FILEPATH=/usr/lib/x86_64-linux-gnu/libreadline.so - -//Path to a file. -Readline_INCLUDE_DIR:PATH=/usr/include - -//Path to a library. -Readline_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libreadline.so - -//Path to a file. -Readline_ROOT_DIR:PATH=/usr - -//OFF -UNITY_BUILD:BOOL=OFF - -//Path to a file. -ZLIB_INCLUDE_DIR:PATH=/usr/include - -//Path to a library. -ZLIB_LIBRARY_DEBUG:FILEPATH=ZLIB_LIBRARY_DEBUG-NOTFOUND - -//Path to a library. -ZLIB_LIBRARY_RELEASE:FILEPATH=/usr/lib/x86_64-linux-gnu/libz.so - -//Value Computed by CMake -fc_BINARY_DIR:STATIC=/home/pbattu/git/18.04/peerplays/libraries/fc - -//Dependencies for the target -fc_LIB_DEPENDS:STATIC=general;-L/usr/local/lib;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_thread.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_date_time.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_filesystem.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_system.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_program_options.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_signals.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_serialization.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_chrono.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_unit_test_framework.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_context.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_locale.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_iostreams.a;general;/home/pbattu/git/18.04/boost_1_67_0/lib/libboost_coroutine.a;general;/usr/lib/x86_64-linux-gnu/libpthread.so;general;/usr/lib/x86_64-linux-gnu/libssl.a;general;/usr/lib/x86_64-linux-gnu/libcrypto.a;general;/usr/lib/x86_64-linux-gnu/libz.so;general;dl;general;rt;general;/usr/lib/x86_64-linux-gnu/libreadline.so;general;secp256k1; - -//Value Computed by CMake -fc_SOURCE_DIR:STATIC=/home/pbattu/git/18.04/peerplays/libraries/fc - -//Dependencies for the target -graphene_account_history_LIB_DEPENDS:STATIC=general;graphene_chain;general;graphene_app; - -//Dependencies for the target -graphene_accounts_list_LIB_DEPENDS:STATIC=general;graphene_chain;general;graphene_app; - -//Dependencies for the target -graphene_affiliate_stats_LIB_DEPENDS:STATIC=general;graphene_chain;general;graphene_app; - -//Dependencies for the target -graphene_app_LIB_DEPENDS:STATIC=general;graphene_market_history;general;graphene_account_history;general;graphene_accounts_list;general;graphene_affiliate_stats;general;graphene_chain;general;fc;general;graphene_db;general;graphene_net;general;graphene_time;general;graphene_utilities;general;graphene_debug_witness;general;graphene_bookie; - -//Dependencies for the target -graphene_bookie_LIB_DEPENDS:STATIC=general;graphene_chain;general;graphene_app; - -//Dependencies for the target -graphene_chain_LIB_DEPENDS:STATIC=general;fc;general;graphene_db; - -//Dependencies for the target -graphene_db_LIB_DEPENDS:STATIC=general;fc; - -//Dependencies for the target -graphene_debug_witness_LIB_DEPENDS:STATIC=general;graphene_chain;general;graphene_app; - -//Dependencies for the target -graphene_delayed_node_LIB_DEPENDS:STATIC=general;graphene_chain;general;graphene_app; - -//Dependencies for the target -graphene_egenesis_brief_LIB_DEPENDS:STATIC=general;graphene_chain;general;fc; - -//Dependencies for the target -graphene_egenesis_full_LIB_DEPENDS:STATIC=general;graphene_chain;general;fc; - -//Dependencies for the target -graphene_egenesis_none_LIB_DEPENDS:STATIC=general;graphene_chain;general;fc; - -//Dependencies for the target -graphene_generate_genesis_LIB_DEPENDS:STATIC=general;graphene_chain;general;graphene_app;general;graphene_time; - -//Dependencies for the target -graphene_generate_uia_sharedrop_genesis_LIB_DEPENDS:STATIC=general;graphene_chain;general;graphene_app;general;graphene_time; - -//Dependencies for the target -graphene_market_history_LIB_DEPENDS:STATIC=general;graphene_chain;general;graphene_app; - -//Dependencies for the target -graphene_net_LIB_DEPENDS:STATIC=general;fc;general;graphene_db; - -//Dependencies for the target -graphene_snapshot_LIB_DEPENDS:STATIC=general;graphene_chain;general;graphene_app; - -//Dependencies for the target -graphene_time_LIB_DEPENDS:STATIC=general;fc; - -//Dependencies for the target -graphene_utilities_LIB_DEPENDS:STATIC=general;fc; - -//Dependencies for the target -graphene_wallet_LIB_DEPENDS:STATIC=general;graphene_app;general;graphene_net;general;graphene_chain;general;graphene_utilities;general;fc;general;dl; - -//Dependencies for the target -graphene_witness_LIB_DEPENDS:STATIC=general;graphene_chain;general;graphene_app; - -//Value Computed by CMake -websocketpp_BINARY_DIR:STATIC=/home/pbattu/git/18.04/peerplays/libraries/fc/vendor/websocketpp - -//Value Computed by CMake -websocketpp_SOURCE_DIR:STATIC=/home/pbattu/git/18.04/peerplays/libraries/fc/vendor/websocketpp - - -######################## -# INTERNAL cache entries -######################## - -//ADVANCED property for variable: BOOST_ROOT -BOOST_ROOT-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_CHRONO_LIBRARY_DEBUG -Boost_CHRONO_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_CHRONO_LIBRARY_RELEASE -Boost_CHRONO_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_CONTEXT_LIBRARY_DEBUG -Boost_CONTEXT_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_CONTEXT_LIBRARY_RELEASE -Boost_CONTEXT_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_COROUTINE_LIBRARY_DEBUG -Boost_COROUTINE_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_COROUTINE_LIBRARY_RELEASE -Boost_COROUTINE_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_DATE_TIME_LIBRARY_DEBUG -Boost_DATE_TIME_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_DATE_TIME_LIBRARY_RELEASE -Boost_DATE_TIME_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_DIR -Boost_DIR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_FILESYSTEM_LIBRARY_DEBUG -Boost_FILESYSTEM_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_FILESYSTEM_LIBRARY_RELEASE -Boost_FILESYSTEM_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_INCLUDE_DIR -Boost_INCLUDE_DIR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_IOSTREAMS_LIBRARY_DEBUG -Boost_IOSTREAMS_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_IOSTREAMS_LIBRARY_RELEASE -Boost_IOSTREAMS_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_LIBRARY_DIR -Boost_LIBRARY_DIR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_LIBRARY_DIR_DEBUG -Boost_LIBRARY_DIR_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_LIBRARY_DIR_RELEASE -Boost_LIBRARY_DIR_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_LOCALE_LIBRARY_DEBUG -Boost_LOCALE_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_LOCALE_LIBRARY_RELEASE -Boost_LOCALE_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG -Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE -Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_SERIALIZATION_LIBRARY_DEBUG -Boost_SERIALIZATION_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_SERIALIZATION_LIBRARY_RELEASE -Boost_SERIALIZATION_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_SIGNALS_LIBRARY_DEBUG -Boost_SIGNALS_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_SIGNALS_LIBRARY_RELEASE -Boost_SIGNALS_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_SYSTEM_LIBRARY_DEBUG -Boost_SYSTEM_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_SYSTEM_LIBRARY_RELEASE -Boost_SYSTEM_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_THREAD_LIBRARY_DEBUG -Boost_THREAD_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_THREAD_LIBRARY_RELEASE -Boost_THREAD_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_UNIT_TEST_FRAMEWORK_LIBRARY_DEBUG -Boost_UNIT_TEST_FRAMEWORK_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Boost_UNIT_TEST_FRAMEWORK_LIBRARY_RELEASE -Boost_UNIT_TEST_FRAMEWORK_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_AR -CMAKE_AR-ADVANCED:INTERNAL=1 -//This is the directory where this CMakeCache.txt was created -CMAKE_CACHEFILE_DIR:INTERNAL=/home/pbattu/git/18.04/peerplays -//Major version of cmake used to create the current loaded cache -CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 -//Minor version of cmake used to create the current loaded cache -CMAKE_CACHE_MINOR_VERSION:INTERNAL=10 -//Patch version of cmake used to create the current loaded cache -CMAKE_CACHE_PATCH_VERSION:INTERNAL=2 -//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE -CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 -//Path to CMake executable. -CMAKE_COMMAND:INTERNAL=/usr/bin/cmake -//Path to cpack program executable. -CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack -//Path to ctest program executable. -CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest -//ADVANCED property for variable: CMAKE_CXX_COMPILER -CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR -CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB -CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS -CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG -CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL -CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE -CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO -CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_COMPILER -CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_COMPILER_AR -CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB -CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS -CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG -CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL -CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE -CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO -CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//Executable file format -CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS -CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG -CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL -CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE -CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS -CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1 -//Name of external makefile project generator. -CMAKE_EXTRA_GENERATOR:INTERNAL= -//Name of generator. -CMAKE_GENERATOR:INTERNAL=Unix Makefiles -//Name of generator platform. -CMAKE_GENERATOR_PLATFORM:INTERNAL= -//Name of generator toolset. -CMAKE_GENERATOR_TOOLSET:INTERNAL= -//Have symbol pthread_create -CMAKE_HAVE_LIBC_CREATE:INTERNAL= -//Have library pthreads -CMAKE_HAVE_PTHREADS_CREATE:INTERNAL= -//Have library pthread -CMAKE_HAVE_PTHREAD_CREATE:INTERNAL=1 -//Have include pthread.h -CMAKE_HAVE_PTHREAD_H:INTERNAL=1 -//Source directory with the top level CMakeLists.txt file for this -// project -CMAKE_HOME_DIRECTORY:INTERNAL=/home/pbattu/git/18.04/peerplays -//Install .so files without execute permission. -CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 -//ADVANCED property for variable: CMAKE_LINKER -CMAKE_LINKER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MAKE_PROGRAM -CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS -CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG -CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL -CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE -CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_NM -CMAKE_NM-ADVANCED:INTERNAL=1 -//number of local generators -CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=37 -//ADVANCED property for variable: CMAKE_OBJCOPY -CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_OBJDUMP -CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 -//Platform information initialized -CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_RANLIB -CMAKE_RANLIB-ADVANCED:INTERNAL=1 -//Path to CMake installation. -CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.10 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS -CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG -CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL -CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE -CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH -CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SKIP_RPATH -CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS -CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG -CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL -CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE -CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STRIP -CMAKE_STRIP-ADVANCED:INTERNAL=1 -//uname command -CMAKE_UNAME:INTERNAL=/bin/uname -//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE -CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CURSES_CURSES_LIBRARY -CURSES_CURSES_LIBRARY-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CURSES_FORM_LIBRARY -CURSES_FORM_LIBRARY-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CURSES_INCLUDE_PATH -CURSES_INCLUDE_PATH-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CURSES_NCURSES_LIBRARY -CURSES_NCURSES_LIBRARY-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: DOXYGEN_DOT_EXECUTABLE -DOXYGEN_DOT_EXECUTABLE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: DOXYGEN_EXECUTABLE -DOXYGEN_EXECUTABLE-ADVANCED:INTERNAL=1 -//Details about finding OpenSSL -FIND_PACKAGE_MESSAGE_DETAILS_OpenSSL:INTERNAL=[/usr/lib/x86_64-linux-gnu/libcrypto.a][/usr/include][v1.1.0g()] -//Details about finding Perl -FIND_PACKAGE_MESSAGE_DETAILS_Perl:INTERNAL=[/usr/bin/perl][v5.26.1()] -//Details about finding Readline -FIND_PACKAGE_MESSAGE_DETAILS_Readline:INTERNAL=[/usr/include][/usr/lib/x86_64-linux-gnu/libreadline.so][v()] -//Details about finding Threads -FIND_PACKAGE_MESSAGE_DETAILS_Threads:INTERNAL=[TRUE][v()] -//Details about finding ZLIB -FIND_PACKAGE_MESSAGE_DETAILS_ZLIB:INTERNAL=[/usr/lib/x86_64-linux-gnu/libz.so][/usr/include][v1.2.11()] -//ADVANCED property for variable: GIT_EXECUTABLE -GIT_EXECUTABLE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: OPENSSL_CRYPTO_LIBRARY -OPENSSL_CRYPTO_LIBRARY-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: OPENSSL_INCLUDE_DIR -OPENSSL_INCLUDE_DIR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: OPENSSL_SSL_LIBRARY -OPENSSL_SSL_LIBRARY-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: PERL_EXECUTABLE -PERL_EXECUTABLE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: PKG_CONFIG_EXECUTABLE -PKG_CONFIG_EXECUTABLE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Readline_INCLUDE_DIR -Readline_INCLUDE_DIR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Readline_LIBRARY -Readline_LIBRARY-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: Readline_ROOT_DIR -Readline_ROOT_DIR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: ZLIB_INCLUDE_DIR -ZLIB_INCLUDE_DIR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: ZLIB_LIBRARY_DEBUG -ZLIB_LIBRARY_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: ZLIB_LIBRARY_RELEASE -ZLIB_LIBRARY_RELEASE-ADVANCED:INTERNAL=1 -//Last used BOOST_ROOT value. -_BOOST_ROOT_LAST:INTERNAL=/home/pbattu/git/18.04/boost_1_67_0 -//Components requested for this build tree. -_Boost_COMPONENTS_SEARCHED:INTERNAL=chrono;context;coroutine;date_time;filesystem;iostreams;locale;program_options;serialization;signals;system;thread;unit_test_framework -//Last used Boost_INCLUDE_DIR value. -_Boost_INCLUDE_DIR_LAST:INTERNAL=/home/pbattu/git/18.04/boost_1_67_0/include -//Last used Boost_LIBRARY_DIR_DEBUG value. -_Boost_LIBRARY_DIR_DEBUG_LAST:INTERNAL=/home/pbattu/git/18.04/boost_1_67_0/lib -//Last used Boost_LIBRARY_DIR value. -_Boost_LIBRARY_DIR_LAST:INTERNAL=/home/pbattu/git/18.04/boost_1_67_0/lib -//Last used Boost_LIBRARY_DIR_RELEASE value. -_Boost_LIBRARY_DIR_RELEASE_LAST:INTERNAL=/home/pbattu/git/18.04/boost_1_67_0/lib -//Last used Boost_NAMESPACE value. -_Boost_NAMESPACE_LAST:INTERNAL=boost -//Last used Boost_USE_MULTITHREADED value. -_Boost_USE_MULTITHREADED_LAST:INTERNAL=TRUE -//Last used Boost_USE_STATIC_LIBS value. -_Boost_USE_STATIC_LIBS_LAST:INTERNAL=ON -_OPENSSL_CFLAGS:INTERNAL= -_OPENSSL_CFLAGS_I:INTERNAL= -_OPENSSL_CFLAGS_OTHER:INTERNAL= -_OPENSSL_FOUND:INTERNAL=1 -_OPENSSL_INCLUDEDIR:INTERNAL=/usr/include -_OPENSSL_INCLUDE_DIRS:INTERNAL= -_OPENSSL_LDFLAGS:INTERNAL=-lssl;-lcrypto -_OPENSSL_LDFLAGS_OTHER:INTERNAL= -_OPENSSL_LIBDIR:INTERNAL=/usr/lib/x86_64-linux-gnu -_OPENSSL_LIBRARIES:INTERNAL=ssl;crypto -_OPENSSL_LIBRARY_DIRS:INTERNAL= -_OPENSSL_LIBS:INTERNAL= -_OPENSSL_LIBS_L:INTERNAL= -_OPENSSL_LIBS_OTHER:INTERNAL= -_OPENSSL_LIBS_PATHS:INTERNAL= -_OPENSSL_PREFIX:INTERNAL=/usr -_OPENSSL_STATIC_CFLAGS:INTERNAL= -_OPENSSL_STATIC_CFLAGS_I:INTERNAL= -_OPENSSL_STATIC_CFLAGS_OTHER:INTERNAL= -_OPENSSL_STATIC_INCLUDE_DIRS:INTERNAL= -_OPENSSL_STATIC_LDFLAGS:INTERNAL=-lssl;-ldl;-lcrypto;-ldl -_OPENSSL_STATIC_LDFLAGS_OTHER:INTERNAL= -_OPENSSL_STATIC_LIBDIR:INTERNAL= -_OPENSSL_STATIC_LIBRARIES:INTERNAL=ssl;dl;crypto;dl -_OPENSSL_STATIC_LIBRARY_DIRS:INTERNAL= -_OPENSSL_STATIC_LIBS:INTERNAL= -_OPENSSL_STATIC_LIBS_L:INTERNAL= -_OPENSSL_STATIC_LIBS_OTHER:INTERNAL= -_OPENSSL_STATIC_LIBS_PATHS:INTERNAL= -_OPENSSL_VERSION:INTERNAL=1.1.0g -_OPENSSL_openssl_INCLUDEDIR:INTERNAL= -_OPENSSL_openssl_LIBDIR:INTERNAL= -_OPENSSL_openssl_PREFIX:INTERNAL= -_OPENSSL_openssl_VERSION:INTERNAL= -__pkg_config_arguments__OPENSSL:INTERNAL=QUIET;openssl -__pkg_config_checked__OPENSSL:INTERNAL=1 -prefix_result:INTERNAL=/usr/lib/x86_64-linux-gnu - diff --git a/clang-format.sh b/clang-format.sh new file mode 100755 index 00000000..3fbbf055 --- /dev/null +++ b/clang-format.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +find ./libraries/app -regex ".*[c|h]pp" | xargs clang-format -i +find ./libraries/chain/hardfork.d -regex ".*hf" | xargs clang-format -i +find ./libraries/plugins/peerplays_sidechain -regex ".*[c|h]pp" | xargs clang-format -i diff --git a/docker/default_config.ini b/docker/default_config.ini deleted file mode 100644 index fc7c2d20..00000000 --- a/docker/default_config.ini +++ /dev/null @@ -1,61 +0,0 @@ -# Endpoint for P2P node to listen on -p2p-endpoint = 0.0.0.0:9090 - -# P2P nodes to connect to on startup (may specify multiple times) -# seed-node = - -# JSON array of P2P nodes to connect to on startup -# seed-nodes = - -# Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints. -# checkpoint = - -# Endpoint for websocket RPC to listen on -rpc-endpoint = 0.0.0.0:8090 - -# Endpoint for TLS websocket RPC to listen on -# rpc-tls-endpoint = - -# The TLS certificate file for this server -# server-pem = - -# Password for this certificate -# server-pem-password = - -# File to read Genesis State from -# genesis-json = - -# Block signing key to use for init witnesses, overrides genesis file -# dbg-init-key = - -# JSON file specifying API permissions -# api-access = - -# Enable block production, even if the chain is stale. -enable-stale-production = false - -# Percent of witnesses (0-99) that must be participating in order to produce blocks -required-participation = false - -# ID of witness controlled by this node (e.g. "1.6.5", quotes are required, may specify multiple times) -# witness-id = - -# Tuple of [PublicKey, WIF private key] (may specify multiple times) -# private-key = ["BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"] - -# Account ID to track history for (may specify multiple times) -# track-account = - -# Track market history by grouping orders into buckets of equal size measured in seconds specified as a JSON array of numbers -# bucket-size = [15,60,300,3600,86400] -bucket-size = [60,300,900,1800,3600,14400,86400] -# for 1 min, 5 mins, 30 mins, 1h, 4 hs and 1 day. i think this should be the default. - -# How far back in time to track history for each bucket size, measured in the number of buckets (default: 1000) -history-per-size = 1000 - -# Max amount of operations to store in the database, per account (drastically reduces RAM requirements) -max-ops-per-account = 1000 - -# Remove old operation history # objects from RAM -partial-operations = true diff --git a/docker/peerplaysentry.sh b/docker/peerplaysentry.sh deleted file mode 100644 index 31caeef2..00000000 --- a/docker/peerplaysentry.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash -PEERPLAYSD="/usr/local/bin/witness_node" - -# For blockchain download -VERSION=`cat /etc/peerplays/version` - -## Supported Environmental Variables -# -# * $PEERPLAYSD_SEED_NODES -# * $PEERPLAYSD_RPC_ENDPOINT -# * $PEERPLAYSD_PLUGINS -# * $PEERPLAYSD_REPLAY -# * $PEERPLAYSD_RESYNC -# * $PEERPLAYSD_P2P_ENDPOINT -# * $PEERPLAYSD_WITNESS_ID -# * $PEERPLAYSD_PRIVATE_KEY -# * $PEERPLAYSD_DEBUG_PRIVATE_KEY -# * $PEERPLAYSD_TRACK_ACCOUNTS -# * $PEERPLAYSD_PARTIAL_OPERATIONS -# * $PEERPLAYSD_MAX_OPS_PER_ACCOUNT -# * $PEERPLAYSD_TRUSTED_NODE -# - -ARGS="" -# Translate environmental variables -if [[ ! -z "$PEERPLAYSD_SEED_NODES" ]]; then - for NODE in $PEERPLAYSD_SEED_NODES ; do - ARGS+=" --seed-node=$NODE" - done -fi -if [[ ! -z "$PEERPLAYSD_RPC_ENDPOINT" ]]; then - ARGS+=" --rpc-endpoint=${PEERPLAYSD_RPC_ENDPOINT}" -fi - -if [[ ! -z "$PEERPLAYSD_REPLAY" ]]; then - ARGS+=" --replay-blockchain" -fi - -if [[ ! -z "$PEERPLAYSD_RESYNC" ]]; then - ARGS+=" --resync-blockchain" -fi - -if [[ ! -z "$PEERPLAYSD_P2P_ENDPOINT" ]]; then - ARGS+=" --p2p-endpoint=${PEERPLAYSD_P2P_ENDPOINT}" -fi - -if [[ ! -z "$PEERPLAYSD_WITNESS_ID" ]]; then - ARGS+=" --witness-id=$PEERPLAYSD_WITNESS_ID" -fi - -if [[ ! -z "$PEERPLAYSD_PRIVATE_KEY" ]]; then - ARGS+=" --private-key=$PEERPLAYSD_PRIVATE_KEY" -fi - -if [[ ! -z "$PEERPLAYSD_DEBUG_PRIVATE_KEY" ]]; then - ARGS+=" --debug-private-key=$PEERPLAYSD_DEBUG_PRIVATE_KEY" -fi - -if [[ ! -z "$PEERPLAYSD_TRACK_ACCOUNTS" ]]; then - for ACCOUNT in $PEERPLAYSD_TRACK_ACCOUNTS ; do - ARGS+=" --track-account=$ACCOUNT" - done -fi - -if [[ ! -z "$PEERPLAYSD_PARTIAL_OPERATIONS" ]]; then - ARGS+=" --partial-operations=${PEERPLAYSD_PARTIAL_OPERATIONS}" -fi - -if [[ ! -z "$PEERPLAYSD_MAX_OPS_PER_ACCOUNT" ]]; then - ARGS+=" --max-ops-per-account=${PEERPLAYSD_MAX_OPS_PER_ACCOUNT}" -fi - -if [[ ! -z "$PEERPLAYSD_TRUSTED_NODE" ]]; then - ARGS+=" --trusted-node=${PEERPLAYSD_TRUSTED_NODE}" -fi - -## Link the peerplays config file into home -## This link has been created in Dockerfile, already -ln -f -s /etc/peerplays/config.ini /var/lib/peerplays - -# Plugins need to be provided in a space-separated list, which -# makes it necessary to write it like this -if [[ ! -z "$PEERPLAYSD_PLUGINS" ]]; then - $PEERPLAYSD --data-dir ${HOME} ${ARGS} ${PEERPLAYSD_ARGS} --plugins "${PEERPLAYSD_PLUGINS}" -else - $PEERPLAYSD --data-dir ${HOME} ${ARGS} ${PEERPLAYSD_ARGS} -fi diff --git a/genesis.json b/genesis-mainnet.json similarity index 100% rename from genesis.json rename to genesis-mainnet.json diff --git a/genesis-testnet.json b/genesis-testnet.json new file mode 100644 index 00000000..55dd9c2c --- /dev/null +++ b/genesis-testnet.json @@ -0,0 +1,10438 @@ +{ + "initial_timestamp": "2018-10-20T20:00:00", + "max_core_supply": "400000000000000", + "initial_parameters": { + "current_fees": { + "parameters": [[ + 0,{ + "fee": 1000, + "price_per_kbyte": 1000 + } + ],[ + 1,{ + "fee": 50 + } + ],[ + 2,{ + "fee": 0 + } + ],[ + 3,{ + "fee": "500000000000" + } + ],[ + 4,{} + ],[ + 5,{ + "basic_fee": 500, + "premium_fee": 250000, + "price_per_kbyte": 1000 + } + ],[ + 6,{ + "fee": 100, + "price_per_kbyte": 1000 + } + ],[ + 7,{ + "fee": 1000 + } + ],[ + 8,{ + "membership_annual_fee": "500000000000", + "membership_lifetime_fee": 500000 + } + ],[ + 9,{ + "fee": 200000 + } + ],[ + 10,{ + "symbol3": "500000000000", + "symbol4": "500000000000", + "long_symbol": 5000000, + "price_per_kbyte": 1000 + } + ],[ + 11,{ + "fee": 100000, + "price_per_kbyte": 100 + } + ],[ + 12,{ + "fee": "500000000000" + } + ],[ + 13,{ + "fee": "500000000000" + } + ],[ + 14,{ + "fee": 1000, + "price_per_kbyte": 1000 + } + ],[ + 15,{ + "fee": 1000 + } + ],[ + 16,{ + "fee": 1000 + } + ],[ + 17,{ + "fee": "500000000000" + } + ],[ + 18,{ + "fee": "500000000000" + } + ],[ + 19,{ + "fee": "500000000000" + } + ],[ + 20,{ + "fee": 800000 + } + ],[ + 21,{ + "fee": 50000 + } + ],[ + 22,{ + "fee": 1000, + "price_per_kbyte": 1000 + } + ],[ + 23,{ + "fee": 1000, + "price_per_kbyte": 1000 + } + ],[ + 24,{ + "fee": 0 + } + ],[ + 25,{ + "fee": 3000 + } + ],[ + 26,{ + "fee": 1000 + } + ],[ + 27,{ + "fee": 1000, + "price_per_kbyte": 1000 + } + ],[ + 28,{ + "fee": 0 + } + ],[ + 29,{ + "fee": 100000 + } + ],[ + 30,{ + "fee": 50000 + } + ],[ + 31,{ + "fee": 1000 + } + ],[ + 32,{ + "fee": 100000 + } + ],[ + 33,{ + "fee": 1000 + } + ],[ + 34,{ + "fee": "500000000000" + } + ],[ + 35,{ + "fee": 1000, + "price_per_kbyte": 1000 + } + ],[ + 36,{ + "fee": 1000 + } + ],[ + 37,{} + ],[ + 38,{ + "fee": 20000, + "price_per_kbyte": 1000 + } + ],[ + 39,{ + "fee": 1000, + "price_per_output": 1000 + } + ],[ + 40,{ + "fee": 1000, + "price_per_output": 1000 + } + ],[ + 41,{ + "fee": 1000 + } + ],[ + 42,{} + ],[ + 43,{ + "fee": 3000 + } + ],[ + 44,{} + ],[ + 45,{ + "fee": 1000 + } + ],[ + 46,{ + "fee": 5000 + } + ],[ + 47,{ + "fee": 0 + } + ],[ + 48,{ + "fee": 100000 + } + ],[ + 49,{ + "distribution_base_fee": 0, + "distribution_fee_per_holder": 0 + } + ] + ], + "scale": 10000 + }, + "block_interval": 3, + "maintenance_interval": 3600, + "maintenance_skip_slots": 3, + "committee_proposal_review_period": 3600, + "maximum_transaction_size": 99999, + "maximum_block_size": 2000000, + "maximum_time_until_expiration": 86400, + "maximum_proposal_lifetime": 2419200, + "maximum_asset_whitelist_authorities": 10, + "maximum_asset_feed_publishers": 10, + "maximum_witness_count": 101, + "maximum_committee_count": 33, + "maximum_authority_membership": 11, + "reserve_percent_of_fee": 0, + "network_percent_of_fee": 10000, + "lifetime_referrer_percent_of_fee": 0, + "cashback_vesting_period_seconds": 9999999, + "cashback_vesting_threshold": 100000, + "count_non_member_votes": true, + "allow_non_member_whitelists": true, + "witness_pay_per_block": 725, + "worker_budget_per_day": 0, + "max_predicate_opcode": 1, + "fee_liquidation_threshold": "500000000000", + "accounts_per_fee_scale": 1000, + "account_fee_scale_bitshifts": 0, + "max_authority_depth": 2, + "witness_schedule_algorithm": 0, + "min_round_delay": 10, + "max_round_delay": 300, + "min_time_per_commit_move": 15, + "max_time_per_commit_move": 15, + "min_time_per_reveal_move": 9, + "max_time_per_reveal_move": 9, + "rake_fee_percentage": 300, + "maximum_registration_deadline": 2592000, + "maximum_players_in_tournament": 256, + "maximum_tournament_whitelist_length": 1000, + "maximum_tournament_start_time_in_future": 5184000, + "maximum_tournament_start_delay": 259200, + "maximum_tournament_number_of_wins": 25, + "extensions": [] + }, + "initial_bts_accounts": [], + "initial_accounts": [ + { + "active_key": "TEST51NyhxsTTbUjS8rrW3n3owtkirv6g5Nb5w7d9zLCdnajtpQxX3", + "owner_key": "TEST4ujJ5T4Bd9miR2DSiMNJzcQL7CouzBQsEQQF3pUtUWHJuRzcmN", + "is_lifetime_member": true, + "name": "init0" + }, + { + "active_key": "TEST6NQ9RCSR6kmnRV6n9NoLipe7a2iGysm4K622ooRqkJeGj4DgB4", + "owner_key": "TEST7gLFvxJwUdoTjjivXsSzu7gVxXFwzBsN1kLxNaCzT9oqSKov3g", + "is_lifetime_member": true, + "name": "init1" + }, + { + "active_key": "TEST6PVG9BTDuyEUWAifcyAmVgo6guDKfDXU8Z3NJspG2yPERAo2i5", + "owner_key": "TEST6PJLpmygLwnUzgDF9vQjH5DZxR3Tvwuf7ZKX4nDBVpR7ocsJfP", + "is_lifetime_member": true, + "name": "init2" + }, + { + "active_key": "TEST85Y6tSCQ1HE4xWB6UfKMdAp2BSLiqi8veg6bonizv5gfCVghnt", + "owner_key": "TEST75A5tEF5pnYSHah93Ch55eHca7hxq3GCqseLKQaxwJDAdSYwhd", + "is_lifetime_member": true, + "name": "init3" + }, + { + "active_key": "TEST6XosFwGmGCZxM6eqrYT3kXabw4V5tgNKu2pz3DehWUWt74SqZ4", + "owner_key": "TEST8dfydJurJRrosBEY4BpcKfdez3qfVrvuxHRCSaTDLJRNFihiKV", + "is_lifetime_member": true, + "name": "init4" + }, + { + "active_key": "TEST7wqtEmqkQhRKZHyrErrM8L5Zo9PEpP18Rr4zDibQD8R7jpno4q", + "owner_key": "TEST7sAshSzYXdnzDqZGTNiqZ4qYZDTZMMWrbcja6yHbQdWSVskuo7", + "is_lifetime_member": true, + "name": "init5" + }, + { + "active_key": "TEST8JzscxvzZY2F7aUDvJUJBSSiiBAjLEZCwHabP89YQVEFKpYeLD", + "owner_key": "TEST5VCDdDmbZGSi1N28TyHmNqLMZr8qnywqHt4eaboKkb382bbS8T", + "is_lifetime_member": true, + "name": "init6" + }, + { + "active_key": "TEST5ZxG67Krp3WebfFzbcZVymUQi3AphGLqr1x6nW6GTvF6ky4zTW", + "owner_key": "TEST86jvTeL2r4pCz1jdfqZ393BtdiMJYyVZssCXSmBhShsBadDSt4", + "is_lifetime_member": true, + "name": "init7" + }, + { + "active_key": "TEST6hG9f5GHjyR3ivdhVoFPLRLJPV3nTdF7Tctws9he8ja7PBP8vo", + "owner_key": "TEST6TbTmCB7VEYWwoPwSgjVLgLYofPXuiU7LtSNwL6LU2wkc6VAg8", + "is_lifetime_member": true, + "name": "init8" + }, + { + "active_key": "TEST5tWgbxKfMoN8BwabpEf4wF7umhd5YQP4vwEUZwdMYXwsqGUh15", + "owner_key": "TEST8aFQt3cJM5Ldc1qZF65Ej2v3FqhtJtDdTHsExG4KYpMQa1zsmT", + "is_lifetime_member": true, + "name": "init9" + }, + { + "active_key": "TEST7Xvv7Fb9UPdfv1DhnqFYayauRgLUwiB9mh8eakbG2rVx788xLU", + "owner_key": "TEST5XqcETk6ZRmqp12Lji1oMGMbKF4e5vt7pPzco9xun6jyLBtuey", + "is_lifetime_member": true, + "name": "init10" + }, + { + "active_key": "TEST7TW4GaHiPjfLtc1zx79syKMvNXDB3duz67EhG3zY9uPir6Ro6M", + "owner_key": "TEST6pNmkwXmp3AsNRrwL28YbSs3N3pa34Ci5Km1dweRULYTk1ZSFw", + "is_lifetime_member": true, + "name": "launcher" + }, + { + "active_key": "TEST8Qme9DtDmved7zusWo1c6ohRmCMTjoLojqK2FxCqGzCtiiZBVx", + "owner_key": "TEST7BYiEHrvhx5yNnExT6C11xzsh4bVfBPakfGr2ErC6pxXjS5KZe", + "is_lifetime_member": true, + "name": "faucet" + }, + { + "active_key": "TEST8foAspmhVtY8AXMLw5CtvpSkLtj3XvshdsRmiMUbrgWV1RHaV9", + "owner_key": "TEST6QsHEqRq2fpvnCuwsW72SwzyoEXgR7GBBn4acYaZmFqJ74MDBw", + "is_lifetime_member": true, + "name": "pbsa" + } + ], + "initial_assets": [ + { + "accumulated_fees": 0, + "collateral_records": [], + "description": "Fun token. Supposed to be worthless!", + "is_bitasset": false, + "issuer_name": "pbsa", + "max_supply": 2100000000000000, + "precision": 8, + "symbol": "BTF" + } + ], + "initial_balances": [ + { + "owner": "TEST51B1EWJZQsJhZQnbiF1j2adGPrDufNXbw", + "asset_symbol": "TEST", + "amount": 9469332 + }, + { + "owner": "TESTLYoTtsy48awZzvY6n5iDHkV4iZGEcvss8", + "asset_symbol": "TEST", + "amount": 19954525 + }, + { + "owner": "TEST75DDNdontbe3Ama3arfCwApoj9tWv12Rn", + "asset_symbol": "TEST", + "amount": 1028562 + }, + { + "owner": "TESTBNMyx8bMZEUNaxyy721BifKwwq48YktS8", + "asset_symbol": "TEST", + "amount": 1970271 + }, + { + "owner": "TESTFELQom3v38HiB5HnWEvoxvZYrq3CwaDZU", + "asset_symbol": "TEST", + "amount": 979214 + }, + { + "owner": "TESTPQLzyJdHpV6XZz67qrhAuQ3zFWL2Ehza5", + "asset_symbol": "TEST", + "amount": 326201 + }, + { + "owner": "TEST9A2v442nFBrnf37BVK7JuYh9hsAaXgEJx", + "asset_symbol": "TEST", + "amount": 141588 + }, + { + "owner": "TEST6rcQGDJfU6TEHBJu6bToviDxHTvSdgW5f", + "asset_symbol": "TEST", + "amount": 5020568 + }, + { + "owner": "TEST9MCRkr1Ny3C61tE8QUrARbHoRZ9ifAAqg", + "asset_symbol": "TEST", + "amount": 206622 + }, + { + "owner": "TEST4bXhEirxXmX34QrFanayjiLLNjw1uGvH1", + "asset_symbol": "TEST", + "amount": 9305262 + }, + { + "owner": "TESTBZwhjW73bKistg9RLHDmYkGovwCKzdmcQ", + "asset_symbol": "TEST", + "amount": 9511260 + }, + { + "owner": "TEST3maV9c1FGu4cpXx7GBYTA1fUkusVyH1Bf", + "asset_symbol": "TEST", + "amount": 168404739 + }, + { + "owner": "TEST96PxfwnDuLuqHm2FTTqjoKu9zgCRG5sGw", + "asset_symbol": "TEST", + "amount": 2130842 + }, + { + "owner": "TESTPc8ECe8AWomSmhrbCmizj7fPzUH9cZjPu", + "asset_symbol": "TEST", + "amount": 9886879 + }, + { + "owner": "TESTMHczuKKGf7NzBjdtCUHRfYX1kXfUq4nyj", + "asset_symbol": "TEST", + "amount": 1601620 + }, + { + "owner": "TESTLz4rdZ3uXR1y8pRcx5mAxo29q7xM1M4R1", + "asset_symbol": "TEST", + "amount": 9316910 + }, + { + "owner": "TESTLiqWPXyV1PzY4exUv85xSzuxdPgV6oatw", + "asset_symbol": "TEST", + "amount": 205066 + }, + { + "owner": "TESTPMGSiSs6Wp2S6De4VZA56JmSNsC9a6XRz", + "asset_symbol": "TEST", + "amount": 1552830 + }, + { + "owner": "TEST35heJ58QRicz3gYFkvc6N7Ew4ZLb2SaGU", + "asset_symbol": "TEST", + "amount": 225992034 + }, + { + "owner": "TEST7n7sB7x7knVAUGo4zeLDfKvA5a3QQJmvX", + "asset_symbol": "TEST", + "amount": 6680471 + }, + { + "owner": "TESTJJJhYdwMQ8PkiMtvQ5tQcaZcyPq7gh3sb", + "asset_symbol": "TEST", + "amount": 6888127 + }, + { + "owner": "TESTKnsKbXfGbCuS5QiXaPYo6ehZKbGi6sSpJ", + "asset_symbol": "TEST", + "amount": 8823849 + }, + { + "owner": "TESTEwr7j6sTpxHwqdacjNy2A9W6vcfyduHWV", + "asset_symbol": "TEST", + "amount": 1814197 + }, + { + "owner": "TEST2hM8wM1grV9vu5YzhA2GD5KGoVDaTP3ty", + "asset_symbol": "TEST", + "amount": 10157435 + }, + { + "owner": "TEST5kuj85HQ1V8qw4HvfuBrS1p95YKmsPsCy", + "asset_symbol": "TEST", + "amount": 6105272 + }, + { + "owner": "TEST4LY3ZDFeVK8oSDLXDhxfnnnQyqDEF2dFv", + "asset_symbol": "TEST", + "amount": 6479240 + }, + { + "owner": "TESTCTNeow9CYciBRjb54kffVk7XpBnNfBPbg", + "asset_symbol": "TEST", + "amount": 23539937 + }, + { + "owner": "TEST65A7oVDTDqLYNNY2myziPVQC9HWge6gxs", + "asset_symbol": "TEST", + "amount": 242890919 + }, + { + "owner": "TEST978Y3o8KSHz4L3wLeL4dwMpAm3n8hLJpC", + "asset_symbol": "TEST", + "amount": 4050870 + }, + { + "owner": "TESTEvA7ASWk4fVRcUdbxse1yjvPxTdJ9Debs", + "asset_symbol": "TEST", + "amount": 1920074 + }, + { + "owner": "TEST94XXhaGYMZoaZDuUJBSvQQBZzbx7Eg5jY", + "asset_symbol": "TEST", + "amount": 1316616 + }, + { + "owner": "TESTDAQuS12un7UZ1QDySiyCjZHPc69Lsm3jF", + "asset_symbol": "TEST", + "amount": 6666099 + }, + { + "owner": "TESTG2MHKrWX2fHYQjJJLRveKQ7sc7GjEpGLw", + "asset_symbol": "TEST", + "amount": 441986127 + }, + { + "owner": "TESTKHp151fSidDbSLhVAiLiNuLL1EZcjvrp2", + "asset_symbol": "TEST", + "amount": 10436685 + }, + { + "owner": "TEST6NkLkD4RSTXCbwREtJxJpJXm889VfrcWN", + "asset_symbol": "TEST", + "amount": 31124707 + }, + { + "owner": "TESTGGJQAzA3NmnRo8z4wujRBAYFAi2buUhAU", + "asset_symbol": "TEST", + "amount": 766137 + }, + { + "owner": "TESTKaicwkJXhHD3tjFD4aVVgLDLo18WUvCNC", + "asset_symbol": "TEST", + "amount": 76202915 + }, + { + "owner": "TESTMVWDbBK9XXkNViZJ8hiCmU6TqxrfCXdjy", + "asset_symbol": "TEST", + "amount": 34361333 + }, + { + "owner": "TESTNSsCnvMw1xrZJhTgQVgPkybZiRcyD18V8", + "asset_symbol": "TEST", + "amount": 1910866 + }, + { + "owner": "TEST4bZdy4WuqjWzT5N6CqmC86usHxcxGUSsV", + "asset_symbol": "TEST", + "amount": 9967426 + }, + { + "owner": "TEST4P5aE2hzePkWr7t4FGXVh98J7GZd4sw3v", + "asset_symbol": "TEST", + "amount": 286751 + }, + { + "owner": "TESTNBbWFWxEgfthVaYsKHy2Yy4fBbW57ARao", + "asset_symbol": "TEST", + "amount": 23689143 + }, + { + "owner": "TESTNDjH8V7AQkr7SRwPfy1VoTGfiqungTTm8", + "asset_symbol": "TEST", + "amount": 662558 + }, + { + "owner": "TESTKg4qz2hW2uteN8yjWK3iLiDUFhJogje8s", + "asset_symbol": "TEST", + "amount": 264885 + }, + { + "owner": "TESTFZx44yu2BPXZdeRwGoEvphn9PbbPuSJcz", + "asset_symbol": "TEST", + "amount": 3832396 + }, + { + "owner": "TESTtNZavztHF6sWur9ZLyyAzZTuCjPGDBPV", + "asset_symbol": "TEST", + "amount": 61056706 + }, + { + "owner": "TESTDTHU98JHjnanmHwkf1xBYbBkk63Ei1C9U", + "asset_symbol": "TEST", + "amount": 3802596 + }, + { + "owner": "TEST9Lg4W7kuXcGQczzDyLkVxkiBzzdbaoQ1D", + "asset_symbol": "TEST", + "amount": 7647493 + }, + { + "owner": "TEST9o4spSuTg4Rczrcma5nka6iPpohM9wuVh", + "asset_symbol": "TEST", + "amount": 1744340 + }, + { + "owner": "TESTKg6V6vCTpPg7Yyau2MVMP5X4pSBpUS6mQ", + "asset_symbol": "TEST", + "amount": 849224 + }, + { + "owner": "TEST2nG9YHw4d7JHrr8V1qp9wnnm6jx7mxdSh", + "asset_symbol": "TEST", + "amount": 58729473 + }, + { + "owner": "TESTDrDHDyzZcyex56s57fumLBxe27o3s2eJo", + "asset_symbol": "TEST", + "amount": 2501036 + }, + { + "owner": "TESTQKDDTr6rets6paEYiMGAMESfWgufXmjwh", + "asset_symbol": "TEST", + "amount": 301785 + }, + { + "owner": "TESTPNSnC3zHAkfvgzXaVrrpxs1U8Hs6mwXe5", + "asset_symbol": "TEST", + "amount": 9373376 + }, + { + "owner": "TESTE6hWCZapBFhK6hKTuLePWmkQQzHiunNg8", + "asset_symbol": "TEST", + "amount": 3360295 + }, + { + "owner": "TEST2Pruus53MXfYEwgdgGpdke5ARyTj51qd4", + "asset_symbol": "TEST", + "amount": 8851645 + }, + { + "owner": "TESTNF4JvrrN8wfk6UqjGHgLHE8rNvLc4SrFZ", + "asset_symbol": "TEST", + "amount": 29163078 + }, + { + "owner": "TESTGQS7a5Dwex8JqbxG9vckdQNHHr7M2XVKQ", + "asset_symbol": "TEST", + "amount": 2561479 + }, + { + "owner": "TEST4fw7gKgqPmYRqsMjc7tjBFazAGmPudaz7", + "asset_symbol": "TEST", + "amount": 1043942 + }, + { + "owner": "TEST5qrY3tZAeS1WPiwE7xBYbL5vKQZy8Uca6", + "asset_symbol": "TEST", + "amount": 1307910 + }, + { + "owner": "TESTP34nALmU5QoiKjSkeq8X23weRum26zd7r", + "asset_symbol": "TEST", + "amount": 1016953 + }, + { + "owner": "TESTD9CZSe8tm961avQvecLVVHkFAA3eK5eGU", + "asset_symbol": "TEST", + "amount": 1957265 + }, + { + "owner": "TESTKzRTkAMRQk8aCpXXoT8CeGpyiPdAK4xPg", + "asset_symbol": "TEST", + "amount": 4001864 + }, + { + "owner": "TESTN87o8fNf3ZmJyr1twTZV8EuGQ29ALWPyq", + "asset_symbol": "TEST", + "amount": 269868 + }, + { + "owner": "TESTJCZcJQuxBiEuZ56TgZ4sXMYyYQ97yS8HN", + "asset_symbol": "TEST", + "amount": 234375 + }, + { + "owner": "TESTHCdzmLEoXUAHaKAhq8tcZuzjzzqytYNJ9", + "asset_symbol": "TEST", + "amount": 5327513 + }, + { + "owner": "TEST3dh7X5X7x6wzR1W6vW8xYV4nhEYeWaZeP", + "asset_symbol": "TEST", + "amount": 574437 + }, + { + "owner": "TESTFXxm25gkfZm2UVDszyjpoAR7MZ61M5VcP", + "asset_symbol": "TEST", + "amount": 10493929 + }, + { + "owner": "TESTBz1rj2LNTF5SWaUaGoSiLUkmwbBHEuFAA", + "asset_symbol": "TEST", + "amount": 718683 + }, + { + "owner": "TESThd4hiezsQwMzfDPz7fS18Xs5SpQJFAjD", + "asset_symbol": "TEST", + "amount": 65903543 + }, + { + "owner": "TESTGmjhfE5BmEufPEJtQymuZB48AnmxbSoWJ", + "asset_symbol": "TEST", + "amount": 57853313 + }, + { + "owner": "TESTF7KCWqCknVgtkjSo2u3vLuA5WuPB63ZWc", + "asset_symbol": "TEST", + "amount": 992507 + }, + { + "owner": "TESTFUd1X75ykhdxWJyBokZHaLor7MoeXfdxd", + "asset_symbol": "TEST", + "amount": 515664 + }, + { + "owner": "TESTRpBXPRod9nar8SaVc61vqwa9fsqY2PGb", + "asset_symbol": "TEST", + "amount": 2074836 + }, + { + "owner": "TEST8NeAbMi8wTVK6pxNghQ1cz6S5DqkGhFh9", + "asset_symbol": "TEST", + "amount": 889413 + }, + { + "owner": "TESTLncJMFmzrnMHwywQmCx28rsD8iQU1Ehpr", + "asset_symbol": "TEST", + "amount": 19412799 + }, + { + "owner": "TESTMWTRuKtWvRcy8QAZpfHacxGDywfqk6xUc", + "asset_symbol": "TEST", + "amount": 1049427 + }, + { + "owner": "TEST6AHR9WBMgfoTsAXHuyxCyL5bSDoyHj6Am", + "asset_symbol": "TEST", + "amount": 35099685 + }, + { + "owner": "TESTLpRSe73SBT3158duJFgcsTRTPWiKS8xhZ", + "asset_symbol": "TEST", + "amount": 11800680 + }, + { + "owner": "TESTJkLZLYkY2BX9rHYcfJXSwTtrkButKoxmQ", + "asset_symbol": "TEST", + "amount": 159827994 + }, + { + "owner": "TESTQ7ScezrrLnT51EDLDnuM4mUobFV8yMdS2", + "asset_symbol": "TEST", + "amount": 33068127 + }, + { + "owner": "TESTF1Jq34jEhU6vVB8RPo94AqnouiQ86CxXP", + "asset_symbol": "TEST", + "amount": 6959 + }, + { + "owner": "TEST268vAvdWaeY7EyVqTHjb9Qpdc9QL6rGPP", + "asset_symbol": "TEST", + "amount": 31311 + }, + { + "owner": "TESTKLmV4ACHnfY1uc7aaU2C55UkR5dGKK6PW", + "asset_symbol": "TEST", + "amount": 10307147 + }, + { + "owner": "TESTNHHcg2C7Fgph9rGLUYGPLeygqPvcpKdfz", + "asset_symbol": "TEST", + "amount": 165778 + }, + { + "owner": "TESTFEJ2tQqE7chFU3fGz9sJZ2XQJL9AvWmrr", + "asset_symbol": "TEST", + "amount": 5004531 + }, + { + "owner": "TESTHT6kdPEUgbS61ntsuQiu1yPRJmy8HD9xu", + "asset_symbol": "TEST", + "amount": 175278 + }, + { + "owner": "TESTJfayAnxcs5C8JvumUhTCqk9DYGrwYkAxc", + "asset_symbol": "TEST", + "amount": 4302716 + }, + { + "owner": "TESTD1jAQgUaLnDWe6eu14ufrcqi9jz6CSwFc", + "asset_symbol": "TEST", + "amount": 6628762 + }, + { + "owner": "TESTMt4t725G6GKnkEiEFQUEz34D36RTtTp6Z", + "asset_symbol": "TEST", + "amount": 3820341 + }, + { + "owner": "TESTK7PNbka7v2jsjA3oojpsNAHJje9LLEYCz", + "asset_symbol": "TEST", + "amount": 9777540 + }, + { + "owner": "TEST994e7d1SiCUmp2MQ1tPyBX1mLd92kdsSs", + "asset_symbol": "TEST", + "amount": 206299707 + }, + { + "owner": "TESTF7YKetL4wd71brRwdWypHUntczKs4tdPj", + "asset_symbol": "TEST", + "amount": 34359 + }, + { + "owner": "TESTLnm9YLfGU5KJnvaA4sK99kpAZzNUFssvE", + "asset_symbol": "TEST", + "amount": 15919561 + }, + { + "owner": "TEST89FumgZ7hd2j2YsiZ2KrmBenycSPTYk6u", + "asset_symbol": "TEST", + "amount": 356998000 + }, + { + "owner": "TEST6NxUJpousMrd3sid7soiUdKdWRTeYk5JP", + "asset_symbol": "TEST", + "amount": 31770535 + }, + { + "owner": "TESTCSWdzDc14VRjdthk3qEG3cGwK3Jo1mkPT", + "asset_symbol": "TEST", + "amount": 2642540 + }, + { + "owner": "TESTFghLAVQvb8PJZ13gkAxoJYwcuTVWwWDv4", + "asset_symbol": "TEST", + "amount": 1983648 + }, + { + "owner": "TEST771gUrrs2ErGP1pigFDr23KFHf3aEEbT2", + "asset_symbol": "TEST", + "amount": 15839597 + }, + { + "owner": "TESTKAr3u1De2REHZpXYEgHkKnUDm696v3hCd", + "asset_symbol": "TEST", + "amount": 1891444 + }, + { + "owner": "TESTP3K6no7ooN6WTJDp6vSPGgfYCQ7w3hM7r", + "asset_symbol": "TEST", + "amount": 17390000 + }, + { + "owner": "TESTPEnGuwTJjAKNRXNjMDmWMwR8mMTf7ykWK", + "asset_symbol": "TEST", + "amount": 3195287 + }, + { + "owner": "TEST6qHGfkSzij7rJTj69bd12pLxHQXcNktRF", + "asset_symbol": "TEST", + "amount": 9910570 + }, + { + "owner": "TESTDZ8FhEdP2e1P1JvaPsWNxq7yrAs6kDpCi", + "asset_symbol": "TEST", + "amount": 4186717 + }, + { + "owner": "TESTDhsRjjLtroVPuyJEYP39pPmKDLnbiARF2", + "asset_symbol": "TEST", + "amount": 40493 + }, + { + "owner": "TEST66d9PRn6zNkw2axtHw7EdimY82Gk67Vwh", + "asset_symbol": "TEST", + "amount": 1169989 + }, + { + "owner": "TEST3zUkMCH15PA5MjRJB9DuNfSUvEa5UGs2B", + "asset_symbol": "TEST", + "amount": 16589642 + }, + { + "owner": "TEST2aY9p8HXXGMCwAHQCKp8SNt93qtFgnR31", + "asset_symbol": "TEST", + "amount": 32492776 + }, + { + "owner": "TESTouKk9o9rtXjHMmUjGFMeu5WudYkHkDXg", + "asset_symbol": "TEST", + "amount": 3389844 + }, + { + "owner": "TESTHu5CUmsQhhY9M642ZQFRGcPDfeQjcstbP", + "asset_symbol": "TEST", + "amount": 3923801 + }, + { + "owner": "TEST6FwEbe9MYaMFMibcQTWeC4PETc8xeHxTG", + "asset_symbol": "TEST", + "amount": 598314 + }, + { + "owner": "TEST6ArYtkooq1ajR112tbNBvwKDCJT6uUxy2", + "asset_symbol": "TEST", + "amount": 66358356 + }, + { + "owner": "TESTEgT3jbiUqyRs1mcupAx1zvnMdiWkNqgsk", + "asset_symbol": "TEST", + "amount": 18850679 + }, + { + "owner": "TESTPa14bn6GEGZG1hqpaU4upDhw356ndAyzS", + "asset_symbol": "TEST", + "amount": 478648626 + }, + { + "owner": "TESTBx8bRcvEewrEfMQXD9UfYfJArkR45pZhh", + "asset_symbol": "TEST", + "amount": 8955305 + }, + { + "owner": "TESTKrJLvhEEnWzAPPRtcL9oDGTmvNpfKLdtq", + "asset_symbol": "TEST", + "amount": 23927453 + }, + { + "owner": "TEST2G37wYSr2n11uDLZDUXQ3XQnw9GhyQoR9", + "asset_symbol": "TEST", + "amount": 104316273 + }, + { + "owner": "TESTPwc8UdcStpuWoAqSVcrPieRuPAhNP9GCM", + "asset_symbol": "TEST", + "amount": 699357 + }, + { + "owner": "TEST57QLvWdY9pXn8b6HidWF8NJqeQpNxox1A", + "asset_symbol": "TEST", + "amount": 4443609 + }, + { + "owner": "TESTF41Z4D3RdGTfFCcDQW4q6H1h3bPurt9qt", + "asset_symbol": "TEST", + "amount": 102771 + }, + { + "owner": "TEST4qkRoNVQtU5JmS7WyrDaBNAmQQjGBcX7y", + "asset_symbol": "TEST", + "amount": 6872267 + }, + { + "owner": "TESTNxfxQciUD2L3cc6pSzbfMxyxmHBzwR2SQ", + "asset_symbol": "TEST", + "amount": 385938 + }, + { + "owner": "TESTJAMGu1e6ZG1Da2h4uweRU4BnPQAMfQfr3", + "asset_symbol": "TEST", + "amount": 26936360 + }, + { + "owner": "TESTDKn5XNN5cKiVnWCvfT9kwxbJygkSBGrZw", + "asset_symbol": "TEST", + "amount": 347581 + }, + { + "owner": "TESTEuUF5Mc7biCvBGQFXwWwegk1aKMP7Q2YN", + "asset_symbol": "TEST", + "amount": 19634691 + }, + { + "owner": "TESTDP6iw8Aqz9AztJTVSYPpJypeveBUte1Ug", + "asset_symbol": "TEST", + "amount": 33347518 + }, + { + "owner": "TEST2RWWtAw8cwTSnLzGwpXynDBqZ6mKh3eHk", + "asset_symbol": "TEST", + "amount": 57129 + }, + { + "owner": "TESTGc8H6M1BPcpeNMLUCocw9MbZzT829PvaW", + "asset_symbol": "TEST", + "amount": 175312 + }, + { + "owner": "TESTAwcHoy565gkJxFCb4RH3rYhWW23YyNyrp", + "asset_symbol": "TEST", + "amount": 5026931 + }, + { + "owner": "TESTFNntmzMELgreynH59wUGRcpYUC3nT2pJN", + "asset_symbol": "TEST", + "amount": 17511784 + }, + { + "owner": "TEST98Hei4CmAcPk1duwAUYhy2rcVY7KndgGL", + "asset_symbol": "TEST", + "amount": 1015437 + }, + { + "owner": "TESTDGwNokD4R6EfhkX7UAiiFPHUZZPusd8Ad", + "asset_symbol": "TEST", + "amount": 60045 + }, + { + "owner": "TESTGYe8Ln1uXUrs9Emd5e7tfxDXwrGoarC8Q", + "asset_symbol": "TEST", + "amount": 204858 + }, + { + "owner": "TESTJZbZuFAo9XPBedu5LWC67HPDHZyXVZnr9", + "asset_symbol": "TEST", + "amount": 411655 + }, + { + "owner": "TEST6iF94znHtm8WdQBNmucggTuUaGXpqPNqt", + "asset_symbol": "TEST", + "amount": 102027000 + }, + { + "owner": "TEST3QghsG78Hs92je5mxnUNh4JnSekEnKGDt", + "asset_symbol": "TEST", + "amount": 5799968 + }, + { + "owner": "TESTDzshKBfxtCS6CzhqGWdMfqNJ7W1yjhPmN", + "asset_symbol": "TEST", + "amount": 2759025 + }, + { + "owner": "TESTEKVgwXPtnw2uVqK8Rk1PMENkSGp7ZuY52", + "asset_symbol": "TEST", + "amount": 6407661 + }, + { + "owner": "TESTC8AgN9et3pkM2vX1skxfooDNvuAwgAW5d", + "asset_symbol": "TEST", + "amount": 25670837 + }, + { + "owner": "TEST4FAufHF7Jx8ezDNh2wXNUYip7TNuk6Xpr", + "asset_symbol": "TEST", + "amount": 246800 + }, + { + "owner": "TESTN5M9HFkzJBoN296rdSQ4gr7gQYpGCxQxp", + "asset_symbol": "TEST", + "amount": 20509242 + }, + { + "owner": "TESTBLtjMhXX54y41yUbUgSNZjYWvuDGTCefq", + "asset_symbol": "TEST", + "amount": 7980210 + }, + { + "owner": "TESTDtAnPrTziTDLkHjBEiQeJMEKi7esatN3F", + "asset_symbol": "TEST", + "amount": 16766634 + }, + { + "owner": "TESTHXErGzkKoMgM3A8UkQ5bSMH9SxyyMsGJg", + "asset_symbol": "TEST", + "amount": 897612 + }, + { + "owner": "TESTnF4HES9NACSCUJb64yG6BF2JF3wiyz8W", + "asset_symbol": "TEST", + "amount": 405881 + }, + { + "owner": "TESTHaVC6uEwWsSCiWPbNF5Jis6yK3WLZMfjz", + "asset_symbol": "TEST", + "amount": 19163867 + }, + { + "owner": "TEST4qdKFHfWKn1NV8qvZm78hPZHLyMZRieUp", + "asset_symbol": "TEST", + "amount": 1569492 + }, + { + "owner": "TESTPj9ic4V5udE2pthmeDE7mHVPHW3QfrJpA", + "asset_symbol": "TEST", + "amount": 1975295 + }, + { + "owner": "TESTEhyj5we3RHnyuypPpM9qFRSBzRnJDRktG", + "asset_symbol": "TEST", + "amount": 7099326 + }, + { + "owner": "TEST3CBYNP9W3xobjU5FxiNXYLpgptFB4h9Uo", + "asset_symbol": "TEST", + "amount": 13748531 + }, + { + "owner": "TESTM4dr8LwbZDsXEHHYHTEU3SuZywwjLi4BK", + "asset_symbol": "TEST", + "amount": 30172078 + }, + { + "owner": "TESTJ9Ld8jLcab6cbvYYB3zJV4xyKGmoSE4Fy", + "asset_symbol": "TEST", + "amount": 16837857 + }, + { + "owner": "TESTGFXBMztTV8mqogSDAnybwV5fkbfb8TZbp", + "asset_symbol": "TEST", + "amount": 34092 + }, + { + "owner": "TEST9npPxrkp1oiWLML2MhMLnzDxTaXVxurK4", + "asset_symbol": "TEST", + "amount": 25095112 + }, + { + "owner": "TESTU44n3BF3emzg7PReKKceS4Y3RkaFG9v2", + "asset_symbol": "TEST", + "amount": 2812466 + }, + { + "owner": "TEST2HWw4uzV9Q1XNHZHF1SBrDWbL4xUT5RjF", + "asset_symbol": "TEST", + "amount": 1696401 + }, + { + "owner": "TEST9C6Mkh4tQCXnFToXopEE82VVRTadcdeWx", + "asset_symbol": "TEST", + "amount": 20166 + }, + { + "owner": "TESTAbr5yH3ZTPqCMU5HzAwC2dk6RrvoL7ZEr", + "asset_symbol": "TEST", + "amount": 1483978 + }, + { + "owner": "TESTKsoXGJNzNy3zVkypcgD7yuyNrDMBJRLPq", + "asset_symbol": "TEST", + "amount": 8949082 + }, + { + "owner": "TESTGPYE72zHmqdwfDvi9eP3rUWLLTBa7R9Vp", + "asset_symbol": "TEST", + "amount": 3429697 + }, + { + "owner": "TESTLVSrv6iHKYmttXpJVgVoT35zcJeGs9Qwd", + "asset_symbol": "TEST", + "amount": 2010293 + }, + { + "owner": "TEST9GhkLA1eBR4HfHANUY5EBTw8GtauEZFsb", + "asset_symbol": "TEST", + "amount": 101248305 + }, + { + "owner": "TESTMiH2pTVVhrqzsciy2JGuWWjELYQW9Rjfo", + "asset_symbol": "TEST", + "amount": 9752137 + }, + { + "owner": "TESTLTGeXAMYfoACi1dhYxDmKHMMhSoqwjhSu", + "asset_symbol": "TEST", + "amount": 574155566 + }, + { + "owner": "TESTDmR5gzUiWUeBPQ9bGsC2B6GDrCc9HWYd9", + "asset_symbol": "TEST", + "amount": 2669708 + }, + { + "owner": "TEST6URBcbpKTV28h9GNfYqx6aTMhCEoyVCJL", + "asset_symbol": "TEST", + "amount": 8827814 + }, + { + "owner": "TESTMpnCKJ4tBTs7VDW5MpGLfzd9397VFQ2Yn", + "asset_symbol": "TEST", + "amount": 2350296 + }, + { + "owner": "TESTKHYmWG5u7aoWz3orrHPnTWsTnGBdREvED", + "asset_symbol": "TEST", + "amount": 62412 + }, + { + "owner": "TEST5gmVv6QY82wywTRei25mKCfwhnGxNM3jo", + "asset_symbol": "TEST", + "amount": 872216 + }, + { + "owner": "TEST7c5SLFmkrRkNXZHYQGD55iU13uvUxLChp", + "asset_symbol": "TEST", + "amount": 979241 + }, + { + "owner": "TESTLwc2GoFLXA2EMY42ZfeJ7nKGcP485NwpR", + "asset_symbol": "TEST", + "amount": 13226734 + }, + { + "owner": "TESTFdwGpwkNaX9M5hM2SQmkC5FaRJzkRP94k", + "asset_symbol": "TEST", + "amount": 88418078 + }, + { + "owner": "TESTAkrLfmmFWK9bDDPxNxFzMec4NcuzDi2yi", + "asset_symbol": "TEST", + "amount": 3982551 + }, + { + "owner": "TESTHQDmWf3Q6BGZaBvFWiB9xVq3vpVd3G8jy", + "asset_symbol": "TEST", + "amount": 4980677 + }, + { + "owner": "TESTswp6pufVRfgpRdKNuxqtqivLAue8Zxig", + "asset_symbol": "TEST", + "amount": 26473682 + }, + { + "owner": "TESTFFtrPhJBHmesFaoDnocSV3U9TFGQrpzaT", + "asset_symbol": "TEST", + "amount": 28566209 + }, + { + "owner": "TESTMtD8F9PMRwqcCJCXTdBcqkoVtDfj3xzSG", + "asset_symbol": "TEST", + "amount": 2355445 + }, + { + "owner": "TESTFHcf4caJabo5U49LTkktcZodu43MKjVXU", + "asset_symbol": "TEST", + "amount": 2687215 + }, + { + "owner": "TEST9FG99PA64h5pdHkGUBKdyJ7kpWGVzmmpp", + "asset_symbol": "TEST", + "amount": 1204602 + }, + { + "owner": "TESTFETX1mSC3reGxNNUNbCfgQki2CDSpZAWr", + "asset_symbol": "TEST", + "amount": 2119366 + }, + { + "owner": "TEST2zoqFhH9oL4VTCEhNXpXiAVkxsVXnsdiP", + "asset_symbol": "TEST", + "amount": 14582167 + }, + { + "owner": "TESTph1YqywcVsiQwh2cZmC4oiSctEtc36CQ", + "asset_symbol": "TEST", + "amount": 1357636 + }, + { + "owner": "TESTNahdgvTCXmSmHEYypvtNq9n9h2qi8nZn8", + "asset_symbol": "TEST", + "amount": 5153761 + }, + { + "owner": "TESTPAt5N3y1t4k8hCdH5RJAetSyxaurYQDkZ", + "asset_symbol": "TEST", + "amount": 12799930 + }, + { + "owner": "TESTCsbzBgxfi55NhG6Cp4UKai4SFJCYjsgim", + "asset_symbol": "TEST", + "amount": 5066717 + }, + { + "owner": "TESTBkpas3sVrAqqqzm7x8dsgBgAjt9THXTth", + "asset_symbol": "TEST", + "amount": 175048 + }, + { + "owner": "TESTKkCT9wuzue8FT7P1MPRguFqHEW2cJmo5", + "asset_symbol": "TEST", + "amount": 322149775 + }, + { + "owner": "TESTNkbrPEUgzSJEWLodVFg4KtwpkAXWXtnSd", + "asset_symbol": "TEST", + "amount": 3544934 + }, + { + "owner": "TEST5bteDcu1EkYvMKJWX4SfeJ4FrkYRKw9xS", + "asset_symbol": "TEST", + "amount": 2458279 + }, + { + "owner": "TESTKBpa3P2C5zKzj8HANrcCRDvEKUC41F5x4", + "asset_symbol": "TEST", + "amount": 4944514 + }, + { + "owner": "TESTHfRiH9uzEshtcrfGdT3cACuEHfLjaU82C", + "asset_symbol": "TEST", + "amount": 6730703 + }, + { + "owner": "TEST82PR9E8i8f5acnBPZbMQs7eeTpTJhr1Js", + "asset_symbol": "TEST", + "amount": 63951386 + }, + { + "owner": "TEST47AUdygz1YZX3ZxksURgtKQNFvcGukAjH", + "asset_symbol": "TEST", + "amount": 15522403 + }, + { + "owner": "TESTCMpeJuBfCpjJrm1MXEf8vMjpFynjsU2g5", + "asset_symbol": "TEST", + "amount": 509150845 + }, + { + "owner": "TESTAPSsSMYJmfyfez7yvgheYn8qTxM42E9qn", + "asset_symbol": "TEST", + "amount": 343236 + }, + { + "owner": "TESTQ8na5TgyozykAcHQiSjXkh68KfNPrRScD", + "asset_symbol": "TEST", + "amount": 6871320 + }, + { + "owner": "TESTAopMp32fo9rBZuYcfozq69FAEDgKVMdk7", + "asset_symbol": "TEST", + "amount": 290582 + }, + { + "owner": "TESTDR1gSs9w3bcjboScchMhfj3cuHryJg7kW", + "asset_symbol": "TEST", + "amount": 436642101 + }, + { + "owner": "TESTP5ybPYgh29zdfKhmBGJi2tGiH1UVX3QeX", + "asset_symbol": "TEST", + "amount": 67788 + }, + { + "owner": "TEST25KHKBAZG3Fv5qfEhuWt4WBHdjBaSis6m", + "asset_symbol": "TEST", + "amount": 17452530 + }, + { + "owner": "TESTLkV2m2TreFTSP3cFt8qi8fBTPGaimYcXz", + "asset_symbol": "TEST", + "amount": 2247358 + }, + { + "owner": "TESTzJoyHbyjRaAB5jQW4nRDyDudPhmgnmBT", + "asset_symbol": "TEST", + "amount": 236594 + }, + { + "owner": "TEST4rESGs4G4knhENnY5YaLLv35RcmbBc1LF", + "asset_symbol": "TEST", + "amount": 999876 + }, + { + "owner": "TEST3maaDvPV83VYYtgGgfdacKxmoCuVX4mZx", + "asset_symbol": "TEST", + "amount": 262381 + }, + { + "owner": "TESTFvTpv91vKWGQdfzFvdi2A2JGMQmQstvuY", + "asset_symbol": "TEST", + "amount": 1756499 + }, + { + "owner": "TEST45Z5WBztTTXtSmGRXZXEuzPRaZamFKbcL", + "asset_symbol": "TEST", + "amount": 32634334 + }, + { + "owner": "TESTKEvSmqXV6cKaq5B5fRBq1mC7fLA2VU69Z", + "asset_symbol": "TEST", + "amount": 14640634 + }, + { + "owner": "TESTLiHzuvoXRBZsPeXp6BPxUGJ1fjGv3iAa", + "asset_symbol": "TEST", + "amount": 10486476 + }, + { + "owner": "TESTM7nN3rVN5rfCWKhLGfY6Vd2jJgfpdnQ4J", + "asset_symbol": "TEST", + "amount": 332003 + }, + { + "owner": "TESTLYeB34ACPHNyZdxrCUWTmkFh1SUWTigbW", + "asset_symbol": "TEST", + "amount": 935982 + }, + { + "owner": "TEST7VhAtQS1jGrDqWGYiPSu63PzkF5zeXJYc", + "asset_symbol": "TEST", + "amount": 4588329 + }, + { + "owner": "TESTDkFeaJAhyqGjqGmTdNAQosdgtyzbA3PM5", + "asset_symbol": "TEST", + "amount": 3439386 + }, + { + "owner": "TEST6mUMdB1zR2EduEqh6Lud46REZDx91iZGE", + "asset_symbol": "TEST", + "amount": 2389253 + }, + { + "owner": "TEST4aY4puaUwpdXMGn2sMHydV4MJcZubLHD4", + "asset_symbol": "TEST", + "amount": 10464082 + }, + { + "owner": "TESTEAHpr4yFmDvMvioEqWTeXuXr144Pdjhz3", + "asset_symbol": "TEST", + "amount": 6456684 + }, + { + "owner": "TESTAupcs9uUwmaXJ8zhuCNPxvrg8o6mcUD9g", + "asset_symbol": "TEST", + "amount": 1850573 + }, + { + "owner": "TEST2vvAqKnvqch89gHEdKzHC3UScFDdTJEug", + "asset_symbol": "TEST", + "amount": 6722500 + }, + { + "owner": "TESTBhhhnWg6okwetBpmCfWvFoXskJJWCCZEL", + "asset_symbol": "TEST", + "amount": 18986002 + }, + { + "owner": "TESTE4CnLkseDqqTU3pf7UxXZMEWdYJCgh8VQ", + "asset_symbol": "TEST", + "amount": 9788208 + }, + { + "owner": "TESTPkhxynEt8XTKMG5uQLpxPQ58bhLjygWQV", + "asset_symbol": "TEST", + "amount": 25599860 + }, + { + "owner": "TEST9EJaxbxaSgojz3ZJTjCdiRfcrkTmHWVq6", + "asset_symbol": "TEST", + "amount": 24781158 + }, + { + "owner": "TESTCXrHgfKzroudCkqt1p1uRobfRmAAGaPi9", + "asset_symbol": "TEST", + "amount": 7121467 + }, + { + "owner": "TESTLQsWqBfc1jKRa8Vdc746hE2vXZbbZ9dbn", + "asset_symbol": "TEST", + "amount": 1788251 + }, + { + "owner": "TESTBf9gdJcpFCbv46Uycnbz24RGN3TRGSmgT", + "asset_symbol": "TEST", + "amount": 5706701 + }, + { + "owner": "TESTGDGz7EtLnhMTci7Voi52UYxbtjFeHXX1F", + "asset_symbol": "TEST", + "amount": 10769996 + }, + { + "owner": "TESTACiTiKR72PieVMtyzMR6QAhPBfqE81Bws", + "asset_symbol": "TEST", + "amount": 908684 + }, + { + "owner": "TESTD4E9DWdhhpMykZFfpNZf7KtWgZrXuzPSV", + "asset_symbol": "TEST", + "amount": 2562182 + }, + { + "owner": "TEST6vnKYzFZp4eR8pk1rvHWt3BhbA6y2gFcS", + "asset_symbol": "TEST", + "amount": 338352 + }, + { + "owner": "TEST3ybQmwx9dg47ZsfXJM8wAw6v9xweASBxy", + "asset_symbol": "TEST", + "amount": 1688678 + }, + { + "owner": "TESTPTwp9DZKCCrqrc4NdHRXzb2A6vYH85QoD", + "asset_symbol": "TEST", + "amount": 273309 + }, + { + "owner": "TESTJFCyTBbPtw7qXkraQJVMwwF72CCdwpzwf", + "asset_symbol": "TEST", + "amount": 50445839 + }, + { + "owner": "TESTEnaXRpCaBSBdEDZqgVxVq46KuQMhr3KGs", + "asset_symbol": "TEST", + "amount": 402127 + }, + { + "owner": "TESTJLz3nuaY7WTABK481tJ8W2Qpute3kb1g5", + "asset_symbol": "TEST", + "amount": 21748936 + }, + { + "owner": "TEST9XAni1Qg9E8mWG3j6haF53BTSMBZUzoXw", + "asset_symbol": "TEST", + "amount": 8096576 + }, + { + "owner": "TESTGcUQAZW7CgVPdoGqk7NNwDX3aNu3nmEzq", + "asset_symbol": "TEST", + "amount": 4281440 + }, + { + "owner": "TEST5o6LUKd91DwnBLRzCHYE8DXcfNKX9SyTo", + "asset_symbol": "TEST", + "amount": 8987782 + }, + { + "owner": "TEST27K3fbTWrdL8qgzHc8npz5mekSTLWiPx1", + "asset_symbol": "TEST", + "amount": 5104733 + }, + { + "owner": "TESTFQNjcmSw5Nzmfqct3DhntaYRbcFJY7yDG", + "asset_symbol": "TEST", + "amount": 2209977 + }, + { + "owner": "TESTKZRo3YYot7wUoUZKt1t6wUZ9Nvk6miZxu", + "asset_symbol": "TEST", + "amount": 34314905 + }, + { + "owner": "TEST4hpSSAdCLVupj9KsngGwwEonjEPrVPPjX", + "asset_symbol": "TEST", + "amount": 323079 + }, + { + "owner": "TESTExCFNihHHvhci2ySKRJgFRsVuhaXLdd3c", + "asset_symbol": "TEST", + "amount": 1508230 + }, + { + "owner": "TESTHpYjeA3HNci2oo4XFe4rG63ihKv1vNBjF", + "asset_symbol": "TEST", + "amount": 4705832 + }, + { + "owner": "TESTAjXVL9qwpMvKTNCZSxktNPEizw2rsi97V", + "asset_symbol": "TEST", + "amount": 1647322 + }, + { + "owner": "TESTLrwKtTGmstq1XXSX7NtbBk3CE4yiJKm7T", + "asset_symbol": "TEST", + "amount": 340750 + }, + { + "owner": "TESTGXaUGGzmtccsXzZ6D1Tpf6B9GCcvFpr2q", + "asset_symbol": "TEST", + "amount": 3375640 + }, + { + "owner": "TESTPUjC6qCdbLddzjUzEi87pzJGUZZmT6b6G", + "asset_symbol": "TEST", + "amount": 84191 + }, + { + "owner": "TEST31L1U6snLtaf584p2xwYdfX212hsuBYgm", + "asset_symbol": "TEST", + "amount": 9600273 + }, + { + "owner": "TESTAXG1EFFd2PB5pmUSwccTPxRFqR7BqraD4", + "asset_symbol": "TEST", + "amount": 1968862 + }, + { + "owner": "TESTL7YdJFV9YyFiBqpkvDzrvnQrAQrWRTKNj", + "asset_symbol": "TEST", + "amount": 33511758 + }, + { + "owner": "TESTCfcQBVPefhzqsJP4tpmwNznCz1vzGDB6A", + "asset_symbol": "TEST", + "amount": 295762 + }, + { + "owner": "TEST23U5vbxBsbLv4kDZHpLBe3sdGH2kwHCHT", + "asset_symbol": "TEST", + "amount": 13805289 + }, + { + "owner": "TESTLhzZfxjqTKAmu4VxhdwCXAXpescP7PiEb", + "asset_symbol": "TEST", + "amount": 1715562 + }, + { + "owner": "TESTMjyFXgfUR3TdKfUQ3qQFSH6Auuh9qyjBB", + "asset_symbol": "TEST", + "amount": 2359791 + }, + { + "owner": "TESTDMHwGnYs1n1a5vsMb5ASpago1aZL4DttE", + "asset_symbol": "TEST", + "amount": 829643 + }, + { + "owner": "TEST81VU3WFyQEmn1nou2TGoZtRaEoZHcVWDF", + "asset_symbol": "TEST", + "amount": 20384417 + }, + { + "owner": "TESTGBwKQJnanPz285tcgcXnmPR9wUfap5TPx", + "asset_symbol": "TEST", + "amount": 5638867 + }, + { + "owner": "TESTMWQeA7EjmeRTzkLQ4NoLr6wpWnWkewvd8", + "asset_symbol": "TEST", + "amount": 1547839 + }, + { + "owner": "TEST8NCC52hU3KSakoYitdEHBVDZnZYGqbBdY", + "asset_symbol": "TEST", + "amount": 2882825 + }, + { + "owner": "TEST2q9dNaZdY4Mjhq2JNaTShJrvTAN2Nu2EX", + "asset_symbol": "TEST", + "amount": 1347594 + }, + { + "owner": "TESTEriMArRB6PWBWaQSXfo5Q2brFmAXvAQxK", + "asset_symbol": "TEST", + "amount": 1121883 + }, + { + "owner": "TEST2avbMwACtxfadChaeYvFkdArDTYmyDdap", + "asset_symbol": "TEST", + "amount": 2305225 + }, + { + "owner": "TESTFacfiiV1bMYd4czZDZsPbmRybBhuuC8Hc", + "asset_symbol": "TEST", + "amount": 987741 + }, + { + "owner": "TESTKWnfv7p4ZNtA2aYPe8scUCvafQrtjja8v", + "asset_symbol": "TEST", + "amount": 2559392 + }, + { + "owner": "TESTH3xyS8MSpCrSEXcMc5tWqTAZg4i8EPHVp", + "asset_symbol": "TEST", + "amount": 12506060 + }, + { + "owner": "TESTKk5B5Yf5xYEY1QrSCiW71qzCvuQbDZqPU", + "asset_symbol": "TEST", + "amount": 4562080 + }, + { + "owner": "TESTCE1EaPqkcH1VjbvXS7rYybrjsYmYwjVgp", + "asset_symbol": "TEST", + "amount": 7647177 + }, + { + "owner": "TESTPyPKVmv6CsizeGKFPE6Ji7abitqD484hR", + "asset_symbol": "TEST", + "amount": 2148528 + }, + { + "owner": "TESTVDeSnXW3YiD6eKQtr5o9efo7zh5cTEvc", + "asset_symbol": "TEST", + "amount": 218854 + }, + { + "owner": "TESTDPG5B5FZTJgnF1gd7HNkdkeSMzCjYyx1w", + "asset_symbol": "TEST", + "amount": 68647105 + }, + { + "owner": "TESTLaidfbTuAQtoAmvRT5N1A3fMJ5Xcy1ndM", + "asset_symbol": "TEST", + "amount": 541184 + }, + { + "owner": "TESTFjbWyFQCCgqNdzYLncAVcMZegykCcVYG8", + "asset_symbol": "TEST", + "amount": 37794146 + }, + { + "owner": "TESTEz3a6giwKzbJHFCrRv6jwYAFynz3HbXXh", + "asset_symbol": "TEST", + "amount": 17328000 + }, + { + "owner": "TESTBXjw8bCxDtcSiExThbyjYgSpoSCFt9fdo", + "asset_symbol": "TEST", + "amount": 95713313 + }, + { + "owner": "TESTCgBHJBFxn6iraAAECeLSjVjbFfjHE9kbv", + "asset_symbol": "TEST", + "amount": 5683640 + }, + { + "owner": "TESTDQ3NHvuUPU3BHuTz8teWzwvchcUUtsB1k", + "asset_symbol": "TEST", + "amount": 8712628 + }, + { + "owner": "TEST4kskptVmJPowunj3x3TgPk4iSo2JeLZJ8", + "asset_symbol": "TEST", + "amount": 16165036 + }, + { + "owner": "TESTFpujVui5T7iuEdURLZ3v6ErsvfVn2tBQv", + "asset_symbol": "TEST", + "amount": 14486519 + }, + { + "owner": "TESTFSZ9YkWcfRmoARNXrbWwXXsboWMkfWMuG", + "asset_symbol": "TEST", + "amount": 1718095 + }, + { + "owner": "TESTKN5NQ1Dyu5eHUkn56JcLzvJWPuRoXXL8w", + "asset_symbol": "TEST", + "amount": 2126839 + }, + { + "owner": "TESTKv9gRNGqNkwsJ7REBgNZmJScTCSiwDkKR", + "asset_symbol": "TEST", + "amount": 3526850 + }, + { + "owner": "TESTJpXbgLR7LiYSbfxTKNA8c2qWWSz12GKvc", + "asset_symbol": "TEST", + "amount": 708641 + }, + { + "owner": "TEST3WjJhQoMcLqQhjabEL1WLcDybbgbzQp9q", + "asset_symbol": "TEST", + "amount": 6586610 + }, + { + "owner": "TEST3sjvyHrueuxvqNvE8qqg9ZFFrnL82ZDeQ", + "asset_symbol": "TEST", + "amount": 68000 + }, + { + "owner": "TESTEnWS9v8NrzuJGsrDpXUGAhNPArBweR8je", + "asset_symbol": "TEST", + "amount": 23157415 + }, + { + "owner": "TESTK8KTu8Mm8417KUcsfU2JfDAo7s9Btom4F", + "asset_symbol": "TEST", + "amount": 23930988 + }, + { + "owner": "TEST3sN5ZQGhkhEvU2GVw9RL9c748S4L6vahH", + "asset_symbol": "TEST", + "amount": 1904518 + }, + { + "owner": "TESTPuD7MHjmPCCjAWSUMJqFVzSDabycBof5m", + "asset_symbol": "TEST", + "amount": 60318933 + }, + { + "owner": "TESTGEXrY62hkkB1M86iFxEPrMJqSQW2J3v48", + "asset_symbol": "TEST", + "amount": 1855821 + }, + { + "owner": "TESTLp6CQ1JkkvcHCChfWa7fWGDxsX5SatAzz", + "asset_symbol": "TEST", + "amount": 2039514 + }, + { + "owner": "TESTD9wG6gqpbUDxUei4tPViurXuXNyb1NyFj", + "asset_symbol": "TEST", + "amount": 10214065 + }, + { + "owner": "TEST9L8w1MZisZY2iGPDs8vvjWf1iMwHK82LW", + "asset_symbol": "TEST", + "amount": 15218692 + }, + { + "owner": "TESTJXxSZE1vk8g7JpTbThhzp4QXbyA7KovQZ", + "asset_symbol": "TEST", + "amount": 3497745 + }, + { + "owner": "TESTNodWx9STeoWZVsQpa56faFhUmSvDKZA59", + "asset_symbol": "TEST", + "amount": 3258682 + }, + { + "owner": "TESTNKX6RFzhjrXEbMwHzTjCngmdBVq2TTjCu", + "asset_symbol": "TEST", + "amount": 16379673 + }, + { + "owner": "TESTitedk3o7SHQsfUW3vCdaUMc2aMMWSro2", + "asset_symbol": "TEST", + "amount": 3366939 + }, + { + "owner": "TESTDzZXDzeTeY7X9Hy2LB38Bs1kvHRCwxkAA", + "asset_symbol": "TEST", + "amount": 1549747 + }, + { + "owner": "TEST6c997V3fhXNTWLHWFEbFh3fiGJn6eX9cU", + "asset_symbol": "TEST", + "amount": 4106522 + }, + { + "owner": "TESTP4noACM7fQZSRTf8ftEhuCT21ZT2exkCy", + "asset_symbol": "TEST", + "amount": 1224927 + }, + { + "owner": "TESTAukz48LATPmYbdVAqAFVLA9J9TdKB7YDu", + "asset_symbol": "TEST", + "amount": 1773587 + }, + { + "owner": "TESTLUaS6kbxSVD6xJ7YZnsFbHkKioQLL2RxV", + "asset_symbol": "TEST", + "amount": 1575005 + }, + { + "owner": "TESTPZz4nRMnB1MHas9qDFaZSh1EQKsBXBLkY", + "asset_symbol": "TEST", + "amount": 22332159 + }, + { + "owner": "TEST3QH6UJzmQtUGg6KszHfNebRZEmhZpj2aY", + "asset_symbol": "TEST", + "amount": 310362 + }, + { + "owner": "TESTQG5Y53yzLhw7DR7E5phpdRaH5GR59uE1C", + "asset_symbol": "TEST", + "amount": 19318269 + }, + { + "owner": "TESTaXvYqbGcaRQn1c7aiLBq4g66T8XJRvLD", + "asset_symbol": "TEST", + "amount": 3321867 + }, + { + "owner": "TESTDeC995doF8F7THj7dqATMdrMnb2vs7p7X", + "asset_symbol": "TEST", + "amount": 350950200 + }, + { + "owner": "TEST2JS8NGjrAvAv7KqtYw7z43PaRuuwogoQ5", + "asset_symbol": "TEST", + "amount": 1699079 + }, + { + "owner": "TEST2dySh1pZfJuu7HYLC5urDzvMN9KFhv7eN", + "asset_symbol": "TEST", + "amount": 113102285 + }, + { + "owner": "TEST58e9BWeXXZdgcKyPXEUv4ipHgWXemq7Ug", + "asset_symbol": "TEST", + "amount": 1014900 + }, + { + "owner": "TEST6tbhmbLBbtrwHEXQhx44yGswYzV7cAZiX", + "asset_symbol": "TEST", + "amount": 156910 + }, + { + "owner": "TEST2qpQUjEnR1DUxn7GoY91M2Dxxmq1f7GxP", + "asset_symbol": "TEST", + "amount": 5620396 + }, + { + "owner": "TESTNQno7nDDuvNnqggEmwZHivr6fqRsFQQoK", + "asset_symbol": "TEST", + "amount": 10732396 + }, + { + "owner": "TESTFRK5FYnXmJbXdpuVoWTsnhu29WuZhVy2S", + "asset_symbol": "TEST", + "amount": 638526 + }, + { + "owner": "TESTPUJCQsd6voYai5N1cGh8ihxota5Y3dcq", + "asset_symbol": "TEST", + "amount": 2591696 + }, + { + "owner": "TEST3R6fscMrMeYiygvu3xD3ATJsKyDqBTKNf", + "asset_symbol": "TEST", + "amount": 103294334 + }, + { + "owner": "TESTM4SmXXwSS1UYk3DpQ9RvC5p62Gxx7ykEA", + "asset_symbol": "TEST", + "amount": 106834380 + }, + { + "owner": "TEST3paR5N1uXiVLRw2yjs9zRMDDn2MstQ3se", + "asset_symbol": "TEST", + "amount": 15591401 + }, + { + "owner": "TEST7Z8WBJgFRWjdyJ6f97LetJyHmJQhboaZQ", + "asset_symbol": "TEST", + "amount": 2320354 + }, + { + "owner": "TESTCPYEwFTLHEwPJSNq2CHkp3ityR9qiYN9o", + "asset_symbol": "TEST", + "amount": 11699895 + }, + { + "owner": "TESTQ9ADSuNFvcpB9zprjMYRjmY77DTzmnvNG", + "asset_symbol": "TEST", + "amount": 4940867 + }, + { + "owner": "TEST5ZJFCfTGYQagC6YuuktHKwTkC3sFnm78U", + "asset_symbol": "TEST", + "amount": 103140000 + }, + { + "owner": "TEST6jtjhEyw7syYHZieGvPWN3R1SkDD8u7KJ", + "asset_symbol": "TEST", + "amount": 6676308 + }, + { + "owner": "TESTcQ684oRGSbBv5Xszjb1W4aQraf1mZWfX", + "asset_symbol": "TEST", + "amount": 166625 + }, + { + "owner": "TESTD3wqgkaVTCHWNMxZgTkQMRGkwnLY9AZPQ", + "asset_symbol": "TEST", + "amount": 15835300 + }, + { + "owner": "TEST3GRG9HaTAxBXa8PJFsvd4WBhgmek2ojms", + "asset_symbol": "TEST", + "amount": 1737921 + }, + { + "owner": "TESTGwVzUYoXezmYNCpovcntMf6jXtL5gYNvV", + "asset_symbol": "TEST", + "amount": 1985332 + }, + { + "owner": "TESTABV583Cv4LYzhcgGTQSAT5PP5tP4cbpX9", + "asset_symbol": "TEST", + "amount": 17161810 + }, + { + "owner": "TESTBLvZw6PzKhPRDGwSvpCGayPFgkiQfCoKq", + "asset_symbol": "TEST", + "amount": 31158844 + }, + { + "owner": "TESTQGk9wpEaEVcdifnLNrV45LZMnpQCdH7K9", + "asset_symbol": "TEST", + "amount": 13491947 + }, + { + "owner": "TEST34zwbLHnQpBuq8nMkHpZMK8XSHUsYU8KU", + "asset_symbol": "TEST", + "amount": 22019713 + }, + { + "owner": "TEST91gExhdX7UdnBp4Y9YZZN93kfZvchoNqF", + "asset_symbol": "TEST", + "amount": 34783480 + }, + { + "owner": "TESTJkHV5oxtmYne5v16Z1dSXxvUaMJw68dor", + "asset_symbol": "TEST", + "amount": 20662569 + }, + { + "owner": "TEST3bgwusTGZ2YTxiPjjgDUothUaVKZ7qfZB", + "asset_symbol": "TEST", + "amount": 6344267 + }, + { + "owner": "TESTPZqUuWrdTLtv9wb4WbGqvTX4oyu46diSF", + "asset_symbol": "TEST", + "amount": 3360886 + }, + { + "owner": "TESTLnX1miT5KcNCBcsve1MNotnh1SDeZ4Pyp", + "asset_symbol": "TEST", + "amount": 4086618 + }, + { + "owner": "TESTGLpNhM1V7xwmQBo8SzYopGXXJfRw3ex5T", + "asset_symbol": "TEST", + "amount": 9325127 + }, + { + "owner": "TESTA1GCoM5L7iK1f69Zb2npCixVbzheQp6SU", + "asset_symbol": "TEST", + "amount": 684106 + }, + { + "owner": "TESTEk1n5ybH4Cs9XD6rRokAk2gXvAodfwKEN", + "asset_symbol": "TEST", + "amount": 20842308 + }, + { + "owner": "TESTG6jJ71Zp1XSxP9mv7EpiDVsSQsEhpjKZm", + "asset_symbol": "TEST", + "amount": 4115096 + }, + { + "owner": "TESTN5hg7s5Gk11A5vAH9Xy6aidiDJcbwUtC2", + "asset_symbol": "TEST", + "amount": 20381950 + }, + { + "owner": "TESTMJTiX7oFzo284ETPu3TnChtENTKx5c9Rb", + "asset_symbol": "TEST", + "amount": 47618858 + }, + { + "owner": "TESTAR9taVnKHjPg14zdgo8AQ95yTA8iBUmjR", + "asset_symbol": "TEST", + "amount": 21519120 + }, + { + "owner": "TESTCutd8TeCgb9VNxAsCEa5SZHcYZzK9WDk4", + "asset_symbol": "TEST", + "amount": 9010352 + }, + { + "owner": "TESTJorM36zudfp8sQmw4fV2zk2NMEQhBsvGW", + "asset_symbol": "TEST", + "amount": 4809857 + }, + { + "owner": "TESTAzUytRLoziGUTqQmCWinMJJ9N29xm51fU", + "asset_symbol": "TEST", + "amount": 62340409 + }, + { + "owner": "TEST4R8QDL2aq3FYnK4m8o9y8UogeMj9W9KRQ", + "asset_symbol": "TEST", + "amount": 4416744 + }, + { + "owner": "TESTEGCg1PhJXxN6VtyPxa8QiPs5XNTaFkvhW", + "asset_symbol": "TEST", + "amount": 118089522 + }, + { + "owner": "TESTcNoWnh4ESfq3rk9awtry5cZV7X3tFS8u", + "asset_symbol": "TEST", + "amount": 16012326 + }, + { + "owner": "TEST68qNUZ7XFKMxRYAUb9xqF3QKeDPPtKiMA", + "asset_symbol": "TEST", + "amount": 2225286 + }, + { + "owner": "TEST3yLvDK2SMUUDHLHheARWDyfsjFrrFjPqn", + "asset_symbol": "TEST", + "amount": 34323619 + }, + { + "owner": "TESTCLnP6SbN6q5RaTwAAZnj9ZpNYwoARg1Ag", + "asset_symbol": "TEST", + "amount": 16965495 + }, + { + "owner": "TEST9X7qRz7XM8abJ1HMy6PX27X1UreLdkPan", + "asset_symbol": "TEST", + "amount": 114643732 + }, + { + "owner": "TEST5JHFoEkz983qyji2wwtV3YTQqYmBQxf7Q", + "asset_symbol": "TEST", + "amount": 356193 + }, + { + "owner": "TEST757iH6M28mEJX6xZbuM6rRzCzBGuZ28D3", + "asset_symbol": "TEST", + "amount": 27029847 + }, + { + "owner": "TESTMjYMjC9j5Ba44xBDnr1xY76rXFaTjSeLN", + "asset_symbol": "TEST", + "amount": 1754971 + }, + { + "owner": "TESTHdDnu1pbKRs4N4eoGXDEMFMehnxochC3D", + "asset_symbol": "TEST", + "amount": 959590 + }, + { + "owner": "TEST4xAEZbaPo6s4jYA829iAqCZT79qamgc3X", + "asset_symbol": "TEST", + "amount": 608656 + }, + { + "owner": "TESTNf6iUEWNsiPTAJHizuGwtX81EDwZdKNb", + "asset_symbol": "TEST", + "amount": 1647575 + }, + { + "owner": "TESTFtsBwYNFVMH9gSmb4NQ4qMkperPoPw9B4", + "asset_symbol": "TEST", + "amount": 3551454 + }, + { + "owner": "TEST8s2wnPkieFLykmqp9yP2Xa8aeeLqf9vLv", + "asset_symbol": "TEST", + "amount": 4737078 + }, + { + "owner": "TESTBX92aA1T5XoovMikMsybmWQBeQzyU1mFm", + "asset_symbol": "TEST", + "amount": 5897174 + }, + { + "owner": "TESTJ5fPY7rzQfR8TT9LCtYh9SvaeDzxkhV3b", + "asset_symbol": "TEST", + "amount": 213998400 + }, + { + "owner": "TEST321KdFFoUEFqTdaiE8FMddaCbbcRqyznc", + "asset_symbol": "TEST", + "amount": 800047 + }, + { + "owner": "TEST39mvq9jpy65QBbXEpPdwF8E7VWVFu6zvX", + "asset_symbol": "TEST", + "amount": 107718 + }, + { + "owner": "TEST4eXkVLFAUcY2YQehirkH5mo4Av5kFVJx9", + "asset_symbol": "TEST", + "amount": 3435886 + }, + { + "owner": "TESTPm51hs6ufT8VfrKFvdfXx4gXfobBTaZgk", + "asset_symbol": "TEST", + "amount": 51103009 + }, + { + "owner": "TEST7gPJAZuiJGud8N2hmkN5usuxZRX2w8km", + "asset_symbol": "TEST", + "amount": 6480456 + }, + { + "owner": "TESTKtxVGfp7FH9d25L6JQHBiwvM7x8a4xno5", + "asset_symbol": "TEST", + "amount": 6903320 + }, + { + "owner": "TESTJTLoJNtw65CjCV9g7wdk2D4sZMBpr4umg", + "asset_symbol": "TEST", + "amount": 4204643 + }, + { + "owner": "TEST5yicXuouC5zTsJ1LKE1gozvUjemMpkNW4", + "asset_symbol": "TEST", + "amount": 13832239 + }, + { + "owner": "TEST8WuGvB9yKxUkbtWYEnTQzMKpmuEBobdY9", + "asset_symbol": "TEST", + "amount": 1686279 + }, + { + "owner": "TESTGpreYczX7nYen5pva6oPiG3oVHx9v6M2Z", + "asset_symbol": "TEST", + "amount": 1030768 + }, + { + "owner": "TESTH2nupMVaScg55PqdtNjM56c1oYdsjZaBe", + "asset_symbol": "TEST", + "amount": 11822800 + }, + { + "owner": "TESTsrrMmFPzuvBXLZogWSrdMwWuhCQvoXK7", + "asset_symbol": "TEST", + "amount": 1673950 + }, + { + "owner": "TEST6KFEc2594Y7TryF1cK18KqkJRPXc6uACi", + "asset_symbol": "TEST", + "amount": 2135964 + }, + { + "owner": "TEST9L8GeRKdt8tnzRrCQ76rV25x4vzJxtXdG", + "asset_symbol": "TEST", + "amount": 2313751 + }, + { + "owner": "TESTNfMTdDTKC1obvArMzrYe1uQgP9ivfmPZZ", + "asset_symbol": "TEST", + "amount": 2363905 + }, + { + "owner": "TESTmqNa74vQDnQrBZKgwQquoWkjXYzZ9Mp3", + "asset_symbol": "TEST", + "amount": 26885375 + }, + { + "owner": "TESTBPgQ2eiPenAzss3xujan6anC1gXxtT8ns", + "asset_symbol": "TEST", + "amount": 1561716 + }, + { + "owner": "TESTErVqvVLkxnWk4MHxBhtVs97Q5NCU5cA39", + "asset_symbol": "TEST", + "amount": 1119566 + }, + { + "owner": "TEST5wX88LFVvjs6DQzyqdveyRLdyHBH1AfGy", + "asset_symbol": "TEST", + "amount": 97830933 + }, + { + "owner": "TEST9CDEFfjpeVk1SGQtCHjHJnXabUjoHTyaK", + "asset_symbol": "TEST", + "amount": 206002 + }, + { + "owner": "TESTPgYzcUvfzd7Pk8iTtLYym38sxLwczteZo", + "asset_symbol": "TEST", + "amount": 7219957 + }, + { + "owner": "TEST5eBvrmbN8MLQ3X8dK2z9H2fmBjfsoAgmJ", + "asset_symbol": "TEST", + "amount": 794523 + }, + { + "owner": "TESTKyh4qt7fzxAgM985sM6nno3149W4p3VpC", + "asset_symbol": "TEST", + "amount": 3903486 + }, + { + "owner": "TESTHnvxkfucAGB3cQuAPwQpmERRaZFyJ6stU", + "asset_symbol": "TEST", + "amount": 11091853 + }, + { + "owner": "TESTDsMywSfkn2WKwYLuMbZVtG3kCRRgRu9Xq", + "asset_symbol": "TEST", + "amount": 5703124 + }, + { + "owner": "TESTMnK9rQhesSjB4PYypY2jzEGGHxa2vQy93", + "asset_symbol": "TEST", + "amount": 1921761 + }, + { + "owner": "TEST6FFirq5MWom8Wvt7h52MBismfTA34KjpC", + "asset_symbol": "TEST", + "amount": 33374808 + }, + { + "owner": "TESTQAUC8y2SDhv4oPdwFDcoMemFUu5hJi6z1", + "asset_symbol": "TEST", + "amount": 1910783 + }, + { + "owner": "TESTJmg1Svyq2vuA2pp29dCY1ebGxH6zs4Jji", + "asset_symbol": "TEST", + "amount": 4726725 + }, + { + "owner": "TESTSdaaJZGn4aLZK9mZ528snraFos2syHD4", + "asset_symbol": "TEST", + "amount": 109978 + }, + { + "owner": "TESTES2MkKaKJzfoRTVsmG6PBZrWAeBZX1JKa", + "asset_symbol": "TEST", + "amount": 2743715 + }, + { + "owner": "TESTFPx7tUff6fCtTHvQRkR4J5q2SSBmNov8J", + "asset_symbol": "TEST", + "amount": 7851132 + }, + { + "owner": "TESTD7Z3mZir1TnpF7ja5TAtxM6rMkBtar1JJ", + "asset_symbol": "TEST", + "amount": 1651861 + }, + { + "owner": "TESTFGgaqPEAiNHGGxkYxdzy3BfnjpnCrEJXk", + "asset_symbol": "TEST", + "amount": 9588757 + }, + { + "owner": "TESTDewtC7APTY7rbtWBduu3hr1c6TwuKDTHE", + "asset_symbol": "TEST", + "amount": 103262080 + }, + { + "owner": "TEST3RJXcuwdX8TrafQQFDXyEPDKEuKtajy7T", + "asset_symbol": "TEST", + "amount": 32732377 + }, + { + "owner": "TEST8h78N3f2TStr7DVp8NfyeGADF68Z9sANu", + "asset_symbol": "TEST", + "amount": 875626 + }, + { + "owner": "TESTJZFxrCMhXm2HwqVkTjszLidTQkZVTH1nG", + "asset_symbol": "TEST", + "amount": 8702 + }, + { + "owner": "TEST5mAwoXFTgY8wzeaBGhZzrUFegvLfqcK2b", + "asset_symbol": "TEST", + "amount": 87691867 + }, + { + "owner": "TEST5kPtDuw7wsHN9zxtEszdVauctTzqepKo4", + "asset_symbol": "TEST", + "amount": 12899100 + }, + { + "owner": "TEST7qrKDdrgKwjExNpKodKpK5qbQPSstkUPt", + "asset_symbol": "TEST", + "amount": 2713631 + }, + { + "owner": "TESTCPPNKiiNSZM9SHcZRdAGJ5ojeP67c4WP7", + "asset_symbol": "TEST", + "amount": 6063007 + }, + { + "owner": "TESTAZDg4TQZ5rd32zf3arbfSt928LV7cgFjs", + "asset_symbol": "TEST", + "amount": 106505802 + }, + { + "owner": "TESTLyKF6RZf8Emwfut5dF3tt6UHRZqg49wNt", + "asset_symbol": "TEST", + "amount": 10599654 + }, + { + "owner": "TEST3xtQjceteBLmzfpud5CQuq12sniSfefHc", + "asset_symbol": "TEST", + "amount": 1400156 + }, + { + "owner": "TESTVvV3ibErptbyeTiC59mo8pwtbvT8Nt8R", + "asset_symbol": "TEST", + "amount": 2478932 + }, + { + "owner": "TEST9qcrihJptwMLG3VLaDPmAKKoni9gEzfG", + "asset_symbol": "TEST", + "amount": 3287269 + }, + { + "owner": "TEST8D4S8w6dBMKQ2dyoN4TQocTjJjkqgS6WJ", + "asset_symbol": "TEST", + "amount": 894500 + }, + { + "owner": "TESTGZcMQRYdqEMuxDjGfJXXTghmdboxwiCM3", + "asset_symbol": "TEST", + "amount": 167525 + }, + { + "owner": "TESTPQxz1XULV9bAT5cAwjbnzEKwd8tbkPHkW", + "asset_symbol": "TEST", + "amount": 19047479 + }, + { + "owner": "TESTDWSth5vRpMCf6opHXAsYRf2oyiL9i8dUw", + "asset_symbol": "TEST", + "amount": 1674252 + }, + { + "owner": "TESTP2rpXy8HpYhc7eeMQvNkNzenTXnkW59Gc", + "asset_symbol": "TEST", + "amount": 1623443 + }, + { + "owner": "TESTNzNnZFfxStobwSHTzXhKScVF5zRR7qUCf", + "asset_symbol": "TEST", + "amount": 17179800 + }, + { + "owner": "TESTNfXnhQRyxY74CKxNZXLLKXr4oFPFxrqr8", + "asset_symbol": "TEST", + "amount": 98936714 + }, + { + "owner": "TESTMshwX9Rq5L2edrVSfDQEw76o76DeDxjzX", + "asset_symbol": "TEST", + "amount": 188887 + }, + { + "owner": "TESTP1u8W5mqcvsG3vpDtG2NKS33YcJJDfpvq", + "asset_symbol": "TEST", + "amount": 290498 + }, + { + "owner": "TEST4e4Rqyv354VmPj5FiEJJ9qM4nLgUePA9z", + "asset_symbol": "TEST", + "amount": 9979918 + }, + { + "owner": "TESTQGGJ31Hcrf977jsTa61BgVttZjueNyF3y", + "asset_symbol": "TEST", + "amount": 11867605 + }, + { + "owner": "TEST4GF1nnvouo9PCpij8o2kfjkG7jPnpGLR1", + "asset_symbol": "TEST", + "amount": 272229534 + }, + { + "owner": "TESTLL2CnfxbcvudW9jUDgzXHFBNgR5gbPEs5", + "asset_symbol": "TEST", + "amount": 4473656 + }, + { + "owner": "TEST468stcQMDtYu6f2wDpfydMKXnubG9ke9X", + "asset_symbol": "TEST", + "amount": 5559703 + }, + { + "owner": "TESTD34DkmudzgSQmC8VCWM8HMqC2sajzxXrx", + "asset_symbol": "TEST", + "amount": 1872664 + }, + { + "owner": "TESTjzZywi3XpnyTZK3ue5ssdsiKDMpSLodV", + "asset_symbol": "TEST", + "amount": 3334497 + }, + { + "owner": "TESTPt6VWLnhLCX8H8dx53eTVLF1K4nJQwddP", + "asset_symbol": "TEST", + "amount": 1996583 + }, + { + "owner": "TESTMrGuewuwgW5Q3rPjGy4i8iz1V7ZzJRfaL", + "asset_symbol": "TEST", + "amount": 6620914 + }, + { + "owner": "TESTFNJvPguqkQL91BF8jxkNEFWt13UPhUiwX", + "asset_symbol": "TEST", + "amount": 5128753 + }, + { + "owner": "TESTB1xMaQWcVXcnMmRK8pBWWq85kH6XYx5Zv", + "asset_symbol": "TEST", + "amount": 117098000 + }, + { + "owner": "TESTPJydUmN5CEvMsgiRGnZV9cRDyTGTNku1K", + "asset_symbol": "TEST", + "amount": 34743893 + }, + { + "owner": "TEST6LfEdLyWYT6PXkpnMyUf6BAFQrM8ykfGZ", + "asset_symbol": "TEST", + "amount": 1143736 + }, + { + "owner": "TEST8bJitTkgZWAKGdF4iCCDJtK8BN8jHJzWZ", + "asset_symbol": "TEST", + "amount": 1060476 + }, + { + "owner": "TESTBjzfPqemH8bNCyQMXVU7TbKNaxpuXopgP", + "asset_symbol": "TEST", + "amount": 8885873 + }, + { + "owner": "TEST3f5mRkwsnX7dtEQTMCVCbdrERvQKL4zM1", + "asset_symbol": "TEST", + "amount": 2430175 + }, + { + "owner": "TEST9up4u7wKz2a7QF9HeLd7UUReSgxzYwtYJ", + "asset_symbol": "TEST", + "amount": 522445 + }, + { + "owner": "TESTLTH5iDXzoaJ1b4sfdRvGK8LQXnPj2dRdh", + "asset_symbol": "TEST", + "amount": 10749745 + }, + { + "owner": "TESTEdLWf2AEnYZzp5dCAJm43Brmqq84KWgpS", + "asset_symbol": "TEST", + "amount": 325908 + }, + { + "owner": "TESTHjpqYUYuwXy1yuzJo9D4Gq9obdqeBEn5E", + "asset_symbol": "TEST", + "amount": 2807873 + }, + { + "owner": "TESTA8FKYUjkbGJG1cTqdAjnqYdWnhgkqDnZK", + "asset_symbol": "TEST", + "amount": 1011875 + }, + { + "owner": "TESTAEEed4whZgx7q2xpszHxtKW5BJQEKgFrW", + "asset_symbol": "TEST", + "amount": 4011755 + }, + { + "owner": "TESTBzTeZe2X6DHcyEXnkHf9owjwfrez7c5xh", + "asset_symbol": "TEST", + "amount": 37181913 + }, + { + "owner": "TESTGHkT6UVFxJDFX58Ck2qFw7nMy91EGsxzU", + "asset_symbol": "TEST", + "amount": 327961066 + }, + { + "owner": "TESTAjFf2dKveU72HL5i1MZj3Wzhg3PsawqQb", + "asset_symbol": "TEST", + "amount": 2961568 + }, + { + "owner": "TESTHnHrKo9xCjGkSAMKF9akn4KUsLEBMFTSo", + "asset_symbol": "TEST", + "amount": 3075940 + }, + { + "owner": "TESTA41DVe78jkU4ovRVBgttmwaYZSUV3en1B", + "asset_symbol": "TEST", + "amount": 16469295 + }, + { + "owner": "TESTar52JxYZLdWKvuiQjN21qhZu2U5ztqc1", + "asset_symbol": "TEST", + "amount": 188815989 + }, + { + "owner": "TESTNuptFDC1Jq595Et9F5bEkPKsBH7CMZ21v", + "asset_symbol": "TEST", + "amount": 8763042 + }, + { + "owner": "TEST55AoSR88rJ1CkmHXvBESc2gMSKroFe74W", + "asset_symbol": "TEST", + "amount": 6660173 + }, + { + "owner": "TEST5ySWHqfMFaKZc77gRGVQyiKcTP4zTy7r3", + "asset_symbol": "TEST", + "amount": 11621537 + }, + { + "owner": "TEST91nFMJ98LWFaJpCTRtCr5nxG1PBHEzjKc", + "asset_symbol": "TEST", + "amount": 1666987 + }, + { + "owner": "TESTDDXHdMB1xguqAh6MwaFRmGBvtU1t2BNyB", + "asset_symbol": "TEST", + "amount": 1738133 + }, + { + "owner": "TEST5hKdZbMWbz7AVFHXe2iRnsX18ijuj5Pi8", + "asset_symbol": "TEST", + "amount": 6267497 + }, + { + "owner": "TESTFjVLanuTM5RgWu9ZH2nGow9tQA48gcvr6", + "asset_symbol": "TEST", + "amount": 512418 + }, + { + "owner": "TESTLpVXg8DNrygnb3dbBFKDzfM58Fo1DdJ28", + "asset_symbol": "TEST", + "amount": 3317229 + }, + { + "owner": "TEST8a3HosrwsmQQPuwQcaF1oB5zdLgAQiGGg", + "asset_symbol": "TEST", + "amount": 16659574 + }, + { + "owner": "TESTD62h2wk9gXnyGCotPMk1i4P2oz64Wdc4d", + "asset_symbol": "TEST", + "amount": 1275816 + }, + { + "owner": "TESTCwo4SJfTScMEfFXJLNZcB8nj2QJUdvniC", + "asset_symbol": "TEST", + "amount": 32065987 + }, + { + "owner": "TEST7ttehHhgypHyn6dSB4ScrNULSx5V9wbdk", + "asset_symbol": "TEST", + "amount": 1650718 + }, + { + "owner": "TEST7x3V4XKcZTo8vS6N3Bakf4z9U5jxUtx4L", + "asset_symbol": "TEST", + "amount": 28049950 + }, + { + "owner": "TESTBzhGbiTX64TGYUWxA6f6RkBE1QhGJSiRB", + "asset_symbol": "TEST", + "amount": 13066610 + }, + { + "owner": "TESTG4h8fdH3QLphmi6bNiacFuttKd9Y1qJqx", + "asset_symbol": "TEST", + "amount": 8118147 + }, + { + "owner": "TESTAGvoiqynxwoJeM9XaqRasD82tp5F1R5gv", + "asset_symbol": "TEST", + "amount": 5602779 + }, + { + "owner": "TEST5Poj1ttyQxDzzQ7Pxi3VbfwjqsXQZbVXD", + "asset_symbol": "TEST", + "amount": 24107077 + }, + { + "owner": "TEST7o5HDYa1QH1fmb5eWPzNKhgi33Uma4DZP", + "asset_symbol": "TEST", + "amount": 15527382 + }, + { + "owner": "TESTHkZhRmA65FRjKH79pP1nhHG9mDmQ6Qwqu", + "asset_symbol": "TEST", + "amount": 1202648 + }, + { + "owner": "TESTPqBFdEGwuj4uLZCG3QxFGqod5qSCEUYLU", + "asset_symbol": "TEST", + "amount": 37266404 + }, + { + "owner": "TEST2wFhU1C1d1uQhoNGTU1MjgSZNXiPuiuxF", + "asset_symbol": "TEST", + "amount": 68669200 + }, + { + "owner": "TESTHPW92CmV9jGKDnpFmVjgMFg4VaLiaqmG4", + "asset_symbol": "TEST", + "amount": 114375265 + }, + { + "owner": "TESTCXvY951fVmishqE8brWy6QHkYK8McA2Dz", + "asset_symbol": "TEST", + "amount": 1005371 + }, + { + "owner": "TESTHp4LL1Tb46nVPLHGLTzb2NeepjrRNhuXS", + "asset_symbol": "TEST", + "amount": 2044330894 + }, + { + "owner": "TESTP2TE5wtDgezZMVNpb5Chw8N4VfzziGoR1", + "asset_symbol": "TEST", + "amount": 343589 + }, + { + "owner": "TESTPPiFMbPPNYZzYwu45awiYyjJ1LGLF87rZ", + "asset_symbol": "TEST", + "amount": 69584152 + }, + { + "owner": "TEST6Q7zZtaVZEaLsGXe3yoSXjfkhZsnso8zk", + "asset_symbol": "TEST", + "amount": 202068 + }, + { + "owner": "TESTBATYnit7n4D33GE6Qcv5AorUm3AHe6Mi", + "asset_symbol": "TEST", + "amount": 521317714 + }, + { + "owner": "TEST98NeDgoWvXcba8Uo5k8iCAgAKHMLCEA5Z", + "asset_symbol": "TEST", + "amount": 33927990 + }, + { + "owner": "TEST8k3TiRg2ogbnb7hn8CLpPnmejkrvHua8F", + "asset_symbol": "TEST", + "amount": 446835 + }, + { + "owner": "TESTNqn24bxT4R5eoaxh4X6JVNAhsKb1rEXJz", + "asset_symbol": "TEST", + "amount": 54116440 + }, + { + "owner": "TESTGN5DKC3RrUqC6KutnYCLb6hBujiMAb28v", + "asset_symbol": "TEST", + "amount": 10264356 + }, + { + "owner": "TESTBLjCt1TSueJhGNZuNNnr43EwMSHsRKioU", + "asset_symbol": "TEST", + "amount": 24355761 + }, + { + "owner": "TESTPcMAADinqQR93beeSKZZnnGK8PkfKefEQ", + "asset_symbol": "TEST", + "amount": 398743 + }, + { + "owner": "TESTrLNUCsUuPiNJpRGkKMfRmXxUs3nqGJK2", + "asset_symbol": "TEST", + "amount": 10309284 + }, + { + "owner": "TESTLDAKcjLmTmDYEUJpbeZqdQqXhDtBk18s2", + "asset_symbol": "TEST", + "amount": 3363645 + }, + { + "owner": "TESTKyHRhLj6YmMQoF2n2LTH6e9ChG46TMJgS", + "asset_symbol": "TEST", + "amount": 5087743 + }, + { + "owner": "TEST4FijceeQcEcKrMzyUQxKDFRvPeDQALqeD", + "asset_symbol": "TEST", + "amount": 2149916 + }, + { + "owner": "TESTAcfLQGZG4YxNFBwqmYcWA5ZMra8Muk7aU", + "asset_symbol": "TEST", + "amount": 235992 + }, + { + "owner": "TESTBDsP7LMfRLMSPvuhykW5TCgFsBN8Rrga", + "asset_symbol": "TEST", + "amount": 897011 + }, + { + "owner": "TESTJvyCAEgcevYXPHFDwp4STAwUubzGJ2MF8", + "asset_symbol": "TEST", + "amount": 810693 + }, + { + "owner": "TESTJNkWBsBVF8WQ2tTtmdBvtyK5vDMnArYKx", + "asset_symbol": "TEST", + "amount": 4862250 + }, + { + "owner": "TESTD4jW4MUbRuTkCvkU4vaMYgojGtipBsWjK", + "asset_symbol": "TEST", + "amount": 222383 + }, + { + "owner": "TESTKnBLWwpgyyNwHKSHJQAVvSwwWSjJDS3uw", + "asset_symbol": "TEST", + "amount": 2683834 + }, + { + "owner": "TESTAneweorifRk6SZrchw8gz7H8s9qAMCAcB", + "asset_symbol": "TEST", + "amount": 1621295 + }, + { + "owner": "TEST3pVGG9tUio1usUoKe4LvMK2por9xJj6U6", + "asset_symbol": "TEST", + "amount": 69028394 + }, + { + "owner": "TESTFHRY7SPUtWbqui9rpvDLntdXH1rPCWuiB", + "asset_symbol": "TEST", + "amount": 412543 + }, + { + "owner": "TEST34ZMFgK7FgHuHa5GgrkG5h77YijvGRqHd", + "asset_symbol": "TEST", + "amount": 1547118 + }, + { + "owner": "TESTGskTo2iEtfojAAGxCQY36ueXw3yDPhGsy", + "asset_symbol": "TEST", + "amount": 688600 + }, + { + "owner": "TEST8UWaYMHwAm9visQvgvv6nZTFjU11swKEi", + "asset_symbol": "TEST", + "amount": 69566 + }, + { + "owner": "TESTLy2woB3c4ZrmeJwoiJtNDaaYkYB8UB8nS", + "asset_symbol": "TEST", + "amount": 5211117 + }, + { + "owner": "TEST4Vje7qUzAXVJNJWwknS5nCtwMREUxEHbY", + "asset_symbol": "TEST", + "amount": 158829 + }, + { + "owner": "TESTPyrBSW7qNDoKred5Tbi3dCJavMVMJJD8", + "asset_symbol": "TEST", + "amount": 5119317 + }, + { + "owner": "TEST29A6rzjTSVeptrMjM8kxQdPY5GD3KpwZF", + "asset_symbol": "TEST", + "amount": 6599137 + }, + { + "owner": "TEST2sPDyE7MS8XmMm63nrV9HF5ivm6SKXHeS", + "asset_symbol": "TEST", + "amount": 6776775 + }, + { + "owner": "TEST7Pjk5LUNZ93jfgdtyjYcW63itDoHZ3egV", + "asset_symbol": "TEST", + "amount": 886138 + }, + { + "owner": "TEST9sbHpZNThq8QWEW7g9DYbdgpy4ycegsPN", + "asset_symbol": "TEST", + "amount": 1490878 + }, + { + "owner": "TEST6xq4Z7AEu5jG4JZS2mFNpvvxGesHbv4Vf", + "asset_symbol": "TEST", + "amount": 1507889 + }, + { + "owner": "TESTGtx4UJxTwX9YE9CxzXa9gL1HacC6iymEz", + "asset_symbol": "TEST", + "amount": 2755251 + }, + { + "owner": "TESTHq6qcLLnCD5PU4VUPvUbPAC6CfXuRchxa", + "asset_symbol": "TEST", + "amount": 99715 + }, + { + "owner": "TESTDQqFvctvPxBiCXVYj7iwHdrtyw2r5jAqs", + "asset_symbol": "TEST", + "amount": 8294450 + }, + { + "owner": "TESTKwgtd2z4yp4ZdtYX9eh8M54RD6cmC9b19", + "asset_symbol": "TEST", + "amount": 109098 + }, + { + "owner": "TEST2sSHBgCmsvxPFXkXTiLW8jF7GBDmUtPHv", + "asset_symbol": "TEST", + "amount": 104678364 + }, + { + "owner": "TESTH9r4ScTSNMmZkiTLsVnJG5NUzpg8jqbW5", + "asset_symbol": "TEST", + "amount": 2585654 + }, + { + "owner": "TESTN485YQkPFjmwg1zJLe8wYRA8RXETGtWbw", + "asset_symbol": "TEST", + "amount": 9316996 + }, + { + "owner": "TEST2pQ2S2dP4vhS4G4GuRHP9dYuzH8aR9A1Y", + "asset_symbol": "TEST", + "amount": 198003 + }, + { + "owner": "TEST6zxTVPVKGjFv2neWGi5LhqBPdLLgCSp61", + "asset_symbol": "TEST", + "amount": 1007527 + }, + { + "owner": "TEST6VxsMk8FEQW6pP9aLnTbmkdr9qZtdVseH", + "asset_symbol": "TEST", + "amount": 11497740 + }, + { + "owner": "TEST8biZ4VBmZ8JqYPoyx6EQUPJAkvnLGPt4m", + "asset_symbol": "TEST", + "amount": 204414 + }, + { + "owner": "TEST3zvYEGe2z2MfHND4sGFCx4LhenwhBcpaZ", + "asset_symbol": "TEST", + "amount": 11952400 + }, + { + "owner": "TEST85A5ftviF3xnefRFMrCjM28qVMg9QS5Pi", + "asset_symbol": "TEST", + "amount": 10008091 + }, + { + "owner": "TESTFgYFHLxmPa1KziLKtsP2KxdJMMYp92jmW", + "asset_symbol": "TEST", + "amount": 332657 + }, + { + "owner": "TEST9fFYWaWxAdS6xMifG4vGjweeyn6DMLT63", + "asset_symbol": "TEST", + "amount": 193612667 + }, + { + "owner": "TEST58zSf34Jn9ZFAWrNmmpUoeEkqViQjAjmq", + "asset_symbol": "TEST", + "amount": 8194015 + }, + { + "owner": "TEST2mxn2PqDMQNeBJMiwXYqF2n6mu7J1eNBx", + "asset_symbol": "TEST", + "amount": 30016327 + }, + { + "owner": "TEST7gXQpVHx89HBqoNmMsyJQisbNotFDW73M", + "asset_symbol": "TEST", + "amount": 12443113 + }, + { + "owner": "TEST6UwAgY9U3wtK1ku3rcKBicPkUqeH5Sh86", + "asset_symbol": "TEST", + "amount": 7310267 + }, + { + "owner": "TESTMDy6dcuXBqbH5gbC9mWPSyxCUfdA2a81P", + "asset_symbol": "TEST", + "amount": 40888 + }, + { + "owner": "TESTN2RLxR8eXDNJrbhoV57rBktXUVvUWyyVP", + "asset_symbol": "TEST", + "amount": 9951887 + }, + { + "owner": "TEST3mrJ8kxeBQge2MTgMoxNFTem4oZzmgTW7", + "asset_symbol": "TEST", + "amount": 2641615 + }, + { + "owner": "TESTKeUj6Fp9Uv4uoX6Ty1wVB2K7wvNBHhXW4", + "asset_symbol": "TEST", + "amount": 3392599 + }, + { + "owner": "TESTA3RZuazzrSk94PiKAdfQicXiTgDZCTq9c", + "asset_symbol": "TEST", + "amount": 3355916 + }, + { + "owner": "TESTPLDwKLWVqMZiNhRm1YzfN4bvWBmsWkAjZ", + "asset_symbol": "TEST", + "amount": 3230 + }, + { + "owner": "TESTJHStEv7dhSu7vAuHEVeN8moQ2TRxFVF9P", + "asset_symbol": "TEST", + "amount": 2033 + }, + { + "owner": "TESTL6GrHyGXsxv4WTzRy3MimiQ6PuGVw1JcT", + "asset_symbol": "TEST", + "amount": 10476633 + }, + { + "owner": "TESTKRAMvK9KFPonnmisJkq9oVARWRuRfYjT4", + "asset_symbol": "TEST", + "amount": 5639944 + }, + { + "owner": "TESTGQe2PoFDJEnNthCDVnpBVGRbXrcSiQZa8", + "asset_symbol": "TEST", + "amount": 5359767 + }, + { + "owner": "TEST7Vt7kyoZ3DfvKWqzxvAs1zik1DnSH2L3q", + "asset_symbol": "TEST", + "amount": 66790813 + }, + { + "owner": "TESTrdUXcwf6EFzmceqFTGauPXTNno8AFx9s", + "asset_symbol": "TEST", + "amount": 845721 + }, + { + "owner": "TESTNv2W36RftG4Tm7jobxqD6WJ9A6Nzf45AB", + "asset_symbol": "TEST", + "amount": 34210213 + }, + { + "owner": "TEST86hQm5GQZsVMeAnjBLqvNwBLZLRyeAsFb", + "asset_symbol": "TEST", + "amount": 12818640 + }, + { + "owner": "TESTFdyvDd2776mGgU9cchnmLxP75DpTkM4Yw", + "asset_symbol": "TEST", + "amount": 19410636 + }, + { + "owner": "TESTFRA7KgKVK2GRMuAAwvSoumiRPVjURBmnD", + "asset_symbol": "TEST", + "amount": 2066508 + }, + { + "owner": "TESTN6ivQ4HUPvaL5T1Syn56hPYgJVwSdRD3K", + "asset_symbol": "TEST", + "amount": 47397 + }, + { + "owner": "TEST5aoGTzbh11H9DDjRqnrk8EFga1cs1ZtJA", + "asset_symbol": "TEST", + "amount": 301730 + }, + { + "owner": "TEST8wdQV3YN6ag695anp9hmGfdhGC9fXJmNv", + "asset_symbol": "TEST", + "amount": 346552 + }, + { + "owner": "TESTEL6t985yKJph4DhJGWn7bzd9unQuxkXV4", + "asset_symbol": "TEST", + "amount": 6608711 + }, + { + "owner": "TESTNMbQXtcKeqWYCjgALhjN6izvHpehcdEsP", + "asset_symbol": "TEST", + "amount": 435190 + }, + { + "owner": "TEST6sFhi3K9zNn5fHQyndVdskaxiTkf7d51j", + "asset_symbol": "TEST", + "amount": 479830490 + }, + { + "owner": "TESTGq6JraoWw7kdg1wG6Q7hvJA8sXDYThUeh", + "asset_symbol": "TEST", + "amount": 4745380 + }, + { + "owner": "TESTCeYfncC8aYQBNSyJp6JovgKQCdAQCoisN", + "asset_symbol": "TEST", + "amount": 1090830 + }, + { + "owner": "TEST5KMARR5AN8DoJcnh2gxSrHMjeBFLPvov8", + "asset_symbol": "TEST", + "amount": 8610159 + }, + { + "owner": "TESTGxqarqkUFGBrmzteDfcXw1EpyJwADJLcq", + "asset_symbol": "TEST", + "amount": 30115372 + }, + { + "owner": "TESTQ3rXPQJMdBwvfS4YxiVVu39n9xEkcRghq", + "asset_symbol": "TEST", + "amount": 47096606 + }, + { + "owner": "TESTLDs3JdXmMtBVG4AP5YNsSRpkHNXadRN3k", + "asset_symbol": "TEST", + "amount": 29030790 + }, + { + "owner": "TESTNvrFEB9mA2rwQD2FJie7pxC19KN7QUeEh", + "asset_symbol": "TEST", + "amount": 3309 + }, + { + "owner": "TESTNp5u4qtRehaRs2XrMoGaMGZvWqSkA65Zz", + "asset_symbol": "TEST", + "amount": 3178178 + }, + { + "owner": "TESTEvamgZVJ7AoRbcqQn4kMzEtYhbeAPCkzC", + "asset_symbol": "TEST", + "amount": 11934037 + }, + { + "owner": "TEST36d2F5bSSr72itFw1XNaacdDbjNyszFPn", + "asset_symbol": "TEST", + "amount": 161189 + }, + { + "owner": "TESTGLsTDGoVuQypdosuScLU5SM6dFBFWkhmf", + "asset_symbol": "TEST", + "amount": 29490964 + }, + { + "owner": "TESTEhyLzNK2TkwN7ZsaTBJPB5fWg41B3iyBh", + "asset_symbol": "TEST", + "amount": 21160200 + }, + { + "owner": "TESTMVVJCyZnzCHNFAAfsnbVYhkGJM2VGdhYq", + "asset_symbol": "TEST", + "amount": 10095505 + }, + { + "owner": "TESTDBMeA2QA3imsdwsSHmkAbGhu3WqDHBS2a", + "asset_symbol": "TEST", + "amount": 77085586 + }, + { + "owner": "TEST9GvxY8CFRjVqGVdG8gsZNBnqPkd2xWCDC", + "asset_symbol": "TEST", + "amount": 203973 + }, + { + "owner": "TESTKDucBVdJA3hcbtB1EJQ5NSMDbA8T3VJKA", + "asset_symbol": "TEST", + "amount": 696004 + }, + { + "owner": "TEST65dzuXmsiYmbxUdL3N6oCKSM3ihJj6cNy", + "asset_symbol": "TEST", + "amount": 5252544 + }, + { + "owner": "TEST2MgbgDkQWGXrg3zoJhX1Tx5TSykVBKKdR", + "asset_symbol": "TEST", + "amount": 25714286 + }, + { + "owner": "TESTDfQMuQ23SAmQoKGvnsuTjFngSu116K8oQ", + "asset_symbol": "TEST", + "amount": 335631 + }, + { + "owner": "TESTKmsCEzQuDueVXu4NxuNXVkUygfAXdgJ2n", + "asset_symbol": "TEST", + "amount": 317497 + }, + { + "owner": "TEST5JDCobvUDsPTEWB4c9TpHjFNwcR47Emfp", + "asset_symbol": "TEST", + "amount": 3139372 + }, + { + "owner": "TESTBHFLyJQDdHxgARKynfA5A2zDf9RzS5EfP", + "asset_symbol": "TEST", + "amount": 1710667 + }, + { + "owner": "TESTArtVFJ2Eq63hu8MzzS5y7oqx8vvJDDx6A", + "asset_symbol": "TEST", + "amount": 34957880 + }, + { + "owner": "TESTL8EBaZSwHou8qK4jtpR9Z2xqLsyhPKKru", + "asset_symbol": "TEST", + "amount": 4582351 + }, + { + "owner": "TESTJCP49fJRUsjn6g3rBY7eeghn17eFRg6M6", + "asset_symbol": "TEST", + "amount": 9323778 + }, + { + "owner": "TEST3oPdh394LwjDnAAop1iMSujLMwsBuHLjQ", + "asset_symbol": "TEST", + "amount": 1639 + }, + { + "owner": "TESTJ4Q8RoFuNFjbNo8XwgwWSo4gzdX8hDrMU", + "asset_symbol": "TEST", + "amount": 1635209 + }, + { + "owner": "TEST4bZemzCZdaXe9rwwJ9tHvXEc4e77xwXFW", + "asset_symbol": "TEST", + "amount": 481897 + }, + { + "owner": "TESTGSi7KMRnidfepeLAJ822zXCLpMEQzpEk5", + "asset_symbol": "TEST", + "amount": 10001278 + }, + { + "owner": "TESTB3ugJ1CUgGwMmn6jztg4vTjPdfLNdFe8N", + "asset_symbol": "TEST", + "amount": 4610509 + }, + { + "owner": "TEST6A1Y8fHNQCRY9N5GQV9oiJcGEUudzZXmm", + "asset_symbol": "TEST", + "amount": 149873 + }, + { + "owner": "TESTFY18wjvMtSNLRfcEorUJd7VVWReVjVt5Q", + "asset_symbol": "TEST", + "amount": 5136000 + }, + { + "owner": "TESTKoMam57WgDrfi5LF4M6Vw6YyuE6WuUdkm", + "asset_symbol": "TEST", + "amount": 607164 + }, + { + "owner": "TEST3Lw45ixjZKBHiG25AYH7EVLR9WFN967FD", + "asset_symbol": "TEST", + "amount": 566428 + }, + { + "owner": "TEST2zS4RwnZHYuJkcn9gwCmhyqJ5k14ZC7HM", + "asset_symbol": "TEST", + "amount": 3435222 + }, + { + "owner": "TEST9STtDwF1DoJqAmQ6PkQvN4mKGwXGvXdz7", + "asset_symbol": "TEST", + "amount": 39370092 + }, + { + "owner": "TESTJjwowMr79auSsrRGGv8kF5atHESLC855B", + "asset_symbol": "TEST", + "amount": 947565 + }, + { + "owner": "TEST31S9hGo84sXW5TXv6gftRXuVSMhdYC13B", + "asset_symbol": "TEST", + "amount": 16359223 + }, + { + "owner": "TESTHwHFFLmpz7xcqtfrZ9SQZzj2nreYL9Qjz", + "asset_symbol": "TEST", + "amount": 10141746 + }, + { + "owner": "TESTBjL3xHFLA9GPjauoje3HDtbZEfAEUmEfs", + "asset_symbol": "TEST", + "amount": 8886406 + }, + { + "owner": "TESTNDnAJdTtNmggK2ARWTRjhASRwKAHBJnN4", + "asset_symbol": "TEST", + "amount": 58111944 + }, + { + "owner": "TEST2ZnjyJWZcaZGxYMmhzZnG5o7pxsdkMndT", + "asset_symbol": "TEST", + "amount": 1889644 + }, + { + "owner": "TESTGcZLqo8Pdq9h1i8SYin9bKpQVfp6k1tcb", + "asset_symbol": "TEST", + "amount": 5593314 + }, + { + "owner": "TESTBSWssA3rZeScpJEkHdyGLWt3SGhVuLNHt", + "asset_symbol": "TEST", + "amount": 69175108 + }, + { + "owner": "TEST3B16GFVJnao4MvoVP5CTziGRHDZdSpkqB", + "asset_symbol": "TEST", + "amount": 4926945 + }, + { + "owner": "TEST6T7kTd8LFjLQJNSN5g9RRqPTLViHa8RMq", + "asset_symbol": "TEST", + "amount": 34971238 + }, + { + "owner": "TEST9W3fyTga7qtJk88Nnq8uXN9N7ycxvhNpY", + "asset_symbol": "TEST", + "amount": 67800476 + }, + { + "owner": "TESTBXJ9YzQFaFsaRJuBdbCihqndFn4tct76m", + "asset_symbol": "TEST", + "amount": 5965112 + }, + { + "owner": "TEST3CQ1atWPx4MNxZeMmtiDpXW7i9V8xo5PY", + "asset_symbol": "TEST", + "amount": 1666710 + }, + { + "owner": "TESTJjA8MDfBN2h8QgP5sAXzh9ZmzXKaZhjsq", + "asset_symbol": "TEST", + "amount": 624525 + }, + { + "owner": "TESTBYueKmKiBTPBtwhonWuo2vXRNCF32tskc", + "asset_symbol": "TEST", + "amount": 2194417 + }, + { + "owner": "TESTBG7RKBHzsV3GqyvLJd5oLVwnhDhsCs2Sh", + "asset_symbol": "TEST", + "amount": 1718067 + }, + { + "owner": "TESTF2Vono4WMCy3QV6x17DrGnajpPWXtz9Yz", + "asset_symbol": "TEST", + "amount": 3994869 + }, + { + "owner": "TESTDTFenQc5NiGGPgGaMZ865BzPNEXXWMRTM", + "asset_symbol": "TEST", + "amount": 2448101 + }, + { + "owner": "TEST4vAgYRqymy7xLhPwVcjeHCDUDeSBSvHKc", + "asset_symbol": "TEST", + "amount": 16381272 + }, + { + "owner": "TEST9NKvFdirdUSJMsptc7VQT9ZemLRgQ8t5L", + "asset_symbol": "TEST", + "amount": 68866286 + }, + { + "owner": "TESTAmhrqcaXTJXeeThesLDLbsjFDK22B7dba", + "asset_symbol": "TEST", + "amount": 1675351 + }, + { + "owner": "TESTExc1UdKHkuLr6N86HH44QjBNgkXSS6EfG", + "asset_symbol": "TEST", + "amount": 461145 + }, + { + "owner": "TEST33ok77ZYW5ZX6eVEZ7a475bTWGqvJmU6A", + "asset_symbol": "TEST", + "amount": 2450664 + }, + { + "owner": "TEST5fhYfJQrvtgniBqfW48QbFSLnUCBctRbY", + "asset_symbol": "TEST", + "amount": 23440765 + }, + { + "owner": "TESTKrRNbwfbb8hsR55LJYKHZzcwVfqNcXWM7", + "asset_symbol": "TEST", + "amount": 2868698 + }, + { + "owner": "TEST2xAB9j6VDhm6MZMHzBpL8cRjmz8z9uyDh", + "asset_symbol": "TEST", + "amount": 16635150 + }, + { + "owner": "TESTLqZ1CAh48ggQWVe6pqNo1poiWrUJ7A4R8", + "asset_symbol": "TEST", + "amount": 10196153 + }, + { + "owner": "TEST6sFszcZrZXUnFtKjsQ6xWoJN5sVZ7GhPk", + "asset_symbol": "TEST", + "amount": 131964137 + }, + { + "owner": "TESTPyr5nFe2o2RifK89BTwuVxoghhXKwDPoM", + "asset_symbol": "TEST", + "amount": 2019905 + }, + { + "owner": "TESTLWJfKZmxKKMt4McsBxoMeZxPqpihZRYam", + "asset_symbol": "TEST", + "amount": 38660681 + }, + { + "owner": "TEST2vzSDVsJFv3VNg6kEtVytbWkB5CQpxkcC", + "asset_symbol": "TEST", + "amount": 26443320 + }, + { + "owner": "TESTdWkvEaDVFvA75RjEyDXxqBJUJxYdV3RP", + "asset_symbol": "TEST", + "amount": 3094625 + }, + { + "owner": "TESTBXXoVkcugJ9h5KPrfQoXDBxxEahcUXrWd", + "asset_symbol": "TEST", + "amount": 2750394 + }, + { + "owner": "TEST8vv82HM5Es4QcPSPTr4pjWmXvskKeNv5M", + "asset_symbol": "TEST", + "amount": 23640000 + }, + { + "owner": "TESTEBuAjv1Cs1Yu3dK1dTPRnpwvs9JXwo9J2", + "asset_symbol": "TEST", + "amount": 17261695 + }, + { + "owner": "TESTJXDDsDJeUkrizmPsFu7uTXxtZgRrBCXbo", + "asset_symbol": "TEST", + "amount": 1739352 + }, + { + "owner": "TESTBiyyM3t4HdTEd6LpuoZAtrYwJBgVjYwkR", + "asset_symbol": "TEST", + "amount": 1306721 + }, + { + "owner": "TEST6cKNvfAA1hs3guuUzhY4bStvfr1EYkG4z", + "asset_symbol": "TEST", + "amount": 11401240 + }, + { + "owner": "TESTLUszmLGynJkRPEEKtjjYGLWfE7n8iyqwy", + "asset_symbol": "TEST", + "amount": 2975199 + }, + { + "owner": "TESTPcB3r68SKcGxvGm82hJfWq2EzqwdPcGHq", + "asset_symbol": "TEST", + "amount": 97436 + }, + { + "owner": "TEST3Y42JQofWSCrFbgimroRQM77pNFdmszhc", + "asset_symbol": "TEST", + "amount": 12527394 + }, + { + "owner": "TEST6PEpLd3K84eREWcFxan2khw4g681E6kht", + "asset_symbol": "TEST", + "amount": 16460794 + }, + { + "owner": "TESTNFgDd1JQfTpKrapkJnAdvZ6LgQtaykRGP", + "asset_symbol": "TEST", + "amount": 6872267 + }, + { + "owner": "TEST2aqMdkwWvwGemVPWeAJdrh5kLzhPUgaha", + "asset_symbol": "TEST", + "amount": 1245480 + }, + { + "owner": "TEST3BrTNjQLVMtrtxVbduUaKymMCZqnpDdHJ", + "asset_symbol": "TEST", + "amount": 1079992 + }, + { + "owner": "TESTmAHtoEGYQaJCajcZKWzN5Bq6ctYwTdjY", + "asset_symbol": "TEST", + "amount": 7159228 + }, + { + "owner": "TESTMFYQpUkPPz9aKByrfwTd59VHugk4CHbFR", + "asset_symbol": "TEST", + "amount": 3012578 + }, + { + "owner": "TESTA4YNTMaMnHmAVPPTDgiR3MEJbgSADCtSi", + "asset_symbol": "TEST", + "amount": 1469308 + }, + { + "owner": "TESTJvNYBwNn3iiMjeKb3yHDD7KVpyoWkzf5a", + "asset_symbol": "TEST", + "amount": 7501048 + }, + { + "owner": "TESTABRmirmcjV7U4vEVpAofFxz4hJh9LYYv7", + "asset_symbol": "TEST", + "amount": 3638247 + }, + { + "owner": "TESTJ7v1tZFdVL3fzqwRVMwLtvcqtaw3vekQz", + "asset_symbol": "TEST", + "amount": 1692370 + }, + { + "owner": "TESTHAXF7AGgRBzbgjberHiJtCFbPKaRNSDFy", + "asset_symbol": "TEST", + "amount": 1181513 + }, + { + "owner": "TESTHWpA29umrwLDEeaEmEK32o9vVoWWMXzLa", + "asset_symbol": "TEST", + "amount": 779034 + }, + { + "owner": "TEST4eHn7NiQnm1eHzTUmmyrFKqJNt5RSKAxY", + "asset_symbol": "TEST", + "amount": 2391548 + }, + { + "owner": "TESTPoDS2nj9sLJm21S5jVzva7a6Hfm5s4PHy", + "asset_symbol": "TEST", + "amount": 1520435 + }, + { + "owner": "TESTNzDBNb1kUmHfMkhPafNZJYy1ShfYUbfAa", + "asset_symbol": "TEST", + "amount": 1620968 + }, + { + "owner": "TEST37Pgxq41f8fV9rLevLLYbDz7moYazn68E", + "asset_symbol": "TEST", + "amount": 10131039 + }, + { + "owner": "TEST7aFLtUeNk9CEeCnwPN3RtgtNTzZpAzo4g", + "asset_symbol": "TEST", + "amount": 1379928 + }, + { + "owner": "TEST5eEdv3aXwxPB4rRqB4ef7xCmpWQKuvan8", + "asset_symbol": "TEST", + "amount": 32371187 + }, + { + "owner": "TESTNvkfraSKKLHvChfP6rXvNyDFFWifMUvZE", + "asset_symbol": "TEST", + "amount": 11810975 + }, + { + "owner": "TESTKCkMKe6AYuxEmCDa4Yhv8TLKqSS1pmUqZ", + "asset_symbol": "TEST", + "amount": 3066890 + }, + { + "owner": "TESTFeME2b9FKkMRTSxmLWLTUwbDKw3AsZuuY", + "asset_symbol": "TEST", + "amount": 19891013 + }, + { + "owner": "TEST5eo4qWwLyg81knRDNK91wTfd7rXCS3MwW", + "asset_symbol": "TEST", + "amount": 1953412 + }, + { + "owner": "TESTP6L1KJJ9hya5aHi6MjQZ6CZJv1FjXBThC", + "asset_symbol": "TEST", + "amount": 1308690 + }, + { + "owner": "TESTBg27rgEXp6QJEzdNNyHicegeFpT34TTWt", + "asset_symbol": "TEST", + "amount": 8650405 + }, + { + "owner": "TESTML2hAhVLeGKQx7hMt5DfnTitmY8GDgtDM", + "asset_symbol": "TEST", + "amount": 3266590 + }, + { + "owner": "TESTC5Z7pjPxZR2ocbHCkoxek1xGh67erYYJB", + "asset_symbol": "TEST", + "amount": 13510009 + }, + { + "owner": "TESTE4ZoDnLKRamj74nxRqPf9QqFoQEZSWhrM", + "asset_symbol": "TEST", + "amount": 3949530 + }, + { + "owner": "TEST3fZDGKrBT9FHsTgrwcoAtF3r9cx7wsPPQ", + "asset_symbol": "TEST", + "amount": 2466543 + }, + { + "owner": "TESTMrz4U6eRYrE6biA4iP1RZns9Y29emvrUT", + "asset_symbol": "TEST", + "amount": 494569 + }, + { + "owner": "TESTCwM9mYTHhRjkQjCDNCuaovs6FK3p719fo", + "asset_symbol": "TEST", + "amount": 11767321 + }, + { + "owner": "TESTMrUJKic5WW5EoRFdtHdy93faXgAMdoQ9", + "asset_symbol": "TEST", + "amount": 1175089 + }, + { + "owner": "TEST7n4wNhQG2ouvuxphv4Yy8oRFzT4LCwwXt", + "asset_symbol": "TEST", + "amount": 979675 + }, + { + "owner": "TESTA4E3hXCEJf6fr5QieXhiJoeTtqLqqvhHc", + "asset_symbol": "TEST", + "amount": 3673953 + }, + { + "owner": "TESTMQcDvPdQkoXjmATbz7i8zQSigJz8wxRgM", + "asset_symbol": "TEST", + "amount": 67518095 + }, + { + "owner": "TESTD7beaX61fRhAtnNyGPNnNdBH8H86wVbxo", + "asset_symbol": "TEST", + "amount": 12274010 + }, + { + "owner": "TESTNaAHjtaKbgNgdpamPYixsGMBwyEs58dBr", + "asset_symbol": "TEST", + "amount": 10488914 + }, + { + "owner": "TEST9gTGkEuCszWY4e42gx3eNVW8NYCWki5dq", + "asset_symbol": "TEST", + "amount": 17253750 + }, + { + "owner": "TEST4BkH4d74HN1WNVYTHN6XKqALwyxa4eseB", + "asset_symbol": "TEST", + "amount": 1677682 + }, + { + "owner": "TESTP2Txs7WkR7XftYjKde4PTxGVQyCXGsgKh", + "asset_symbol": "TEST", + "amount": 4481189 + }, + { + "owner": "TESTKLStxrXfwXAjLZtZDuYAyXMRmJS1WBCPL", + "asset_symbol": "TEST", + "amount": 2880609 + }, + { + "owner": "TESTM7jtzAox3ixi3pPKSPamqTQ5TRmakgW2c", + "asset_symbol": "TEST", + "amount": 996433 + }, + { + "owner": "TEST5nHhC1f6ekRbRcNfVo8qaXoL1imBbHt8o", + "asset_symbol": "TEST", + "amount": 1462928 + }, + { + "owner": "TEST9ueDweMEYKQUVy5oeqkYPRibkHGioQL39", + "asset_symbol": "TEST", + "amount": 20455 + }, + { + "owner": "TESTBejdf99AdykRoYXXsGw77vYqsrByvsU8Z", + "asset_symbol": "TEST", + "amount": 13226368 + }, + { + "owner": "TEST5DttXH9EupVXyqr6Acghu9rvAuJfev5fq", + "asset_symbol": "TEST", + "amount": 27067306 + }, + { + "owner": "TEST2JNLs94efKPkwjcqD9NriMVnLnPkgfBj2", + "asset_symbol": "TEST", + "amount": 3149 + }, + { + "owner": "TESTEHPYqqcco5r9fs8UFyLrgoa6A73sRZVMw", + "asset_symbol": "TEST", + "amount": 3078476 + }, + { + "owner": "TEST4XgaW6V39rBYtgaiMKfUcJksC9k1vm9Mz", + "asset_symbol": "TEST", + "amount": 597496 + }, + { + "owner": "TESTBxc51VzydrpzDFBBcUXCXXhCPcWqmpoq3", + "asset_symbol": "TEST", + "amount": 10114157 + }, + { + "owner": "TESTBswrcaGt4fvnP9hvmEXCvaPsDEsHBSX9o", + "asset_symbol": "TEST", + "amount": 34971238 + }, + { + "owner": "TESTNLf1p43Bps6DdZquBUhgL5YfDsTEumZcd", + "asset_symbol": "TEST", + "amount": 82527586 + }, + { + "owner": "TESTMcJNq6Twie9R5E6W8yH6fdfLamxNYbjX5", + "asset_symbol": "TEST", + "amount": 400800 + }, + { + "owner": "TESTFT6R22CLztwrvLqD8HM1dZ6qnLyatewCH", + "asset_symbol": "TEST", + "amount": 1739604 + }, + { + "owner": "TEST8MHiELYK9G8YaKHEYxYiLqXq53f8mdshJ", + "asset_symbol": "TEST", + "amount": 169929667 + }, + { + "owner": "TEST2wYoH9JK2XYsJXguddHp1TbXuNARzderV", + "asset_symbol": "TEST", + "amount": 963278 + }, + { + "owner": "TESTCJq9LndN7E5WVHb55jMrWHUainfqDbs9k", + "asset_symbol": "TEST", + "amount": 487302044 + }, + { + "owner": "TESTKoNWJH5g8P4xfqfzcXTE6MBt6fy5jrxnf", + "asset_symbol": "TEST", + "amount": 2357804 + }, + { + "owner": "TESTDvWmbgCs87WGyUqJH95Fi1S5zmvZnHiom", + "asset_symbol": "TEST", + "amount": 3464876 + }, + { + "owner": "TESTKFAmtSzk4TAwXwiUyhdSRB9PuudZNDAVN", + "asset_symbol": "TEST", + "amount": 101933486 + }, + { + "owner": "TESTLErGEtFS26zq4PjLRSgEWAfWeNkU6a9Pn", + "asset_symbol": "TEST", + "amount": 2066960 + }, + { + "owner": "TESTPHnziXFxs6DigVUdscsUVot3oHP4JYPSy", + "asset_symbol": "TEST", + "amount": 43702493 + }, + { + "owner": "TESTFVFhvwKSsZL2pH9aotXRf7sCuYTnLvADK", + "asset_symbol": "TEST", + "amount": 3194000 + }, + { + "owner": "TESTGWZgcLi3bqBmU2tBTbqgaf6Q42NDE4Nh8", + "asset_symbol": "TEST", + "amount": 59094 + }, + { + "owner": "TESTHvmNjAWFSdb9mTSN9pDFjLDxkDSnqWRRF", + "asset_symbol": "TEST", + "amount": 3680985 + }, + { + "owner": "TESTHHRB9LDwBu9NQ52ww1QkZfH3w7aWEfwaG", + "asset_symbol": "TEST", + "amount": 11990018 + }, + { + "owner": "TESTNxbxHrKbSrzHgDvVqQ8ZxgEV8RpmQ1K1G", + "asset_symbol": "TEST", + "amount": 333923 + }, + { + "owner": "TEST9zSWdRAJjHoireXruhMe2q9iHZrfnXERt", + "asset_symbol": "TEST", + "amount": 65012952 + }, + { + "owner": "TESTPQVY53R9D1MGHvipmXv7q6RA13Cvu2E7G", + "asset_symbol": "TEST", + "amount": 1502873 + }, + { + "owner": "TESTENVDaMX9L8MG7VVzCcKyuX4DkkQJkzyFW", + "asset_symbol": "TEST", + "amount": 21186379 + }, + { + "owner": "TESTLRED7CuY5z436s2UK6Zog2zjj1pe4XRLb", + "asset_symbol": "TEST", + "amount": 10066938 + }, + { + "owner": "TESTGUhxvvKJ5PrMEB34ojGjZeHDNBMR47Fbh", + "asset_symbol": "TEST", + "amount": 9419757 + }, + { + "owner": "TESTMWxogiQrHDQJRCju8wV2aVG7VXJEfQXJ8", + "asset_symbol": "TEST", + "amount": 1740364 + }, + { + "owner": "TESTL8gGCWvQzwWtCZ9A7WouoJHyWqY9AowRX", + "asset_symbol": "TEST", + "amount": 1734251 + }, + { + "owner": "TESTD48qdjJWRmYcyZqpPQkTkjZgzbZnu3R86", + "asset_symbol": "TEST", + "amount": 27175400 + }, + { + "owner": "TEST6JADBYq1jKry3zA2Zf8AYRRqvtJdS5wB7", + "asset_symbol": "TEST", + "amount": 21918 + }, + { + "owner": "TEST7EoaCGnZksK8neyfSHKNgkfLoKsoCqmRH", + "asset_symbol": "TEST", + "amount": 1321125 + }, + { + "owner": "TEST9SQXDwXPKwujsQGFezggPrWscKNT8cgBT", + "asset_symbol": "TEST", + "amount": 146577462 + }, + { + "owner": "TEST2WRbMd8jQJ4DsabHaWtovXJtCQZjAXr9q", + "asset_symbol": "TEST", + "amount": 1890000 + }, + { + "owner": "TEST5a7B2nDy7CyZZeYA8oK889yU2s8m8g6LT", + "asset_symbol": "TEST", + "amount": 384548 + }, + { + "owner": "TESTPhSM1JazgPQGx3reJLgsVAMKQcKaKHYKZ", + "asset_symbol": "TEST", + "amount": 6676947 + }, + { + "owner": "TEST4QWuvsgSnuFgQUkq2qKKftPb2u4oymSi5", + "asset_symbol": "TEST", + "amount": 13861364 + }, + { + "owner": "TESTDA5qbPdWFQmNPUv1RW3f9AnPmnmPB6ub2", + "asset_symbol": "TEST", + "amount": 41892000 + }, + { + "owner": "TESTEDH1cG7AGAW42wrdfLxZx83DRTFNEdj73", + "asset_symbol": "TEST", + "amount": 4640616 + }, + { + "owner": "TEST2BgFzpkeNtUfg5Yh2YGqqHUc2wUsBbYWW", + "asset_symbol": "TEST", + "amount": 1072324 + }, + { + "owner": "TEST4YKCXABJUdQPefULHnhCtgKHLpwaQL5Ub", + "asset_symbol": "TEST", + "amount": 957437 + }, + { + "owner": "TESTNgK6vTKEH1ntRqW6pgoSaMH3YB9XXaybo", + "asset_symbol": "TEST", + "amount": 9040288 + }, + { + "owner": "TESTMDD3QsmYM5fsE3XvcWZ4HkU3CXSxrpd9", + "asset_symbol": "TEST", + "amount": 2676614 + }, + { + "owner": "TESTHDJHjov1KDB2q8Z59y1yZEMPR62mu8xiQ", + "asset_symbol": "TEST", + "amount": 81829072 + }, + { + "owner": "TEST7T5NXb89jM9TLaCZEfvTmG1oNQiDiUtPn", + "asset_symbol": "TEST", + "amount": 1374853 + }, + { + "owner": "TESTFpxwEUsCAjNA7xa6PhC2EYmaDaiL3szoV", + "asset_symbol": "TEST", + "amount": 3615935 + }, + { + "owner": "TESTRfzoiWDQLkwfMuy2QZgiqG5heNqSyYmX", + "asset_symbol": "TEST", + "amount": 84151371 + }, + { + "owner": "TEST6S6eSCz3juYK3Lw3fqeK1JwcSCdJh5Fgf", + "asset_symbol": "TEST", + "amount": 11308900 + }, + { + "owner": "TESTFQAnUU2ATxvbKoLagXiqXaBi5PJArBeYv", + "asset_symbol": "TEST", + "amount": 1167091 + }, + { + "owner": "TEST6oDYKuJDTfoZz4mvVySzsjHnXq4iU719x", + "asset_symbol": "TEST", + "amount": 965091 + }, + { + "owner": "TEST8uUSuy5uUtvmowaC2r4NkxErsGf6jtCs7", + "asset_symbol": "TEST", + "amount": 1150 + }, + { + "owner": "TESTQ2UiF7WZ3f3s54K9RHQ43Aw1wPTNgLbz4", + "asset_symbol": "TEST", + "amount": 2033814 + }, + { + "owner": "TESTA4XNsSdtaxrcqbLnp1Lwc7JZ9jE5CLJt5", + "asset_symbol": "TEST", + "amount": 23887307 + }, + { + "owner": "TESTKyMmi1G4g6qC15CBpw74odqdtArAfNvsy", + "asset_symbol": "TEST", + "amount": 3435886 + }, + { + "owner": "TESTAmQ5FB7dyYnbUkbmmWeZ5jfsAFAKuP6nm", + "asset_symbol": "TEST", + "amount": 200719 + }, + { + "owner": "TEST2h7xtRhghok77YF435Un5sBsxuJYd1Qcz", + "asset_symbol": "TEST", + "amount": 14282429 + }, + { + "owner": "TESTHzFjM27BAGQdRnr1PdSu2VSB71Q34S9Bg", + "asset_symbol": "TEST", + "amount": 5983470 + }, + { + "owner": "TESTBhjq6xpum2527j7svNeSiFUbtNiRdhC2T", + "asset_symbol": "TEST", + "amount": 377615 + }, + { + "owner": "TEST8ZCqrHJ18Pt7YbyAcvPsrTArB7wBJPCzc", + "asset_symbol": "TEST", + "amount": 6289744 + }, + { + "owner": "TEST6SEjxQK2vaZrNwi1hYSGv6aRf5ur8Tun1", + "asset_symbol": "TEST", + "amount": 755325 + }, + { + "owner": "TESTGn2198DBzrQncBuVoJLCCefyLE6S8ZuFY", + "asset_symbol": "TEST", + "amount": 23639767 + }, + { + "owner": "TEST7hfhvDwLw2bMsD8UjozzoipLUyiiFPkr9", + "asset_symbol": "TEST", + "amount": 16560303 + }, + { + "owner": "TEST5LgmdZJqNejQyFV7JbsvmXLVXkWLyx4bu", + "asset_symbol": "TEST", + "amount": 4048184 + }, + { + "owner": "TESTFwZHKFKhtPiZqGG4UeXf35JA7QbfUYiP4", + "asset_symbol": "TEST", + "amount": 46588239 + }, + { + "owner": "TESTCvAetYkJXg39GnrxTqyrR63QfrzUEoeF7", + "asset_symbol": "TEST", + "amount": 6641301 + }, + { + "owner": "TESTJwMP3K6Dxg5N8tiUkW6HCK6gF5E8SbGR4", + "asset_symbol": "TEST", + "amount": 16422451 + }, + { + "owner": "TEST8bvtU51pgCmgJSaSkaqv7nhXa2hn6HhSH", + "asset_symbol": "TEST", + "amount": 6865415 + }, + { + "owner": "TESTKJbWMeFxoG219HV92cimADgm28W6YbYmW", + "asset_symbol": "TEST", + "amount": 72518840 + }, + { + "owner": "TEST8H5WvvptmQPwFXe1Dc35yr2YPQ56H4994", + "asset_symbol": "TEST", + "amount": 15940059 + }, + { + "owner": "TESTF25cg2r8RQUgnZ79bmeoFEsTpHfWRmMUm", + "asset_symbol": "TEST", + "amount": 7931275 + }, + { + "owner": "TEST9urTtLwcEs5rH6AtgAxTFXHwkW2F7siwg", + "asset_symbol": "TEST", + "amount": 24324883 + }, + { + "owner": "TEST7HgwoWZ4fJaXsoJEAb3MF71yYo6RJBnhd", + "asset_symbol": "TEST", + "amount": 34327045 + }, + { + "owner": "TESTDNfYCFTSF41SVXemxA2wSFXjX1Urkb2YK", + "asset_symbol": "TEST", + "amount": 18613653 + }, + { + "owner": "TESTEihfLBnFHHeV7iAgDi3dX6fXTd8gphQy2", + "asset_symbol": "TEST", + "amount": 14508555 + }, + { + "owner": "TESTEWquX51ZMqY2nVLPfETJqyx6SrXmupbd1", + "asset_symbol": "TEST", + "amount": 49852788 + }, + { + "owner": "TESTKVjDA8ziDsbKnxBCMpC4HJAGUYnXHehLC", + "asset_symbol": "TEST", + "amount": 3376134 + }, + { + "owner": "TESTBFQVFKvX8bVpFdHCwa68TswpZ6H9Lufaq", + "asset_symbol": "TEST", + "amount": 12000367 + }, + { + "owner": "TEST3iLKTdZ2AK6ynF5RNKVGykLxg5uQzNxww", + "asset_symbol": "TEST", + "amount": 49755646 + }, + { + "owner": "TESTC9w4rgK7CLqzG5pvKkWsfgN2nQUVUg6wu", + "asset_symbol": "TEST", + "amount": 36758135 + }, + { + "owner": "TEST3SbuZh8cd2R1nR7J9842XEhLU8nC6EF6Q", + "asset_symbol": "TEST", + "amount": 335939 + }, + { + "owner": "TEST62DPUKoExQMYUeg1nH7DqBoQgCYATGcZF", + "asset_symbol": "TEST", + "amount": 1229265 + }, + { + "owner": "TESTEST8s5JN5tCSsTSJnPJ5d3YKa2YteyV4R", + "asset_symbol": "TEST", + "amount": 30942000 + }, + { + "owner": "TESTGWUDfqurbVVNGHURDkNtUkyxTYVNzQp8X", + "asset_symbol": "TEST", + "amount": 166221459 + }, + { + "owner": "TESTAriQusw4d9tJ2V3c7GwdF6jXX97HPruTS", + "asset_symbol": "TEST", + "amount": 199424 + }, + { + "owner": "TEST2sZx63r9JdJcTRoP8LTaC5gjgghFrEX3S", + "asset_symbol": "TEST", + "amount": 6895054 + }, + { + "owner": "TEST8NPs3Bauyj2mtS1Beawp3bLAFPeVWZrcr", + "asset_symbol": "TEST", + "amount": 248233712 + }, + { + "owner": "TESTGjm4HAkkhoJToVzoJ61iXcdKxBUpuQi6M", + "asset_symbol": "TEST", + "amount": 9361283 + }, + { + "owner": "TESTF1h1xrGAveBVUc2mUHNobFRRHDAHuNsHH", + "asset_symbol": "TEST", + "amount": 329720 + }, + { + "owner": "TESTJgKgXCiJXZBLRL81uJ3YScwGVp1tdjBD8", + "asset_symbol": "TEST", + "amount": 128304677 + }, + { + "owner": "TESTJ9rsY2Vy3zBogVoQT6piv8zHa2yzSUAAC", + "asset_symbol": "TEST", + "amount": 2081785 + }, + { + "owner": "TESTMq4ST5znHiQrP5dGZzZaJQBBGY1dAkQej", + "asset_symbol": "TEST", + "amount": 66696239 + }, + { + "owner": "TESTQ5RcW4bxKzRTSn5ZCwEvgyvdNbmBpyYx1", + "asset_symbol": "TEST", + "amount": 34436434 + }, + { + "owner": "TESTJCCMzUBSD8PuwvaPG9yaVJkKUrzemiKKH", + "asset_symbol": "TEST", + "amount": 258270 + }, + { + "owner": "TESTE8YCpGQ4grHUqFcWk7cZSwJ3mzvspN7HC", + "asset_symbol": "TEST", + "amount": 15732843 + }, + { + "owner": "TESTAVJhwGViffm1JMw48EZJpLDdN3qaLN5a1", + "asset_symbol": "TEST", + "amount": 9567821 + }, + { + "owner": "TEST9iNLYPp6vDzPHJFWSXrhy9CxhaLZi9EJb", + "asset_symbol": "TEST", + "amount": 6594738 + }, + { + "owner": "TESTLRbmzQCa5j3zTWyR31udLvhuni6Ag7d73", + "asset_symbol": "TEST", + "amount": 4715254 + }, + { + "owner": "TESTb7LCRgfVEyoD3McsBeY81fswkPUJWgNs", + "asset_symbol": "TEST", + "amount": 22655719 + }, + { + "owner": "TEST4A1Nko4Y6AgZuSkbRRFUugRz9uvpws962", + "asset_symbol": "TEST", + "amount": 5695436 + }, + { + "owner": "TESTFfd8daPKwDTHvNJHdHzQHdRBZwUpurG7f", + "asset_symbol": "TEST", + "amount": 28448557 + }, + { + "owner": "TESTDGnr9W7ht4YYo7KeBaGAwyEeiJVVrBND9", + "asset_symbol": "TEST", + "amount": 102048286 + }, + { + "owner": "TEST7r4fXRxAsTUCqSME2v6gpCPvBVwvFksvP", + "asset_symbol": "TEST", + "amount": 50042474 + }, + { + "owner": "TESTAm1KuVnsk8J4rKwuy9wnCx7y85HbRVuQd", + "asset_symbol": "TEST", + "amount": 10974623 + }, + { + "owner": "TEST9kTroU6sUd439NkEGN4vG7faRZ1pmbRXK", + "asset_symbol": "TEST", + "amount": 5993169 + }, + { + "owner": "TESTqZ5iKxTEUhaUJWJ1FkDNAHqcFbgpmn6y", + "asset_symbol": "TEST", + "amount": 95619783 + }, + { + "owner": "TEST2DsaJ8pwuEr9SMe7uH1g9j9dCoNTWgtRc", + "asset_symbol": "TEST", + "amount": 208079 + }, + { + "owner": "TESTDPZ82U3hdfTAcnczwXKLvqymXfP8yBKgP", + "asset_symbol": "TEST", + "amount": 19150080 + }, + { + "owner": "TESTNEN8G5epTLAgmbR1tQMJT3y7hNiCxFFMp", + "asset_symbol": "TEST", + "amount": 814615 + }, + { + "owner": "TESTJ9upfqHDmZEuhAFkTCnZmNvEYsPidNejU", + "asset_symbol": "TEST", + "amount": 3409231 + }, + { + "owner": "TESTCCtVXJJ1dT2mftEwtBTa49zH7j1rstadL", + "asset_symbol": "TEST", + "amount": 34554900 + }, + { + "owner": "TESTHBYZku5okVNJWumFcgXbCe4FcyraiEQNf", + "asset_symbol": "TEST", + "amount": 1973706 + }, + { + "owner": "TEST61KfsXuHWH58Pepgg1j2Xnt2SEt3A8Bp4", + "asset_symbol": "TEST", + "amount": 2301347 + }, + { + "owner": "TEST53g7qU4d8dDpyQRkebM1r8WCWVpDR7w4B", + "asset_symbol": "TEST", + "amount": 1737323 + }, + { + "owner": "TEST3oeqTkkZF4oH491Mp9qoDXBJPv1Rq97y8", + "asset_symbol": "TEST", + "amount": 2206739 + }, + { + "owner": "TESTAixGPqHBQhk1SyLD6qEQPMXZjv3mWy9Y4", + "asset_symbol": "TEST", + "amount": 1528986 + }, + { + "owner": "TEST5o6r3MwCEE17TYXT8kVMXGeCcGFViB17o", + "asset_symbol": "TEST", + "amount": 10041152 + }, + { + "owner": "TESTJrVF5VnfwA21kNwRwtnzhZkJJsCCPLVU4", + "asset_symbol": "TEST", + "amount": 21760748 + }, + { + "owner": "TESTDsDqQ5x4LekUsH2z8v5eoeasTdBdkMwD7", + "asset_symbol": "TEST", + "amount": 8411433 + }, + { + "owner": "TEST2bX4KahoFkS52nQNGDnbrrgUJej2kLc7M", + "asset_symbol": "TEST", + "amount": 32188980 + }, + { + "owner": "TESTBcJKNnwGVry4xmg2HQmFS5Lc9cm4KykLU", + "asset_symbol": "TEST", + "amount": 1748244 + }, + { + "owner": "TESTAhzscfiJT5CDmxiSwyw47D6zscDM8M15p", + "asset_symbol": "TEST", + "amount": 5013528 + }, + { + "owner": "TEST8qDFW6cf99Co28mwNSMVYw1mndkerNAkz", + "asset_symbol": "TEST", + "amount": 34285714 + }, + { + "owner": "TEST3FfLu5So8giqEH65Zjxo9kzwzLtRjn7uB", + "asset_symbol": "TEST", + "amount": 130466960 + }, + { + "owner": "TEST9N7AJqHkRbBqW6o2gYZ6fRpJKxbcBkr3s", + "asset_symbol": "TEST", + "amount": 4900199 + }, + { + "owner": "TEST2Rpb9CLBuiL4o7vgRxMZCH1N1R7ndXzg3", + "asset_symbol": "TEST", + "amount": 3432355 + }, + { + "owner": "TESTJoGo84Zk4D4tSUJ4FfKtCBGpWqHemsAQR", + "asset_symbol": "TEST", + "amount": 338984 + }, + { + "owner": "TEST5xkXZUMAVqCC6oXDhrUXV6MvfHmQXgxbx", + "asset_symbol": "TEST", + "amount": 681505 + }, + { + "owner": "TESTBPpbkroZcEcvECfdhqNrKPQHidtXq9KG", + "asset_symbol": "TEST", + "amount": 5222550 + }, + { + "owner": "TESTEzKL3bmV499AcPRRpU35ifer3xpj2fpMN", + "asset_symbol": "TEST", + "amount": 5752 + }, + { + "owner": "TEST5wma5cCbHWKxRvzhnJcMW2M4JSb2wJCbm", + "asset_symbol": "TEST", + "amount": 1785112 + }, + { + "owner": "TESTJTEqGzmSmBpC6Y9SCDrN9v4LfTpdPoUFR", + "asset_symbol": "TEST", + "amount": 533962 + }, + { + "owner": "TESTCN49vqbcN78JsdgHjQo2VytxCjWEWnFiy", + "asset_symbol": "TEST", + "amount": 2001647 + }, + { + "owner": "TEST46c2NjdnPrir2FyiY5KVhtQrT4zpAGtKD", + "asset_symbol": "TEST", + "amount": 229494 + }, + { + "owner": "TEST5ikMFJUmwYY946CuPxnyTDSTbEE6w8VwA", + "asset_symbol": "TEST", + "amount": 2330175 + }, + { + "owner": "TESTGuVdMAhYpJyTx8ArtGfzovvN4xNGnDLcX", + "asset_symbol": "TEST", + "amount": 824958 + }, + { + "owner": "TEST5Kw11tZpM9pNiX4eMxGGm3Zwm88FXAsxL", + "asset_symbol": "TEST", + "amount": 2642295 + }, + { + "owner": "TESTB2bfcSQQyMY8aYJ1hSYENqeVjkMSQVQ8W", + "asset_symbol": "TEST", + "amount": 1869643 + }, + { + "owner": "TESTJRYtoxQXyx4J9pk8qvi1wT4N2QBKPb318", + "asset_symbol": "TEST", + "amount": 1511633 + }, + { + "owner": "TESTG1TkT37ZegajMaNW7SjqriWpQJfco5DsR", + "asset_symbol": "TEST", + "amount": 58728 + }, + { + "owner": "TESTAQhtin4EN2oaFUiDF1AKPCt6Mp4ksSK3A", + "asset_symbol": "TEST", + "amount": 3820158 + }, + { + "owner": "TESTAWDhqhSZYHVdt5qceuwEBh5aVb6EyRfAC", + "asset_symbol": "TEST", + "amount": 206507 + }, + { + "owner": "TESTNpwcA22tkhTCPbUjtaduYB2n9fAiCVfRN", + "asset_symbol": "TEST", + "amount": 18583330 + }, + { + "owner": "TESTpdS4691rBSbWefDjwAt2LZcPR8qG934e", + "asset_symbol": "TEST", + "amount": 3840818 + }, + { + "owner": "TEST6ZPVfofaMMzsZL9uJweQKiBoXNYszjTmV", + "asset_symbol": "TEST", + "amount": 1764146 + }, + { + "owner": "TESTD48fc5dMhtmBKcnN5F9BjHp9ogZ38VHfC", + "asset_symbol": "TEST", + "amount": 683817 + }, + { + "owner": "TESTFEM8C51RSroLucZSBAw6MofK8JrAWhBJw", + "asset_symbol": "TEST", + "amount": 34792076 + }, + { + "owner": "TESTPjwJDABRpqMk6zLv8iKUpabDJnwYXAaVA", + "asset_symbol": "TEST", + "amount": 13915951 + }, + { + "owner": "TEST7arMBnpBNhsAi6FsD8YuXH6MMWhW7nhjL", + "asset_symbol": "TEST", + "amount": 33909379 + }, + { + "owner": "TEST37feqYzKSFuxbPxAWt1vi8F1vo2MgwUrj", + "asset_symbol": "TEST", + "amount": 14827882 + }, + { + "owner": "TESTPb1uVEXvP3zT6NqZH7sumsF2x41STySwh", + "asset_symbol": "TEST", + "amount": 9176741 + }, + { + "owner": "TEST6KSrokh96bF72fcb4NZnkqwjdZM3fQ7dL", + "asset_symbol": "TEST", + "amount": 10183003 + }, + { + "owner": "TEST587Gzn4VSbhrTfuBRig8DXdZ1P7fGiNVK", + "asset_symbol": "TEST", + "amount": 33900238 + }, + { + "owner": "TESTAmYYhGSh4mFvLTB9MhPsN4DzjqnsyPogv", + "asset_symbol": "TEST", + "amount": 4705980 + }, + { + "owner": "TESTFiuJx6T3sCLMXAZZc2qWW6M7dZeUjBptg", + "asset_symbol": "TEST", + "amount": 1571053 + }, + { + "owner": "TESTJozQKVdP8xjq2Ty3Y6SB6a2FhBRZZjpou", + "asset_symbol": "TEST", + "amount": 3313725 + }, + { + "owner": "TEST7ajiVnWeaypqoJi9mEDF5rFgypQPnZksd", + "asset_symbol": "TEST", + "amount": 20339800 + }, + { + "owner": "TESTFsWX8oVn7J1hhxznJubyEyfmBnGDTT6N9", + "asset_symbol": "TEST", + "amount": 23638297 + }, + { + "owner": "TEST53hg7TEUNoqi8ENU8ywa5d36bEwH6aoLa", + "asset_symbol": "TEST", + "amount": 16816788 + }, + { + "owner": "TESTGW66HEFogJKR1oDmXEJsqP2GKuPt1g2CR", + "asset_symbol": "TEST", + "amount": 21057012 + }, + { + "owner": "TESTG5TxVrWryLdmHnp926qnw5F7qSdJxEf7V", + "asset_symbol": "TEST", + "amount": 8448862 + }, + { + "owner": "TEST8xhf9TN4LSKK7PwYKB36Jjmdr9sw56ssw", + "asset_symbol": "TEST", + "amount": 26229142 + }, + { + "owner": "TESTC4Ac6wPKeeHQUx7EDPMPvYuBJUzppNKJB", + "asset_symbol": "TEST", + "amount": 1397751 + }, + { + "owner": "TESTG1or37CrzrsRrPEycQn7znAR2YDAkMefT", + "asset_symbol": "TEST", + "amount": 499083 + }, + { + "owner": "TESTHtY8vFg1UpYPyp26BNR9K8QxqG3Cr5jiP", + "asset_symbol": "TEST", + "amount": 9873988 + }, + { + "owner": "TEST9jmsDi6cbfUhsgd2vcxPjavK27EUVP6Y", + "asset_symbol": "TEST", + "amount": 1736597 + }, + { + "owner": "TEST8Zx2aBnpSgRNsP4PhzzooBg3qG6n2nNMo", + "asset_symbol": "TEST", + "amount": 4067832 + }, + { + "owner": "TEST3kDymwpL55iLgg8pyQLKAeX4YWgSeTbJr", + "asset_symbol": "TEST", + "amount": 850891 + }, + { + "owner": "TEST9vg1Hea5EQGjWCMZo7WU3B71aBccDz37W", + "asset_symbol": "TEST", + "amount": 2499560 + }, + { + "owner": "TEST7TzE3ReWUCT7VYVAWnzWtmPULUJnCLcaP", + "asset_symbol": "TEST", + "amount": 1738790 + }, + { + "owner": "TESTLXVffLjY4pYWp3ztF1w6Gcg1zHvoWdsfm", + "asset_symbol": "TEST", + "amount": 3167060 + }, + { + "owner": "TESTPaz3XDWHzvdvdZMKzVD1BGTeXGHimatV1", + "asset_symbol": "TEST", + "amount": 46808999 + }, + { + "owner": "TEST2R3hYjGynZVdeiadS6JmbfYj6Xig6e743", + "asset_symbol": "TEST", + "amount": 154235 + }, + { + "owner": "TESTCiUCEmA5FwuDUofS79QV4hzGUcb5F3Gkf", + "asset_symbol": "TEST", + "amount": 1202776 + }, + { + "owner": "TESTAYEgGougiJovQPeBgnAsajNzUijoVcQ5H", + "asset_symbol": "TEST", + "amount": 2087555 + }, + { + "owner": "TESTExCC6riz6kXVPgdjZ3FNsJq6jnPTWLmTX", + "asset_symbol": "TEST", + "amount": 211586 + }, + { + "owner": "TESTGcWVECYpXpQxWcCKJo3QHUrqUXwtsWMoG", + "asset_symbol": "TEST", + "amount": 85842 + }, + { + "owner": "TESTHaTQ7V2FdruV9sHTd92NijLLFEWorad4e", + "asset_symbol": "TEST", + "amount": 107748194 + }, + { + "owner": "TESTBzTQu6Xkgd7WA56gZxqv7nx5eqFv37iR1", + "asset_symbol": "TEST", + "amount": 627341 + }, + { + "owner": "TESTCtDLUmcbG2JBofZspbuLb8Q9euyv2WevZ", + "asset_symbol": "TEST", + "amount": 80794 + }, + { + "owner": "TESTFnkqPJHUGwmFHhrwLAMdTqQ7eAEL3efG6", + "asset_symbol": "TEST", + "amount": 10039332 + }, + { + "owner": "TESTH8zpVuxPfyqRVM85rv6Lh29Vf4XiCTcM", + "asset_symbol": "TEST", + "amount": 12338310 + }, + { + "owner": "TESTNxu1fTrAyVMW2aLBRrpAshWzXuscAnQWu", + "asset_symbol": "TEST", + "amount": 1609956 + }, + { + "owner": "TEST12oMWk88tgAa6s1tHyrw6ZjBv6Nb1xNS7", + "asset_symbol": "TEST", + "amount": 3435717 + }, + { + "owner": "TEST4FBSwV2JfbNVwGyZ7KWDp1AVSN9AvkDF4", + "asset_symbol": "TEST", + "amount": 549775 + }, + { + "owner": "TESTK47WJbigAzfVviCFJySjQUVptnMweDP79", + "asset_symbol": "TEST", + "amount": 375955 + }, + { + "owner": "TESTGzN8gdRfBJ71WCHsPsRrYZyby9eS3ozR7", + "asset_symbol": "TEST", + "amount": 2139759 + }, + { + "owner": "TESTJtvmqKFZiTWXuEc6pg65xiorhWCJFXK4h", + "asset_symbol": "TEST", + "amount": 2977354 + }, + { + "owner": "TEST5QPMLKgfShWCpZdZt33AXVbVrGE7rJoKu", + "asset_symbol": "TEST", + "amount": 2618008 + }, + { + "owner": "TEST61R5UyR7GNpo6kReoNejWKyuUteF7hXuC", + "asset_symbol": "TEST", + "amount": 2398816 + }, + { + "owner": "TESTCSre9Ti8HFhbMNZF35E2ovzpHwFvf71ua", + "asset_symbol": "TEST", + "amount": 1571220 + }, + { + "owner": "TESTM5MrrmwPPfwvMkDrzgryNXWkdtfwqQrSL", + "asset_symbol": "TEST", + "amount": 26935246 + }, + { + "owner": "TEST2i4DQw4TVjf99is1U7pE2UD52ZqbSTJ5W", + "asset_symbol": "TEST", + "amount": 3231394 + }, + { + "owner": "TESTL7Via8a7NE2kvwuQvMrHeUB4uCucr7Z22", + "asset_symbol": "TEST", + "amount": 51172991 + }, + { + "owner": "TEST4MyFscnmffmCmtzMTeHktjELXSxor3349", + "asset_symbol": "TEST", + "amount": 2500156 + }, + { + "owner": "TESTPF9V7LyVkDhQev3BD3B1i6g3uq7Ty4SwP", + "asset_symbol": "TEST", + "amount": 5561584 + }, + { + "owner": "TESTGV5C7k9BZnzgpTR82FvAxzMZYndhKBwV8", + "asset_symbol": "TEST", + "amount": 473686 + }, + { + "owner": "TEST3n8pocywZpiJjhvRfJz71sCmYCsiBQZD6", + "asset_symbol": "TEST", + "amount": 86815580 + }, + { + "owner": "TESTL9rHxY22YE9gWzWYgEobFFdueNCj5jbKz", + "asset_symbol": "TEST", + "amount": 6345020 + }, + { + "owner": "TESTYr42D9KbdG1PX617P88qLfrBb9Xpam1n", + "asset_symbol": "TEST", + "amount": 276415 + }, + { + "owner": "TEST2nCms7CSBzkbbM87GVMQZhrmSLba2WUWJ", + "asset_symbol": "TEST", + "amount": 67658821 + }, + { + "owner": "TESTLgXSXjsuZopxJjqeRMj6KnuSzDxMFhh19", + "asset_symbol": "TEST", + "amount": 10249488 + }, + { + "owner": "TEST6P2bkKtfxPrjDQ3B87Cok4TJ9wou51m8Z", + "asset_symbol": "TEST", + "amount": 9771617 + }, + { + "owner": "TESTFKnmHzubN3n1JQKXcQYudP3uTbXD2eFgm", + "asset_symbol": "TEST", + "amount": 10261582 + }, + { + "owner": "TESTP3tSSxp2W41enym3fRMGAFXrRchJRhEBZ", + "asset_symbol": "TEST", + "amount": 23120 + }, + { + "owner": "TESTTgBDB8duzKDfJ7Acs4oSRbm2S8PdKtJv", + "asset_symbol": "TEST", + "amount": 3499737 + }, + { + "owner": "TESTBFLZCmTxfQenPGY8HcNZtLnSb7p4QxDt2", + "asset_symbol": "TEST", + "amount": 1212293 + }, + { + "owner": "TEST74wv2ASL2yDYbSeUZoRB3SFJDV1ZuMUzH", + "asset_symbol": "TEST", + "amount": 513143 + }, + { + "owner": "TESTHA5EhjDh3U3rBrTCzVR1tDvfEB1XEPYM7", + "asset_symbol": "TEST", + "amount": 464441 + }, + { + "owner": "TEST5SQjWUTmUqhYL6mxkdq1WtHXz2XqiKZk6", + "asset_symbol": "TEST", + "amount": 19922978 + }, + { + "owner": "TEST2VdPNNwGyCEe6Hf8na3PRnVUo47H33PLR", + "asset_symbol": "TEST", + "amount": 1119741 + }, + { + "owner": "TESTLMAE3X7hwbguxZWnXDuC1ZWAdPPhQXdCR", + "asset_symbol": "TEST", + "amount": 65283237 + }, + { + "owner": "TESTBd6PNkBocnnLPhLPeCjTk2NMbkDyQZGB4", + "asset_symbol": "TEST", + "amount": 1922884 + }, + { + "owner": "TEST14FjodsMggpr8sU5wi33Z1NFbMRKmAvMz", + "asset_symbol": "TEST", + "amount": 652415 + }, + { + "owner": "TESTCN9RXyhqCLgnARWtg97ZoJzrwZoQXuWMf", + "asset_symbol": "TEST", + "amount": 35614438 + }, + { + "owner": "TESTLZ7yVmj6abCf2GFwKiStKvNiLvBsANTv3", + "asset_symbol": "TEST", + "amount": 1159793 + }, + { + "owner": "TESTDxUu48pyMGdjf4R4UnrTdEGYsmfRthMWr", + "asset_symbol": "TEST", + "amount": 6124828 + }, + { + "owner": "TEST4r3MG4ga4NmZSK7uLw8A79gAMSZqEkJeU", + "asset_symbol": "TEST", + "amount": 347921 + }, + { + "owner": "TEST5oPJiLdU3qwfbgb9y96qWrF1miYvbfPMA", + "asset_symbol": "TEST", + "amount": 17203050 + }, + { + "owner": "TESTPL8ER5dyfyVswvzBTHf6jhp6vf9FzDKZs", + "asset_symbol": "TEST", + "amount": 18327747 + }, + { + "owner": "TESTFgxH7PsrbmVokV6VRKHxgEvwkHvfiM2Hh", + "asset_symbol": "TEST", + "amount": 96742986 + }, + { + "owner": "TEST9vVnEvdEpAHAJqrUbpR7F2AxidbbXGHpw", + "asset_symbol": "TEST", + "amount": 6901500 + }, + { + "owner": "TESTGxDpLJ93wUbyDTquBwgXJQpP6Eaobu152", + "asset_symbol": "TEST", + "amount": 6319960 + }, + { + "owner": "TEST3D5MSeZS46AMhfWBjZXvoaXVqqKL9PKiF", + "asset_symbol": "TEST", + "amount": 891943 + }, + { + "owner": "TESTDXWw2CACQwqpmLHw8W8uwDPxMsmey1vpP", + "asset_symbol": "TEST", + "amount": 23702160 + }, + { + "owner": "TEST9CtVD2xmKK2tWxqQWxFSEQSNZSQ2LsfCo", + "asset_symbol": "TEST", + "amount": 33749435 + }, + { + "owner": "TESTPvunJFx6YNs4NCoKVntkW4ZPdUVKJYU6F", + "asset_symbol": "TEST", + "amount": 2049904 + }, + { + "owner": "TESTEhnAr3gb8khZ8fouM3MsN4zWUooyiwf1a", + "asset_symbol": "TEST", + "amount": 4741168 + }, + { + "owner": "TEST8eYdb8cKhPdgLCHP6hCFwCq7K9MyNBuSz", + "asset_symbol": "TEST", + "amount": 133964320 + }, + { + "owner": "TESTPB19gHvVCN1ExJiUSGfaAXZxL3Sfz1qtX", + "asset_symbol": "TEST", + "amount": 5014877 + }, + { + "owner": "TESTB2g89sjU3TUm3xmB6wGMU2KQYRQSFYNj8", + "asset_symbol": "TEST", + "amount": 1087402 + }, + { + "owner": "TESTHaN4mCmK7fophNeiWg3pD9R5W8utqpV7K", + "asset_symbol": "TEST", + "amount": 12516376 + }, + { + "owner": "TESTDoT6H7kGanRxBjwuf87rDWAHWELJmK9A3", + "asset_symbol": "TEST", + "amount": 5118234 + }, + { + "owner": "TESTAEx1iQtU2QnbAqdGcDoGeaV1r6vetpdMT", + "asset_symbol": "TEST", + "amount": 3463379 + }, + { + "owner": "TESTQCtxcFkYxZnb9W7Vfc2a6gpFAEHnBxL6y", + "asset_symbol": "TEST", + "amount": 1047826 + }, + { + "owner": "TESTLoNBvwLtWAD7unsi8Jgj2ecLY1x3Ph3EC", + "asset_symbol": "TEST", + "amount": 102494914 + }, + { + "owner": "TESTKyiaMk8yeY5JBp8kC7RU3AQkivUh9KahP", + "asset_symbol": "TEST", + "amount": 1979979 + }, + { + "owner": "TEST73awx5Aso7MXJzZjYdHW5WsuaUjg2yrj6", + "asset_symbol": "TEST", + "amount": 19032299 + }, + { + "owner": "TESTJRBKK8PW8VmEog1LsXTs374TYABqkJ9y9", + "asset_symbol": "TEST", + "amount": 536994950 + }, + { + "owner": "TESTPWPprcNdKxp4CYCo8gqJ64nB745qT5dC1", + "asset_symbol": "TEST", + "amount": 228102 + }, + { + "owner": "TESTH1ToGN4tvY9npEUbGHKKJjk84h8aJ4CpR", + "asset_symbol": "TEST", + "amount": 8962023 + }, + { + "owner": "TESTNLLGoaGsneedD9jFJD5GZ3GBLiNB92X6u", + "asset_symbol": "TEST", + "amount": 6605613 + }, + { + "owner": "TEST6NR41VA5dvECaoEkBfzoFsuQ2fAcPRGKG", + "asset_symbol": "TEST", + "amount": 2078926 + }, + { + "owner": "TESTC22DL554EPYaR52XjHJdvxyHtFdu22CCy", + "asset_symbol": "TEST", + "amount": 16744644 + }, + { + "owner": "TESTGEoXPeeef4xUF7eh1yMsSsLyhXJuLLHYU", + "asset_symbol": "TEST", + "amount": 30041 + }, + { + "owner": "TESTQ5BGrbaHuQYxD4KZRK6odANAsVxDYeXnH", + "asset_symbol": "TEST", + "amount": 5406511 + }, + { + "owner": "TEST8bR28zL4sKn3oANFdCPiWZXdLwVJ1tfqF", + "asset_symbol": "TEST", + "amount": 9270809 + }, + { + "owner": "TEST4mTGkAHFnqCopwzY5AHqrZ3RsxjmLLeDD", + "asset_symbol": "TEST", + "amount": 224077 + }, + { + "owner": "TEST9ao6LEJnLhdB3ke3CuG7muYzJ2JUehqGP", + "asset_symbol": "TEST", + "amount": 4921786 + }, + { + "owner": "TESTL5b6RUxEuVQcaFyitnjQrMp6MbSm6nF8L", + "asset_symbol": "TEST", + "amount": 11762254 + }, + { + "owner": "TESTLHAxUaH6htJtkXLTXnY4SrgM4695zNVBb", + "asset_symbol": "TEST", + "amount": 69092571 + }, + { + "owner": "TESTFQP1AAMFeLfqjLUH19YsonSoHfj9evA4p", + "asset_symbol": "TEST", + "amount": 694908 + }, + { + "owner": "TESTHL8ZWxT5HMmRcdKhZug6APSVkBUyhJEwU", + "asset_symbol": "TEST", + "amount": 116378280 + }, + { + "owner": "TESTCaB6wwYzEbVbGG48dx98QBSULDX2pXiXK", + "asset_symbol": "TEST", + "amount": 368513 + }, + { + "owner": "TESTJB5bwziPgzsqdtv4ioPS49sDqaJzfBWV9", + "asset_symbol": "TEST", + "amount": 1872701 + }, + { + "owner": "TESTFyeBGCW2Wxrj1Z8KhDpLdEezB7SJyxQbX", + "asset_symbol": "TEST", + "amount": 308776 + }, + { + "owner": "TESTNaRMuDceJsbAti6aZbJG8FBLUS8uetmcb", + "asset_symbol": "TEST", + "amount": 859172 + }, + { + "owner": "TESTNnBvNWsPByQL91CHgpp6Xqcx4JJRwSKnL", + "asset_symbol": "TEST", + "amount": 3432362 + }, + { + "owner": "TESTQHW6kCsUYnBFRmqDoKP6DX7Jsa6KApXvs", + "asset_symbol": "TEST", + "amount": 20181816 + }, + { + "owner": "TESTD4U8KchwWBYA88pNpXHnoZdomzZSokHUN", + "asset_symbol": "TEST", + "amount": 4085577 + }, + { + "owner": "TESTDqVKV9ZcCTXM7vghJzvZzM3iPF9DehJ5o", + "asset_symbol": "TEST", + "amount": 19081614 + }, + { + "owner": "TESTLMRpzuq85EGQpmJfSCpCZSCBWee4vdj71", + "asset_symbol": "TEST", + "amount": 432900 + }, + { + "owner": "TESTAUmMBj2qVGgtDKYVL4cDeu2r2eMb9yvDG", + "asset_symbol": "TEST", + "amount": 1986190 + }, + { + "owner": "TESTB6aN3sAaHEpd9oG63gZNAbS2Nom6P2gu2", + "asset_symbol": "TEST", + "amount": 1013983 + }, + { + "owner": "TESTFq4KTb5yuNCTwicEZMyb74Ln89mk2pnrf", + "asset_symbol": "TEST", + "amount": 1130673 + }, + { + "owner": "TEST7xaoUvGrxVxa5L92u7WpHjcUB1TBR2AfM", + "asset_symbol": "TEST", + "amount": 2330731 + }, + { + "owner": "TEST7rSv219mBUkPY72vqSrDk6ihw5b6Zxurm", + "asset_symbol": "TEST", + "amount": 247100981 + }, + { + "owner": "TESTJLJK2jxM3t2vg4JPpcAJkDxTYNDu9g9gQ", + "asset_symbol": "TEST", + "amount": 1597677 + }, + { + "owner": "TESTK36ubzF3UBrn6QMQMvtd7rYmPVTazTc6p", + "asset_symbol": "TEST", + "amount": 5674580 + }, + { + "owner": "TEST4xgzG6u8grWBh3nUgZaXynsJnWWNzg8r9", + "asset_symbol": "TEST", + "amount": 6656639 + }, + { + "owner": "TEST3nsTLwTvf2c5q51FN8r72XiPQFiptbQVB", + "asset_symbol": "TEST", + "amount": 6802538 + }, + { + "owner": "TESTF8R5u48w8ADkXYVV9YDs6rzHvMPDeg3hx", + "asset_symbol": "TEST", + "amount": 6188064 + }, + { + "owner": "TEST6kijGv7hSGvELhbFx8145oiBVZWSwB8Vo", + "asset_symbol": "TEST", + "amount": 6497803 + }, + { + "owner": "TESTQKkKvp8zkDgDgsuEqeLGonGAHGnqfhbDS", + "asset_symbol": "TEST", + "amount": 85836500 + }, + { + "owner": "TEST69r8svahTmzdTYQsxfsQhL5pyHL19fWRz", + "asset_symbol": "TEST", + "amount": 26246730 + }, + { + "owner": "TESTCkbFVDwmSefqWYahuhvrdzcM6P1r6aSnh", + "asset_symbol": "TEST", + "amount": 1904445 + }, + { + "owner": "TESTJtGz48Qvwtrdh37cwYRPcTjppz8JCdVZE", + "asset_symbol": "TEST", + "amount": 8354469 + }, + { + "owner": "TEST7QxaBDqaAYyF1nbtYDqmFaJhEWVsttwku", + "asset_symbol": "TEST", + "amount": 102857143 + }, + { + "owner": "TEST6xRkqvCdZFci2aS9CuRVfvh3AHKJSAxnY", + "asset_symbol": "TEST", + "amount": 1897031 + }, + { + "owner": "TEST672spw2tZuADzV2u2FsS3aBn3vhNQwvU2", + "asset_symbol": "TEST", + "amount": 94475 + }, + { + "owner": "TESTHhhbaLcZC4ja9ehF8x99o2ecUrfHwPhbi", + "asset_symbol": "TEST", + "amount": 161246500 + }, + { + "owner": "TEST587qDEf76dYjQMnFapyktDsVAYZbgvEvg", + "asset_symbol": "TEST", + "amount": 29192714 + }, + { + "owner": "TESTKg4AKehiEXHzigM7S4A7MUptwuo1DvkZt", + "asset_symbol": "TEST", + "amount": 105801000 + }, + { + "owner": "TESTNB1N49BqRjVUTcXmW3eULM82krNRPaEx7", + "asset_symbol": "TEST", + "amount": 7058491 + }, + { + "owner": "TEST3D5LnEFqiy8sMaYLYyVcG7E2qYRHpBmqZ", + "asset_symbol": "TEST", + "amount": 4890636 + }, + { + "owner": "TESTHeHLH3QCMgkNHbXHk6a7k6GpEuCry31Du", + "asset_symbol": "TEST", + "amount": 3388144 + }, + { + "owner": "TESTJDJfjpopk8YGQjLaGeuTYQyRHLTEqUvt8", + "asset_symbol": "TEST", + "amount": 16489452 + }, + { + "owner": "TEST2Sp4tm4JgdCXuWRdjZXhebze63CgGjwSJ", + "asset_symbol": "TEST", + "amount": 611686 + }, + { + "owner": "TEST4zmKf1icN4mGTxYVHhBUZK7751ch4Z7m4", + "asset_symbol": "TEST", + "amount": 155812541 + }, + { + "owner": "TESTBzeWG3ho822VTYpjcgUJQconSBF9PYPug", + "asset_symbol": "TEST", + "amount": 23663800 + }, + { + "owner": "TESTCJYCfgeTfZRkA7BVSiiRKgP2XWiKcxt6p", + "asset_symbol": "TEST", + "amount": 37745 + }, + { + "owner": "TEST6tgehEoRTwU6wLW8So4rcY59GvXe9vG1A", + "asset_symbol": "TEST", + "amount": 19907 + }, + { + "owner": "TEST2GU33JAqHFkrTbcGceK54CRTtcytn3wC8", + "asset_symbol": "TEST", + "amount": 6592437 + }, + { + "owner": "TEST6AnKn28CfZRAQR39ezJZR1CpxDydPcopb", + "asset_symbol": "TEST", + "amount": 910426 + }, + { + "owner": "TEST6Z8u35rtQQQEgk2QMRsXm5vYr7skm777T", + "asset_symbol": "TEST", + "amount": 4740432 + }, + { + "owner": "TEST8ttdjjoCtv8n2r8jZ6UYYXVKhFMh31svr", + "asset_symbol": "TEST", + "amount": 5718304 + }, + { + "owner": "TESTMT1DCdZLAjUikM9mMD6B1CRKJeCYYPm4G", + "asset_symbol": "TEST", + "amount": 26479 + }, + { + "owner": "TESTCoKBUNGecsN4ZxKdZuyLRwDezCJBAZ2K2", + "asset_symbol": "TEST", + "amount": 1630888 + }, + { + "owner": "TESTGsyuc68A34f6j1Pi4fKDeAfejnmudoSQu", + "asset_symbol": "TEST", + "amount": 37193915 + }, + { + "owner": "TESTBDETuuU3wMipyx6dHQGbauoYxdip6TthX", + "asset_symbol": "TEST", + "amount": 1094242 + }, + { + "owner": "TEST5zzaVFXe6AHDEGQCqgn8G9dPRdv2o13PX", + "asset_symbol": "TEST", + "amount": 1747754 + }, + { + "owner": "TESTB2muKDktUuFUMxfbTVcELpWirkvLfuRke", + "asset_symbol": "TEST", + "amount": 6859395 + }, + { + "owner": "TESTBArpjj2vKFqghgE6biJt8Mus68M5BJwPR", + "asset_symbol": "TEST", + "amount": 2100242 + }, + { + "owner": "TESTJEk6D3PFS4w44AGKutxt768ZfUwPLKe5U", + "asset_symbol": "TEST", + "amount": 5529747 + }, + { + "owner": "TEST5FkJWp8QWZ1LCmWLb9DeQ3aCThcjvj2XN", + "asset_symbol": "TEST", + "amount": 4726488 + }, + { + "owner": "TESTC6KrwJ1djDbMqjZ89Ee95HFQmgFxETLBE", + "asset_symbol": "TEST", + "amount": 20718172 + }, + { + "owner": "TESTJ3YrBha84gjUHanDuhoDD38SB68rBC7Gd", + "asset_symbol": "TEST", + "amount": 88813924 + }, + { + "owner": "TESTH1Fzia3Qs9B35RDVik61AGYnvGPiPSeLw", + "asset_symbol": "TEST", + "amount": 3275299 + }, + { + "owner": "TEST7FubkazaoLKgYpss8jfQ1pEGUYaGxuz9V", + "asset_symbol": "TEST", + "amount": 8591542 + }, + { + "owner": "TEST6rnyg5FvZ7hVPPy5wBLhozHMHntXGPvxc", + "asset_symbol": "TEST", + "amount": 14038008 + }, + { + "owner": "TESTA4AmK8jbc9VW48R4KudDpygu1mtDj1E2t", + "asset_symbol": "TEST", + "amount": 4776909 + }, + { + "owner": "TESTLynNjiqj6DuBAueA6CWijgtiNWktZYo4m", + "asset_symbol": "TEST", + "amount": 38562914 + }, + { + "owner": "TESTBrBZctAL1LomjuSFXbh3hp5ofT5xu68ip", + "asset_symbol": "TEST", + "amount": 526909 + }, + { + "owner": "TESTNBeDxbgk6bSRBi7u6YVZjWHTN62VzF4VF", + "asset_symbol": "TEST", + "amount": 3561146 + }, + { + "owner": "TEST2KzufJuLVUryvEJSVnM3WojvySRb2WQu8", + "asset_symbol": "TEST", + "amount": 510269 + }, + { + "owner": "TESTJ3GCx4MEdjzaxVCHwWWSFyuD5fR5YwiXy", + "asset_symbol": "TEST", + "amount": 1744841 + }, + { + "owner": "TESTPKraTYeRHyrM5BN9o6ihoFabYv6tkNPjw", + "asset_symbol": "TEST", + "amount": 16104134 + }, + { + "owner": "TEST4ZfCnX9qnTHuiUzqby7Xm63p5hcC8fCh3", + "asset_symbol": "TEST", + "amount": 22800550 + }, + { + "owner": "TESTAPraEzhYzg5DT9eLsbprRmCEiGQ5u5W6P", + "asset_symbol": "TEST", + "amount": 782183 + }, + { + "owner": "TESTHsfEcehpMbXUFhazKcGZDit2L2McsmSMJ", + "asset_symbol": "TEST", + "amount": 957381 + }, + { + "owner": "TESTNBtzVfhTCDexRfAefgo8ze8ye8NJGUnYz", + "asset_symbol": "TEST", + "amount": 753732 + }, + { + "owner": "TEST4uizZo4FeWm2vbb3a3a58Tr6YvQoXdARD", + "asset_symbol": "TEST", + "amount": 1341700 + }, + { + "owner": "TESTGpvhxsUfj68nXygp9XXXtce8T261vyS99", + "asset_symbol": "TEST", + "amount": 323105 + }, + { + "owner": "TESTEBehTsmBpb4vckMgV3jSJvgkn5M6dvPV9", + "asset_symbol": "TEST", + "amount": 1004956 + }, + { + "owner": "TESTKiThkzW4zDt9UccXSwYWCMVjoFFLwBcrC", + "asset_symbol": "TEST", + "amount": 2191535 + }, + { + "owner": "TEST9SWSn5T4oJWLv4N5hjgMLYN3A4WJC1w2U", + "asset_symbol": "TEST", + "amount": 16831 + }, + { + "owner": "TESTKyx7Yxvvcr7FvH4K7tvs3M6hTwW22Cu2x", + "asset_symbol": "TEST", + "amount": 1644693 + }, + { + "owner": "TEST3zaPzN3GuWU3ENx4bxK1c4CrYYjWV7Xt3", + "asset_symbol": "TEST", + "amount": 53630884 + }, + { + "owner": "TESTMadVnS5xYcsN5LaGEZoLe46B8QYBoomMz", + "asset_symbol": "TEST", + "amount": 32269 + }, + { + "owner": "TESTQ3qsoNz7tHip9KZ4aQrv2yLheqn7LN3uE", + "asset_symbol": "TEST", + "amount": 846657 + }, + { + "owner": "TEST5ikuu5nGqbKqA7mrJ33r5zj6SVz8ikraC", + "asset_symbol": "TEST", + "amount": 10270573 + }, + { + "owner": "TESTDDA6Y5JcXV4eV9ybBUo7mPBKL9ZM4RLAa", + "asset_symbol": "TEST", + "amount": 21634204 + }, + { + "owner": "TEST7KAtgjTfnBaVgDobEvRKM3JYYeJtSf8Nh", + "asset_symbol": "TEST", + "amount": 912228 + }, + { + "owner": "TESTPYLYjCacioMxc1Y58y7YCcrhzGUCMq1c7", + "asset_symbol": "TEST", + "amount": 174526 + }, + { + "owner": "TESTMVPwQz39FXMhCfGfwBESxnEX5aNgkCjW5", + "asset_symbol": "TEST", + "amount": 2179391 + }, + { + "owner": "TEST7nmo1psrujHnTco7JKD1BJrM8GaxkRvk2", + "asset_symbol": "TEST", + "amount": 24448000 + }, + { + "owner": "TEST2i4CrwYChbUehxTukBcx2NasUAciy3Xkh", + "asset_symbol": "TEST", + "amount": 6773007 + }, + { + "owner": "TESTMajvVp3v9P5joA9DWNk2r3qV9yoTYiCXo", + "asset_symbol": "TEST", + "amount": 313538779 + }, + { + "owner": "TESTAd4RrnqjZtvud7NL3kqguojtbQuKXhvWk", + "asset_symbol": "TEST", + "amount": 21755800 + }, + { + "owner": "TESTNQTJcXiX1ojW2PWCBkR2mAuH346Sebin1", + "asset_symbol": "TEST", + "amount": 3174498 + }, + { + "owner": "TESTH7vQDt5TpBUZ2HYHRkPgT884idRG55zmc", + "asset_symbol": "TEST", + "amount": 4151570 + }, + { + "owner": "TESTMLkLi3QQLpEz5iYUht43vMYX1ZX9TYPE", + "asset_symbol": "TEST", + "amount": 25471582 + }, + { + "owner": "TESTCHSH9oe83UiCuE7UrYs5cKa4h85ubfPpp", + "asset_symbol": "TEST", + "amount": 166042 + }, + { + "owner": "TESTK1p9LBSPSx9oSoYBm2XaWzwCLMMTfFaF9", + "asset_symbol": "TEST", + "amount": 141723 + }, + { + "owner": "TEST6DXpYHgy83pUafXBQbCm7siNGw9VW7w9D", + "asset_symbol": "TEST", + "amount": 5041101 + }, + { + "owner": "TESTBQgZkCp1okohXDCr9ir7djV1pZYYXdSbz", + "asset_symbol": "TEST", + "amount": 761434 + }, + { + "owner": "TESTFvnWGYhtaqx31YEtQgfWBCxTpEp49oZpp", + "asset_symbol": "TEST", + "amount": 919617 + }, + { + "owner": "TESTGENVN6Ub6hSw5xmfwozQbAumZ5wPcSD8u", + "asset_symbol": "TEST", + "amount": 16212394 + }, + { + "owner": "TEST7azNW6CR1MuVDnDZjNcDkGQoSgk8RFXzo", + "asset_symbol": "TEST", + "amount": 24368274 + }, + { + "owner": "TEST5KYKwqiFHHtvQQyh2ZZQBqeW7iT6FxfaB", + "asset_symbol": "TEST", + "amount": 1080241 + }, + { + "owner": "TESTPXiPyPZQ4dAzxAM3ktPCUhn4kJZmLUpAc", + "asset_symbol": "TEST", + "amount": 16811695 + }, + { + "owner": "TESTtJtxeZ8q4xCPJgmiAQqoX9f6qMkZv6Qk", + "asset_symbol": "TEST", + "amount": 4124181 + }, + { + "owner": "TEST69xyCzfjGTvnUoYrd1VzvDZhhAKJtBNGz", + "asset_symbol": "TEST", + "amount": 1977325 + }, + { + "owner": "TESTASRhy4qMrNXEQh7apNy3ZWXZj2GTpc4QK", + "asset_symbol": "TEST", + "amount": 167504 + }, + { + "owner": "TESTG54D6JoZnu6Wam892D1kBTyd4CUMepkLp", + "asset_symbol": "TEST", + "amount": 3827345 + }, + { + "owner": "TESTM2hK46Pk9UANo9Cx2GvqXtncgmvHTRX6n", + "asset_symbol": "TEST", + "amount": 6837426 + }, + { + "owner": "TESTDiUKRfVT29MT3rDAo7aBzYXWoRQsQwN8m", + "asset_symbol": "TEST", + "amount": 27216327 + }, + { + "owner": "TEST8guVfUWT33qGvokn299aVCNK7NEXiy8in", + "asset_symbol": "TEST", + "amount": 23259021 + }, + { + "owner": "TEST6PMF2rjBoCe4yTM4BaVPpwMDjV7ZCdPW6", + "asset_symbol": "TEST", + "amount": 16600099 + }, + { + "owner": "TESTEH7bFvaP3AqBdyiZ6nLwVzmqsvC9CizbY", + "asset_symbol": "TEST", + "amount": 20628568 + }, + { + "owner": "TEST3KJycevpfKiQ47HtADAWWESwU5Pbk3XPL", + "asset_symbol": "TEST", + "amount": 4032244 + }, + { + "owner": "TEST6Jh7p22viruuaUEFq3pNiLWWBJndjoseU", + "asset_symbol": "TEST", + "amount": 3325140 + }, + { + "owner": "TESTNCceMWXH4rZmSEBq6wd4YGdBfrgExFmM7", + "asset_symbol": "TEST", + "amount": 505127 + }, + { + "owner": "TEST7BYqPBzNibmemGVjXdUiKPTcp434kazmb", + "asset_symbol": "TEST", + "amount": 6122975 + }, + { + "owner": "TEST5ggDw23UMNCEyW1z4bJPEiMxxjfXENFPs", + "asset_symbol": "TEST", + "amount": 19507865 + }, + { + "owner": "TESTNgcZKMZhBdW6TEMxs1VpDcUy9dxHzsWqd", + "asset_symbol": "TEST", + "amount": 24382876 + }, + { + "owner": "TESTP8pJuq3Dqw5svv36PZn6H1pUraMkxgwrx", + "asset_symbol": "TEST", + "amount": 16444157 + }, + { + "owner": "TESTNw6qnbesW2j4zhLjRjs1uJTj2Q9CzzHBK", + "asset_symbol": "TEST", + "amount": 16811695 + }, + { + "owner": "TESTKpFE6gHVnvSX89Vu5cGmqN6LKJT9o9Khz", + "asset_symbol": "TEST", + "amount": 2054550 + }, + { + "owner": "TESTJ3kUGJGzosNA8HyBZwBPudggTqaCmoeUS", + "asset_symbol": "TEST", + "amount": 11696513 + }, + { + "owner": "TESTNX7wsMgE73wERCgEaN9tot7idUnVKnwLQ", + "asset_symbol": "TEST", + "amount": 4203477 + }, + { + "owner": "TESTEnvbcf7G2yuDyHxTxprkzmJ46is28Nz9s", + "asset_symbol": "TEST", + "amount": 251308 + }, + { + "owner": "TESTGYy3DFoo5ky8Cc9PnKyYZqLGGH3ck1Ljn", + "asset_symbol": "TEST", + "amount": 515420 + }, + { + "owner": "TESTAQgcBB2nJce7mUbogdg47vXztPrNhDCot", + "asset_symbol": "TEST", + "amount": 1182485 + }, + { + "owner": "TESTJT5eBaRN2ARwfdVbMagZKFWdWvf3QNXrV", + "asset_symbol": "TEST", + "amount": 3281394 + }, + { + "owner": "TESTN8XxVEETbTg8zFR8BxVeZ4xQ9EENrzFRG", + "asset_symbol": "TEST", + "amount": 34898683 + }, + { + "owner": "TESTBdemimct6FWyPHwAMKwkxh1GcMgEmsGNJ", + "asset_symbol": "TEST", + "amount": 132148819 + }, + { + "owner": "TESTM4L2yzpjKKCaeSrG4KuqR9ZZp9BmaRRYp", + "asset_symbol": "TEST", + "amount": 22901777 + }, + { + "owner": "TESTDLdmWXBH41EA5Za1aShqrLoY1hdAqLgEu", + "asset_symbol": "TEST", + "amount": 1009773 + }, + { + "owner": "TEST7ufbfHfHnHyJNfAUJww7jaEqKJwH1Nmw2", + "asset_symbol": "TEST", + "amount": 39526566 + }, + { + "owner": "TESTNiiUNHV9JPJkYUY5FshTP3kmdkUTSyEgK", + "asset_symbol": "TEST", + "amount": 34514197 + }, + { + "owner": "TEST3cV4U62iPLJD8GiPcdy8qxFfVE89HKn5C", + "asset_symbol": "TEST", + "amount": 518358 + }, + { + "owner": "TEST6NhLWaFMLoWT41zVssSskzHumQ6mv7swA", + "asset_symbol": "TEST", + "amount": 94776 + }, + { + "owner": "TESTPXSFiyEgCqW8H3vhutiNXU7cJscDcvCir", + "asset_symbol": "TEST", + "amount": 17025116 + }, + { + "owner": "TEST5nPbPSZcVh7A9xyybyoXKhSkpwYhAERL5", + "asset_symbol": "TEST", + "amount": 3388828 + }, + { + "owner": "TESTHbQMkpXDWq8ey4oeuEjJnupsrBJLMzXRY", + "asset_symbol": "TEST", + "amount": 1666082 + }, + { + "owner": "TESTNeBTgTWj7A9S9Ebj1ayaQvjCZJBaz36f6", + "asset_symbol": "TEST", + "amount": 4064870 + }, + { + "owner": "TESTGuXfZQqkpcyBMUbKb5ntVdEftVyD1S2yL", + "asset_symbol": "TEST", + "amount": 64649054 + }, + { + "owner": "TESTLvJ284mcv5EkjCEM4dApszQHHCYvC3DdM", + "asset_symbol": "TEST", + "amount": 3998508 + }, + { + "owner": "TEST2TQe7WTY2CJs4H9FoyJ2ZvdXe196LUx2L", + "asset_symbol": "TEST", + "amount": 152101 + }, + { + "owner": "TEST3c3NdG1uctjjhxkUfcMxi7PV8RWCSSMLQ", + "asset_symbol": "TEST", + "amount": 18300590 + }, + { + "owner": "TESTPbMTQ9UU8tbptNgSjaAahhini84CPyjS", + "asset_symbol": "TEST", + "amount": 5165650 + }, + { + "owner": "TEST8eSFc5nmZuhHvg3HL6sNCSJ1srqKA7MSj", + "asset_symbol": "TEST", + "amount": 2859013 + }, + { + "owner": "TEST8vNVkFD8CPDbEtbsFPPJME7ECrtpBY6DW", + "asset_symbol": "TEST", + "amount": 482709 + }, + { + "owner": "TESTFF1n1zMZu7dTyZZFXzWbzeAktRG5HEbe6", + "asset_symbol": "TEST", + "amount": 123457597 + }, + { + "owner": "TESTGjS5STFYR1RJuBSLLGV8oG5uMmgksHT4R", + "asset_symbol": "TEST", + "amount": 448897 + }, + { + "owner": "TESTL3CNjTs9jdx3n17xHA6aEEB1SGbUyQHQw", + "asset_symbol": "TEST", + "amount": 3410343 + }, + { + "owner": "TEST6SDHgFAGzDeaFdabJLAs6YvWJokNMnDUn", + "asset_symbol": "TEST", + "amount": 34775810 + }, + { + "owner": "TESTNxX7DuWFPwkhc7aQgCutFgR4becLYEemS", + "asset_symbol": "TEST", + "amount": 1433988 + }, + { + "owner": "TESTBYvyvBcEaEYdURfVJPjbku6zSPX59cpds", + "asset_symbol": "TEST", + "amount": 87752053 + }, + { + "owner": "TESTFLwpXAJezEm4Rie5MDapqEFSWXbejATap", + "asset_symbol": "TEST", + "amount": 1743855 + }, + { + "owner": "TESTDD8pDmDEN17YTrTPidXwctpXgPo5CD7N1", + "asset_symbol": "TEST", + "amount": 14785649 + }, + { + "owner": "TESTCnGGDtJeeMUQ1tFQvbwZpP4C42xDnsiFf", + "asset_symbol": "TEST", + "amount": 2058610 + }, + { + "owner": "TEST5f1QJZ2rfhSzR7jFmJyJxUveAwM2PtgRT", + "asset_symbol": "TEST", + "amount": 4630657 + }, + { + "owner": "TESTKnHRuqs9vgy4gJwaFGP47KM8K4btKZeW4", + "asset_symbol": "TEST", + "amount": 164803143 + }, + { + "owner": "TEST4gfeiDxFdV33FfkG8my3nBq91Ap8XDD2W", + "asset_symbol": "TEST", + "amount": 9585150 + }, + { + "owner": "TESTK6RpLL2wg7NTjJedWnMWTA57pbMnGHNAm", + "asset_symbol": "TEST", + "amount": 11606342 + }, + { + "owner": "TEST3w8bWsBvockkU8nbmLDQMdnyEM7SpzvRs", + "asset_symbol": "TEST", + "amount": 3778100 + }, + { + "owner": "TEST82R5CdnQL3zqNkwPKZuuCip919RiWuL5x", + "asset_symbol": "TEST", + "amount": 34072794 + }, + { + "owner": "TESTJZnJoWPH6VzUHLY3fPFwjzZp1eKKkeufs", + "asset_symbol": "TEST", + "amount": 596456 + }, + { + "owner": "TEST4eUjReJExVe8HniYVQkrqhktAnvjPp31i", + "asset_symbol": "TEST", + "amount": 20912965 + }, + { + "owner": "TESTKX8Mqt7HLva7mpFVXaZ2ZZ1n4fXqWAm1c", + "asset_symbol": "TEST", + "amount": 160556 + }, + { + "owner": "TEST9bxEVCyyTj3mrcqzPXtnYV6PdB5LdwmBa", + "asset_symbol": "TEST", + "amount": 4050581 + }, + { + "owner": "TESTHj84qCztWd2ubQ4SRkyTVcZkebMZC6wBc", + "asset_symbol": "TEST", + "amount": 41560880 + }, + { + "owner": "TEST73FiA27PokGpUmfj7f47KvV5PEyyRNEcg", + "asset_symbol": "TEST", + "amount": 10789703 + }, + { + "owner": "TEST9oFAAh913wNxEjGgVpYLe2WcXsB4DKLpM", + "asset_symbol": "TEST", + "amount": 182159011 + }, + { + "owner": "TESTPURiM5cofjhnroh15LwyH7vVJ8BNGces8", + "asset_symbol": "TEST", + "amount": 23684740 + }, + { + "owner": "TESTM9E3AYMAjQDZmCfYGTxfFZXvnvhqnyUDU", + "asset_symbol": "TEST", + "amount": 1953344 + }, + { + "owner": "TESTJo2oycNmv1cQKZsUidWTKiQ3dd1fXZcGh", + "asset_symbol": "TEST", + "amount": 3783218 + }, + { + "owner": "TESTChMnfzhn321baPcAHxSn5RVVU8Yj9FjNS", + "asset_symbol": "TEST", + "amount": 26841219 + }, + { + "owner": "TEST6mkYBa7uMZWMxHFb8umiBtPJLwR4SrsM1", + "asset_symbol": "TEST", + "amount": 2105981 + }, + { + "owner": "TESTEt37a7RZs4rrLiQhDjhdCcSLAcbbakTPC", + "asset_symbol": "TEST", + "amount": 404401 + }, + { + "owner": "TEST4RXQbZuKcCE9SF5znf2rELuVcDozK4BdH", + "asset_symbol": "TEST", + "amount": 6396251 + }, + { + "owner": "TESTBeH9bqyTEbyGMtFQsGFnD8ttDj8UdxXvW", + "asset_symbol": "TEST", + "amount": 1122088 + }, + { + "owner": "TESTwxgvw13qvkWRuYuuvfcpLvpHaq1Wsfic", + "asset_symbol": "TEST", + "amount": 5921690 + }, + { + "owner": "TESTPwrBn1YuVrTjSB9UoUbP9zchBNBQPUmyy", + "asset_symbol": "TEST", + "amount": 535649 + }, + { + "owner": "TEST7ouD13MDm5LdnYiiNyWNddUumSCA6vZAi", + "asset_symbol": "TEST", + "amount": 41580025 + }, + { + "owner": "TESTQqiqHCmyaZf1tqvcJot5KsGeiN4xBFWj", + "asset_symbol": "TEST", + "amount": 6360000 + }, + { + "owner": "TESTAEuAwUYSoortKuRCC7KYsgqopcxY43JcA", + "asset_symbol": "TEST", + "amount": 581634 + }, + { + "owner": "TEST78CStZ5jot9AjJ33knnm5so9yuzdr9Jni", + "asset_symbol": "TEST", + "amount": 97673219 + }, + { + "owner": "TESTAfkWckFnuUTpbPJzsPbhVK8neYDBvmYb1", + "asset_symbol": "TEST", + "amount": 236700 + }, + { + "owner": "TESTNcXSNbixC2WZjQSZWnax6RTyUky7PWfQs", + "asset_symbol": "TEST", + "amount": 100987926 + }, + { + "owner": "TEST2zGhboDHMnVSn3iQnW7xkbqEJNaxMJzi7", + "asset_symbol": "TEST", + "amount": 15239913 + }, + { + "owner": "TESTKQpNrtdgXiJrd2dbFEJmdWYQ1NawXVC49", + "asset_symbol": "TEST", + "amount": 1780 + }, + { + "owner": "TESTNs7Mq8nAX45igEQUApGpaAVqVw8sDVyrp", + "asset_symbol": "TEST", + "amount": 71251910 + }, + { + "owner": "TESTFBqvQbamC4KubjhSvkYnRbgj97SV6xxtx", + "asset_symbol": "TEST", + "amount": 33083746 + }, + { + "owner": "TESTGFQ88Nwjr4YSD213hfkKbAkcWZpYQ7f1K", + "asset_symbol": "TEST", + "amount": 8881333 + }, + { + "owner": "TESTPBKTpMSpY3aNUSKNkVdrhYAetP6KWbcqB", + "asset_symbol": "TEST", + "amount": 574697 + }, + { + "owner": "TEST7yFNwxHNwi9XPeK1Sy7hi7LeJzPGxEdAt", + "asset_symbol": "TEST", + "amount": 1172842 + }, + { + "owner": "TESTLcP3b2eXQ2bQVCiKPmqscuH5WaXKkVVdy", + "asset_symbol": "TEST", + "amount": 2101985 + }, + { + "owner": "TESTGPLBmJQruHPHskMd3Jbj5k4GKfksBrvFC", + "asset_symbol": "TEST", + "amount": 3055584 + }, + { + "owner": "TEST9JFbYhJBpNpe2MksjLJxfSXY8XvoAMUQv", + "asset_symbol": "TEST", + "amount": 58179459 + }, + { + "owner": "TESTG3nksyTr2TnuuLw9ae7f2VnpNPNiRfXta", + "asset_symbol": "TEST", + "amount": 1668593 + }, + { + "owner": "TEST6KobLV94qR3GS4YgmabCiu1f2bDLazH5h", + "asset_symbol": "TEST", + "amount": 7037601 + }, + { + "owner": "TESTHc6vpnKJ9K3Hb1YPJYRC4RzeHX3f6SqzR", + "asset_symbol": "TEST", + "amount": 35272637 + }, + { + "owner": "TESTGXXmUpJ7i8opnKKr2gmWW3YFhHMpRB2rM", + "asset_symbol": "TEST", + "amount": 779099 + }, + { + "owner": "TEST3UvD1CCz6mhm4H7F22VBGb1U2MTEocKU6", + "asset_symbol": "TEST", + "amount": 546487 + }, + { + "owner": "TEST4RdNdsBR19wR4EEFgXFvZhSyzXegxpnj2", + "asset_symbol": "TEST", + "amount": 1713385 + }, + { + "owner": "TEST3a6Wxxow429R82nMrRqrFbPiruZqTA8w2", + "asset_symbol": "TEST", + "amount": 172189571 + }, + { + "owner": "TESTAtFqKW7nxUbonPSjG9GcKNvyw42TtovY1", + "asset_symbol": "TEST", + "amount": 988499 + }, + { + "owner": "TEST9VmfWr4YBxndefh3KTvHv1yYHPCr37WFw", + "asset_symbol": "TEST", + "amount": 10810958 + }, + { + "owner": "TESTAxbSSvhiDUvJkrxfuN7RRu8EYTgzNzxbT", + "asset_symbol": "TEST", + "amount": 103638857 + }, + { + "owner": "TEST2U6LFsVN8Nhu5vRozWmgbvVNw4CBVtk9t", + "asset_symbol": "TEST", + "amount": 320000 + }, + { + "owner": "TESTK8Ctsct51CE4ib3CJojt3Xb4fB49hx5QU", + "asset_symbol": "TEST", + "amount": 2226328 + }, + { + "owner": "TEST674gCJe3jnBmh2kFRsPYgL9uqL3YfpZN3", + "asset_symbol": "TEST", + "amount": 496002 + }, + { + "owner": "TESTVe7i4CuaYkJFuaCVerDubsCCcWQQMMDA", + "asset_symbol": "TEST", + "amount": 6437654 + }, + { + "owner": "TEST7RpNtYXYxeULqeHfjA59fHsR29WEFWhpj", + "asset_symbol": "TEST", + "amount": 1413990 + }, + { + "owner": "TESTDkwHYz6U3oLwnXuZqghXwbr5CJBqZX1Xi", + "asset_symbol": "TEST", + "amount": 3964725 + }, + { + "owner": "TESTL9XpsYGMfBnKDQHHCMkH6PNaQUQA16JCV", + "asset_symbol": "TEST", + "amount": 124707845 + }, + { + "owner": "TEST3DSqtHYRCCLQC2azn6CpmXkQ6oeJYp44x", + "asset_symbol": "TEST", + "amount": 1949407 + }, + { + "owner": "TESTLJ2rCbtnLnpsK22nnB9LFNkdoS19dnMPv", + "asset_symbol": "TEST", + "amount": 24277852 + }, + { + "owner": "TEST9zJMG5c7aULhfoFL8dXaeuKSX68vmR4V4", + "asset_symbol": "TEST", + "amount": 13458158 + }, + { + "owner": "TESTKXWrZjyw19ZzDGSjqf8vMPxBifad35a1R", + "asset_symbol": "TEST", + "amount": 9367920 + }, + { + "owner": "TESTHFYovDkZ9Zz2vEkef8YXdrNuxKk9DLcE4", + "asset_symbol": "TEST", + "amount": 2156682 + }, + { + "owner": "TEST4oRxpVKurNwRLSL6dVDXbQWmrZXF985Uo", + "asset_symbol": "TEST", + "amount": 10720195 + }, + { + "owner": "TESTNGkrsPk9f7XdkgeirHVmMJ1pYbuTLToK9", + "asset_symbol": "TEST", + "amount": 15957 + }, + { + "owner": "TESTNkHpgK2aE6Tf3dCvaMC79dWo3NNYxH4v5", + "asset_symbol": "TEST", + "amount": 39338771 + }, + { + "owner": "TESTP74FrSi7kSsqGNyCdsKxN79Atz2zZ435z", + "asset_symbol": "TEST", + "amount": 19695557 + }, + { + "owner": "TEST6YQxzCKvmDq4TXmZhDCpZ9K9EoFuT8XpP", + "asset_symbol": "TEST", + "amount": 17190000 + }, + { + "owner": "TESTMPtimnNRQaLKVkQQmsm8t4rRX17K2ctjP", + "asset_symbol": "TEST", + "amount": 52909 + }, + { + "owner": "TEST544idHuP462i4wGqUFJcUeZCA3yaMSh2j", + "asset_symbol": "TEST", + "amount": 9826113 + }, + { + "owner": "TESTGLu8wpSJktouYEtjMizWSGwgv1fMar7Qn", + "asset_symbol": "TEST", + "amount": 159722056 + }, + { + "owner": "TESTP73gYCNWRdj2Lm6pM82LjwavNxUbsi5K8", + "asset_symbol": "TEST", + "amount": 48114389 + }, + { + "owner": "TEST4p6m7qioUeS6gdDTQky5pXnoym2PDTVm1", + "asset_symbol": "TEST", + "amount": 3554935 + }, + { + "owner": "TESTKD1jqiszT9ExH2HybXDtoe7nZRzAoV7Gg", + "asset_symbol": "TEST", + "amount": 979241 + }, + { + "owner": "TEST4euT6konp3ysPTgAoqxX3xgdkXKyFbFYA", + "asset_symbol": "TEST", + "amount": 2400660 + }, + { + "owner": "TEST5osm9uGtMTwVPte28k5dH1LnLtiWKQs2r", + "asset_symbol": "TEST", + "amount": 468396 + }, + { + "owner": "TESTLiiUeEBZ2ZNfHZPnmmcXCQocHrwc196N4", + "asset_symbol": "TEST", + "amount": 3916577 + }, + { + "owner": "TESTEcAUYkahh3MFFkaq54KNMZtBrcCys526w", + "asset_symbol": "TEST", + "amount": 144077760 + }, + { + "owner": "TEST6YKsXvQihLtF675wvnbL2iaNW17ZvroGF", + "asset_symbol": "TEST", + "amount": 3005985 + }, + { + "owner": "TESTLkD6Y5WNbS3515cuCy3sZUWgzE3QdQaGv", + "asset_symbol": "TEST", + "amount": 1261987 + }, + { + "owner": "TESTGTbCvThqS8EQ4UPrDFyLzbBkLJ8b97kFV", + "asset_symbol": "TEST", + "amount": 9717169 + }, + { + "owner": "TESTEiy9C3CsS6QoVuvm2fkXTSswvnTkJyvpP", + "asset_symbol": "TEST", + "amount": 347374 + }, + { + "owner": "TEST9F4HbajDY1NH8whr1YGBHbBk2Z3u6Yse", + "asset_symbol": "TEST", + "amount": 15236963 + }, + { + "owner": "TESTDCcQTx4AtaGLhZC2KGdPwb3Sy3nhVwQ7k", + "asset_symbol": "TEST", + "amount": 3133440 + }, + { + "owner": "TEST4CXkXBrdJzKU1vGt5xeeLV3jbyMmvMr2W", + "asset_symbol": "TEST", + "amount": 49994593 + }, + { + "owner": "TEST3WdouWrGPst9i6wEMVzQL6MBePAKkP7NE", + "asset_symbol": "TEST", + "amount": 3814338 + }, + { + "owner": "TESTHyHbAeVdexNbHpnK4s7w3wQfwQxM2WK69", + "asset_symbol": "TEST", + "amount": 8586464 + }, + { + "owner": "TESTBfw8i5LAw73RAEiKnt3gg616TGVsFLKWo", + "asset_symbol": "TEST", + "amount": 11445869 + }, + { + "owner": "TESTPMenP5JrwXq24US3fTJJDDa9Yiq3yzM5q", + "asset_symbol": "TEST", + "amount": 9649159 + }, + { + "owner": "TEST4ugpLdbVmd1h36JisofFtJC4H2vBfVGrh", + "asset_symbol": "TEST", + "amount": 3432362 + }, + { + "owner": "TESTNhJaYptjxXDznCoXFKDYAvTz5byMdtMRz", + "asset_symbol": "TEST", + "amount": 110684760 + }, + { + "owner": "TESTAK9p9tLKoMzxVebFoJ9REBWo3auQY7mbJ", + "asset_symbol": "TEST", + "amount": 19410980 + }, + { + "owner": "TEST4ujcNuN9ttZzuTbP1DPS2jArfGpFsWf1j", + "asset_symbol": "TEST", + "amount": 4338605 + }, + { + "owner": "TEST4vWRg7Wz9CnJ3LvquEac64fmfSNFwo35n", + "asset_symbol": "TEST", + "amount": 4706880 + }, + { + "owner": "TEST4CVCPUqS9iLaaxP8bdffbXJJLcKenc8KP", + "asset_symbol": "TEST", + "amount": 15784806 + }, + { + "owner": "TEST588rCGcMKgEmTjNRvaTrG1JH9JhjNZA4X", + "asset_symbol": "TEST", + "amount": 32119470 + }, + { + "owner": "TESTAL4SoNhm2P1nuoixJMcYVAaYQavRE38Qy", + "asset_symbol": "TEST", + "amount": 4976465 + }, + { + "owner": "TESTFkz1sBxYgwZDbnAWJ3xfbSdoKcL4q7g6T", + "asset_symbol": "TEST", + "amount": 9872334 + }, + { + "owner": "TEST7zzFnubgPd1DsiAVDhBAYCUxiqUuE3iKh", + "asset_symbol": "TEST", + "amount": 4432135 + }, + { + "owner": "TESTCQPgmcaMLwep2ee1cCUHLLXpC9sUuvA51", + "asset_symbol": "TEST", + "amount": 340169 + }, + { + "owner": "TESTEyeZE4GRHinTznHcTQRNZSVSXdYWdrUoq", + "asset_symbol": "TEST", + "amount": 4932014 + }, + { + "owner": "TESTBH2YUAwmf5iBUL1uoXPS3km1tqBaqp2eL", + "asset_symbol": "TEST", + "amount": 3388681 + }, + { + "owner": "TESTLQVgZAsJrbSaSzrZZJEaa9Gt127RXuMtU", + "asset_symbol": "TEST", + "amount": 1326190 + }, + { + "owner": "TESTNJDc3mGQ8qxMitaNujQW6gkyHMKkdXRLp", + "asset_symbol": "TEST", + "amount": 9781203 + }, + { + "owner": "TESTDQb9MGWkv1h5DWeiSoBVRCiMVZN72H9iP", + "asset_symbol": "TEST", + "amount": 5573147 + }, + { + "owner": "TEST4ZZVsczvfmgr3iKEXpDPexMvcr5bRZMBy", + "asset_symbol": "TEST", + "amount": 86297535 + }, + { + "owner": "TESTJrZwy9UW6TzDF8ApRZepNrESEWk49yce9", + "asset_symbol": "TEST", + "amount": 184695 + }, + { + "owner": "TESTDR1D942fepbBdXXbqkqW7J2eTGsJsyWyx", + "asset_symbol": "TEST", + "amount": 602368 + }, + { + "owner": "TESTJqxhUTaby4rYydYCJH5NQwcq51XF8X2Q2", + "asset_symbol": "TEST", + "amount": 4516780 + }, + { + "owner": "TESTHq8JCstPE3KKEQQwwarzrZMMYUJXypXnA", + "asset_symbol": "TEST", + "amount": 219529 + }, + { + "owner": "TESTAomXuZySnr3GrmDMieGacco5PTafbMQJS", + "asset_symbol": "TEST", + "amount": 1803119 + }, + { + "owner": "TEST7m5ZZiwXduzctc8uTVWcvggzP5pUeeJcn", + "asset_symbol": "TEST", + "amount": 5028065 + }, + { + "owner": "TEST7zN7AW85NLVXHV3S9ERfW4BQQSqEfs2VT", + "asset_symbol": "TEST", + "amount": 4522425 + }, + { + "owner": "TEST2YbRhGXimfJLJb7GJj9trEwhM7qJCMiUM", + "asset_symbol": "TEST", + "amount": 192061 + }, + { + "owner": "TESTBU3BfimXssZKWM7GwpUwuycGoqxtLLyY5", + "asset_symbol": "TEST", + "amount": 663206 + }, + { + "owner": "TESTGCHqqr7p1jPuFcRfXqeowFJ4Man2YKawm", + "asset_symbol": "TEST", + "amount": 4434857 + }, + { + "owner": "TESTMxsk1GMdbxk5o4D2ywr8KPXaHwEJBah9y", + "asset_symbol": "TEST", + "amount": 179437202 + }, + { + "owner": "TESTUujRLFxBVF4MHaGVKXCZT5GrPZQPYPgm", + "asset_symbol": "TEST", + "amount": 46375 + }, + { + "owner": "TEST21sMy8WwRngapiWHpoqavqkgZLfeF4V3G", + "asset_symbol": "TEST", + "amount": 67635079 + }, + { + "owner": "TESTGggmUD4k18pTkvZaMkUsbCFUbk4WT3yos", + "asset_symbol": "TEST", + "amount": 17569718 + }, + { + "owner": "TESTPFiuwbreDkUas9Uijuj6fuKJ88BPGpnxJ", + "asset_symbol": "TEST", + "amount": 8797130 + }, + { + "owner": "TEST6KCNk16SamDgHg2RxPHeEEjC1Eqbg4YPj", + "asset_symbol": "TEST", + "amount": 595026 + }, + { + "owner": "TESTD3RnSiMJy1R4js27qFRMPaP7ZT5MSH2ru", + "asset_symbol": "TEST", + "amount": 23585203 + }, + { + "owner": "TESTG4oa6BQbR6rumeHWi4jeWpgR4qm7kUxcr", + "asset_symbol": "TEST", + "amount": 4141797 + }, + { + "owner": "TESTEYWq2sRaQrFYSPStqLqswFNo7YVbfdPUV", + "asset_symbol": "TEST", + "amount": 3413383 + }, + { + "owner": "TESTMYELoVUFcrkTkUD26RYFec9vkPKuvYEhv", + "asset_symbol": "TEST", + "amount": 4421078 + }, + { + "owner": "TESTJXWsaDYPnmwbqn5GT49GG5qHeD5cDnMYV", + "asset_symbol": "TEST", + "amount": 363140 + }, + { + "owner": "TESTCpkD7dXKtB7hVz8Z6CjvdYrNZG8SEbH4T", + "asset_symbol": "TEST", + "amount": 524030041 + }, + { + "owner": "TESTAVVYNbsJtY8kqmPJkpY5AU2JRupLHeBQf", + "asset_symbol": "TEST", + "amount": 35799663 + }, + { + "owner": "TEST3Y7rdtUPsWHihkqdTQqm44AjdAkJ1JM3d", + "asset_symbol": "TEST", + "amount": 5986915 + }, + { + "owner": "TESTLY9xMZCLwC7UvQcb9yu3zaTjk5YF1rfif", + "asset_symbol": "TEST", + "amount": 95322422 + }, + { + "owner": "TESTEii8onNZwGKjvEVtf6wRwJvp5jDi8CRWK", + "asset_symbol": "TEST", + "amount": 188674 + }, + { + "owner": "TESTAu38c5bZac5Z3Hgf9gFHE5WmMwWnnF9dw", + "asset_symbol": "TEST", + "amount": 520765588 + }, + { + "owner": "TEST7SiHRXifTNmekZnHBniMBBHanRbHQ3hRT", + "asset_symbol": "TEST", + "amount": 4369362 + }, + { + "owner": "TEST4AuT8nZ3tDS2m28seUFxzeYf1X4ksdjwu", + "asset_symbol": "TEST", + "amount": 1245580 + }, + { + "owner": "TESTAei4SyaHWzKeWBkUKZQbaMQyupQtDZeDH", + "asset_symbol": "TEST", + "amount": 6236099 + }, + { + "owner": "TEST67pFM3xcYxBGntEh8dnN1KgKpDdhfZ6DD", + "asset_symbol": "TEST", + "amount": 80653 + }, + { + "owner": "TESTALgr7puSoHdyYZxzMKmZXDYK6Nay1ndaf", + "asset_symbol": "TEST", + "amount": 114111 + }, + { + "owner": "TESTFfHvf6RAeZNW2GWBcehAUUJU1fW2urziB", + "asset_symbol": "TEST", + "amount": 11724900 + }, + { + "owner": "TESTHM2ncAUWdpbxYhsWkTv2gdKJg7Zo3sxL2", + "asset_symbol": "TEST", + "amount": 912837 + }, + { + "owner": "TESTH6nSmYhH9qkVGRYxH49QHtgh4J3a39bsR", + "asset_symbol": "TEST", + "amount": 3744572 + }, + { + "owner": "TEST3HH7uuv3ZrAQAhe56pBzbPNcq7F5RP2ZW", + "asset_symbol": "TEST", + "amount": 14580567 + }, + { + "owner": "TEST8jNN7BE2sjYVwAZhfBJVoikKEWAMhcBnp", + "asset_symbol": "TEST", + "amount": 1986542 + }, + { + "owner": "TESTKfmhWQtYfLYRyzAsey1eignhBXr9Fgp1S", + "asset_symbol": "TEST", + "amount": 17313100 + }, + { + "owner": "TESTDu7mzt8BRfsYdGh5oQD3P868utJWC9WQk", + "asset_symbol": "TEST", + "amount": 9544197 + }, + { + "owner": "TESTDJXfQZTjGb5A1ezwnKu3p8vBz2NFLJqGA", + "asset_symbol": "TEST", + "amount": 82874489 + }, + { + "owner": "TESTKDsKqnSiLJEKsG83U5JQ93eAj6wS77KBN", + "asset_symbol": "TEST", + "amount": 2282722 + }, + { + "owner": "TESTCVnorbDA79rH3aMMW5XUbU5uoVkQ8xBLi", + "asset_symbol": "TEST", + "amount": 19135916 + }, + { + "owner": "TEST2ULbHHv2icg4bhz2McPqekdvA7MMxGMY7", + "asset_symbol": "TEST", + "amount": 6264846 + }, + { + "owner": "TEST3MeYawXFhmwxYJtjzComNovPwWxP1i2wh", + "asset_symbol": "TEST", + "amount": 6043660 + }, + { + "owner": "TESTPXVBEanVEtRFn3uWSQBbtroXUu5SwJJKC", + "asset_symbol": "TEST", + "amount": 4880494 + }, + { + "owner": "TESTPSSn8BAxaeVJZ8rT3tHKW8EMmb7Cmb9j2", + "asset_symbol": "TEST", + "amount": 45229699 + }, + { + "owner": "TEST9YHGcrQk93RnomKVebZqTGFBouAB4aZo5", + "asset_symbol": "TEST", + "amount": 1882413 + }, + { + "owner": "TEST374YSSFgjMjzZnH4kdkd87vpm4TRMHQQx", + "asset_symbol": "TEST", + "amount": 24012957 + }, + { + "owner": "TEST3iNPee81ybbtgHVATpdx6qF3QD4u8Zsm9", + "asset_symbol": "TEST", + "amount": 5972915 + }, + { + "owner": "TESTChzVoAzi8vinkGKkDvWxxGe1cLQrXBLRm", + "asset_symbol": "TEST", + "amount": 4537051 + }, + { + "owner": "TESTKNxXVb4EMXmqcViJMMpN7yEyUBwQtRxSh", + "asset_symbol": "TEST", + "amount": 109557 + }, + { + "owner": "TEST9Kbmses3Fv3o6dmUqAxXT8XjqweXXXub2", + "asset_symbol": "TEST", + "amount": 20127724 + }, + { + "owner": "TESTLTHeDT77YJmMuaycTLLZzuCwdxhAH1tfM", + "asset_symbol": "TEST", + "amount": 2781772 + }, + { + "owner": "TESTJpj2ybuvdY9WbnGk8cJg56AoDTFTMCQpd", + "asset_symbol": "TEST", + "amount": 11820879 + }, + { + "owner": "TEST2ARg813SjqwUmNxtUwUGQQs5pZpw3kbjh", + "asset_symbol": "TEST", + "amount": 948496 + }, + { + "owner": "TESTHQ2CjczCKYrbuU2DLRyFwKXQQkZ7JhvpT", + "asset_symbol": "TEST", + "amount": 1403943 + }, + { + "owner": "TESTCSrwbKXhfM1YUT5HFnRLLL2N53hawpSte", + "asset_symbol": "TEST", + "amount": 848918 + }, + { + "owner": "TEST3kTJfsWDh6HcMFuPHNpdirPHLDHFgaEQ2", + "asset_symbol": "TEST", + "amount": 10491368 + }, + { + "owner": "TESTEvRGoqLNceHYQtWGFtKWipJidunP2zEgT", + "asset_symbol": "TEST", + "amount": 10281864 + }, + { + "owner": "TESTE8JardNAvE58n8p8SWG7PrqaH7mkknPRQ", + "asset_symbol": "TEST", + "amount": 17834508 + }, + { + "owner": "TESTFynDtiQqJtk3PU3a1NqVS9aUmwEn515My", + "asset_symbol": "TEST", + "amount": 81537079 + }, + { + "owner": "TEST8iww4n615i6T6qgroRJdxH4j7wGmV5vK9", + "asset_symbol": "TEST", + "amount": 6578400 + }, + { + "owner": "TESTNEZx2aKXxeZRphzaEXbEc1GGZXLwwwgaB", + "asset_symbol": "TEST", + "amount": 1779396 + }, + { + "owner": "TESTHAbWh1SggaZtkv81UjEJ8wC7x4PQuWdan", + "asset_symbol": "TEST", + "amount": 15373980 + }, + { + "owner": "TESTey126HoyuAYMno5NwDZcpboYPra1SM25", + "asset_symbol": "TEST", + "amount": 34046476 + }, + { + "owner": "TESTCD18G14M6P7zMhE6pbcTVYUCPynDEh5D2", + "asset_symbol": "TEST", + "amount": 84150 + }, + { + "owner": "TESTQ8zzAomE1F27dQdDBdNy2ajsyVuYEZPtw", + "asset_symbol": "TEST", + "amount": 344173 + }, + { + "owner": "TESTL5djC9x1RXBex5BxbUrKsgRJGvzThKk95", + "asset_symbol": "TEST", + "amount": 74363549 + }, + { + "owner": "TESTHJom9CCUm4qkAvhBgR58vASfBxYaBMsxY", + "asset_symbol": "TEST", + "amount": 12550000 + }, + { + "owner": "TEST7nnmNr91762o1ZxnY4D5WCrjcQ3HDokxt", + "asset_symbol": "TEST", + "amount": 45104060 + }, + { + "owner": "TEST4xSufY1ME2m2V4y2vxQJYexTq8NcQLrGw", + "asset_symbol": "TEST", + "amount": 6905129 + }, + { + "owner": "TEST7rLaNgmti8eCpYThT2MEzUphB6QQ2bgMX", + "asset_symbol": "TEST", + "amount": 23396680 + }, + { + "owner": "TESTCaSDmbjyG2wUVn6JGB15mdNcLSGXwquas", + "asset_symbol": "TEST", + "amount": 6309978 + }, + { + "owner": "TESTMaXqrRZwTZ35VWDyj1s4uTx5GoRDiQK4i", + "asset_symbol": "TEST", + "amount": 49908507 + }, + { + "owner": "TEST7WYWZ2opzquEogX6UYU2af7KsxBWnjURy", + "asset_symbol": "TEST", + "amount": 23599833 + }, + { + "owner": "TEST9N2nduAkrRmjZdHb8NXdeDFsLPV36p2t1", + "asset_symbol": "TEST", + "amount": 2415621 + }, + { + "owner": "TEST3Yb9YPZoEkbAVhFgT5FL2tS2bNb2uJsCe", + "asset_symbol": "TEST", + "amount": 253488 + }, + { + "owner": "TESTGb38doR2taRREMUt5GD6hsirn2TCj1fco", + "asset_symbol": "TEST", + "amount": 94555520 + }, + { + "owner": "TESTCZQ29qQzk3mdQ9Nk9rWBXDVzUGygYbUHc", + "asset_symbol": "TEST", + "amount": 17136424 + }, + { + "owner": "TESTJBvTCCKEhT7xv21krRhJZVyogBRM9oLJY", + "asset_symbol": "TEST", + "amount": 111284674 + }, + { + "owner": "TESTGtgoifgN1guLW9KMiRsbDXeYCVw2Lku6N", + "asset_symbol": "TEST", + "amount": 3723539 + }, + { + "owner": "TESTFpCqbkkPFTAL4KCat34MAVPgUen577DQs", + "asset_symbol": "TEST", + "amount": 2503480 + }, + { + "owner": "TEST8t6RXK6SA4MUy3FJ3GVgQG7xVquyWVjzc", + "asset_symbol": "TEST", + "amount": 35569926 + }, + { + "owner": "TESTFNCV1rCjRNAXasHHYrB915LB3LiwrV4QK", + "asset_symbol": "TEST", + "amount": 17640360 + }, + { + "owner": "TESTGot12iZuggkvnCVKXnvXwpM3TJYwsxa7R", + "asset_symbol": "TEST", + "amount": 5150717 + }, + { + "owner": "TESTFtvvwyzvVyw9jpxWbDcgnuFJ986gTCYsA", + "asset_symbol": "TEST", + "amount": 950425 + }, + { + "owner": "TESTJngTfuLcXNVDYpR4FpsVHz3YvavCiHqxB", + "asset_symbol": "TEST", + "amount": 10316748 + }, + { + "owner": "TESTEhJYSPBW1UxJmEucqZwbVP3YxVjwS3wv", + "asset_symbol": "TEST", + "amount": 107939247 + }, + { + "owner": "TESTBBDwGgFmNbq56P5r8RW2HheEoaXqogbQs", + "asset_symbol": "TEST", + "amount": 4769364 + }, + { + "owner": "TESTMbFxFoqK88rCgtdafWP8RLZgmVT6EsD1o", + "asset_symbol": "TEST", + "amount": 17379205 + }, + { + "owner": "TESTCPHcLnSrr1YmQsL38VeFaWG133VHmGs1s", + "asset_symbol": "TEST", + "amount": 1250960 + }, + { + "owner": "TEST782oaViNVsiTbmXp9RteTKiB66DzrgbJg", + "asset_symbol": "TEST", + "amount": 10989 + }, + { + "owner": "TEST6irccAdw3HgCfac6s4Mf5Tb3fohXv7Uij", + "asset_symbol": "TEST", + "amount": 473105491 + }, + { + "owner": "TESTN5ygAsHJBxWrpixcuW9egm6oqaFH4Z1ro", + "asset_symbol": "TEST", + "amount": 6693136 + }, + { + "owner": "TEST2tkyjM9ESruqvR91U3GTr6bTbKmS4gsM9", + "asset_symbol": "TEST", + "amount": 6691392 + }, + { + "owner": "TESTEvJxzqPSCVvmK7XbJRo6THkrBaoyMy6sK", + "asset_symbol": "TEST", + "amount": 12566772 + }, + { + "owner": "TESTLtTS7PTMGtLLXdYMpNzKVhzB6P59bFjnq", + "asset_symbol": "TEST", + "amount": 12123564 + }, + { + "owner": "TESTJtkNWXim1GRSTmDNLhx1YyDM7eE8ygPzY", + "asset_symbol": "TEST", + "amount": 5578443 + }, + { + "owner": "TESTNKsEDL9LJNQH3kbsS4CuQLmUd5WeJMHdY", + "asset_symbol": "TEST", + "amount": 66608068 + }, + { + "owner": "TEST7jQiyE7hSfsdoNJa7YqVyj1rEeBwZpZBA", + "asset_symbol": "TEST", + "amount": 4168987 + }, + { + "owner": "TEST2EC4gPi2WebbWJeXj4yjjYEbXhXDWkWTq", + "asset_symbol": "TEST", + "amount": 983908 + }, + { + "owner": "TESTGs2HNeuPWnELqcEXho9n92QTr72oC3JkR", + "asset_symbol": "TEST", + "amount": 11699895 + }, + { + "owner": "TESTCyHtwLCks1Nr3uyXPHk2irbxZEEDkwqqs", + "asset_symbol": "TEST", + "amount": 5008 + }, + { + "owner": "TESTAgf8GZGndoi3Dgue1e1iHCnmgbYzLzrp7", + "asset_symbol": "TEST", + "amount": 88416274 + }, + { + "owner": "TESTMjvnL8vLvp1tRvWvd9yBTrZqm2iBqMScj", + "asset_symbol": "TEST", + "amount": 7618519 + }, + { + "owner": "TESTB3xmoCoGypxwwsfpZM7LhMpys3Tae2xKN", + "asset_symbol": "TEST", + "amount": 18894838 + }, + { + "owner": "TESTAYKDM99VxZZgrKTcGRu18vqswbxZVyEg2", + "asset_symbol": "TEST", + "amount": 3149567 + }, + { + "owner": "TESTHDqfJ7WSL2uDZ9ALEgM7QeJujfKhqBc2T", + "asset_symbol": "TEST", + "amount": 67889143 + }, + { + "owner": "TEST3X1SgwQacYUT3Jx8LpvCQ6LGk9eTCcQvL", + "asset_symbol": "TEST", + "amount": 9522919 + }, + { + "owner": "TEST6Zy9JiZXb7KqzYToi7oqF3JW6ZTmdQXMX", + "asset_symbol": "TEST", + "amount": 62987862 + }, + { + "owner": "TESTEbFQexkEMmWGzgD5xFPKMPPsVJ9SuiJyD", + "asset_symbol": "TEST", + "amount": 1392003 + }, + { + "owner": "TEST4r3jj9EVNbemi6oJ5VNeUEoVnQKevzSxT", + "asset_symbol": "TEST", + "amount": 104240 + }, + { + "owner": "TESTQEPGHUzDr7o1HAL2cwczEbBYzmnVXQeWo", + "asset_symbol": "TEST", + "amount": 49944218 + }, + { + "owner": "TESTM1Wy5bMymDiavL6Us7QR6n8CbM5BipRfv", + "asset_symbol": "TEST", + "amount": 785054 + }, + { + "owner": "TESTGeVUy3HvkuZ7agMLQTA8WtcNHdY6vXLo1", + "asset_symbol": "TEST", + "amount": 33081384 + }, + { + "owner": "TEST5nddVGPYZPEAmbSoDdf5qSXJoLPhBJfEg", + "asset_symbol": "TEST", + "amount": 999777 + }, + { + "owner": "TEST8Mjrch1Xo6jUj3AY5UTLpudGjzXHcwdF7", + "asset_symbol": "TEST", + "amount": 6795486 + }, + { + "owner": "TEST2FCXdFyGGov4ibqSUGs3XTjiN5HLTPS8M", + "asset_symbol": "TEST", + "amount": 351563 + }, + { + "owner": "TESTDR6pb2QrvN6DesK8v3hL733CTTsRRrra", + "asset_symbol": "TEST", + "amount": 51599600 + }, + { + "owner": "TESTKQhBgShmUSPZnMZS5oxWdKqJ2Ge7jEsTM", + "asset_symbol": "TEST", + "amount": 5263168 + }, + { + "owner": "TEST9TArsqXZSTa9MkP7MEYcCCxZ4MApB986U", + "asset_symbol": "TEST", + "amount": 11691813 + }, + { + "owner": "TESTCsXEnqNasVF2zF2HDKKQQktXEL4ixFwGJ", + "asset_symbol": "TEST", + "amount": 49466683 + }, + { + "owner": "TESTMX2X4WfgqdrPF1Nw18DVK3dmwPww5ZNX5", + "asset_symbol": "TEST", + "amount": 43727290 + }, + { + "owner": "TESTC5NRLm9CwoccLQocgCqQdbYvo1VBJqrSP", + "asset_symbol": "TEST", + "amount": 8066119 + }, + { + "owner": "TESTB2hwRXMu3yaxNnefGgWE2R6mrzoQ83y4N", + "asset_symbol": "TEST", + "amount": 1029072 + }, + { + "owner": "TEST77FE3zpkd37W8LsEBRa3uBLTg42XZMYGg", + "asset_symbol": "TEST", + "amount": 33616305 + }, + { + "owner": "TESTANzNtHECsPnPo13SHdJTNbNPGebq244ZH", + "asset_symbol": "TEST", + "amount": 1933236 + }, + { + "owner": "TEST5VzYbdVXvY88jpuCePomymf8zp99LbugY", + "asset_symbol": "TEST", + "amount": 40474221 + }, + { + "owner": "TESTFHTz6WzJfhiNmYZMgmoqwgxVp67B4ALAD", + "asset_symbol": "TEST", + "amount": 6894873 + }, + { + "owner": "TESTD83uKvM3s5s48b147obx1XiGxA7Dkoa4c", + "asset_symbol": "TEST", + "amount": 17438700 + }, + { + "owner": "TESTC1KebJqN5spLTc4kbAAmLg1rX4YcmAdKy", + "asset_symbol": "TEST", + "amount": 1549026 + }, + { + "owner": "TESTBA7V67T7fYkDkW6K62jyyLoBsTo1RnrZN", + "asset_symbol": "TEST", + "amount": 346454 + }, + { + "owner": "TESTHjvUfQ5jzK5eEwMQ8jTWDqBXgz4jNfjac", + "asset_symbol": "TEST", + "amount": 1624964 + }, + { + "owner": "TESTG63NKAKju5ejQ4JaM1QU3CwkL7tnJqngB", + "asset_symbol": "TEST", + "amount": 104337037 + }, + { + "owner": "TESTAKFZTnY3MErRgkogaHuVKffiXyNhZ6f87", + "asset_symbol": "TEST", + "amount": 7525333 + }, + { + "owner": "TESTJef4cNLofBz4KcYZt6xhvhZ6ya32HjboH", + "asset_symbol": "TEST", + "amount": 4566095 + }, + { + "owner": "TESTJ2iWXb3wk8wbEuWDRUALxyzBpBJjCSenM", + "asset_symbol": "TEST", + "amount": 15460243 + }, + { + "owner": "TESTNy2yb45X21GfyCS6DfBfbBcDq9RM86xud", + "asset_symbol": "TEST", + "amount": 1909932 + }, + { + "owner": "TEST6WW2zvjSTdtxjqtzyeAtsdUNeXLiJZn8M", + "asset_symbol": "TEST", + "amount": 673049 + }, + { + "owner": "TESTMroso5u7EwojMnzMpdzvLSfwPi7afhFWV", + "asset_symbol": "TEST", + "amount": 1913660 + }, + { + "owner": "TESTH6xHRs7MFBstc9brCahjbf27bCYWYA945", + "asset_symbol": "TEST", + "amount": 6113905 + }, + { + "owner": "TESTLLHffF9LyLQu2wYYqZLUctt5f3bbuhdyF", + "asset_symbol": "TEST", + "amount": 34801200 + }, + { + "owner": "TESTHuGUaN5q5b4JEkdzwTyoJxJatNUe9fyFe", + "asset_symbol": "TEST", + "amount": 473 + }, + { + "owner": "TESTJa6kPEZ8AJgPPTMaSX6osjboVJmaNDEAk", + "asset_symbol": "TEST", + "amount": 4200975 + }, + { + "owner": "TESTCZH9iarwGMeTofZJBJnNX1dGDAdSaWq4V", + "asset_symbol": "TEST", + "amount": 4191035 + }, + { + "owner": "TESTAPjpve4yJ3Tri7TZe4GhZGHFocofWHF5X", + "asset_symbol": "TEST", + "amount": 2007301 + }, + { + "owner": "TEST79MHuw5yXgEYNEsto8Vz1KHkPzNzdzDqA", + "asset_symbol": "TEST", + "amount": 3087381 + }, + { + "owner": "TEST642uE4T8hB7oQe9Din7psycBX4CUJktTP", + "asset_symbol": "TEST", + "amount": 6234900 + }, + { + "owner": "TESTPFiqzQsnb8DnTLZu3u6jFV2rVm3gKEUUZ", + "asset_symbol": "TEST", + "amount": 5271099 + }, + { + "owner": "TEST9aBZX18qjy68Wvkre2XgofxLJVZPJq4Yu", + "asset_symbol": "TEST", + "amount": 13361635 + }, + { + "owner": "TEST7zUgLoMr42TW1BHAgWdLKCEG7NhY1zbCa", + "asset_symbol": "TEST", + "amount": 102970857 + }, + { + "owner": "TEST66zo4zoL5mQHNWzmCSkcpxXSuW4jZaP2s", + "asset_symbol": "TEST", + "amount": 378785 + }, + { + "owner": "TESTAjJNsaTPtqKxa2EA6rDat34gzB7SvA69F", + "asset_symbol": "TEST", + "amount": 1671500 + }, + { + "owner": "TEST4Y2TbuZZEpwxPDEZHypoReh9TrVfjb1Ds", + "asset_symbol": "TEST", + "amount": 13165307 + }, + { + "owner": "TESTB8qZpJayBUbVzDYmrs2iF9U6jr3bHox2H", + "asset_symbol": "TEST", + "amount": 343800 + }, + { + "owner": "TEST2WtM4i49nF3mXZ4hsJtCqbrxJRLwFeqrD", + "asset_symbol": "TEST", + "amount": 33938 + }, + { + "owner": "TESTPuYmotAsHFGmCKwBsR9X6MXZjdVzr2qhU", + "asset_symbol": "TEST", + "amount": 7185135 + }, + { + "owner": "TESTNScsahGixPxjEZqLkQyxHqoRwe4TEu1Zd", + "asset_symbol": "TEST", + "amount": 330502754 + }, + { + "owner": "TEST5bHLd5bLGdkCWM4BKmv3bwFtke5WJvCc1", + "asset_symbol": "TEST", + "amount": 1955120000 + }, + { + "owner": "TESTJ632W1S9aFAQdCGFAkY7bfifcMBz8Rdth", + "asset_symbol": "TEST", + "amount": 31884927 + }, + { + "owner": "TESTDsGLjNjMATiT518v9La7BwrZR8MMKwdzS", + "asset_symbol": "TEST", + "amount": 7944469 + }, + { + "owner": "TEST5fNJxV62zWXfpZhcvuCZrM7BNFWU1jjHR", + "asset_symbol": "TEST", + "amount": 208586693 + }, + { + "owner": "TESTFEy5HFEeUaBwb38QMHLcejTWXsqBw6Kmv", + "asset_symbol": "TEST", + "amount": 25306569 + }, + { + "owner": "TESTEpjswo7sXAetj1Prbvd6h4W7XYzG6TXeM", + "asset_symbol": "TEST", + "amount": 31961413 + }, + { + "owner": "TESTHtFRp6ct3TkERZWJG1wDRFXoQfW8jADX1", + "asset_symbol": "TEST", + "amount": 20571425 + }, + { + "owner": "TESTPMHm5v2tTVaL4xPZcUzXiGVzbx9aQLspt", + "asset_symbol": "TEST", + "amount": 817662 + }, + { + "owner": "TEST2CvWgLb3vocc1dSLZqSN4thZnyZoa4heb", + "asset_symbol": "TEST", + "amount": 190057 + }, + { + "owner": "TEST2pdTzShVkqWnEkAHLtncn9Cp17MvpyHL7", + "asset_symbol": "TEST", + "amount": 1105170 + }, + { + "owner": "TESTPT9NjM7VoP9XepAjXXuthMimwxmcskiMr", + "asset_symbol": "TEST", + "amount": 1030567 + }, + { + "owner": "TESTN3Pn7LFRXJGDQTCYdTDyk2BkUBe8cSVD3", + "asset_symbol": "TEST", + "amount": 10176568 + }, + { + "owner": "TEST65jr2NnAz7szmXEjwXHCKrDFWQyaqFu2p", + "asset_symbol": "TEST", + "amount": 451213 + }, + { + "owner": "TESTYccHVAEhNMDWtaf4At55yiQwNtMeMx5G", + "asset_symbol": "TEST", + "amount": 33137 + }, + { + "owner": "TEST4cubVf1xHcuDYmggj1DA1fZBGtHMHjtgh", + "asset_symbol": "TEST", + "amount": 423541 + }, + { + "owner": "TEST7p7tXKXZaGjw8BznWUtsdTwxPUPYeZ5vk", + "asset_symbol": "TEST", + "amount": 4010124 + }, + { + "owner": "TESTFjWpbpUqCbPEArNWnD8puLAaju8NhjEaQ", + "asset_symbol": "TEST", + "amount": 6640403 + }, + { + "owner": "TEST2nonAPKtWnXmoo1zrUTWkQTQnaZvB79Cg", + "asset_symbol": "TEST", + "amount": 6613680 + }, + { + "owner": "TESTHfxASWSwPhAGAA76rYU2JuB8WLZFzKhaB", + "asset_symbol": "TEST", + "amount": 33370982 + }, + { + "owner": "TESTG9LqUkcQt9niVmCkyUt3uvA4eXSMzyw6Z", + "asset_symbol": "TEST", + "amount": 1210106 + }, + { + "owner": "TESTJdHFQJQzzds4eYiA1shzFYi7jQ4cjpdF7", + "asset_symbol": "TEST", + "amount": 1263776 + }, + { + "owner": "TESTH9HoZgUa1iRSFEf72wBvgG8Li3ZGxyQEQ", + "asset_symbol": "TEST", + "amount": 1418257 + }, + { + "owner": "TESTAZ4R2X6Bt31JcvCxXdzGtcYAo8AWDPkny", + "asset_symbol": "TEST", + "amount": 611564 + }, + { + "owner": "TESTQDv3zxP9qjtQTDzk2Q9Qcd29sy2ZLEK62", + "asset_symbol": "TEST", + "amount": 814213 + }, + { + "owner": "TEST4jwJZJMP6ypjXm9ha8TnBy8Uo3MJt8NpH", + "asset_symbol": "TEST", + "amount": 7583087 + }, + { + "owner": "TESTBJtzaWEAAs65TyM8YapzxQTjCtBnPEu1m", + "asset_symbol": "TEST", + "amount": 46532160 + }, + { + "owner": "TESTNF2gSJ76MRX6w6eLYwNvqzEy3Et9Na3pL", + "asset_symbol": "TEST", + "amount": 30018492 + }, + { + "owner": "TEST89GXmtERWu29MBRgNPraUZPeHM1YqQsef", + "asset_symbol": "TEST", + "amount": 175291 + }, + { + "owner": "TESTE29LprgZ5LUP7ZaRMZhyjS9P5UHahqZeH", + "asset_symbol": "TEST", + "amount": 352237 + }, + { + "owner": "TESTDjucvRDe1xpUUq6LaT32YmnENkQ1cdNsV", + "asset_symbol": "TEST", + "amount": 5168935 + }, + { + "owner": "TESTN1aS4FijFRs4Fzt9goJKKtRJCz12suegy", + "asset_symbol": "TEST", + "amount": 323051 + }, + { + "owner": "TESTPCCMJbr1L4MU6XdGJogey6j48Wsk9GKqg", + "asset_symbol": "TEST", + "amount": 168313102 + }, + { + "owner": "TESTaR4QsmQDYVrQ5mg86R8MKzcpEjkNUsia", + "asset_symbol": "TEST", + "amount": 563680 + }, + { + "owner": "TEST2cBucS7MNxmUZzLjTGbjRYEZYDNbyMeoY", + "asset_symbol": "TEST", + "amount": 8328234 + }, + { + "owner": "TESTK5NUjH7fRfrgFBAeEvct3AxmJWTs2v7k", + "asset_symbol": "TEST", + "amount": 13713422 + }, + { + "owner": "TESTLYpd68mmSP3dkF1wbpk7WFGPgSNWML48V", + "asset_symbol": "TEST", + "amount": 13295178 + }, + { + "owner": "TESTJQXeNagFCB1q4iniUQMA7oDBGvkn4KcsL", + "asset_symbol": "TEST", + "amount": 143149440 + }, + { + "owner": "TESTH8P4xdZzK5mtgUUFXnnm123ASFnBA8Cam", + "asset_symbol": "TEST", + "amount": 7157612 + }, + { + "owner": "TEST2UdDcZmQN2tN9er6WuCpzFeD7yKfvgpNQ", + "asset_symbol": "TEST", + "amount": 35738820 + }, + { + "owner": "TESTDRD3uGnztqhEY2PreFvQc7keTMeGsfdET", + "asset_symbol": "TEST", + "amount": 2016719 + }, + { + "owner": "TEST77EP8FKsctsiobNinriK5kEAFrdPWzsdC", + "asset_symbol": "TEST", + "amount": 3160560 + }, + { + "owner": "TEST8r4Xa1ieBn3Hfn66uUbsux5N4TfjD8CQ6", + "asset_symbol": "TEST", + "amount": 17546383 + }, + { + "owner": "TEST5LqeaaY8Bixf9zL9MU55ekmn3uQkRHeEG", + "asset_symbol": "TEST", + "amount": 15845015 + }, + { + "owner": "TEST13VuVyCeaKhSoBCevEv96fnhdamRrAGNs", + "asset_symbol": "TEST", + "amount": 2578370 + }, + { + "owner": "TESTFKsvueR5T4imGs2uf11mbaz28oiBSADw8", + "asset_symbol": "TEST", + "amount": 2409090 + }, + { + "owner": "TESTM5oH6xnoa8rqrPgibhHZms354RLe5Y3LW", + "asset_symbol": "TEST", + "amount": 44934 + }, + { + "owner": "TESTCzPgPHZe2jfTAng1Xs7g84qZWo4pj9cFz", + "asset_symbol": "TEST", + "amount": 6379107 + }, + { + "owner": "TESTC3jA7WM1wmrjsnbEQQikg5US5Gq6XznPp", + "asset_symbol": "TEST", + "amount": 6319880 + }, + { + "owner": "TESTHiSBeDfKW1WCksd1cb3Sb7r3tPawJRJVu", + "asset_symbol": "TEST", + "amount": 2316903 + }, + { + "owner": "TESTEgaV92kFQFQgDJiQ92Yzddy5ihSygqkfb", + "asset_symbol": "TEST", + "amount": 35227782 + }, + { + "owner": "TESTLDduDe1c3sVRw6GfMYsT1kZXN8fopZtCL", + "asset_symbol": "TEST", + "amount": 847866 + }, + { + "owner": "TESTGAAHfo347NsKJFbDFJbE7PshKAuRi4Hao", + "asset_symbol": "TEST", + "amount": 5792041 + }, + { + "owner": "TESTJnREd5jT9WMnyzhbMeavRD9JXWmUJjCkK", + "asset_symbol": "TEST", + "amount": 3319406 + }, + { + "owner": "TEST5i1WJmhPwWumQAsKmUXmZKnx6NASjVhzg", + "asset_symbol": "TEST", + "amount": 161096 + }, + { + "owner": "TEST26Jv5uKw4RTRU9Ux4sCVWfFgCMeXfFEx8", + "asset_symbol": "TEST", + "amount": 7998941 + }, + { + "owner": "TEST2yKtjbQgVBrzidCZ8U2tdiMrE91KwW5C3", + "asset_symbol": "TEST", + "amount": 67796889 + }, + { + "owner": "TESTF3V39dvCNPBoSdD9D5YBsrDRpuku8QCQS", + "asset_symbol": "TEST", + "amount": 1478227 + }, + { + "owner": "TESTPrBjab8Bp8MFNofbFvL4DJUFgxwDewzRX", + "asset_symbol": "TEST", + "amount": 21861186 + }, + { + "owner": "TEST5VcSFJ8ZBz3H43Gos55XdssKBVzWeqU9g", + "asset_symbol": "TEST", + "amount": 163925684 + }, + { + "owner": "TEST4AJqwKjAbm2nA9ZZfP6pzr53XQBnJTwDg", + "asset_symbol": "TEST", + "amount": 2955285 + }, + { + "owner": "TESTLsSwdsZz4DMbn5RT8HXQB9WHe4YrL3ivP", + "asset_symbol": "TEST", + "amount": 6482860 + }, + { + "owner": "TESTNsFhYoeKemv1JpzRrJNsA84NoTzL3jX83", + "asset_symbol": "TEST", + "amount": 5664992 + }, + { + "owner": "TEST3rWRaiRBabbzpsaPvTtUeMC8vJZBd91fH", + "asset_symbol": "TEST", + "amount": 845191 + }, + { + "owner": "TESTNqHLvLh9AXQsQho6ZzBXoHbN2tWUQXrW", + "asset_symbol": "TEST", + "amount": 343048800 + }, + { + "owner": "TEST3twfEDA5EqJKQsg8mHwCVH9XhxtMbD3JD", + "asset_symbol": "TEST", + "amount": 7445544 + }, + { + "owner": "TESTNvBQZDDmk4CWcospqHycM8Crnf6hThYLq", + "asset_symbol": "TEST", + "amount": 15124881 + }, + { + "owner": "TEST38aY7DkBCrE52QGxtYt7RkwXsdahCd84Q", + "asset_symbol": "TEST", + "amount": 187868 + }, + { + "owner": "TEST7dZwhT4FZQB4SC9qXPgusr8yqJAKUdxCn", + "asset_symbol": "TEST", + "amount": 2515896 + }, + { + "owner": "TESTCn43dtQZpsDn56w8ayZ9RxPFtrVYB9mSj", + "asset_symbol": "TEST", + "amount": 3285120 + }, + { + "owner": "TESTHKo46vWUPH7D22jiu242cE8AFKezaLWM4", + "asset_symbol": "TEST", + "amount": 34743213 + }, + { + "owner": "TEST3GCxW3NL5t27AoJ8jB23QoekdB4ETMeYp", + "asset_symbol": "TEST", + "amount": 1815346 + }, + { + "owner": "TESTHNur4VxtY3Vc4AQdxm7W87jCrWwStKrft", + "asset_symbol": "TEST", + "amount": 117664 + }, + { + "owner": "TEST2sXnAkRNE9rW3mqVt3PVBrzNGyQLzS8yn", + "asset_symbol": "TEST", + "amount": 4852106 + }, + { + "owner": "TESTNzFnPvR2x59GbAS87bter4qZyqkQ2TGRT", + "asset_symbol": "TEST", + "amount": 4003092 + }, + { + "owner": "TESTG6XbRRTfnSJ5KLhSA6RmQY1RhQs7PEmz4", + "asset_symbol": "TEST", + "amount": 5009192 + }, + { + "owner": "TEST3FiQnNe4FYckvqiahGBMwBSU4P5G54A5U", + "asset_symbol": "TEST", + "amount": 1281532 + }, + { + "owner": "TEST5XwqZvN5SdbcxTQLYHYmjuyFgmHAVKPuM", + "asset_symbol": "TEST", + "amount": 4831243 + }, + { + "owner": "TEST9KTsFrL1pqD5HkKTKA6dveNxpGyWdWAXc", + "asset_symbol": "TEST", + "amount": 70254819 + }, + { + "owner": "TEST2UrsiWp2bothQEoLQ1wZEUeFr155ZMkgQ", + "asset_symbol": "TEST", + "amount": 213663 + }, + { + "owner": "TESTDNy9yLupjChs5gMkzmn2ZbU7TN97rqwGS", + "asset_symbol": "TEST", + "amount": 15225745 + }, + { + "owner": "TEST2FVW1y7xWtEbFuKZJgEkQ1NHvj7x9K64J", + "asset_symbol": "TEST", + "amount": 6693685 + }, + { + "owner": "TESTKSLPSLyD7b5UfCAnRQR8C7jS4oamCmift", + "asset_symbol": "TEST", + "amount": 29312550 + }, + { + "owner": "TESTKGKquebubCFhrUzU8wauAEP2PqEhj9xvT", + "asset_symbol": "TEST", + "amount": 1027073 + }, + { + "owner": "TESTEVtmVnniaRLP3cp4Pi8DTi4cSEHJhpGf6", + "asset_symbol": "TEST", + "amount": 82259048 + }, + { + "owner": "TESTauxPdV5hyWhMeoRRLCvmEjwBJRwZNMfp", + "asset_symbol": "TEST", + "amount": 1713385 + }, + { + "owner": "TESTNrnM3hVvr9JFBcQczKVoRAHdqQvKXfFox", + "asset_symbol": "TEST", + "amount": 3414974 + }, + { + "owner": "TESTFaefg9p8TU3bqBnfNSgf8oY3hXbitSBB5", + "asset_symbol": "TEST", + "amount": 200555 + }, + { + "owner": "TEST79VTRRpUHS7FgSNTFovUdhiipQcEqtx6b", + "asset_symbol": "TEST", + "amount": 1215468 + }, + { + "owner": "TESTL93FFGF8ZVxjA9oD7EYtMp1BPXV8nC5WG", + "asset_symbol": "TEST", + "amount": 685139 + }, + { + "owner": "TESTAWLh7SCJBaNDDhSLkowfxxXmtsSBpj67S", + "asset_symbol": "TEST", + "amount": 2413376 + }, + { + "owner": "TEST6HxsXYnJMLDQbF1w5mmawJGEpDBtY5bNJ", + "asset_symbol": "TEST", + "amount": 6970562 + }, + { + "owner": "TESTCVrFGcicZXr2DkcDwWhoaYjEXfHDxpdfZ", + "asset_symbol": "TEST", + "amount": 96297 + }, + { + "owner": "TESTGds3qr5ddvivEC5AXWQ1ycUGjHmwUCq4Q", + "asset_symbol": "TEST", + "amount": 25500000 + }, + { + "owner": "TEST5sZkLg8rX6fyZGC6S2J9rNc7GvPnC7rJW", + "asset_symbol": "TEST", + "amount": 2025143 + }, + { + "owner": "TESTPUzztnHdXz1TcNq7AoQA6YTUxji2H8GEH", + "asset_symbol": "TEST", + "amount": 7085605 + }, + { + "owner": "TESTMbLh787oTmsixFDqVAPTak8VgFofRKzGG", + "asset_symbol": "TEST", + "amount": 13607734 + }, + { + "owner": "TESTEz8oiVYSkwLcoNgdkbhnyaiomdw1a9RTg", + "asset_symbol": "TEST", + "amount": 60345865 + }, + { + "owner": "TESTBnEUWa4nhtt2STEmHn8ZJmWPiDXR5Eocy", + "asset_symbol": "TEST", + "amount": 8549892 + }, + { + "owner": "TEST5FnisKNJojViPVFWoT4aQkCCB193toihq", + "asset_symbol": "TEST", + "amount": 2492050 + }, + { + "owner": "TESTPQbxeFSHtpvkegDERNLjuZo7MapDyHCkP", + "asset_symbol": "TEST", + "amount": 1070994 + }, + { + "owner": "TESTDRCYkt3SA7zxAYhBqLmHUFP3JCxNMJnLv", + "asset_symbol": "TEST", + "amount": 3247778 + }, + { + "owner": "TESTPruoF8BTDcrfMYu2oub8QEz71PUYwfqtz", + "asset_symbol": "TEST", + "amount": 42791960 + }, + { + "owner": "TEST7ruXTNoZrKKdwvW92KnVbjS2WsKsLso2v", + "asset_symbol": "TEST", + "amount": 37847613 + }, + { + "owner": "TESTFeSV8LZrqicfUyTUkgzdA8QdRoLhbbCfa", + "asset_symbol": "TEST", + "amount": 914004 + }, + { + "owner": "TESTJ5GXEQQvexenZXuVJTvypgrq8KHuCTR2Z", + "asset_symbol": "TEST", + "amount": 23890 + }, + { + "owner": "TESTKFjUEfZQvcZNiCatovughWERgRRfBAyie", + "asset_symbol": "TEST", + "amount": 3620948 + }, + { + "owner": "TESTLMapWhBdgaAkJ9B38nJwAvqGFGvnkvWmR", + "asset_symbol": "TEST", + "amount": 7713442 + }, + { + "owner": "TESTJTQt2AeGiEd8uFsgvvwVn8acgSfXYYEdV", + "asset_symbol": "TEST", + "amount": 6584317 + }, + { + "owner": "TESTFNLzce2uKAwpczZvp4jdcDj12avXYRGpc", + "asset_symbol": "TEST", + "amount": 1926368 + }, + { + "owner": "TESTJcX4wpCM61hPeFwNkQStT1PCtTyCz6Qu1", + "asset_symbol": "TEST", + "amount": 37237934 + }, + { + "owner": "TESTM9cWp4jJDjiG4ikks67Q5iV66uaLN1HsS", + "asset_symbol": "TEST", + "amount": 2053794 + }, + { + "owner": "TESTBKronKKese5YHVUfRHL8zshGUPD6VVjar", + "asset_symbol": "TEST", + "amount": 814301 + }, + { + "owner": "TESTHP597M9WdSqvMLVxDgCDtqqGLVk4WWUGj", + "asset_symbol": "TEST", + "amount": 93599160 + }, + { + "owner": "TESTLzqb4oyDiGCYFwLk4BYY74TwngGJcYQy3", + "asset_symbol": "TEST", + "amount": 2050912 + }, + { + "owner": "TESTHfzQjuMbhJ8AfLwR4t7t4ppraCaC5csuX", + "asset_symbol": "TEST", + "amount": 698055 + }, + { + "owner": "TESTPPPmbdCzjMnhxefjAd3vKLXs4XCHDU2V6", + "asset_symbol": "TEST", + "amount": 1329117 + }, + { + "owner": "TEST8FeVGmzbjGeyCRtNh4kL3ZQSc4ZAcv7PZ", + "asset_symbol": "TEST", + "amount": 2429417 + }, + { + "owner": "TEST7JMDM2VNSP7hbjeRytG2F2MC6pHRJksKi", + "asset_symbol": "TEST", + "amount": 6474299 + }, + { + "owner": "TESTak32tc6zV5XyivK9rbE1ajCT7SHsPY3C", + "asset_symbol": "TEST", + "amount": 5730838 + }, + { + "owner": "TEST8YorubhogWU4tY9UazYPq7Y95aea4PCoP", + "asset_symbol": "TEST", + "amount": 713671 + }, + { + "owner": "TESToGiNJrRjCi5nwK5pKJN8Yg2NC7aE5s1Y", + "asset_symbol": "TEST", + "amount": 4687508 + }, + { + "owner": "TESTFjASAGjABUGunKeFVHxoxovSFgGoSG1ho", + "asset_symbol": "TEST", + "amount": 92863 + }, + { + "owner": "TESTNCNeMM3WWWHJDWAmGV5C9HMz2QjZFnEhj", + "asset_symbol": "TEST", + "amount": 13876587 + }, + { + "owner": "TESTH5c7YkFa2m3Vz79KjiikDDAw54abzKuY1", + "asset_symbol": "TEST", + "amount": 51542000 + }, + { + "owner": "TEST6niTQKK3Lk9a7RkUqBDkb7qexTFKnvEoD", + "asset_symbol": "TEST", + "amount": 1956599 + }, + { + "owner": "TESTLydZDnCZfPcQ3pDzHN8YTw4RzGqzesuV8", + "asset_symbol": "TEST", + "amount": 23860160 + }, + { + "owner": "TESTAvvTf3rrZfM12T1qSsCdbruz7AfR988JD", + "asset_symbol": "TEST", + "amount": 4046425 + }, + { + "owner": "TESTFVFC3GEpBpmaSLTR8uj5tjx9cZWnjNFmQ", + "asset_symbol": "TEST", + "amount": 34009000 + }, + { + "owner": "TEST76Xx6PQbSQ5jvqbTHSpQDBbAFXpgu2n4S", + "asset_symbol": "TEST", + "amount": 1215312 + }, + { + "owner": "TESTBLC14sxDoxyNAaaT9SonM4nKNXomdXNUN", + "asset_symbol": "TEST", + "amount": 318406 + }, + { + "owner": "TEST3ymn9oMjFiP5X8B61JCRvJPrp8qqU1NdW", + "asset_symbol": "TEST", + "amount": 8855413 + }, + { + "owner": "TEST9geGyQch71W1YtzuBghsfUZWoL3TXPgv3", + "asset_symbol": "TEST", + "amount": 748920701 + }, + { + "owner": "TESTEguvgmcMS2pHsBua7q3EvqXbPEkheGN8c", + "asset_symbol": "TEST", + "amount": 7096973 + }, + { + "owner": "TESTPW2k5a47JrV6sSVjjf8KfDUZsuwCs7Vo2", + "asset_symbol": "TEST", + "amount": 50226573 + }, + { + "owner": "TESTKQfhNsxAfEiPYLuuiFgDVdSHB7Kfdeb4M", + "asset_symbol": "TEST", + "amount": 8181920 + }, + { + "owner": "TEST5EXbKrpCW3NZxTp1xqcCAMkP8PXLbtv1G", + "asset_symbol": "TEST", + "amount": 72199580 + }, + { + "owner": "TESTDNXFFFPKyZxPrvs5dLNzwncsw6xQ4C92Z", + "asset_symbol": "TEST", + "amount": 1660581 + }, + { + "owner": "TEST3Ufe3Vz2btQffK4TS8VhtsPKLvEkLtKe8", + "asset_symbol": "TEST", + "amount": 75416 + }, + { + "owner": "TEST75WVfUnwUhQCmL261L6DZWc2xdwhipJ5U", + "asset_symbol": "TEST", + "amount": 32592 + }, + { + "owner": "TESTDDe2J8HM1bH1nkE7jTbmvzMx2mdAoYo9d", + "asset_symbol": "TEST", + "amount": 20370926 + }, + { + "owner": "TESTNjBRBMrRosH3nT9D9xf8VjxLxk293NezD", + "asset_symbol": "TEST", + "amount": 16766357 + }, + { + "owner": "TESTGheBHTHvZnqgHZ2fZhCCz9X1Zv9FK2XDG", + "asset_symbol": "TEST", + "amount": 6582653 + }, + { + "owner": "TESTPnTvHuiiVDSMLKfHyCtuvjp9uWqZ7vSMa", + "asset_symbol": "TEST", + "amount": 119332583 + }, + { + "owner": "TESTDA2FSSgCDBZiAGmnQibWDHU8C9bw3iPkS", + "asset_symbol": "TEST", + "amount": 2776788 + }, + { + "owner": "TEST7RCnfJcAwVXXFJdLVXnsRnys7PQxG7R1w", + "asset_symbol": "TEST", + "amount": 20800534 + }, + { + "owner": "TESTE7XTmigJ9Rnb8tpUD5DCTJSkxQ8rMdnG6", + "asset_symbol": "TEST", + "amount": 3263324 + }, + { + "owner": "TESTArYn4HaStavrmWTnTAPFmxqdDWTBWVuCo", + "asset_symbol": "TEST", + "amount": 32609140 + }, + { + "owner": "TESTDmh7jfghSzuADVL9kJt36bV5dgCCkzt5u", + "asset_symbol": "TEST", + "amount": 347532 + }, + { + "owner": "TESTNnM9PHGrDAbgp49HJnsnGtBPnbYDtpMjS", + "asset_symbol": "TEST", + "amount": 16647520 + }, + { + "owner": "TEST8NuXzp15wLf6GYX2h7JFHU88nnwdxwZ1b", + "asset_symbol": "TEST", + "amount": 36085135 + }, + { + "owner": "TESTEQ9bxCjaiMw9KWXoBwaRAr6bQgDfEbug3", + "asset_symbol": "TEST", + "amount": 6096248 + }, + { + "owner": "TESTpR5YJgucxq3oTBe1KhEdpr3bekVnDsVA", + "asset_symbol": "TEST", + "amount": 1682722 + }, + { + "owner": "TESTBpcfJQh9ErMSUvXmHMzFudK9jedrpJ7A7", + "asset_symbol": "TEST", + "amount": 1841905 + }, + { + "owner": "TESTDHeu8CF5yMNtVv13ViyK8jd51impGeVyc", + "asset_symbol": "TEST", + "amount": 1475222 + }, + { + "owner": "TEST5YRAEZ7oT6ZEMovYTM7P7bzGvyE2iZfAi", + "asset_symbol": "TEST", + "amount": 43043756 + }, + { + "owner": "TESTJ1UUbFsaUYxBRKBqjHnbF9uTLA8t2upj8", + "asset_symbol": "TEST", + "amount": 3146220 + }, + { + "owner": "TESTAb6iJ6CjEtuFMp1F2hZV1ASZReEqm8rx9", + "asset_symbol": "TEST", + "amount": 477664 + }, + { + "owner": "TESTGfu3JHZEVh1xNpJ859LkpWWvkKq3uNCSM", + "asset_symbol": "TEST", + "amount": 49984308 + }, + { + "owner": "TESTPRMWk3zzq6bzqbAaQJRrTuDnGycNaMtYB", + "asset_symbol": "TEST", + "amount": 3388967 + }, + { + "owner": "TESTL6za2Gz9YEn7yHbFEohZrXCZ76pZGpUA1", + "asset_symbol": "TEST", + "amount": 6768782 + }, + { + "owner": "TESTHPaY1Nd26E84eJbxu37ET7MvHPdiUjdBH", + "asset_symbol": "TEST", + "amount": 4745391 + }, + { + "owner": "TESTMcjuozavQXDnp5Qoggxwoy8WYaYrhB925", + "asset_symbol": "TEST", + "amount": 103749504 + }, + { + "owner": "TESTA4dgXo8sN4EiP5tTDB77wqqebdYx3RTLL", + "asset_symbol": "TEST", + "amount": 6801800 + }, + { + "owner": "TESTMRJ3CKLMsVA8aYmT5EvRMyWjMYEiwHCnP", + "asset_symbol": "TEST", + "amount": 24667880 + }, + { + "owner": "TEST3nk3q8mDBbu74h35hqapbF91bwpAAZWJe", + "asset_symbol": "TEST", + "amount": 19307514 + }, + { + "owner": "TESTtDQLFUAziQktFH7Juxo5erbmQ2kaS3ZV", + "asset_symbol": "TEST", + "amount": 470190 + }, + { + "owner": "TEST4Ka5VtNRr9cEfD9XxnFgt2Nn3toZhn5Xm", + "asset_symbol": "TEST", + "amount": 148284857 + }, + { + "owner": "TEST49crmb1S38eyQ6ZbCuEtaCJXANGX1GWbo", + "asset_symbol": "TEST", + "amount": 70498 + }, + { + "owner": "TESTA6hwJJh5osCsVpU11F5xqEdBzZVjHBbxD", + "asset_symbol": "TEST", + "amount": 4059374 + }, + { + "owner": "TESTZ3TSdygHDE56GBt4fy6QxPmkavq7wRLG", + "asset_symbol": "TEST", + "amount": 7454988 + }, + { + "owner": "TEST6ZWfvFkiCgoGybAeGvTEBdZetgHCZrd42", + "asset_symbol": "TEST", + "amount": 55485 + }, + { + "owner": "TESTMpnfzqsFHsi19dfwkNJeQmfjARmYCuyJr", + "asset_symbol": "TEST", + "amount": 34046895 + }, + { + "owner": "TESTKT2pM2DJu64kS9PZGTRvqqmv3SwLQqJfs", + "asset_symbol": "TEST", + "amount": 1850166 + }, + { + "owner": "TESTQDCo7vmvb8X4tetQLbU7CyYNhjRt6hv9a", + "asset_symbol": "TEST", + "amount": 423361 + }, + { + "owner": "TESTHynzSiPWcH38asGpD4CMLqPGMfwskJKhk", + "asset_symbol": "TEST", + "amount": 3459118 + }, + { + "owner": "TESTNpJ8WcTs8FV5uTJvgtNDeduZ4hLdd6JQM", + "asset_symbol": "TEST", + "amount": 5143859 + }, + { + "owner": "TEST8qfqci5qim6LEf2pXjWB5AfPVRLuybP9b", + "asset_symbol": "TEST", + "amount": 11512646 + }, + { + "owner": "TEST7YLJSmVgcxE9GQXcJbmmfKUaNqaqaYV9o", + "asset_symbol": "TEST", + "amount": 102872340 + }, + { + "owner": "TEST9CUzt31koPGZAGuffRD4kHTgK8sjdTQ7q", + "asset_symbol": "TEST", + "amount": 578012 + }, + { + "owner": "TESTQ1vK6X2oSAD78iWZAgn81r17ZaYbg9W4b", + "asset_symbol": "TEST", + "amount": 35286556 + }, + { + "owner": "TESTKx7HHXNV6JXHpsRiR3vRkbGkaXNjRGugV", + "asset_symbol": "TEST", + "amount": 344753 + }, + { + "owner": "TESTCn4Jcf6XbvVPHz3CtnMAQMBzshsoRHx2X", + "asset_symbol": "TEST", + "amount": 303042 + }, + { + "owner": "TESTHvuALsxqih9sJrRagtPVKz5H9BLkgyuLn", + "asset_symbol": "TEST", + "amount": 2565070 + }, + { + "owner": "TESTD7ed9eXqHw5KvkVEa7u8n12y5ktswiiu", + "asset_symbol": "TEST", + "amount": 5108381 + }, + { + "owner": "TESTNTrL6p8d9o69QgJQwvNCDM8XrTKNtpyiF", + "asset_symbol": "TEST", + "amount": 3401105 + }, + { + "owner": "TESTCDiFFAphts9HZoHr19bKJKjc2L1dciNZG", + "asset_symbol": "TEST", + "amount": 9685022 + }, + { + "owner": "TEST3XK2Cj7WGhnCGKdJb1dqfWhtL7ZC5zaRH", + "asset_symbol": "TEST", + "amount": 5365990 + }, + { + "owner": "TESTBqxGHyA27LV4XgE5md5BCigVxnQtw6mvY", + "asset_symbol": "TEST", + "amount": 453500 + }, + { + "owner": "TESTCFSxDNoxC7mYgZmtJwnA6JSAgA3xWpuSh", + "asset_symbol": "TEST", + "amount": 11600207 + }, + { + "owner": "TEST4XMgxF6brnNxK9QEte7b4VfhyB62YEtSm", + "asset_symbol": "TEST", + "amount": 1500884 + }, + { + "owner": "TESTMsEkhAgSCqoaSQR45kXHabKZ4inY7UnAT", + "asset_symbol": "TEST", + "amount": 7665104 + }, + { + "owner": "TEST6DU7fxx84M4hzo5Ysd4NpFGMfMofYT7Sb", + "asset_symbol": "TEST", + "amount": 910159 + }, + { + "owner": "TEST6oUj4CgbSz1cHBfWeg3Ws6BYoRpZD2UYX", + "asset_symbol": "TEST", + "amount": 21468294 + }, + { + "owner": "TESTD1zLvmfBncCRDvx1fqerpuAVyK8VEFCh1", + "asset_symbol": "TEST", + "amount": 5567599 + }, + { + "owner": "TESTDNmdK8RbBwwKT9Y99xJqBaiLGxx8f9ph5", + "asset_symbol": "TEST", + "amount": 7083264 + }, + { + "owner": "TESTDLn35c9fvQjtAspZR7CEdKrQs4mGgPHds", + "asset_symbol": "TEST", + "amount": 2844147 + }, + { + "owner": "TEST2i5SyuK6KmLaLysWSMMLnSXDZ1v6bW6BC", + "asset_symbol": "TEST", + "amount": 105049524 + }, + { + "owner": "TEST3g2T9BMDhjsSu1TzGDu1CHziWPL6UKXzm", + "asset_symbol": "TEST", + "amount": 57507336 + }, + { + "owner": "TESTDVuse8pTcDezJponRsy5rnf1p95Q7vdCF", + "asset_symbol": "TEST", + "amount": 65126922 + }, + { + "owner": "TEST6osmN17d6KTGUraMfr87h6HWKYadL8hp2", + "asset_symbol": "TEST", + "amount": 117940856 + }, + { + "owner": "TEST9oXK4SDhWyT2uQ7NaKnvsNBxFZV5EByAa", + "asset_symbol": "TEST", + "amount": 20698873 + }, + { + "owner": "TEST3Lf1Ynq7rDG5zS2PVv9xFXy2Pb9WFteMP", + "asset_symbol": "TEST", + "amount": 4346497 + }, + { + "owner": "TESTG3mKGxrC88UHh3uezoJpCEmSPw3REMZGu", + "asset_symbol": "TEST", + "amount": 4577055 + }, + { + "owner": "TESTMxx8mMLuCUveG3zpWdfr84pzqKCYuFCNk", + "asset_symbol": "TEST", + "amount": 34072021 + }, + { + "owner": "TEST4KUN9ybWWodrJrLceaGDYeJbvLURB3zB1", + "asset_symbol": "TEST", + "amount": 381469 + }, + { + "owner": "TESTKiXrDCdKMd5LNB6h8L23KxNVdJMFRb5up", + "asset_symbol": "TEST", + "amount": 521204 + }, + { + "owner": "TESTJ4y6wK1oXNgJYMDdkJSDeJApPL8ychbwz", + "asset_symbol": "TEST", + "amount": 5646311 + }, + { + "owner": "TESTQB8Dz8qhw4fkJCBNZvPtzV5yHsJ2Xh8ZB", + "asset_symbol": "TEST", + "amount": 644002 + }, + { + "owner": "TEST4PHURF12xTNACFQq3dakwAEDQaTVDDH1w", + "asset_symbol": "TEST", + "amount": 34127467 + }, + { + "owner": "TESTDU1Lop3S72iB2Y2nqZ1yYCi7cWWQn1aA", + "asset_symbol": "TEST", + "amount": 65215 + }, + { + "owner": "TESTP3tKhFEfcxMRQA1qS38b2MNSm5vdVPeLX", + "asset_symbol": "TEST", + "amount": 14039874 + }, + { + "owner": "TEST23NrKGG15SX7AqD8hEp75r88RPktxx3CR", + "asset_symbol": "TEST", + "amount": 16571074 + }, + { + "owner": "TESTAHCgW7Crd4JDbNziryPommzPEaPoNnYxs", + "asset_symbol": "TEST", + "amount": 197908 + }, + { + "owner": "TESTEpYrk1LtxqU2DCZBALwdbuC2qxo8Wn4bv", + "asset_symbol": "TEST", + "amount": 893254 + }, + { + "owner": "TESTCeR6K1M8oZNVGxpVhUgxKWe5LARBWsrYE", + "asset_symbol": "TEST", + "amount": 627566 + }, + { + "owner": "TEST91FAXruWNoekpjTbYvB9r4QmxuAWYZqKt", + "asset_symbol": "TEST", + "amount": 870000 + }, + { + "owner": "TESTMXzpp6kJFf7LEVSYmBiEHS5u1eXkETvcw", + "asset_symbol": "TEST", + "amount": 3973114 + }, + { + "owner": "TESTE4RNSNQvq1mzXohRVPsDeMrAGYkncfKxx", + "asset_symbol": "TEST", + "amount": 6317680 + }, + { + "owner": "TEST74LvVTaZD1h7VMcsfbFa2KVLxHDzd46z9", + "asset_symbol": "TEST", + "amount": 1620000 + }, + { + "owner": "TESTNsyPnkVhxeiYG5YmZwbqc9T9ifL6CXXst", + "asset_symbol": "TEST", + "amount": 4071132 + }, + { + "owner": "TEST4b37Nu4gqTxgH2CkHwtGMy1B3f2YhZ325", + "asset_symbol": "TEST", + "amount": 2047593 + }, + { + "owner": "TESTD3JFMyXAmSaNNSB6KVCJvsvACVrs7PvZg", + "asset_symbol": "TEST", + "amount": 1739682 + }, + { + "owner": "TESTLbrhAewba5R4LfjbBuvhkkmArhUmj764i", + "asset_symbol": "TEST", + "amount": 1659505 + }, + { + "owner": "TESTH2qg1FuZRhxvB2R2Z4SruExmWr24efcho", + "asset_symbol": "TEST", + "amount": 10994834 + }, + { + "owner": "TESTENJuRAYmziJAygfYaFGXrBHU7njEERWxa", + "asset_symbol": "TEST", + "amount": 35045618 + }, + { + "owner": "TESTBasLXkQbfbGDDcYN9ue6tCy5jGkKNcF35", + "asset_symbol": "TEST", + "amount": 247784 + }, + { + "owner": "TESTPMiu1GT7AtuGszczDtEcbfpNWXmhd6b2k", + "asset_symbol": "TEST", + "amount": 6740003 + }, + { + "owner": "TEST4oz8FkcXXtESTMR5BZSuJsG6vrA78aW3R", + "asset_symbol": "TEST", + "amount": 17130845 + }, + { + "owner": "TESTLjuowrG1Ty1RgoKiJbhDtMkuBSF4RVqLN", + "asset_symbol": "TEST", + "amount": 5135208 + }, + { + "owner": "TESTGsj7nGxzN5WCJuiDCVpRZLJYKvZTSpth3", + "asset_symbol": "TEST", + "amount": 1586208 + }, + { + "owner": "TESTHWUyS8KJ7siUPDTCJJYyPkSacETkiix4", + "asset_symbol": "TEST", + "amount": 5041707 + }, + { + "owner": "TEST9BLL8GAG6v8LwHzKGhbpBKsMiCgGvwaCR", + "asset_symbol": "TEST", + "amount": 1576086 + }, + { + "owner": "TEST83FVETTSMsf8L8hDr4rn1DuBeBmoxMuYH", + "asset_symbol": "TEST", + "amount": 3624565 + }, + { + "owner": "TESTAX62wGDT5pDJUwd9eRmJAg4eM27YVf7Xm", + "asset_symbol": "TEST", + "amount": 4742395 + }, + { + "owner": "TEST8rMwEdp7QtREtpfShhqb9oLEEsvp3TKCU", + "asset_symbol": "TEST", + "amount": 1621036 + }, + { + "owner": "TESTN9fmYABBKo3XBG2PND2m69VdK4URMAWGK", + "asset_symbol": "TEST", + "amount": 13577346 + }, + { + "owner": "TESTJv98n9L6Kg9V6MNeFCMEgZURkma1DACzx", + "asset_symbol": "TEST", + "amount": 73160377 + }, + { + "owner": "TESTAbDRjUkQh16PdaBmagYA65xVysjskkbsD", + "asset_symbol": "TEST", + "amount": 16996821 + }, + { + "owner": "TESTMAbY2bysd5oyWBa8fJ1c6BW4RgDbZQ4Vx", + "asset_symbol": "TEST", + "amount": 3407872 + }, + { + "owner": "TEST15oQNBZbAyd1NmqtcPfqx4YCW1xteMd6Q", + "asset_symbol": "TEST", + "amount": 3398283 + }, + { + "owner": "TESTPzapdyxmLvsX5HZAwy6EuxCyDbm98EVgj", + "asset_symbol": "TEST", + "amount": 4163874 + }, + { + "owner": "TESTbkvUPStuaN3SUQAyiMDYPjKNjk7ei2W8", + "asset_symbol": "TEST", + "amount": 3727230 + }, + { + "owner": "TEST3ubuVEgYQWf8TGXrmWfFtMeTHTxVsZQQY", + "asset_symbol": "TEST", + "amount": 3283999 + }, + { + "owner": "TESTBiN3RVWhWNs6UGXb3ugYsXHPKJJmyHH2k", + "asset_symbol": "TEST", + "amount": 3395768 + }, + { + "owner": "TESTEvAFZ9LnFk21CtkGGhtnsfFPm9MxjQJ7E", + "asset_symbol": "TEST", + "amount": 11900 + }, + { + "owner": "TEST6HMEmf5a2TwwWbsgYZY6yDkxBJtupGjQK", + "asset_symbol": "TEST", + "amount": 70212560 + }, + { + "owner": "TEST7AKZSTiLvDGtUf8wg6tr5dvP8BadqTanJ", + "asset_symbol": "TEST", + "amount": 19936714 + }, + { + "owner": "TESTJ3WoxhkXkbQ8UAmq24rpakG6KS19TTzb6", + "asset_symbol": "TEST", + "amount": 4303 + }, + { + "owner": "TESTFf6MVPz36DhP7yDDMnLU1thVRJgSS1FXc", + "asset_symbol": "TEST", + "amount": 9948886 + }, + { + "owner": "TESTE9vbHaJXq6tEe2ZFHvQjHDbU4Jyw2NoM1", + "asset_symbol": "TEST", + "amount": 2756793 + }, + { + "owner": "TEST3pgMqyNsrMCPsCQMoDnMtQQkNkmXTKMBd", + "asset_symbol": "TEST", + "amount": 6848850 + }, + { + "owner": "TESTF3xFAW2cRa63Lsvt1rgNtHcnFYdk6pSZS", + "asset_symbol": "TEST", + "amount": 309316 + }, + { + "owner": "TESTJ4FLe1HVbUPeV26GncrV4X2iLi1Sgjcy8", + "asset_symbol": "TEST", + "amount": 5181 + }, + { + "owner": "TEST5T54ETVqpymzYbUTyVG74sHyFeDvuW3fA", + "asset_symbol": "TEST", + "amount": 7993518 + }, + { + "owner": "TESTQ6p6ybxue8s11M5r2PqXfdTDEY5wTAoF9", + "asset_symbol": "TEST", + "amount": 213716 + }, + { + "owner": "TESTH9nu8NVuNbFCsw2Hj1LkgzJdFTp35GGa3", + "asset_symbol": "TEST", + "amount": 20553015 + }, + { + "owner": "TESTPxLUELoBEFDffXTcBzsuhtkduSNqVHm5E", + "asset_symbol": "TEST", + "amount": 1458434 + }, + { + "owner": "TEST48SLB4Atp8LhcwzRgmQSzk8Qcanhb85NS", + "asset_symbol": "TEST", + "amount": 30627 + }, + { + "owner": "TESTL6nzdhgMbDT8xH3i3ZxsoiKLhoShQC39o", + "asset_symbol": "TEST", + "amount": 17927847 + }, + { + "owner": "TESTCtPd1N1EBQNE9vihKbEAVTnRBVUap6527", + "asset_symbol": "TEST", + "amount": 7151964 + }, + { + "owner": "TESTNLiGq6qbfJG7HTGd1BCALahsPsU2fmXUJ", + "asset_symbol": "TEST", + "amount": 2784583 + }, + { + "owner": "TESTCj9hohdbhjiAWFgNZgP4gnzMKDdPJbsdd", + "asset_symbol": "TEST", + "amount": 1501342 + }, + { + "owner": "TESTJF6xKJfUbZtxDm94P6ruGJFBSYn6Ez2U7", + "asset_symbol": "TEST", + "amount": 841461 + }, + { + "owner": "TESTGc3o2YFue9i9KDh7GbEcfodc6y1jhmfzx", + "asset_symbol": "TEST", + "amount": 14081223 + }, + { + "owner": "TESTLbbyF7gsrieqUSt1az9cUXDvj8x1X1zJg", + "asset_symbol": "TEST", + "amount": 344377 + }, + { + "owner": "TESTgMvB5W7kbjaihu6vdxhvyc2unh3U1bw7", + "asset_symbol": "TEST", + "amount": 157532 + }, + { + "owner": "TEST5849vMiJisJaP8GUAjs3VCvZctiiCn1FT", + "asset_symbol": "TEST", + "amount": 3469641 + }, + { + "owner": "TESTKv3Ff92jfZ3dYsUqe8hqaVByBgGXryka7", + "asset_symbol": "TEST", + "amount": 1837229 + }, + { + "owner": "TEST12S3LVBfmUPXiNccjwCi2xuv5V49JurUv", + "asset_symbol": "TEST", + "amount": 9063499 + }, + { + "owner": "TESTLgB8qVBScQrtBYadiRFRoMSAo4eqGwb8b", + "asset_symbol": "TEST", + "amount": 10867715 + }, + { + "owner": "TEST12NVx9E59btKPTu3RvMXdoQGZV3qsScy7", + "asset_symbol": "TEST", + "amount": 9964333 + }, + { + "owner": "TEST7TLhtVtVPGzwrv6JbMHi1FB9HhaCdseN1", + "asset_symbol": "TEST", + "amount": 968254 + }, + { + "owner": "TEST8n2eYcgaWZbZ9WuzU4a5cCp2hRA9hYH8n", + "asset_symbol": "TEST", + "amount": 882860 + }, + { + "owner": "TESTAApzWdaCWoA9zgkL3g2HENMEq2g19NKT7", + "asset_symbol": "TEST", + "amount": 21370796 + }, + { + "owner": "TEST32ak785fnK8ERihqZqFQ1Nw8CDXXU5DCW", + "asset_symbol": "TEST", + "amount": 3552501 + }, + { + "owner": "TEST13MyG4vennD33L895XgQWEYH7La8vAajM", + "asset_symbol": "TEST", + "amount": 69790229 + }, + { + "owner": "TESTERSXwCLhpoHzXBZpthiBr46KkEaCojNgo", + "asset_symbol": "TEST", + "amount": 5039215 + }, + { + "owner": "TESTL9Fn4NzJCTsaMrUbtcMkbvKp7UUnbtd6s", + "asset_symbol": "TEST", + "amount": 2794527 + }, + { + "owner": "TEST7zrpFLPjz2tgrsnTQHRYcyokfqyWU41Mw", + "asset_symbol": "TEST", + "amount": 404319 + }, + { + "owner": "TESTHNbbWxLkqPTxzCjztrSgxduDqcgXPaWFc", + "asset_symbol": "TEST", + "amount": 2141561 + }, + { + "owner": "TESTAjPfj6v32bmc7rQDhbQs1TYCDmmPwPZcr", + "asset_symbol": "TEST", + "amount": 8706910 + }, + { + "owner": "TESTPysddpUsvaB2dCfzv3EkU85F7hUHueYqx", + "asset_symbol": "TEST", + "amount": 102150933 + }, + { + "owner": "TEST2pTB8D2f57kopfSBpoA7nyvVJNhwUiQGJ", + "asset_symbol": "TEST", + "amount": 413399 + }, + { + "owner": "TESTJQtf9cgAjXsTwoVZtBEnUGJ3k15rUymwv", + "asset_symbol": "TEST", + "amount": 10069400 + }, + { + "owner": "TESTHzmAtG2GgwYb677zvzGdYB2cUQ6W91Jko", + "asset_symbol": "TEST", + "amount": 854388 + }, + { + "owner": "TESTMPNjtzsvEcUmwcEaw3Fcoi7eGcWW2ua6A", + "asset_symbol": "TEST", + "amount": 1067358 + }, + { + "owner": "TEST6UqjCTXg9z5pGhZMAYue9nVzhBtPxL29g", + "asset_symbol": "TEST", + "amount": 23833650 + }, + { + "owner": "TEST3CcDGcDRf45jYGSVAXYYeMs5ewqgTsvyW", + "asset_symbol": "TEST", + "amount": 8356614 + }, + { + "owner": "TEST4m9Am1xbynKKwfKfRPLT2juJSCuMhT1rC", + "asset_symbol": "TEST", + "amount": 66916730 + }, + { + "owner": "TESTGe3mkYbF81gt7ywEGoP2RHwjRvf6iDBq1", + "asset_symbol": "TEST", + "amount": 32608309 + }, + { + "owner": "TESTHKLCWNeYrYd4u8SH3ev3rTmXL5E6DPk5d", + "asset_symbol": "TEST", + "amount": 11824406 + }, + { + "owner": "TESTEjKFVKujDABKHjS3uzKwvi41Y91wgeiuT", + "asset_symbol": "TEST", + "amount": 10478910 + }, + { + "owner": "TESTFbSh4xRRv4bGmG28vQ4YPo85obTnvESrD", + "asset_symbol": "TEST", + "amount": 23867958 + }, + { + "owner": "TESTMDxJteY4Gc5Psky4bSDTrJUxjfATHfLfm", + "asset_symbol": "TEST", + "amount": 1254185 + }, + { + "owner": "TEST223tF8MmmbZ76gTxzAWEgvRKxTrpcNpGa", + "asset_symbol": "TEST", + "amount": 6633280 + }, + { + "owner": "TEST3G8Rbu7Hhcf51B6m6asEidTYSPxRUyKnd", + "asset_symbol": "TEST", + "amount": 343236 + }, + { + "owner": "TESTK1EyrzLRE7nAJHc3prdeTeA4Q1GPeeAqy", + "asset_symbol": "TEST", + "amount": 9926599 + }, + { + "owner": "TESTPKyj8oe4ZpxieiLfkw4RNXs68QGPYvLcj", + "asset_symbol": "TEST", + "amount": 1818561 + }, + { + "owner": "TESTN33EbhWc1VkmY4Y4CoYdCZixC9ZX6uF73", + "asset_symbol": "TEST", + "amount": 215025 + }, + { + "owner": "TESTJFHrjhWrdyQhj8a8D2GeoXtmUsX39JhpH", + "asset_symbol": "TEST", + "amount": 13763083 + }, + { + "owner": "TEST2QwzsjLycuP6aM8DKLR8vtbVGLFi2ikbs", + "asset_symbol": "TEST", + "amount": 1332304 + }, + { + "owner": "TESTGDSxr9engtJw47JVyBHCWPvvawvyvvxPZ", + "asset_symbol": "TEST", + "amount": 64821051 + }, + { + "owner": "TEST3cWuXWtCEB9HxdgcoUHNFwReP8N7GUDYQ", + "asset_symbol": "TEST", + "amount": 19091877 + }, + { + "owner": "TEST9TH2oBRkjMofLJFJsv4wBmonY4Jugv9WA", + "asset_symbol": "TEST", + "amount": 12279411 + }, + { + "owner": "TEST4zFJfFuRKHLc2srNx94GijCzci6FqaL1F", + "asset_symbol": "TEST", + "amount": 289532 + }, + { + "owner": "TESTJpb5WsMwuSxx5u97BHPFcbtZzSQo7JoGu", + "asset_symbol": "TEST", + "amount": 13662246 + }, + { + "owner": "TESTLjCbz3JjzjYTEhd8HMFJRSjZVLzRgpJR5", + "asset_symbol": "TEST", + "amount": 1268121 + }, + { + "owner": "TESTD5RQE9YUeyQ33trGdEkdLe8gT735zW6je", + "asset_symbol": "TEST", + "amount": 7930716 + }, + { + "owner": "TESTGbAiC9qUiYQ3pAyB9i2NfB4Na7t2sdjvn", + "asset_symbol": "TEST", + "amount": 1200367 + }, + { + "owner": "TESTNwBy1TMHLUWoqNm5Wm8zWnkZmTU6wBpWN", + "asset_symbol": "TEST", + "amount": 5024837 + }, + { + "owner": "TESTNhdGhLioFmYHjQuJ52HaQSzsBd4oaj6X3", + "asset_symbol": "TEST", + "amount": 527447 + }, + { + "owner": "TEST89nveUMMKPErZhoWsJaZVVz25tjP6ubC3", + "asset_symbol": "TEST", + "amount": 859599 + }, + { + "owner": "TESTCGWdfAFHVjV7LcYnWU3vitwuDYxri19mh", + "asset_symbol": "TEST", + "amount": 5142805 + }, + { + "owner": "TESTFtzvmQjC4Jf98fLy2nzAeLiLLQi3ExYkR", + "asset_symbol": "TEST", + "amount": 1029568 + }, + { + "owner": "TESTqYekwD69X9YLCrdoFArLX5jwWFswudsR", + "asset_symbol": "TEST", + "amount": 32380000 + }, + { + "owner": "TEST6A96N9euEpdF8sHjzxE4avzGasSqk5SYX", + "asset_symbol": "TEST", + "amount": 67914 + }, + { + "owner": "TESTNw3xZr1en2g1wrQtDaLi2HwkV4nR3UvKs", + "asset_symbol": "TEST", + "amount": 2171377 + }, + { + "owner": "TESTKQH3jWa7vrM3eAMVUE6dR62Spj3RVAS1S", + "asset_symbol": "TEST", + "amount": 379887 + }, + { + "owner": "TESTLYK1tZssE4bLWmwxPDxqVG52fdXAobh2f", + "asset_symbol": "TEST", + "amount": 1909984 + }, + { + "owner": "TESTHz69iwQFQGp3ARNCL4dFfYCKUySRquze1", + "asset_symbol": "TEST", + "amount": 17465686 + }, + { + "owner": "TEST41De1FSdNvQWg9mNxF15Kjm1Jhhsh4BL1", + "asset_symbol": "TEST", + "amount": 693907 + }, + { + "owner": "TESTJDFBHNetfEnoBukRdVz7y3T27Qc6YC4LU", + "asset_symbol": "TEST", + "amount": 554071 + }, + { + "owner": "TESTM5ggUx5cAUjRSPVgBF7LsAU4Dn1uWWjoJ", + "asset_symbol": "TEST", + "amount": 2817661 + }, + { + "owner": "TESTLPLJEG3xyutw4D8tHu7UTfF9bqBvEPLcH", + "asset_symbol": "TEST", + "amount": 9743391 + }, + { + "owner": "TEST2n5ChXWVFuj5xMFJt5UNxSR2VHncWHYM6", + "asset_symbol": "TEST", + "amount": 1739147 + }, + { + "owner": "TESTA7hsvhQ9XG8rxyvUK5zZqEhkRfHDSoLXL", + "asset_symbol": "TEST", + "amount": 3926026 + }, + { + "owner": "TESTGL6xBfJcg3B8o27Ya4G1r2iyuPqA9xATG", + "asset_symbol": "TEST", + "amount": 102546 + }, + { + "owner": "TESTiKJC1Vv58CGkAVpi4t4yuRkS9qfUqvAQ", + "asset_symbol": "TEST", + "amount": 631992 + }, + { + "owner": "TESTJFNvfz1BJ4NPNmgw6j7uzgfLkXEft9poM", + "asset_symbol": "TEST", + "amount": 4167789 + }, + { + "owner": "TESTDocgFHyQakLUwmJtMU9krQNVnVtm4knjY", + "asset_symbol": "TEST", + "amount": 39007768 + }, + { + "owner": "TESTB3JsfaKA5V2Zvz2sbA3MQVJdpKc8aHGsq", + "asset_symbol": "TEST", + "amount": 5165658 + }, + { + "owner": "TEST2gRgkK3B1bqWxUCgem4Lrof8LyiG6YVWa", + "asset_symbol": "TEST", + "amount": 34546286 + }, + { + "owner": "TEST6TehCU1KHsPPPt1WiurjSD9LP7VtnXHme", + "asset_symbol": "TEST", + "amount": 1364777 + }, + { + "owner": "TEST9PfD2PNwoC6HsMhGTWfSqzxNcWMA2ntCw", + "asset_symbol": "TEST", + "amount": 1020478 + }, + { + "owner": "TESTiLcBaEwEg21xN3ujWgJFpqVCZAuCUSkt", + "asset_symbol": "TEST", + "amount": 62723040 + }, + { + "owner": "TESTLVAninKppP9wBwf6z968Eh4uKtr4NR4H3", + "asset_symbol": "TEST", + "amount": 3133655 + }, + { + "owner": "TESTAMARmP3SMfKM4LFykG4qoBdtw6RLXV6b1", + "asset_symbol": "TEST", + "amount": 202165 + }, + { + "owner": "TESTDfV7c2jzTTGo6vSTxLsdbGnGsu7QRX41J", + "asset_symbol": "TEST", + "amount": 11381781 + }, + { + "owner": "TEST432X3X97DaLs2J1QX3RW1z6ju9am9cXgU", + "asset_symbol": "TEST", + "amount": 96426768 + }, + { + "owner": "TEST8anDm3P8smHAXusV5LVLFim4HSj26Ew6k", + "asset_symbol": "TEST", + "amount": 913364 + }, + { + "owner": "TESTJ6RuCgF4nZ4fH6PPrEcdbkXo2a1oJnTfU", + "asset_symbol": "TEST", + "amount": 3440667 + }, + { + "owner": "TEST7ahDwskgrMzNkGae7whR1H2ZaFn4dB4bt", + "asset_symbol": "TEST", + "amount": 11563662 + }, + { + "owner": "TESTJvN8RCcwTymJtKdyUV1XkE2pwVEbcCXSg", + "asset_symbol": "TEST", + "amount": 20739342 + }, + { + "owner": "TESTLeoyAd3TPapsH3Xw7NKGo6A6ax78vFzou", + "asset_symbol": "TEST", + "amount": 2719881 + }, + { + "owner": "TESTLcJR6ZHSELpLLsQotUfniWus3JRK9Fk1w", + "asset_symbol": "TEST", + "amount": 35292457 + }, + { + "owner": "TEST8RZ74Z7KAin3u81Lw8UYHPL2pnBGZc1vW", + "asset_symbol": "TEST", + "amount": 12759613 + }, + { + "owner": "TESTFFSFdp4HU3zMokuEZzP7UTsLEeJunrDgD", + "asset_symbol": "TEST", + "amount": 81178523 + }, + { + "owner": "TESTNxpmaMYreTvzeH5ihtbDvyZV8xJ5N87ig", + "asset_symbol": "TEST", + "amount": 369179 + }, + { + "owner": "TESTJhdWsueD4BwREAJ4SYjPxukYJNoeHr5x6", + "asset_symbol": "TEST", + "amount": 836795 + }, + { + "owner": "TEST2M6izAQAtTAephxY2uA4Dp6zSyrHoLsVR", + "asset_symbol": "TEST", + "amount": 510495 + }, + { + "owner": "TESTKvky7oZv4Z1ewjiMse8ws9VNiAxx3xnQo", + "asset_symbol": "TEST", + "amount": 477888 + }, + { + "owner": "TEST4FEiiSSPLypznCG7jL615cPR8tt9ee6tF", + "asset_symbol": "TEST", + "amount": 1499281 + }, + { + "owner": "TEST5kiQM6QjYVRa4aB5ESegYLEjYt8aos2wu", + "asset_symbol": "TEST", + "amount": 4440608 + }, + { + "owner": "TESTEuAXdfuhSYPwu2VEvnE4LvQyCSzZTUoYT", + "asset_symbol": "TEST", + "amount": 380855 + }, + { + "owner": "TEST63H1psHYRgqrpJGzjU57WgUyNyR4QxMsi", + "asset_symbol": "TEST", + "amount": 10085499 + }, + { + "owner": "TESTM8BMKsFcBMkPgN4eZn7Qbsrs4NXVd4azB", + "asset_symbol": "TEST", + "amount": 6034311 + }, + { + "owner": "TESTCh9jkPgdZU3nMJFbj1pz4sTc8UCDs2tx2", + "asset_symbol": "TEST", + "amount": 4005127 + }, + { + "owner": "TESTL96jWRGeuveN91zERY3RJW66bHUsdpxoo", + "asset_symbol": "TEST", + "amount": 552106 + }, + { + "owner": "TESTFx3vaGYx8ZusWa9iveVEgg7MazAm9g595", + "asset_symbol": "TEST", + "amount": 8037383 + }, + { + "owner": "TESTKBghGKMnxBohchuFiyC3iZWxx5Z4tySeu", + "asset_symbol": "TEST", + "amount": 264243445 + }, + { + "owner": "TESTGk1SpHG85edXkXQW7McpztzfpsFTdw1q6", + "asset_symbol": "TEST", + "amount": 1057227 + }, + { + "owner": "TEST3HeecfHa1vD55GYLuRhGW2uXoGypETupr", + "asset_symbol": "TEST", + "amount": 2075822 + }, + { + "owner": "TEST93ZLWjfnvZ9ciP9ZqtkWqiororNvedhWV", + "asset_symbol": "TEST", + "amount": 55716952 + }, + { + "owner": "TEST6xJ855eG8pTXWSgV9GnTbYE4KBTLForGo", + "asset_symbol": "TEST", + "amount": 125656759 + }, + { + "owner": "TEST9mALG8ZFWjFnHAJCak3yhwV2zm7xZCuUN", + "asset_symbol": "TEST", + "amount": 4804790 + }, + { + "owner": "TEST37dbQDi7JPC1wywrafebXAEJpjTni2zG8", + "asset_symbol": "TEST", + "amount": 2192651 + }, + { + "owner": "TEST2Sd6v5BfHE91J5aLca9MXAMRnpkDHsiER", + "asset_symbol": "TEST", + "amount": 3300762 + }, + { + "owner": "TEST8ufyghbjrRDY7dPtn1Wo7aNjAu5bAwRTm", + "asset_symbol": "TEST", + "amount": 374770 + }, + { + "owner": "TEST4BmRuPiaTtQUNwjWAYVETW7FnVyjxCXt6", + "asset_symbol": "TEST", + "amount": 94080626 + }, + { + "owner": "TESTMCHS4gwDgTNgR5nHa4AnmcaNUBzq7spQM", + "asset_symbol": "TEST", + "amount": 1289663 + }, + { + "owner": "TESTERjaTQGgwwsLtgzwPxpypnHEJX56XrPEB", + "asset_symbol": "TEST", + "amount": 34782933 + }, + { + "owner": "TESTJ9McAswZgWuA65QcoqC9ofFWhbK6muPQu", + "asset_symbol": "TEST", + "amount": 16091457 + }, + { + "owner": "TESTQ4EjAGSJniQmuY2tgzKqCa514Xc4vMRm3", + "asset_symbol": "TEST", + "amount": 49379466 + }, + { + "owner": "TEST6w6nGQeCNZ3Wbr6F4KpXZBU3a8H65oyuY", + "asset_symbol": "TEST", + "amount": 9621173 + }, + { + "owner": "TESTQ9731ejGXfgGCD5LXi8dKcTJXdN7TwZnP", + "asset_symbol": "TEST", + "amount": 179278467 + }, + { + "owner": "TEST2xniLHVbiBGNTb48paERu229xGTQdXL4G", + "asset_symbol": "TEST", + "amount": 4024200 + }, + { + "owner": "TESTJCreoqc7UF7kMhV8z5X3JmRtvWhMoPy1w", + "asset_symbol": "TEST", + "amount": 8449847 + }, + { + "owner": "TESTQ87UQm81qwAmuNaEL4sRFmDanMfLNUFQj", + "asset_symbol": "TEST", + "amount": 8305162 + }, + { + "owner": "TEST6UaSijMWfKeqmcFj9HTYkmkgxcoaBqQHx", + "asset_symbol": "TEST", + "amount": 151936364 + }, + { + "owner": "TESTPq5gtatgNYUwy5k5y7M9F8TaLejW7dzfg", + "asset_symbol": "TEST", + "amount": 122060821 + }, + { + "owner": "TESTAbXwKxeEjTpYxWXGDoHxT5PiWAD1VXtX1", + "asset_symbol": "TEST", + "amount": 46933801 + }, + { + "owner": "TEST57A1gKmR7bGo9SAk2Z1xcPrkZYkHUeWSe", + "asset_symbol": "TEST", + "amount": 9746041 + }, + { + "owner": "TESTA78vMSoZ1485vrPMhgHVuQPx6XKg6Ccnp", + "asset_symbol": "TEST", + "amount": 1256198 + }, + { + "owner": "TEST5RbDrJD9E4oYYFsXss7XsioRndDVh4vhQ", + "asset_symbol": "TEST", + "amount": 18865263 + }, + { + "owner": "TESTGc5BbgCTqSTtiqbUHuoouYgUcrCZezoRV", + "asset_symbol": "TEST", + "amount": 5213174 + }, + { + "owner": "TEST4k5h7JqHcjDLNjCAd75v2NZq9ZxtYzuK8", + "asset_symbol": "TEST", + "amount": 381086708 + }, + { + "owner": "TESTERsouVv6JDTstb4NZDBMCa9CGVcxkmVv", + "asset_symbol": "TEST", + "amount": 6465287 + }, + { + "owner": "TEST31JZBRUmwac2sDL68BmA2RMPnyzDoVGVS", + "asset_symbol": "TEST", + "amount": 1590240 + }, + { + "owner": "TESTDmriBMGcecc7S78frupvN7GtWWjgNSCvR", + "asset_symbol": "TEST", + "amount": 7349442 + }, + { + "owner": "TESTGtAJXYtnD4nz7fEc82rBiTWvCrhU1VboG", + "asset_symbol": "TEST", + "amount": 675424 + }, + { + "owner": "TESTKa5LzEj55HnkqF3P3XtN95hQkLaLdYctQ", + "asset_symbol": "TEST", + "amount": 6513695 + }, + { + "owner": "TEST7PobQTrSkyPYdpQnNsd4rVhT5ys7nysee", + "asset_symbol": "TEST", + "amount": 325886444 + }, + { + "owner": "TEST67W6ziQvzcH33zTjgRMwHBWfsWoZtwiNK", + "asset_symbol": "TEST", + "amount": 16469477 + }, + { + "owner": "TEST6vhwTqygeod3rHFa2gasJA4Es5gsuA55a", + "asset_symbol": "TEST", + "amount": 248253018 + }, + { + "owner": "TESTDVTg13L3zKPbpvg31qFqokxvHC7M1cyRA", + "asset_symbol": "TEST", + "amount": 101664838 + }, + { + "owner": "TESTAhsQWGiUUsmiiwUhYsih1TKBKKJ2B5oUW", + "asset_symbol": "TEST", + "amount": 6573347 + }, + { + "owner": "TESTBx8t9foQxorzXiLoj3sGxCKW2zgj8zPSy", + "asset_symbol": "TEST", + "amount": 840454 + }, + { + "owner": "TEST5DX3pTL62oWJZoB3zLc4D6WnNptuMEZdY", + "asset_symbol": "TEST", + "amount": 19447281 + }, + { + "owner": "TESTKnkwox6cwJdHaDk4GVUcQjrHYy4EuSsGc", + "asset_symbol": "TEST", + "amount": 17224049 + }, + { + "owner": "TESTPbMFd4gJn9FCpwUH9mn6WFDyv1ZbDq5sD", + "asset_symbol": "TEST", + "amount": 8288969 + }, + { + "owner": "TEST9FNbkju4ukLMCFmX9cevUR3BEvBFWFMiL", + "asset_symbol": "TEST", + "amount": 29847388 + }, + { + "owner": "TESTccWYGgxp9z8V4nLNA2Zuow3E8C6oguQt", + "asset_symbol": "TEST", + "amount": 6085751 + }, + { + "owner": "TESTHxphmXgikudnpyEpxTPn1CgV7ND4WK4qC", + "asset_symbol": "TEST", + "amount": 3374266 + }, + { + "owner": "TESTECQkH35MYtEEGszVQrA63pYFzmmzXmqHX", + "asset_symbol": "TEST", + "amount": 1973643 + }, + { + "owner": "TESTCxpRZiwvmeCNwKKXUjWwS2MA28LWMKRWH", + "asset_symbol": "TEST", + "amount": 964311 + }, + { + "owner": "TEST2JFu1VH1X2WwAjBzhbNjMeTjntXcsmbn7", + "asset_symbol": "TEST", + "amount": 138910196 + }, + { + "owner": "TESTHdjrYNWS99gCtd4tiY4rKH85RrTP8j8vY", + "asset_symbol": "TEST", + "amount": 3937954 + }, + { + "owner": "TEST8HhtvkeqyfhRZJus9fFRk3rwH927uwrgn", + "asset_symbol": "TEST", + "amount": 4427352 + }, + { + "owner": "TESTAVBrokm18LNnwzPPb2AKM9dvewGipWSpQ", + "asset_symbol": "TEST", + "amount": 275494787 + }, + { + "owner": "TESTPkC5koTkniUetL8V3QrqfjN11skAjQp3t", + "asset_symbol": "TEST", + "amount": 225540710 + }, + { + "owner": "TESTHTzGJrhe8WvhGJPSvMfNRLY497fRnsGDb", + "asset_symbol": "TEST", + "amount": 2075786 + }, + { + "owner": "TESTDie7D8NLePGKUxKUvGrsP5F3HaQA4vNdK", + "asset_symbol": "TEST", + "amount": 2073952 + }, + { + "owner": "TEST8EiscU1bDo15vi6BY9XgYfDWzeXi5Ag2z", + "asset_symbol": "TEST", + "amount": 1259347 + }, + { + "owner": "TESTN4CzMTENQy1bat2bWuRcyB4Czu6nVMnHm", + "asset_symbol": "TEST", + "amount": 190078 + }, + { + "owner": "TESTQExgsatd5xkYGn8YvR6yrkTsyqX52Zn3Q", + "asset_symbol": "TEST", + "amount": 7589881 + }, + { + "owner": "TESTCSsxh8RbfUGVpLwv5yu2uRdUJbFeJGfDM", + "asset_symbol": "TEST", + "amount": 3551983 + }, + { + "owner": "TEST3Lr4J29rL2CEUQjT7ghaK1X64LbpLfBkT", + "asset_symbol": "TEST", + "amount": 9277044 + }, + { + "owner": "TESTLhN4R5KRPrWFedZLg1UArPchu6zTSXkBP", + "asset_symbol": "TEST", + "amount": 1221050 + }, + { + "owner": "TEST3MQkQu5HVJU9fPEatskTpYoktFZQt59Ty", + "asset_symbol": "TEST", + "amount": 10528506 + }, + { + "owner": "TEST4L3TLvsHg2awAZCQMMjj89KGWShejtvKJ", + "asset_symbol": "TEST", + "amount": 10969596 + }, + { + "owner": "TESTMxfWhDWjtmcMcJ2SLcakBLgCcbNEKbcxn", + "asset_symbol": "TEST", + "amount": 479052 + }, + { + "owner": "TESTJbzyRXZTCKcgw9J1WZTzXLaJVmAisoenS", + "asset_symbol": "TEST", + "amount": 2832894 + }, + { + "owner": "TESTP4TuKyndiefGc1QZpdATRnNPzGS1DYYWk", + "asset_symbol": "TEST", + "amount": 20265527 + }, + { + "owner": "TESTjNKUGsxSExG68fR8nSTtznRSaV7dY9Uv", + "asset_symbol": "TEST", + "amount": 32525708 + }, + { + "owner": "TEST54uSkvMN4kHYpJrq5YZE6ABTthzVgZYHE", + "asset_symbol": "TEST", + "amount": 12549489 + }, + { + "owner": "TESTDiwHMMu1mJeBikZiJDe3xsiAJ9x1Y1XZK", + "asset_symbol": "TEST", + "amount": 11811324 + }, + { + "owner": "TEST85UN9kMsPFHWzhsE2Pprfvf8cCpRg6FMe", + "asset_symbol": "TEST", + "amount": 10398488 + }, + { + "owner": "TEST3beFrHJfJ1DLLNJF4y6yFaw8M5AUVDNZr", + "asset_symbol": "TEST", + "amount": 1756149 + }, + { + "owner": "TESTDA4EP3FBsmzohajEFNnPpWuzsrNV6BLra", + "asset_symbol": "TEST", + "amount": 27232456 + }, + { + "owner": "TESTMbiitaQMRnrGSzUkuAUqxcZHrjXAcxRRS", + "asset_symbol": "TEST", + "amount": 2345579 + }, + { + "owner": "TEST7dz9nEKJ9rfyvdpMmhg5a7ALAesNaD9QM", + "asset_symbol": "TEST", + "amount": 1885976 + }, + { + "owner": "TESTCRFKLDFfRKKDQwHfaiXbtnSeyqD3Ftgor", + "asset_symbol": "TEST", + "amount": 23639767 + }, + { + "owner": "TESTMk43ywSxbxmmCFZaUz1dZVmutZEvCGtP1", + "asset_symbol": "TEST", + "amount": 34979953 + }, + { + "owner": "TESTMJuk4ZDRNUykkDdWHEMH8DVyrc3rvQ3JS", + "asset_symbol": "TEST", + "amount": 69492933 + }, + { + "owner": "TEST6jrtCCeCfhTKobLfRW3BC9S6P5op5cMAm", + "asset_symbol": "TEST", + "amount": 446847 + }, + { + "owner": "TESTNZjPqboaQdwMYKHWWjD4HWXgE81YyqQbs", + "asset_symbol": "TEST", + "amount": 8352381 + }, + { + "owner": "TESTEtDfXgxzQjM8JYVUe9dAKLgzGyGR94XQ6", + "asset_symbol": "TEST", + "amount": 11364974 + }, + { + "owner": "TESTBStyp58qgjG1pyinGCMKgVVe5YfiKwut8", + "asset_symbol": "TEST", + "amount": 6576859 + }, + { + "owner": "TEST3FkAQXygnj653iBpYin1VpimzgMLZ5aZL", + "asset_symbol": "TEST", + "amount": 71292654 + }, + { + "owner": "TESTAezr8pkPCNxDY9cQWoXRJZmwqbdbuPd9m", + "asset_symbol": "TEST", + "amount": 29196778 + }, + { + "owner": "TESTLyki2Zm4V71JuQiosKvtdtavJeJVJeiDa", + "asset_symbol": "TEST", + "amount": 100505930 + }, + { + "owner": "TESTFxyEqDniBpu6JywVxXXNWfk5krWidz7Wx", + "asset_symbol": "TEST", + "amount": 16067210 + }, + { + "owner": "TESTHqrnmQ8vELuzyaMChSVfVabgook4fac58", + "asset_symbol": "TEST", + "amount": 399404 + }, + { + "owner": "TESTKTYsqGKPcQboasZJwhsVGFGTAbaodcTck", + "asset_symbol": "TEST", + "amount": 74978181 + }, + { + "owner": "TESTLCbqVBymQAnkWUdEUtktYP95m3XRGWUYR", + "asset_symbol": "TEST", + "amount": 395668 + }, + { + "owner": "TESTFq2Wxi4bhv7dN8MNVJJrfCL4HWbX9x2Vi", + "asset_symbol": "TEST", + "amount": 11705303 + }, + { + "owner": "TESTNx6y7e2QjdAe82QtX6JxtQJNCstd4tQSi", + "asset_symbol": "TEST", + "amount": 3576386 + }, + { + "owner": "TESTD7NmRM5wShWyuyMhxqaVQsrtimz6bSxyz", + "asset_symbol": "TEST", + "amount": 1930673 + }, + { + "owner": "TESTK5vgZW5mYsZHP4eQDyQxbNRiLn296B1Rc", + "asset_symbol": "TEST", + "amount": 1994335 + }, + { + "owner": "TEST9DNhXnSQjnQhFBiQTj4S1CvYpC3FyVijM", + "asset_symbol": "TEST", + "amount": 10361422 + }, + { + "owner": "TESTDEPksvjqnC8Em3r3MZrhcSjrcTmcz76LU", + "asset_symbol": "TEST", + "amount": 3278 + }, + { + "owner": "TEST6bi6WRb1SxHN7x4HyCMqatsWSv9r1EEta", + "asset_symbol": "TEST", + "amount": 921410 + }, + { + "owner": "TEST4mtJz7P247FfQkKviqyBtPYTWrbeGxfSu", + "asset_symbol": "TEST", + "amount": 9716205 + }, + { + "owner": "TESTBojUP8im3Dee3VmbPYsZtqs6q4zqT2H8n", + "asset_symbol": "TEST", + "amount": 91060 + }, + { + "owner": "TEST8CU7M71WxwyEscAFfFcHyLDnbrrKcRtAt", + "asset_symbol": "TEST", + "amount": 14117392 + }, + { + "owner": "TESTBsTFNuFb8BXFnJ2yRfReqvsvJ3DjFLnXz", + "asset_symbol": "TEST", + "amount": 2150920 + }, + { + "owner": "TEST3Habs3hyuEXK1m7eUv3GcNMRU3y3QSo63", + "asset_symbol": "TEST", + "amount": 214955091 + }, + { + "owner": "TESTHzth7cdZFeTE7C6N4mJC4QettX6RzAGLv", + "asset_symbol": "TEST", + "amount": 3199842 + }, + { + "owner": "TESTJXDVpqeemyWP5SGAy96sPTjz3asFrokjL", + "asset_symbol": "TEST", + "amount": 499940 + }, + { + "owner": "TEST9fbLrNUtabbsKjrRFZZxqfbC7GT3LitJU", + "asset_symbol": "TEST", + "amount": 165884263 + }, + { + "owner": "TESTBKXzc1CZQr3pMP5KFeXmfZeCohFYAujfC", + "asset_symbol": "TEST", + "amount": 32344987 + }, + { + "owner": "TEST6SdmD9yHFndEhpsh1c8SkE3hAGKcFa7Ho", + "asset_symbol": "TEST", + "amount": 395189359 + }, + { + "owner": "TESTBEH1LrhpDvzbFTyxwHXrrKYCFsnCQnQaM", + "asset_symbol": "TEST", + "amount": 2713205 + }, + { + "owner": "TEST8Ha4it6MuArpNDjy8NNCKxrtWyEJgDYmf", + "asset_symbol": "TEST", + "amount": 1133256 + }, + { + "owner": "TESTA67p8yJ8PzUy4pngjaShR7yEULYKpL7Nj", + "asset_symbol": "TEST", + "amount": 36961988 + }, + { + "owner": "TESTGkSuo7KhxTdN5V2tudaAtKtb4HL9dRjV8", + "asset_symbol": "TEST", + "amount": 2872512 + }, + { + "owner": "TESTHAj6ND5VubABDTSv8D3iWVfE3o1xk7Qpr", + "asset_symbol": "TEST", + "amount": 4926450 + }, + { + "owner": "TESTKXzx6c6m3WJdog1VrYLcR8rB628EQHq8t", + "asset_symbol": "TEST", + "amount": 4979802 + }, + { + "owner": "TESTNHWKRw6PkkKhkdhNAdYfQo9VLzQJx2fwc", + "asset_symbol": "TEST", + "amount": 295498 + }, + { + "owner": "TESTEkhzzhm9YEpyzhnjLiQXUWyT6F5d3FMvc", + "asset_symbol": "TEST", + "amount": 37286641 + }, + { + "owner": "TEST9NdzvyYo71jZXyRKfmccSDNey3kBrz3KQ", + "asset_symbol": "TEST", + "amount": 39964726 + }, + { + "owner": "TESTBvthVWr2UFfDPKV1KCKbm7sA5HyXRnjXi", + "asset_symbol": "TEST", + "amount": 3465382 + }, + { + "owner": "TESTG7amWKJ2gocMMrkPZGKfeajXUcNLwaB4t", + "asset_symbol": "TEST", + "amount": 5029836 + }, + { + "owner": "TESTJ54Uqw2uKaFHjdusBSuS8hLehn4HM35Qb", + "asset_symbol": "TEST", + "amount": 99285894 + }, + { + "owner": "TEST3eqCMpsxRm7Qz4PYW15hV9ngA7gR4y4Ci", + "asset_symbol": "TEST", + "amount": 12562911 + }, + { + "owner": "TESTDAnDbTSiiNmyXL99tteRrgzDaoo96d1RA", + "asset_symbol": "TEST", + "amount": 4372228 + }, + { + "owner": "TEST8ssPPfWMruLwnoTw5dav3tzQy1DMyaKDq", + "asset_symbol": "TEST", + "amount": 11709900 + }, + { + "owner": "TESTHFW7DiPmmf63g8N9C8Emne4DduFtdyLxT", + "asset_symbol": "TEST", + "amount": 5577826 + }, + { + "owner": "TESTGfv7p29MLmDLDmCJ5c6oD2hX3NPbNLHTr", + "asset_symbol": "TEST", + "amount": 8902865 + }, + { + "owner": "TESTCk6v3WBU4VJVe66dCAjKz4bvrUCaCRRkp", + "asset_symbol": "TEST", + "amount": 32625820 + }, + { + "owner": "TESTPreKQoxdgaGrsFUyeaZXTLQyZCtzHXopG", + "asset_symbol": "TEST", + "amount": 1120512 + }, + { + "owner": "TEST4L1x1hwSpAPD3BdHtVnpvpyXJodJL6sTE", + "asset_symbol": "TEST", + "amount": 3444077 + }, + { + "owner": "TESTdcfkMgmWLwVrs9yXTQBXQsENTThRaEHU", + "asset_symbol": "TEST", + "amount": 2869386 + }, + { + "owner": "TESTAXB8WDc2mXhL32ytBKTZz6F5EqyytruCd", + "asset_symbol": "TEST", + "amount": 30275 + }, + { + "owner": "TEST9TPJedPcnMwePdSPWWabEoLNmFVqmnbcF", + "asset_symbol": "TEST", + "amount": 113142 + }, + { + "owner": "TESTPShfjVW2ps8MB1BMjGJTcHwXdP3EvM6Mq", + "asset_symbol": "TEST", + "amount": 39352622 + }, + { + "owner": "TESTKjVnW9VJzc29WA2pYd2B7MfPJ5jBRRMJz", + "asset_symbol": "TEST", + "amount": 8618817 + }, + { + "owner": "TESTCWQpJJKKTiuoFhSWfGCh8b569awhsGt9k", + "asset_symbol": "TEST", + "amount": 32884381 + }, + { + "owner": "TESTByTMb8DY5GrC2zusGDQUXXLh4PuphzQcX", + "asset_symbol": "TEST", + "amount": 32956773 + }, + { + "owner": "TESTMga9YWokQg56QUnxbhsNzh5Eh3p5WmeJ1", + "asset_symbol": "TEST", + "amount": 499389 + }, + { + "owner": "TESTBiSDnSqqNP9LL7E57MBRgKLCaiARJZq61", + "asset_symbol": "TEST", + "amount": 13641837 + }, + { + "owner": "TESTNhEZbzJJ5rNgHNk1PDYenXFJ1EHQUeada", + "asset_symbol": "TEST", + "amount": 5153854 + }, + { + "owner": "TESTNV5W1tBY6j9mj7bssXnS2HrTcG6AGEQqC", + "asset_symbol": "TEST", + "amount": 672237 + }, + { + "owner": "TESTDriRThaEPtLfgDAh4WVQHh1gZWUrovdLk", + "asset_symbol": "TEST", + "amount": 2088859 + }, + { + "owner": "TESTD1pozXFRz4tcmNuzwMJtmoetJ9SzLm3Kx", + "asset_symbol": "TEST", + "amount": 6523960 + }, + { + "owner": "TESTG3b9EfXujNw4AQ2yqbivpugYmULpPkrqw", + "asset_symbol": "TEST", + "amount": 1795305 + }, + { + "owner": "TESTM6uWTxjErH7hwMAGKWHNMYHJ9sKtRe2p8", + "asset_symbol": "TEST", + "amount": 6563391 + }, + { + "owner": "TEST3t6ASKC9tFTJfBoWEJ33VMBZUMB4cyCYC", + "asset_symbol": "TEST", + "amount": 34388777 + }, + { + "owner": "TESTDippUXSZoVR7Gbrk2QM9RNCAWV88YVaSK", + "asset_symbol": "TEST", + "amount": 3231587 + }, + { + "owner": "TEST4icjnF1DsHobwYBzy9J7FS9zRsxGWCQQT", + "asset_symbol": "TEST", + "amount": 845891 + }, + { + "owner": "TEST98y17cgAp4du7kgGeRVPq3L2HTvqSWLA4", + "asset_symbol": "TEST", + "amount": 3269953 + }, + { + "owner": "TESTAKho9gZutuiocRaffoAZfg7x5KXkTbniK", + "asset_symbol": "TEST", + "amount": 3460641 + }, + { + "owner": "TESTLChZHQVwrihwNmDapDiHYmn3TCX2uuoem", + "asset_symbol": "TEST", + "amount": 10087252 + }, + { + "owner": "TEST9GS82nqnh1y1cFVWq5tvHZtLvr1pJPhcp", + "asset_symbol": "TEST", + "amount": 6353795 + }, + { + "owner": "TEST44H811jTg1kwVZVThj8g3SmQF87JLTCdJ", + "asset_symbol": "TEST", + "amount": 12038343 + }, + { + "owner": "TESTAhoGsjobE4LRYRrnZ3LGXRnF3QqCYffSy", + "asset_symbol": "TEST", + "amount": 1190509 + }, + { + "owner": "TEST6rgarBoe8nkScpc493wW14APcc5ywmnTa", + "asset_symbol": "TEST", + "amount": 1604292 + }, + { + "owner": "TESTCxnANemdYeJfUKBRihZs27stPtpdnnFya", + "asset_symbol": "TEST", + "amount": 2053959 + }, + { + "owner": "TESTDmSqLUfQ7xRN7RnR4GhJbRqCN9iGYAQnP", + "asset_symbol": "TEST", + "amount": 3346071 + }, + { + "owner": "TEST8LadywANgxaGGsPcjESPXfUdU8y2vkFsF", + "asset_symbol": "TEST", + "amount": 71366154 + }, + { + "owner": "TEST6o72tsyaqq6pfgUK1ewzJmYWmg3uDxTV9", + "asset_symbol": "TEST", + "amount": 1115512 + }, + { + "owner": "TESTC1Jvhmv5X2dNPgLRK1eJfeHZUJCJdDwWh", + "asset_symbol": "TEST", + "amount": 1721604 + }, + { + "owner": "TESTEtPHXr6CHhusSnVc9VGWHvkvxnLG1aobv", + "asset_symbol": "TEST", + "amount": 1660581 + }, + { + "owner": "TESTACebjW6Cfp4v45UpCB3kcRVBYUig3KeRA", + "asset_symbol": "TEST", + "amount": 35250858 + }, + { + "owner": "TEST7YK4ABqsPiFf26dtLSctMGwVegE3UExAY", + "asset_symbol": "TEST", + "amount": 25723372 + }, + { + "owner": "TESTCSPUfydg34hNBPf6ouB2TUqAyxnwL7CvE", + "asset_symbol": "TEST", + "amount": 2520097 + }, + { + "owner": "TEST25iAwGpKbmQixD3NoUPV1z7wAFaa1BiMa", + "asset_symbol": "TEST", + "amount": 2088475 + }, + { + "owner": "TESTCkY1yVLbrTUpyq7A92TvnC5GaqWyQwcpU", + "asset_symbol": "TEST", + "amount": 3326196 + }, + { + "owner": "TESTCL1orCs1gJ5WPG5TYpH6DRDrpAEv36t8d", + "asset_symbol": "TEST", + "amount": 105022 + }, + { + "owner": "TEST5atYGpEoGSAP97Wr3zwRNsnyFLmoF2onX", + "asset_symbol": "TEST", + "amount": 66654407 + }, + { + "owner": "TESTBn4CCb71fW7VqLXz41k28obTKi89Suc9n", + "asset_symbol": "TEST", + "amount": 206042 + }, + { + "owner": "TEST4L3CDTfx3f7Sxm4rKQRizddhkMHKjPZz1", + "asset_symbol": "TEST", + "amount": 34380000 + }, + { + "owner": "TEST13bPCp663vizwu1VbM2j51Qh2pEjKjMTh", + "asset_symbol": "TEST", + "amount": 2378174 + }, + { + "owner": "TEST9QJuMMjkFwAAsK4AN1wgUhQw2ete2Lt7v", + "asset_symbol": "TEST", + "amount": 136405 + }, + { + "owner": "TESTCHrqMoFvzhvQgxqr5v9Us6ng6a7LU1dNm", + "asset_symbol": "TEST", + "amount": 10053333 + }, + { + "owner": "TESTKAjoKA8uBJe3JJ5HPVbHQFuezGRwVhPw5", + "asset_symbol": "TEST", + "amount": 18815812 + }, + { + "owner": "TESTCZ2v4kYgBjH3spFNUaAvejSCaf874bfPo", + "asset_symbol": "TEST", + "amount": 11740336 + }, + { + "owner": "TESTKYGdhjFwSeGrHeZAVdGcexJAeMsYuuU4", + "asset_symbol": "TEST", + "amount": 8298516 + }, + { + "owner": "TESTLusZA2uxznS7RrfFFiX5vnji6W9gKBSD8", + "asset_symbol": "TEST", + "amount": 1650289 + }, + { + "owner": "TESTCs6jLYypz5rBJP23ts8SfxA3eswuCn1x7", + "asset_symbol": "TEST", + "amount": 17380667 + }, + { + "owner": "TESTvwfzSiUjBwSQArtuQSepRdCa8BJs9cLH", + "asset_symbol": "TEST", + "amount": 4102147 + }, + { + "owner": "TESTBoig7BZbkSTF2Sj2AwkcNsLDdRmBcyatU", + "asset_symbol": "TEST", + "amount": 409370415 + }, + { + "owner": "TESTFm1HRdDWb9tsovYQ13iWZHLAtdZD7LgZK", + "asset_symbol": "TEST", + "amount": 24888493 + }, + { + "owner": "TESTMW3RSnLfDotxNV9xDqQDhfD2YMUocWzBq", + "asset_symbol": "TEST", + "amount": 4248693 + }, + { + "owner": "TEST4AourZtspG5zKangfTtt7DoisVNAfJ7CJ", + "asset_symbol": "TEST", + "amount": 32971238 + }, + { + "owner": "TEST2syNgmQBs8pChRi6eZXv5TrK3txadiBf3", + "asset_symbol": "TEST", + "amount": 503826 + }, + { + "owner": "TESTBN8ZpC3emsCAkiDiMcTe1tp17vWhHL17w", + "asset_symbol": "TEST", + "amount": 2015486 + }, + { + "owner": "TESTDvKYM2BY1Vea8RWyppuXCvQiPPLtGvbcq", + "asset_symbol": "TEST", + "amount": 7520909 + }, + { + "owner": "TESTHCCq1xZhy7sqSpPwxYgV4hNQUwt7rPX5", + "asset_symbol": "TEST", + "amount": 949252 + }, + { + "owner": "TEST2EH69zBbkxVJbMtUhu2gvJKBUWFv8ckLm", + "asset_symbol": "TEST", + "amount": 21312000 + }, + { + "owner": "TESTGED8AMA9NaGfhJYDsBuZFdUNutN1za5wQ", + "asset_symbol": "TEST", + "amount": 301603 + }, + { + "owner": "TESTNWmKFhtT2Ei2miujS4pjzAdijsn35MM49", + "asset_symbol": "TEST", + "amount": 36709113 + }, + { + "owner": "TEST5GkRyrwXv7BMwq4F69nv3reHrwpdFAbPE", + "asset_symbol": "TEST", + "amount": 687227 + }, + { + "owner": "TESTMoc94CbgPWmHXPwcim1cwHBCFskUjGmD5", + "asset_symbol": "TEST", + "amount": 119931367 + }, + { + "owner": "TEST7REhX1bPfoD4UKG7NxVUf6MUqZtHqeWSf", + "asset_symbol": "TEST", + "amount": 9359997 + }, + { + "owner": "TEST3eeYKmrefzMHqK6qbCnkcdVbmSHUFWwm2", + "asset_symbol": "TEST", + "amount": 704107 + }, + { + "owner": "TESTKTkksTb6ATAyRauBkSMVF3cLH2721A6TD", + "asset_symbol": "TEST", + "amount": 231957 + }, + { + "owner": "TESTEiPYGbNdhs3pwDWHSYYMioAkxuQK3wnAx", + "asset_symbol": "TEST", + "amount": 125456430 + }, + { + "owner": "TEST2XQoiWRkavksk7WLnqquHaHGGcHfS9Ldj", + "asset_symbol": "TEST", + "amount": 69308 + }, + { + "owner": "TESTGSkkLWXRuDWjuqSUm18X4hqt2Q7BmHYsg", + "asset_symbol": "TEST", + "amount": 2711821 + }, + { + "owner": "TEST7NckQSMXQcskmzGGZtAALRiCS9ddWaXVy", + "asset_symbol": "TEST", + "amount": 448843 + }, + { + "owner": "TEST8uRhPeyv8KfbJqaKR5gu8REymzFk11iw2", + "asset_symbol": "TEST", + "amount": 200430 + }, + { + "owner": "TESTHEUJwZaZX3Lo6nawowq5npe5N3Qpw9vGD", + "asset_symbol": "TEST", + "amount": 6462854 + }, + { + "owner": "TESTNpPGYXJXnPAG625azH9Dio894aqcyP5D4", + "asset_symbol": "TEST", + "amount": 336757 + }, + { + "owner": "TESTDaU4awoz36R4sLmofge1gZSaHK9VQZyJf", + "asset_symbol": "TEST", + "amount": 19717286 + }, + { + "owner": "TEST2FxAR8HScqbsXfE2pf5tXxRRA3AXVT1aq", + "asset_symbol": "TEST", + "amount": 44450720 + }, + { + "owner": "TEST4bDJKYX6xo3ojQH43xCLdtFQvMzgMFETa", + "asset_symbol": "TEST", + "amount": 27225135 + }, + { + "owner": "TESTMX8qCk2hFgGNrLarCvK9E56XqXPiamTFW", + "asset_symbol": "TEST", + "amount": 23399790 + }, + { + "owner": "TESTEgLGBu3uGC487QeYmaLfYzX8ZsbL85ujc", + "asset_symbol": "TEST", + "amount": 1660045 + }, + { + "owner": "TESTJPJD5x4kFYDJmGVf22U5c8TCePetjiRnE", + "asset_symbol": "TEST", + "amount": 6809379 + }, + { + "owner": "TEST3NsE9DHAkQ9Ftd8VSVBzUtHPRNfSUmXog", + "asset_symbol": "TEST", + "amount": 35502352 + }, + { + "owner": "TEST56ycLjxj2ZSgnrxjAii1bNPG4wnSQeJ1N", + "asset_symbol": "TEST", + "amount": 1668995 + }, + { + "owner": "TEST2XB7oVHLCc5AFpA2a4Lrx141AXJnsRLYi", + "asset_symbol": "TEST", + "amount": 199314772 + }, + { + "owner": "TESTB27h4wJaPDQesDFXYfzayAyVFbaUE2JnV", + "asset_symbol": "TEST", + "amount": 8218859 + }, + { + "owner": "TESTKKGjLMpFMgx7iW53pBTqg2DM2Gz7GYSjM", + "asset_symbol": "TEST", + "amount": 17474013 + }, + { + "owner": "TESTBYimW4xfLNhop4obwFvCRUysWoJhMQY1W", + "asset_symbol": "TEST", + "amount": 184455 + }, + { + "owner": "TESTQ9hLYRbCCgioRuC6WpGMZgPCprRfSscyo", + "asset_symbol": "TEST", + "amount": 34255644 + }, + { + "owner": "TESTEa4WCrfuW19gpXfBHmN3EDx8haXgDJQ6c", + "asset_symbol": "TEST", + "amount": 16599460 + }, + { + "owner": "TESTAGKaoKWkf92k4qkmNAnP95mcZJ8yafEqx", + "asset_symbol": "TEST", + "amount": 41497389 + }, + { + "owner": "TESTNSdYUaMc9uUeJDrf7fqNonrVj1gFNzuC3", + "asset_symbol": "TEST", + "amount": 8374960 + }, + { + "owner": "TESTCTVSujB7mbbFQ4cCwNYBuZPkEhZ9aA6yS", + "asset_symbol": "TEST", + "amount": 1780 + }, + { + "owner": "TESTGYTBp25K4wrMtSVtEYrjwRuUFFDK7yUg7", + "asset_symbol": "TEST", + "amount": 11164361 + }, + { + "owner": "TESTP1p2uyPLu57Wa7Y78mw6AhRNq39YBBQAs", + "asset_symbol": "TEST", + "amount": 258858 + }, + { + "owner": "TESTBGVJB3bkkt1311VHfpib2nDPfaFZhK1is", + "asset_symbol": "TEST", + "amount": 156477 + }, + { + "owner": "TESTMXYqhJCfxroBoJGvshvD7XMEAiZSqZT3o", + "asset_symbol": "TEST", + "amount": 2711384 + }, + { + "owner": "TESTArJycJCoxZ1J6uzFWEHfSsgNBZw522Ex4", + "asset_symbol": "TEST", + "amount": 16560093 + }, + { + "owner": "TEST9BHE3DACgscQbQBabGFktuJrWxc8KtkYa", + "asset_symbol": "TEST", + "amount": "6500000000" + }, + { + "owner": "TEST2StUCCUCzV1qqfbVzwhVFJST5M7wvD2WE", + "asset_symbol": "TEST", + "amount": "7500000000" + }, + { + "owner": "TEST8pC3U8WWygRWNcRUMD4cE3uTAYXvfqrcS", + "asset_symbol": "TEST", + "amount": 1500000000 + }, + { + "owner": "TESTM8TpVp3ihnZ2UgPNxfDdfKP9668UTnA9Y", + "asset_symbol": "TEST", + "amount": 2500000000 + }, + { + "owner": "TESTMQafQXKXGzpzQWTZ4K4abit8snNPJShNR", + "asset_symbol": "TEST", + "amount": 1000000000 + }, + { + "owner": "TESTESMxHh4SSwYX58AA7CawPVdmSTC2ofJdm", + "asset_symbol": "TEST", + "amount": "10000000000" + }, + { + "owner": "TESTEE2yA5ZWHUonqE5v4WHfjCaFATFW7pgFW", + "asset_symbol": "TEST", + "amount": "6000000000" + }, + { + "owner": "TESTKLingoj1ACaMvr8iZVgNKt8sfyrAe9CY3", + "asset_symbol": "TEST", + "amount": "5000000000" + }, + { + "owner": "TEST2XADrvirTPRxjbTJNkTHwYEMhf57tirDh", + "asset_symbol": "TEST", + "amount": 1500000000 + }, + { + "owner": "TESTNasFGAwaB82P26vsnxjSsbNzbsVsYj3Ao", + "asset_symbol": "TEST", + "amount": 650000000 + }, + { + "owner": "TEST3cjPk3jRcK8kdzfdxbikmGLd5nuTz2ZoH", + "asset_symbol": "TEST", + "amount": 2000000000 + }, + { + "owner": "TESTMvmgou7vqTZhhukKbUMVZchq3nNGUomBL", + "asset_symbol": "TEST", + "amount": "4730000000" + }, + { + "owner": "TEST9DkFeiBrnp7EaL3PknFK2hZGna2WzjEAh", + "asset_symbol": "TEST", + "amount": 490000000 + }, + { + "owner": "TEST7bFPuoKRGV9tzrn3kP9ARQ47x2e7sFt7t", + "asset_symbol": "TEST", + "amount": 290000000 + }, + { + "owner": "TEST7Ph4fDG9dmL8wwrmjtL8udPqxKu3w8eWL", + "asset_symbol": "TEST", + "amount": 230000000 + }, + { + "owner": "TEST7sKWhmnFzWDvC2HmAxqo9JJqxsHYmkKUb", + "asset_symbol": "TEST", + "amount": 260000000 + }, + { + "owner": "TESTDASxq7NXpf4MPHCdhq6ucmJY74vYoVcec", + "asset_symbol": "TEST", + "amount": 420000000 + }, + { + "owner": "TESTPnWTrE7T8PkdQWbSQHiZY8bEG5s1etDzw", + "asset_symbol": "TEST", + "amount": 320000000 + }, + { + "owner": "TESTCubmSZ8Ge5FkAZuxyLhH7cF7EJDKCqbY8", + "asset_symbol": "TEST", + "amount": 210000000 + }, + { + "owner": "TESTC5XVHbPTQbcpwMdCnUqJ8gzTnzBqx51nj", + "asset_symbol": "TEST", + "amount": 470000000 + }, + { + "owner": "TEST6ZwPskR2x4mCNHqmZ6mhEWtkY3N84UEc2", + "asset_symbol": "TEST", + "amount": 160000000 + }, + { + "owner": "TESTBaurY7wwGWRyNfJSMXw9PxKWnGvvMZrqC", + "asset_symbol": "TEST", + "amount": 180000000 + }, + { + "owner": "TESTBt4352CALsC8p7evMdenxg2rrKGpeXhc7", + "asset_symbol": "TEST", + "amount": 180000000 + }, + { + "owner": "TESTGQtoJducTadAmdQaEGAkGbM6HPsCv8Sja", + "asset_symbol": "TEST", + "amount": 250000000 + }, + { + "owner": "TESTK3n9kEk6yVbxRtsCpdSFLVUpejxjkVBW8", + "asset_symbol": "TEST", + "amount": 260000000 + }, + { + "owner": "TESTL5YrWL7YrGryp4uZ1dVQXLUeGf29GQoc9", + "asset_symbol": "TEST", + "amount": 200000000 + }, + { + "owner": "TESTN4E31sJqk8SrM2uYgWiZ5KkgstzMTUZf2", + "asset_symbol": "TEST", + "amount": 140000000 + }, + { + "owner": "TEST6c9oJ5ad4mehRVzTrvKXG8X3dpYQhxecY", + "asset_symbol": "TEST", + "amount": 230000000 + }, + { + "owner": "TEST9U7DXd8Fg9FnpWUwX4RWRwR4ordVgnwz3", + "asset_symbol": "TEST", + "amount": 330000000 + }, + { + "owner": "TEST2UKeiZy6r1aEVpd4rQBgo7rqXmsLdxWGc", + "asset_symbol": "TEST", + "amount": 150000000 + }, + { + "owner": "TEST4yfHivY1JrQaQGDiwkLEFa4yfTWEAw25k", + "asset_symbol": "TEST", + "amount": 270000000 + }, + { + "owner": "TESTLXVHq3ifDAWhafdCfHWBHGJAdGVAEShxU", + "asset_symbol": "TEST", + "amount": 340000000 + }, + { + "owner": "TESTWVwyJHmiq2F4SE69AdCqcfFRfEy2yYhA", + "asset_symbol": "TEST", + "amount": 140000000 + }, + { + "owner": "TESTJ2wJyNi1ty1Ag4WqxUrNfGHzvKk1eKq3N", + "asset_symbol": "TEST", + "amount": 240000000 + }, + { + "owner": "TEST8EM9J6fVjidz3m9ktddUrJhuSAWppm2zj", + "asset_symbol": "TEST", + "amount": 400000000 + }, + { + "owner": "TESTDx3RM6Jj5GKHHcVLAt1BGZGJNH2qFb3h7", + "asset_symbol": "TEST", + "amount": 440000000 + }, + { + "owner": "TESTAAbqZD5UjTAJKVJDp2V2eNQvsoiqBe2bh", + "asset_symbol": "TEST", + "amount": 400000000 + }, + { + "owner": "TESTLusY9gAXghbrxgPjZnycGA26QCgv2uELq", + "asset_symbol": "TEST", + "amount": 500000000 + }, + { + "owner": "TEST9k5jhTAsqKRHw44kjE94j8CfTG3CuxeLp", + "asset_symbol": "TEST", + "amount": 350000000 + }, + { + "owner": "TEST6S5Qf3UymzjeMqDRewAitkM11nwghJXF7", + "asset_symbol": "TEST", + "amount": 300000000 + }, + { + "owner": "TESTA3ECj6NfKnzGcapTDxcsdUn5ge5UFm4q5", + "asset_symbol": "TEST", + "amount": 340000000 + }, + { + "owner": "TESTPEqGGih7Go5tdZ7G9vwgMSaKHWaEUVkoN", + "asset_symbol": "TEST", + "amount": 230000000 + }, + { + "owner": "TEST14thQY2FJhg5EnATodBUZxmbJUQYkMRqe", + "asset_symbol": "TEST", + "amount": 330000000 + }, + { + "owner": "TESTGbrXpoVTyK6RuuUiiVSrasVPdPYGBpimp", + "asset_symbol": "TEST", + "amount": 480000000 + }, + { + "owner": "TEST4CHxonyfjSdNZDE6A41LZo1Jv7fjrdZbw", + "asset_symbol": "TEST", + "amount": 290000000 + }, + { + "owner": "TESTCBACMuzxNsYtSTE5N4dyENGZYguvEhLFR", + "asset_symbol": "TEST", + "amount": 180000000 + }, + { + "owner": "TESTERcc1t6Vq9tG7LaU4EbPmbArAmZAs7Dr8", + "asset_symbol": "TEST", + "amount": 300000000 + }, + { + "owner": "TESTERaNVbeWtTTuEuppoBokupFgPfxGMqwt6", + "asset_symbol": "TEST", + "amount": 1900000000 + }, + { + "owner": "TESTGfnKLkGwjciAWZhVVBRGrHCmpQBod3ff8", + "asset_symbol": "TEST", + "amount": 80000000 + }, + { + "owner": "TESTJ5s6gMpWXwcpWexwn3cYpMZfbEk5TbfJz", + "asset_symbol": "TEST", + "amount": 1000000000 + }, + { + "owner": "TESTBpuGahFA9pMVkFsYfGsGbpYFr7RWMzosN", + "asset_symbol": "TEST", + "amount": 720000000 + }, + { + "owner": "TEST3ewQw6r5Jv1UU7WyzyPTWV3b41bxTWmMn", + "asset_symbol": "TEST", + "amount": 629200000 + }, + { + "owner": "TESTLTaqTGVjDaStPBGSmQw21ZN7GzDB5X5Cz", + "asset_symbol": "TEST", + "amount": 1432000000 + }, + { + "owner": "TESTLg9yhhxb7SiE4Uu4EvYx2hmMvSFusyjMc", + "asset_symbol": "TEST", + "amount": 1200000000 + }, + { + "owner": "TESTBabRnBMjWhkoeVrg7TVPFUTkZDS3zn25V", + "asset_symbol": "TEST", + "amount": 3680000000 + }, + { + "owner": "TEST9YYYKPvpPM4uDwqHwZaN3LCms5rpr3Rz2", + "asset_symbol": "TEST", + "amount": 616000000 + }, + { + "owner": "TESTC5DWo5kNYWPbu44yW4YBnm5qTEAjLP6z5", + "asset_symbol": "TEST", + "amount": 1760000000 + }, + { + "owner": "TESTEUChVsY5JXUDmnGig8QhfycF63CXn5jdu", + "asset_symbol": "TEST", + "amount": 1760000000 + }, + { + "owner": "TESTKUpEazuoz9bu1at57QjMXc8H6rFsvw26v", + "asset_symbol": "TEST", + "amount": 1760000000 + }, + { + "owner": "TESTCwXrSakaUWF2sU75nknLvLfX926i6nR6G", + "asset_symbol": "TEST", + "amount": 480000000 + }, + { + "owner": "TESTGvDT4czKtSLNfjCDJsCs2saaRobNyTuLu", + "asset_symbol": "TEST", + "amount": 480000000 + }, + { + "owner": "TESTLs8SNSAyecfDWxp5Dbc4geCrLpk3oCp5h", + "asset_symbol": "TEST", + "amount": 480000000 + }, + { + "owner": "TEST4Wh5Br8KUmj3FWGZnSHpj6Xq6Cx6ehdkV", + "asset_symbol": "TEST", + "amount": 640000000 + }, + { + "owner": "TEST59CwH9qvpSriRbqaW5bN4e18gdmWBYfV6", + "asset_symbol": "TEST", + "amount": 640000000 + }, + { + "owner": "TEST4NnaYBips4mNE3wCR74TgQUXq3uxd7Uif", + "asset_symbol": "TEST", + "amount": 2560000000 + }, + { + "owner": "TEST2fEznaxLEbRJ4AUrtebpomHcb6Lyk3n8w", + "asset_symbol": "TEST", + "amount": 640000000 + }, + { + "owner": "TEST47VrTVn4Tzipe4AmLy2xWWd8MBPUYjYdX", + "asset_symbol": "TEST", + "amount": 1520000000 + }, + { + "owner": "TESTEjE1D9btW9AjwqS11LCX9xhCzTCZ2x8Mz", + "asset_symbol": "TEST", + "amount": 1520000000 + }, + { + "owner": "TEST5srz2ooKi9CvpNj5ozdXQcHzkdAjxq9wL", + "asset_symbol": "TEST", + "amount": 1520000000 + }, + { + "owner": "TEST87UN19jy2UntDPyfS8GQt5nxbY48ibQn8", + "asset_symbol": "TEST", + "amount": 1200000000 + }, + { + "owner": "TESTPqziQhNthdUtUPaZBnzDS52X57HUnweFW", + "asset_symbol": "TEST", + "amount": 1200000000 + }, + { + "owner": "TESTMP3DesBZdf4nqSMa1qhFaBceQ5VRNuDyB", + "asset_symbol": "TEST", + "amount": 1200000000 + }, + { + "owner": "TESTEXGLptBHyZFw1MRTzPtTHPjTz51hQjA1W", + "asset_symbol": "TEST", + "amount": 52800000 + }, + { + "owner": "TESTK8upvutxXao7exFnQa38Wopouv4PxTMUc", + "asset_symbol": "TEST", + "amount": 1200000000 + }, + { + "owner": "TESTFePh3fvmRrGJkzzEt1ib3CvqX7vJpM4LD", + "asset_symbol": "TEST", + "amount": 1600000000 + }, + { + "owner": "TESTEY72dSF9hnUuftzSKPMszLJUf6YJwFxKr", + "asset_symbol": "TEST", + "amount": 2086000000 + }, + { + "owner": "TEST2J5iLznc8TCEwFgLXk8j3aKEXZHmoP6rA", + "asset_symbol": "TEST", + "amount": 1280000000 + }, + { + "owner": "TESTFm4tcuySR2qqLbYrzELekNpxsW7okgonP", + "asset_symbol": "TEST", + "amount": 1440000000 + }, + { + "owner": "TESTGtBMitWcGbzf7tZnvT1BHQJY7KcyFQhHA", + "asset_symbol": "TEST", + "amount": 400000000 + }, + { + "owner": "TEST277eCDueHDDzUnYVHnDW3BBkqrd64956N", + "asset_symbol": "TEST", + "amount": 160000000 + }, + { + "owner": "TESTEffstjdh5dBHndpFa3cwDeR6VvHvdmCwf", + "asset_symbol": "TEST", + "amount": 720000000 + }, + { + "owner": "TEST54W61wWEzkEQMSXjNwmwciWKDUeNBLGJ6", + "asset_symbol": "TEST", + "amount": 1160000000 + }, + { + "owner": "TEST57aDPjUMacezgvRuMxhLzAAjrxGJCDQf8", + "asset_symbol": "TEST", + "amount": 1496000000 + }, + { + "owner": "TESTNrDGugSG6gnfnXqhj3uH5U9khwqce8t44", + "asset_symbol": "TEST", + "amount": 3760000000 + }, + { + "owner": "TESTCUkwv159i9MhCqLtuP7NXW7LsH7x9XVZ7", + "asset_symbol": "TEST", + "amount": "5480000000" + }, + { + "owner": "TEST6CfAfbZUAXkuU2jsYbfpfQBaQni8mnLu5", + "asset_symbol": "TEST", + "amount": 2480000000 + }, + { + "owner": "TESTKhjYpShNaDnvwtiLSxmjpHyKcdBUV4SmE", + "asset_symbol": "TEST", + "amount": "14880000000" + }, + { + "owner": "TESTGP2p8s3keFEBKaRy5qvvZyhc1Y68ZRFzq", + "asset_symbol": "TEST", + "amount": 960000000 + }, + { + "owner": "TEST6MrCqFSN7oS6eU6zK3fGihgmgG5A8p7TF", + "asset_symbol": "TEST", + "amount": 4184000000 + }, + { + "owner": "TEST91RmfFr19BxSy5Y3ysSojDiTz9rpfyD2m", + "asset_symbol": "TEST", + "amount": 3360000000 + }, + { + "owner": "TESTAMYBwLRko5Z6fAZ1RUjCZtwirCHtw9Kdo", + "asset_symbol": "TEST", + "amount": 1280000000 + }, + { + "owner": "TEST8oKju1fqmU8RBZmyYxKy7CtZgqKmzF7LL", + "asset_symbol": "TEST", + "amount": 1120000000 + }, + { + "amount": "768107718921", + "asset_symbol": "TEST", + "owner": "TESTAgL9otQ95hN7hUWq25jgHty7mJPpyBcvT" + }, + { + "amount": "100000000000", + "asset_symbol": "TEST", + "owner": "TESTNoTdMkmsSgUeThzbw6p3gjhZ29AzjbrFZ" + } + ], + "initial_vesting_balances": [], + "initial_active_witnesses": 11, + "initial_witness_candidates": [ + { + "owner_name": "init0", + "block_signing_key": "TEST7S1jYoP7oN88YgzjgDvmfG7WDdQjAyYt3VThEf5HYcWmxsPaAj" + }, + { + "owner_name": "init1", + "block_signing_key": "TEST7sS3Kz7QouaUwm8qHKx34gM2vCLmhF7zgJktNcSrhXK4w4iv4Y" + }, + { + "owner_name": "init2", + "block_signing_key": "TEST5piXBNR1go29URD5uDMjCYCT4ZNhogni1S8kdr9FjrNgDwAyty" + }, + { + "owner_name": "init3", + "block_signing_key": "TEST7MbpeAfyKmpsm1G5A6xojVtoqHXoJBw9vrSycP11j4Urw41epS" + }, + { + "owner_name": "init4", + "block_signing_key": "TEST8TEzWdRHynggRnfH4dsgpodHp3AtmeXn8eDrY1SsM5AkQf5cqW" + }, + { + "owner_name": "init5", + "block_signing_key": "TEST7e5L2SXJo7ba6TBYi8ER9cyatyKdofcEmYAQ2xHRAaPudKHqSf" + }, + { + "owner_name": "init6", + "block_signing_key": "TEST4zmiFg1J7VsUSbAa8kTtbphq1hxEYwtHiNhVcXFZ3sEj4X16Uk" + }, + { + "owner_name": "init7", + "block_signing_key": "TEST5MejQWYeCMMeUi8nch8Guza8R69iwbweMw1h8z6NPmzJvDMgAj" + }, + { + "owner_name": "init8", + "block_signing_key": "TEST76KyrYVYK1qEJ8py8RzVaLpd8Qykc9Vw2WnuZCGcw2jfujwdP2" + }, + { + "owner_name": "init9", + "block_signing_key": "TEST6KER8MFtJRA73U2amyJZKhZmb8gPXwdvpPXsSXaJmqcd77fKEZ" + }, + { + "owner_name": "init10", + "block_signing_key": "TEST6MweWfigJsru3JCRcqSXatSbLyPAx4aGubcvd2g6zqryFLbRMH" + } + ], + "initial_committee_candidates": [ + { + "owner_name": "init0" + }, + { + "owner_name": "init1" + }, + { + "owner_name": "init2" + }, + { + "owner_name": "init3" + }, + { + "owner_name": "init4" + }, + { + "owner_name": "init5" + }, + { + "owner_name": "init6" + } + ], + "initial_worker_candidates": [], + "initial_chain_id": "aa34045518f1469a28fa4578240d5f039afa9959c0b95ce3b39674efa691fb21", + "immutable_parameters": { + "min_committee_member_count": 9, + "min_witness_count": 11, + "num_special_accounts": 0, + "num_special_assets": 0 + } +} \ No newline at end of file diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 18ca3130..cf2355f1 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,12 +1,10 @@ -add_subdirectory( fc ) -add_subdirectory( db ) -#add_subdirectory( deterministic_openssl_rand ) +add_subdirectory( app ) add_subdirectory( chain ) +add_subdirectory( db ) add_subdirectory( egenesis ) +add_subdirectory( fc ) add_subdirectory( net ) -#add_subdirectory( p2p ) +add_subdirectory( plugins ) add_subdirectory( time ) add_subdirectory( utilities ) -add_subdirectory( app ) -add_subdirectory( plugins ) add_subdirectory( wallet ) diff --git a/libraries/app/CMakeLists.txt b/libraries/app/CMakeLists.txt index e0e5e6c2..12a6616b 100644 --- a/libraries/app/CMakeLists.txt +++ b/libraries/app/CMakeLists.txt @@ -4,16 +4,19 @@ file(GLOB EGENESIS_HEADERS "../egenesis/include/graphene/app/*.hpp") add_library( graphene_app api.cpp application.cpp + config_util.cpp database_api.cpp plugin.cpp - config_util.cpp ${HEADERS} ${EGENESIS_HEADERS} ) # need to link graphene_debug_witness because plugins aren't sufficiently isolated #246 #target_link_libraries( graphene_app graphene_market_history graphene_account_history graphene_chain fc graphene_db graphene_net graphene_utilities graphene_debug_witness ) -target_link_libraries( graphene_app graphene_market_history graphene_account_history graphene_accounts_list graphene_affiliate_stats graphene_chain fc graphene_db graphene_net graphene_time graphene_utilities graphene_debug_witness graphene_bookie graphene_elasticsearch peerplays_sidechain ) +target_link_libraries( graphene_app + PUBLIC graphene_net graphene_utilities + graphene_account_history graphene_accounts_list graphene_affiliate_stats graphene_bookie graphene_debug_witness graphene_elasticsearch graphene_es_objects graphene_generate_genesis graphene_market_history ) + target_include_directories( graphene_app PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../egenesis/include" ) @@ -30,3 +33,25 @@ INSTALL( TARGETS ARCHIVE DESTINATION lib ) INSTALL( FILES ${HEADERS} DESTINATION "include/graphene/app" ) + + + +add_library( graphene_plugin + plugin.cpp + + include/graphene/app/plugin.hpp + ) + +target_link_libraries( graphene_plugin + PUBLIC graphene_net graphene_utilities ) + +target_include_directories( graphene_plugin + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) + +INSTALL( TARGETS + graphene_app + + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index eb36cd9f..eac6d3b8 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -26,16 +26,16 @@ #include #include #include +#include #include #include -#include -#include -#include #include +#include +#include #include #include #include -#include +#include #include #include @@ -50,828 +50,597 @@ template class fc::api; template class fc::api; template class fc::api; - namespace graphene { namespace app { - login_api::login_api(application& a) - :_app(a) - { - } +login_api::login_api(application &a) : + _app(a) { +} - login_api::~login_api() - { - } +login_api::~login_api() { +} - bool login_api::login(const string& user, const string& password) - { - optional< api_access_info > acc = _app.get_api_access_info( user ); - if( !acc.valid() ) - return false; - if( acc->password_hash_b64 != "*" ) - { - std::string password_salt = fc::base64_decode( acc->password_salt_b64 ); - std::string acc_password_hash = fc::base64_decode( acc->password_hash_b64 ); +bool login_api::login(const string &user, const string &password) { + optional acc = _app.get_api_access_info(user); + if (!acc.valid()) + return false; + if (acc->password_hash_b64 != "*") { + std::string password_salt = fc::base64_decode(acc->password_salt_b64); + std::string acc_password_hash = fc::base64_decode(acc->password_hash_b64); - fc::sha256 hash_obj = fc::sha256::hash( password + password_salt ); - if( hash_obj.data_size() != acc_password_hash.length() ) - return false; - if( memcmp( hash_obj.data(), acc_password_hash.c_str(), hash_obj.data_size() ) != 0 ) - return false; - } + fc::sha256 hash_obj = fc::sha256::hash(password + password_salt); + if (hash_obj.data_size() != acc_password_hash.length()) + return false; + if (memcmp(hash_obj.data(), acc_password_hash.c_str(), hash_obj.data_size()) != 0) + return false; + } - for( const std::string& api_name : acc->allowed_apis ) - enable_api( api_name ); - return true; - } + for (const std::string &api_name : acc->allowed_apis) + enable_api(api_name); + return true; +} - void login_api::enable_api( const std::string& api_name ) - { - if( api_name == "database_api" ) - { - _database_api = std::make_shared< database_api >( std::ref( *_app.chain_database() ) ); - } - else if( api_name == "block_api" ) - { - _block_api = std::make_shared< block_api >( std::ref( *_app.chain_database() ) ); - } - else if( api_name == "network_broadcast_api" ) - { - _network_broadcast_api = std::make_shared< network_broadcast_api >( std::ref( _app ) ); - } - else if( api_name == "history_api" ) - { - _history_api = std::make_shared< history_api >( _app ); - } - else if( api_name == "network_node_api" ) - { - _network_node_api = std::make_shared< network_node_api >( std::ref(_app) ); - } - else if( api_name == "crypto_api" ) - { - _crypto_api = std::make_shared< crypto_api >(); - } - else if( api_name == "asset_api" ) - { - _asset_api = std::make_shared< asset_api >( _app ); - } - else if( api_name == "debug_api" ) - { - // can only enable this API if the plugin was loaded - if( _app.get_plugin( "debug_witness" ) ) - _debug_api = std::make_shared< graphene::debug_witness::debug_api >( std::ref(_app) ); - } - else if( api_name == "bookie_api" ) - { - // can only enable this API if the plugin was loaded - if( _app.get_plugin( "bookie" ) ) - _bookie_api = std::make_shared(std::ref(_app)); - } - else if( api_name == "affiliate_stats_api" ) - { - // can only enable this API if the plugin was loaded - if( _app.get_plugin( "affiliate_stats" ) ) - _affiliate_stats_api = std::make_shared(std::ref(_app)); - } - return; - } +void login_api::enable_api(const std::string &api_name) { + if (api_name == "database_api") { + _database_api = std::make_shared(std::ref(*_app.chain_database())); + } else if (api_name == "block_api") { + _block_api = std::make_shared(std::ref(*_app.chain_database())); + } else if (api_name == "network_broadcast_api") { + _network_broadcast_api = std::make_shared(std::ref(_app)); + } else if (api_name == "history_api") { + _history_api = std::make_shared(_app); + } else if (api_name == "network_node_api") { + _network_node_api = std::make_shared(std::ref(_app)); + } else if (api_name == "crypto_api") { + _crypto_api = std::make_shared(); + } else if (api_name == "asset_api") { + _asset_api = std::make_shared(_app); + } else if (api_name == "debug_api") { + // can only enable this API if the plugin was loaded + if (_app.get_plugin("debug_witness")) + _debug_api = std::make_shared(std::ref(_app)); + } else if (api_name == "bookie_api") { + // can only enable this API if the plugin was loaded + if (_app.get_plugin("bookie")) + _bookie_api = std::make_shared(std::ref(_app)); + } else if (api_name == "affiliate_stats_api") { + // can only enable this API if the plugin was loaded + if (_app.get_plugin("affiliate_stats")) + _affiliate_stats_api = std::make_shared(std::ref(_app)); + } + return; +} - // block_api - block_api::block_api(graphene::chain::database& db) : _db(db) { } - block_api::~block_api() { } +// block_api +block_api::block_api(graphene::chain::database &db) : + _db(db) { +} +block_api::~block_api() { +} - vector> block_api::get_blocks(uint32_t block_num_from, uint32_t block_num_to)const - { - FC_ASSERT( block_num_to >= block_num_from && block_num_to - block_num_from <= 100, "Total blocks to be returned should be less than 100"); - vector> res; - for(uint32_t block_num=block_num_from; block_num<=block_num_to; block_num++) { - res.push_back(_db.fetch_block_by_number(block_num)); - } - return res; - } +vector> block_api::get_blocks(uint32_t block_num_from, uint32_t block_num_to) const { + FC_ASSERT(block_num_to >= block_num_from && block_num_to - block_num_from <= 100, "Total blocks to be returned should be less than 100"); + vector> res; + for (uint32_t block_num = block_num_from; block_num <= block_num_to; block_num++) { + res.push_back(_db.fetch_block_by_number(block_num)); + } + return res; +} - network_broadcast_api::network_broadcast_api(application& a):_app(a) - { - _applied_block_connection = _app.chain_database()->applied_block.connect([this](const signed_block& b){ on_applied_block(b); }); - } +network_broadcast_api::network_broadcast_api(application &a) : + _app(a) { + _applied_block_connection = _app.chain_database()->applied_block.connect([this](const signed_block &b) { + on_applied_block(b); + }); +} - void network_broadcast_api::on_applied_block( const signed_block& b ) - { - if( _callbacks.size() ) - { - /// we need to ensure the database_api is not deleted for the life of the async operation - auto capture_this = shared_from_this(); - for( uint32_t trx_num = 0; trx_num < b.transactions.size(); ++trx_num ) - { - const auto& trx = b.transactions[trx_num]; - auto id = trx.id(); - auto itr = _callbacks.find(id); - if( itr != _callbacks.end() ) - { - 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 }, - GRAPHENE_MAX_NESTED_OBJECTS ) ); - } ); - } - } - } - } +void network_broadcast_api::on_applied_block(const signed_block &b) { + if (_callbacks.size()) { + /// we need to ensure the database_api is not deleted for the life of the async operation + auto capture_this = shared_from_this(); + for (uint32_t trx_num = 0; trx_num < b.transactions.size(); ++trx_num) { + const auto &trx = b.transactions[trx_num]; + auto id = trx.id(); + auto itr = _callbacks.find(id); + if (itr != _callbacks.end()) { + 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}, + GRAPHENE_MAX_NESTED_OBJECTS)); + }); + } + } + } +} - void network_broadcast_api::broadcast_transaction(const signed_transaction& trx) - { - trx.validate(); - _app.chain_database()->check_transaction_for_duplicated_operations(trx); - _app.chain_database()->push_transaction(trx); - if( _app.p2p_node() != nullptr ) - _app.p2p_node()->broadcast_transaction(trx); - } +void network_broadcast_api::broadcast_transaction(const signed_transaction &trx) { + trx.validate(); + _app.chain_database()->check_transaction_for_duplicated_operations(trx); + _app.chain_database()->push_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) - { - _app.chain_database()->check_transaction_for_duplicated_operations(trx); - - fc::promise::ptr prom( new fc::promise() ); - broadcast_transaction_with_callback( [=]( const fc::variant& v ){ - prom->set_value(v); - }, trx ); +fc::variant network_broadcast_api::broadcast_transaction_synchronous(const signed_transaction &trx) { + _app.chain_database()->check_transaction_for_duplicated_operations(trx); - return fc::future(prom).wait(); - } + fc::promise::ptr prom(new fc::promise()); + broadcast_transaction_with_callback([=](const fc::variant &v) { + prom->set_value(v); + }, + trx); - void network_broadcast_api::broadcast_block( const signed_block& b ) - { - _app.chain_database()->push_block(b); - if( _app.p2p_node() != nullptr ) - _app.p2p_node()->broadcast( net::block_message( b )); - } + return fc::future(prom).wait(); +} - void network_broadcast_api::broadcast_transaction_with_callback(confirmation_callback cb, const signed_transaction& trx) - { - trx.validate(); - _callbacks[trx.id()] = cb; - _app.chain_database()->push_transaction(trx); - if( _app.p2p_node() != nullptr ) - _app.p2p_node()->broadcast_transaction(trx); - } +void network_broadcast_api::broadcast_block(const signed_block &b) { + _app.chain_database()->push_block(b); + if (_app.p2p_node() != nullptr) + _app.p2p_node()->broadcast(net::block_message(b)); +} - network_node_api::network_node_api( application& a ) : _app( a ) - { - _pending_trx_connection = _app.chain_database()->on_pending_transaction.connect([this]( const signed_transaction& transaction ){ +void network_broadcast_api::broadcast_transaction_with_callback(confirmation_callback cb, const signed_transaction &trx) { + trx.validate(); + _callbacks[trx.id()] = cb; + _app.chain_database()->push_transaction(trx); + if (_app.p2p_node() != nullptr) + _app.p2p_node()->broadcast_transaction(trx); +} - auto transaction_it = _pending_transactions.find(transaction.id()); - if (_pending_transactions.end() == transaction_it) - { - _pending_transactions[transaction.id()] = transaction; - } +network_node_api::network_node_api(application &a) : + _app(a) { + _pending_trx_connection = _app.chain_database()->on_pending_transaction.connect([this](const signed_transaction &transaction) { + auto transaction_it = _pending_transactions.find(transaction.id()); + if (_pending_transactions.end() == transaction_it) { + _pending_transactions[transaction.id()] = transaction; + } - if (_on_pending_transaction) - { - _on_pending_transaction(fc::variant(transaction, GRAPHENE_MAX_NESTED_OBJECTS)); - } - }); + if (_on_pending_transaction) { + _on_pending_transaction(fc::variant(transaction, GRAPHENE_MAX_NESTED_OBJECTS)); + } + }); - _applied_block_connection = _app.chain_database()->applied_block.connect([this]( const signed_block& block ){ - for (const auto& transaction: block.transactions) - { - auto transaction_it = _pending_transactions.find(transaction.id()); - if (_pending_transactions.end() != transaction_it) - { - _pending_transactions.erase(transaction_it); - } - } + _applied_block_connection = _app.chain_database()->applied_block.connect([this](const signed_block &block) { + for (const auto &transaction : block.transactions) { + auto transaction_it = _pending_transactions.find(transaction.id()); + if (_pending_transactions.end() != transaction_it) { + _pending_transactions.erase(transaction_it); + } + } - /* + /* * Remove expired transactions from pending_transactions */ - for (const auto& transaction: _pending_transactions) - { - if (transaction.second.expiration < block.timestamp) - { - auto transaction_it = _pending_transactions.find(transaction.second.id()); - if (_pending_transactions.end() != transaction_it) - { - _pending_transactions.erase(transaction_it); - } - } + for (const auto &transaction : _pending_transactions) { + if (transaction.second.expiration < block.timestamp) { + auto transaction_it = _pending_transactions.find(transaction.second.id()); + if (_pending_transactions.end() != transaction_it) { + _pending_transactions.erase(transaction_it); } - }); - } - - fc::variant_object network_node_api::get_info() const - { - fc::mutable_variant_object result = _app.p2p_node()->network_get_info(); - result["connection_count"] = _app.p2p_node()->get_connection_count(); - return result; - } - - void network_node_api::add_node(const fc::ip::endpoint& ep) - { - _app.p2p_node()->add_node(ep); - } - - std::vector network_node_api::get_connected_peers() const - { - return _app.p2p_node()->get_connected_peers(); - } - - std::vector network_node_api::get_potential_peers() const - { - return _app.p2p_node()->get_potential_peers(); - } - - fc::variant_object network_node_api::get_advanced_node_parameters() const - { - return _app.p2p_node()->get_advanced_node_parameters(); - } - - void network_node_api::set_advanced_node_parameters(const fc::variant_object& params) - { - return _app.p2p_node()->set_advanced_node_parameters(params); - } - - map network_node_api::list_pending_transactions() const - { - return _pending_transactions; - } - - void network_node_api::subscribe_to_pending_transactions( std::function callback ) - { - _on_pending_transaction = callback; - } - - void network_node_api::unsubscribe_from_pending_transactions() - { - _on_pending_transaction = std::function(); - } - - fc::api login_api::network_broadcast()const - { - FC_ASSERT(_network_broadcast_api); - return *_network_broadcast_api; - } - - fc::api login_api::block()const - { - FC_ASSERT(_block_api); - return *_block_api; - } - - fc::api login_api::network_node()const - { - FC_ASSERT(_network_node_api); - return *_network_node_api; - } - - fc::api login_api::database()const - { - FC_ASSERT(_database_api); - return *_database_api; - } - - fc::api login_api::history() const - { - FC_ASSERT(_history_api); - return *_history_api; - } - - fc::api login_api::crypto() const - { - FC_ASSERT(_crypto_api); - return *_crypto_api; - } - - fc::api login_api::asset() const - { - FC_ASSERT(_asset_api); - return *_asset_api; - } - - fc::api login_api::debug() const - { - FC_ASSERT(_debug_api); - return *_debug_api; - } - - fc::api login_api::bookie() const - { - FC_ASSERT(_bookie_api); - return *_bookie_api; - } - - fc::api login_api::affiliate_stats() const - { - FC_ASSERT(_affiliate_stats_api); - return *_affiliate_stats_api; - } - -#if 0 - vector get_relevant_accounts( const object* obj ) - { - vector result; - if( obj->id.space() == protocol_ids ) - { - switch( (object_type)obj->id.type() ) - { - case null_object_type: - case base_object_type: - case OBJECT_TYPE_COUNT: - return result; - case account_object_type:{ - result.push_back( obj->id ); - break; - } case asset_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->issuer ); - break; - } case force_settlement_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->owner ); - break; - } case committee_member_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->committee_member_account ); - break; - } case witness_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->witness_account ); - break; - } case limit_order_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->seller ); - break; - } case call_order_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->borrower ); - break; - } case custom_object_type:{ - break; - } case proposal_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - flat_set impacted; - transaction_get_impacted_accounts( aobj->proposed_transaction, impacted ); - result.reserve( impacted.size() ); - for( auto& item : impacted ) result.emplace_back(item); - break; - } case operation_history_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - flat_set impacted; - operation_get_impacted_accounts( aobj->op, impacted ); - result.reserve( impacted.size() ); - for( auto& item : impacted ) result.emplace_back(item); - break; - } case withdraw_permission_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->withdraw_from_account ); - result.push_back( aobj->authorized_account ); - break; - } case vesting_balance_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->owner ); - break; - } case worker_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->worker_account ); - break; - } case balance_object_type:{ - /** these are free from any accounts */ - break; - } case son_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->son_account ); - break; - } case sidechain_address_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->sidechain_address_account ); - break; - } - case sport_object_type: - case event_group_object_type: - case event_object_type: - case betting_market_group_object_type: - case betting_market_object_type: - /** these are free from any accounts */ - break; - case bet_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->bettor_id ); - } case tournament_object_type:{ - const tournament_object* tournament_obj = dynamic_cast(obj); - assert(tournament_obj); - const tournament_details_object& details = tournament_obj->tournament_details_id(*_app.chain_database()); - flat_set impacted = details.registered_players; - impacted.insert(tournament_obj->creator); - std::copy(impacted.begin(), impacted.end(), std::back_inserter(result)); - break; - } - } - } - else if( obj->id.space() == implementation_ids ) - { - switch( (impl_object_type)obj->id.type() ) - { - case impl_global_property_object_type: - break; - case impl_dynamic_global_property_object_type: - break; - case impl_reserved0_object_type: - break; - case impl_asset_dynamic_data_type: - break; - case impl_asset_bitasset_data_type: - break; - case impl_account_balance_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->owner ); - break; - } case impl_account_statistics_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.push_back( aobj->owner ); - break; - } case impl_transaction_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - flat_set impacted; - transaction_get_impacted_accounts( aobj->trx, impacted ); - result.reserve( impacted.size() ); - for( auto& item : impacted ) result.emplace_back(item); - break; - } case impl_blinded_balance_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - result.reserve( aobj->owner.account_auths.size() ); - for( const auto& a : aobj->owner.account_auths ) - result.push_back( a.first ); - break; - } case impl_block_summary_object_type: - break; - case impl_account_transaction_history_object_type: - break; - case impl_chain_property_object_type: - break; - case impl_witness_schedule_object_type: - break; - case impl_budget_record_object_type: - break; - case impl_special_authority_object_type: - break; - case impl_buyback_object_type: - break; - case impl_fba_accumulator_object_type: - break; - case impl_betting_market_position_object_type: - break; - case impl_global_betting_statistics_object_type: - break; - } - } - return result; - } // end get_relevant_accounts( obj ) -#endif - - vector 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().indices().get(); - history_key hkey; - hkey.base = a; - hkey.quote = b; - hkey.sequence = std::numeric_limits::min(); - - uint32_t count = 0; - auto itr = history_idx.lower_bound( hkey ); - vector result; - while( itr != history_idx.end() && count < limit) - { - if( itr->key.base != a || itr->key.quote != b ) break; - result.push_back( *itr ); - ++itr; - ++count; - } - - return result; - } - - vector 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 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; } - - if(_app.is_plugin_enabled("elasticsearch")) { - auto es = _app.get_plugin("elasticsearch"); - if(es.get()->get_running_mode() != elasticsearch::mode::only_save) { - if(!_app.elasticsearch_thread) - _app.elasticsearch_thread= std::make_shared("elasticsearch"); - - return _app.elasticsearch_thread->async([&es, &account, &stop, &limit, &start]() { - return es->get_account_history(account, stop, limit, start); - }, "thread invoke for method " BOOST_PP_STRINGIZE(method_name)).wait(); - } - } - - const auto& hist_idx = db.get_index_type(); - const auto& by_op_idx = hist_idx.indices().get(); - auto index_start = by_op_idx.begin(); - auto itr = by_op_idx.lower_bound(boost::make_tuple(account, start)); - - 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 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, - unsigned limit) const - { - FC_ASSERT( _app.chain_database() ); - const auto& db = *_app.chain_database(); - FC_ASSERT( limit <= 100 ); - vector 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); - if( start == operation_history_id_type() ) - start = node->operation_id; - - while(node && node->operation_id.instance.value > stop.instance.value && result.size() < limit) - { - if( node->operation_id.instance.value <= start.instance.value ) { - - 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 history_api::get_relative_account_history( const std::string account_id_or_name, - uint32_t stop, - unsigned limit, - uint32_t start) const - { - FC_ASSERT( _app.chain_database() ); - const auto& db = *_app.chain_database(); - FC_ASSERT(limit <= 100); - vector 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; - else - start = min( stats.total_ops, start ); - - - if( start >= stop && start > stats.removed_ops && limit > 0 ) - { - const auto& hist_idx = db.get_index_type(); - const auto& by_seq_idx = hist_idx.indices().get(); - - auto itr = by_seq_idx.upper_bound( boost::make_tuple( account, start ) ); - auto itr_stop = by_seq_idx.lower_bound( boost::make_tuple( account, stop ) ); - - do - { - --itr; - result.push_back( itr->operation_id(db) ); - } - while ( itr != itr_stop && result.size() < limit ); - } - return result; - } - - vector history_api::list_core_accounts()const - { - auto list = _app.get_plugin( "accounts_list" ); - FC_ASSERT( list ); - return list->list_accounts(); - } - - flat_set history_api::get_market_history_buckets()const - { - auto hist = _app.get_plugin( "market_history" ); - FC_ASSERT( hist ); - return hist->tracked_buckets(); - } - - vector 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 result; - result.reserve(200); - - if( a > b ) std::swap(a,b); - - const auto& bidx = db.get_index_type(); - const auto& by_key_idx = bidx.indices().get(); - - auto itr = by_key_idx.lower_bound( bucket_key( a, b, bucket_seconds, start ) ); - while( itr != by_key_idx.end() && itr->key.open <= end && result.size() < 200 ) - { - if( !(itr->key.base == a && itr->key.quote == b && itr->key.seconds == bucket_seconds) ) - { - return result; - } - result.push_back(*itr); - ++itr; - } - return result; - } FC_CAPTURE_AND_RETHROW( (asset_a)(asset_b)(bucket_seconds)(start)(end) ) } - - crypto_api::crypto_api(){}; - - commitment_type crypto_api::blind( const blind_factor_type& blind, uint64_t value ) - { - return fc::ecc::blind( blind, value ); - } - - blind_factor_type crypto_api::blind_sum( const std::vector& blinds_in, uint32_t non_neg ) - { - return fc::ecc::blind_sum( blinds_in, non_neg ); - } - - bool crypto_api::verify_sum( const std::vector& commits_in, const std::vector& neg_commits_in, int64_t excess ) - { - return fc::ecc::verify_sum( commits_in, neg_commits_in, excess ); - } - - verify_range_result crypto_api::verify_range( const commitment_type& commit, const std::vector& proof ) - { - verify_range_result result; - result.success = fc::ecc::verify_range( result.min_val, result.max_val, commit, proof ); - return result; - } - - std::vector crypto_api::range_proof_sign( uint64_t min_value, - const commitment_type& commit, - const blind_factor_type& commit_blind, - const blind_factor_type& nonce, - int8_t base10_exp, - uint8_t min_bits, - uint64_t actual_value ) - { - return fc::ecc::range_proof_sign( min_value, commit, commit_blind, nonce, base10_exp, min_bits, actual_value ); - } - - verify_range_proof_rewind_result crypto_api::verify_range_proof_rewind( const blind_factor_type& nonce, - const commitment_type& commit, - const std::vector& proof ) - { - verify_range_proof_rewind_result result; - result.success = fc::ecc::verify_range_proof_rewind( result.blind_out, - result.value_out, - result.message_out, - nonce, - result.min_val, - result.max_val, - const_cast< commitment_type& >( commit ), - proof ); - return result; - } - - range_proof_info crypto_api::range_get_info( const std::vector& proof ) - { - return fc::ecc::range_get_info( proof ); - } - - // asset_api - 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 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 ) ); - - vector result; - - uint32_t index = 0; - for( const account_balance_object& bal : boost::make_iterator_range( range.first, range.second ) ) - { - if( result.size() >= limit ) - break; - - if( bal.balance.value == 0 ) - continue; - - if( index++ < start ) - continue; - - const auto account = _db.find(bal.owner); - - account_asset_balance aab; - aab.name = account->name; - aab.account_id = account->id; - aab.amount = bal.balance.value; - - result.push_back(aab); + } } + }); +} +fc::variant_object network_node_api::get_info() const { + fc::mutable_variant_object result = _app.p2p_node()->network_get_info(); + result["connection_count"] = _app.p2p_node()->get_connection_count(); + return result; +} + +void network_node_api::add_node(const fc::ip::endpoint &ep) { + _app.p2p_node()->add_node(ep); +} + +std::vector network_node_api::get_connected_peers() const { + return _app.p2p_node()->get_connected_peers(); +} + +std::vector network_node_api::get_potential_peers() const { + return _app.p2p_node()->get_potential_peers(); +} + +fc::variant_object network_node_api::get_advanced_node_parameters() const { + return _app.p2p_node()->get_advanced_node_parameters(); +} + +void network_node_api::set_advanced_node_parameters(const fc::variant_object ¶ms) { + return _app.p2p_node()->set_advanced_node_parameters(params); +} + +map network_node_api::list_pending_transactions() const { + return _pending_transactions; +} + +void network_node_api::subscribe_to_pending_transactions(std::function callback) { + _on_pending_transaction = callback; +} + +void network_node_api::unsubscribe_from_pending_transactions() { + _on_pending_transaction = std::function(); +} + +fc::api login_api::network_broadcast() const { + FC_ASSERT(_network_broadcast_api); + return *_network_broadcast_api; +} + +fc::api login_api::block() const { + FC_ASSERT(_block_api); + return *_block_api; +} + +fc::api login_api::network_node() const { + FC_ASSERT(_network_node_api); + return *_network_node_api; +} + +fc::api login_api::database() const { + FC_ASSERT(_database_api); + return *_database_api; +} + +fc::api login_api::history() const { + FC_ASSERT(_history_api); + return *_history_api; +} + +fc::api login_api::crypto() const { + FC_ASSERT(_crypto_api); + return *_crypto_api; +} + +fc::api login_api::asset() const { + FC_ASSERT(_asset_api); + return *_asset_api; +} + +fc::api login_api::debug() const { + FC_ASSERT(_debug_api); + return *_debug_api; +} + +fc::api login_api::bookie() const { + FC_ASSERT(_bookie_api); + return *_bookie_api; +} + +fc::api login_api::affiliate_stats() const { + FC_ASSERT(_affiliate_stats_api); + return *_affiliate_stats_api; +} + +vector 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().indices().get(); + history_key hkey; + hkey.base = a; + hkey.quote = b; + hkey.sequence = std::numeric_limits::min(); + + uint32_t count = 0; + auto itr = history_idx.lower_bound(hkey); + vector result; + while (itr != history_idx.end() && count < limit) { + if (itr->key.base != a || itr->key.quote != b) + break; + result.push_back(*itr); + ++itr; + ++count; + } + + return result; +} + +vector 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 <= api_limit_get_account_history, + "Number of querying accounts can not be greater than ${configured_limit}", + ("configured_limit", api_limit_get_account_history)); + + vector 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; - } - // get number of asset holders. - int asset_api::get_asset_holders_count( std::string asset ) const { + } + + if (_app.is_plugin_enabled("elasticsearch")) { + auto es = _app.get_plugin("elasticsearch"); + if (es.get()->get_running_mode() != elasticsearch::mode::only_save) { + if (!_app.elasticsearch_thread) + _app.elasticsearch_thread = std::make_shared("elasticsearch"); + + return _app.elasticsearch_thread->async([&es, &account, &stop, &limit, &start]() { + return es->get_account_history(account, stop, limit, start); + }, + "thread invoke for method " BOOST_PP_STRINGIZE(method_name)) + .wait(); + } + } + + const auto &hist_idx = db.get_index_type(); + const auto &by_op_idx = hist_idx.indices().get(); + auto index_start = by_op_idx.begin(); + auto itr = by_op_idx.lower_bound(boost::make_tuple(account, start)); + + 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 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, + unsigned limit) const { + FC_ASSERT(_app.chain_database()); + const auto &db = *_app.chain_database(); + FC_ASSERT(limit <= api_limit_get_account_history_operations, + "Number of querying history accounts can not be greater than ${configured_limit}", + ("configured_limit", api_limit_get_account_history_operations)); + + vector 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); + if (start == operation_history_id_type()) + start = node->operation_id; + + while (node && node->operation_id.instance.value > stop.instance.value && result.size() < limit) { + if (node->operation_id.instance.value <= start.instance.value) { + + 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 history_api::get_relative_account_history(const std::string account_id_or_name, + uint32_t stop, + unsigned limit, + uint32_t start) const { + FC_ASSERT(_app.chain_database()); + const auto &db = *_app.chain_database(); + FC_ASSERT(limit <= api_limit_get_relative_account_history, + "Number of querying accounts can not be greater than ${configured_limit}", + ("configured_limit", api_limit_get_relative_account_history)); + + vector 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; + else + start = min(stats.total_ops, start); + + if (start >= stop && start > stats.removed_ops && limit > 0) { + const auto &hist_idx = db.get_index_type(); + const auto &by_seq_idx = hist_idx.indices().get(); + + auto itr = by_seq_idx.upper_bound(boost::make_tuple(account, start)); + auto itr_stop = by_seq_idx.lower_bound(boost::make_tuple(account, stop)); + + do { + --itr; + result.push_back(itr->operation_id(db)); + } while (itr != itr_stop && result.size() < limit); + } + return result; +} + +vector history_api::list_core_accounts() const { + auto list = _app.get_plugin("accounts_list"); + FC_ASSERT(list); + return list->list_accounts(); +} + +flat_set history_api::get_market_history_buckets() const { + auto hist = _app.get_plugin("market_history"); + FC_ASSERT(hist); + return hist->tracked_buckets(); +} + +vector 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 result; + result.reserve(200); + + if (a > b) + std::swap(a, b); + + const auto &bidx = db.get_index_type(); + const auto &by_key_idx = bidx.indices().get(); + + auto itr = by_key_idx.lower_bound(bucket_key(a, b, bucket_seconds, start)); + while (itr != by_key_idx.end() && itr->key.open <= end && result.size() < 200) { + if (!(itr->key.base == a && itr->key.quote == b && itr->key.seconds == bucket_seconds)) { + return result; + } + result.push_back(*itr); + ++itr; + } + return result; + } + FC_CAPTURE_AND_RETHROW((asset_a)(asset_b)(bucket_seconds)(start)(end)) +} + +crypto_api::crypto_api(){}; + +commitment_type crypto_api::blind(const blind_factor_type &blind, uint64_t value) { + return fc::ecc::blind(blind, value); +} + +blind_factor_type crypto_api::blind_sum(const std::vector &blinds_in, uint32_t non_neg) { + return fc::ecc::blind_sum(blinds_in, non_neg); +} + +bool crypto_api::verify_sum(const std::vector &commits_in, const std::vector &neg_commits_in, int64_t excess) { + return fc::ecc::verify_sum(commits_in, neg_commits_in, excess); +} + +verify_range_result crypto_api::verify_range(const commitment_type &commit, const std::vector &proof) { + verify_range_result result; + result.success = fc::ecc::verify_range(result.min_val, result.max_val, commit, proof); + return result; +} + +std::vector crypto_api::range_proof_sign(uint64_t min_value, + const commitment_type &commit, + const blind_factor_type &commit_blind, + const blind_factor_type &nonce, + int8_t base10_exp, + uint8_t min_bits, + uint64_t actual_value) { + return fc::ecc::range_proof_sign(min_value, commit, commit_blind, nonce, base10_exp, min_bits, actual_value); +} + +verify_range_proof_rewind_result crypto_api::verify_range_proof_rewind(const blind_factor_type &nonce, + const commitment_type &commit, + const std::vector &proof) { + verify_range_proof_rewind_result result; + result.success = fc::ecc::verify_range_proof_rewind(result.blind_out, + result.value_out, + result.message_out, + nonce, + result.min_val, + result.max_val, + const_cast(commit), + proof); + return result; +} + +range_proof_info crypto_api::range_get_info(const std::vector &proof) { + return fc::ecc::range_get_info(proof); +} + +// asset_api +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 asset_api::get_asset_holders(std::string asset, uint32_t start, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_get_asset_holders, + "Number of querying asset holder accounts can not be greater than ${configured_limit}", + ("configured_limit", api_limit_get_asset_holders)); + + asset_id_type asset_id = database_api.get_asset_id_from_string(asset); + const auto &bal_idx = _db.get_index_type().indices().get(); + auto range = bal_idx.equal_range(boost::make_tuple(asset_id)); + + vector result; + + uint32_t index = 0; + for (const account_balance_object &bal : boost::make_iterator_range(range.first, range.second)) { + if (result.size() >= limit) + break; + + if (bal.balance.value == 0) + continue; + + if (index++ < start) + continue; + + const auto account = _db.find(bal.owner); + + account_asset_balance aab; + aab.name = account->name; + aab.account_id = account->id; + aab.amount = bal.balance.value; + + result.push_back(aab); + } + + return result; +} +// get number of asset holders. +int asset_api::get_asset_holders_count(std::string asset) const { + + const auto &bal_idx = _db.get_index_type().indices().get(); + 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; +} +// function to get vector of system assets with holders count. +vector asset_api::get_all_asset_holders() const { + + vector result; + + vector total_assets; + for (const asset_object &asset_obj : _db.get_index_type().indices()) { + const auto &dasset_obj = asset_obj.dynamic_asset_data_id(_db); + + asset_id_type asset_id; + asset_id = dasset_obj.id; + + const auto &bal_idx = _db.get_index_type().indices().get(); + auto range = bal_idx.equal_range(boost::make_tuple(asset_id)); - 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; - } - // function to get vector of system assets with holders count. - vector asset_api::get_all_asset_holders() const { + asset_holders ah; + ah.asset_id = asset_id; + ah.count = count; - vector result; + result.push_back(ah); + } - vector total_assets; - for( const asset_object& asset_obj : _db.get_index_type().indices() ) - { - const auto& dasset_obj = asset_obj.dynamic_asset_data_id(_db); + return result; +} - asset_id_type asset_id; - asset_id = dasset_obj.id; - - 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 ) ); - - int count = boost::distance(range) - 1; - - asset_holders ah; - ah.asset_id = asset_id; - ah.count = count; - - result.push_back(ah); - } - - return result; - } - -} } // graphene::app +}} // namespace graphene::app diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 46ebab04..713a204a 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -34,19 +34,19 @@ #include #include -#include #include +#include +#include #include +#include #include #include -#include -#include -#include -#include -#include #include +#include +#include +#include #include @@ -57,16 +57,16 @@ #include namespace graphene { namespace app { +using net::block_message; using net::item_hash_t; using net::item_id; using net::message; -using net::block_message; using net::trx_message; using chain::block_header; -using chain::signed_block_header; -using chain::signed_block; using chain::block_id_type; +using chain::signed_block; +using chain::signed_block_header; using std::vector; @@ -74,118 +74,112 @@ namespace bpo = boost::program_options; namespace detail { - genesis_state_type create_example_genesis() { - auto nathan_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("nathan"))); - dlog("Allocating all stake to ${key}", ("key", utilities::key_to_wif(nathan_key))); - genesis_state_type initial_state; - initial_state.initial_parameters.current_fees = std::make_shared(fee_schedule::get_default()); - initial_state.initial_active_witnesses = GRAPHENE_DEFAULT_MIN_WITNESS_COUNT; - initial_state.initial_timestamp = time_point_sec(time_point::now().sec_since_epoch() / - initial_state.initial_parameters.block_interval * - initial_state.initial_parameters.block_interval); - for( uint64_t i = 0; i < initial_state.initial_active_witnesses; ++i ) - { - auto name = "init"+fc::to_string(i); - initial_state.initial_accounts.emplace_back(name, - nathan_key.get_public_key(), - nathan_key.get_public_key(), - true); - initial_state.initial_committee_candidates.push_back({name}); - initial_state.initial_witness_candidates.push_back({name, nathan_key.get_public_key()}); - } - - initial_state.initial_accounts.emplace_back("nathan", nathan_key.get_public_key()); - initial_state.initial_balances.push_back({nathan_key.get_public_key(), - GRAPHENE_SYMBOL, - GRAPHENE_MAX_SHARE_SUPPLY}); - initial_state.initial_chain_id = fc::sha256::hash( "BOGUS" ); - - return initial_state; +genesis_state_type create_example_genesis() { + auto nathan_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("nathan"))); + dlog("Allocating all stake to ${key}", ("key", utilities::key_to_wif(nathan_key))); + genesis_state_type initial_state; + initial_state.initial_parameters.current_fees = std::make_shared(fee_schedule::get_default()); + initial_state.initial_active_witnesses = GRAPHENE_DEFAULT_MIN_WITNESS_COUNT; + initial_state.initial_timestamp = time_point_sec(time_point::now().sec_since_epoch() / + initial_state.initial_parameters.block_interval * + initial_state.initial_parameters.block_interval); + for (uint64_t i = 0; i < initial_state.initial_active_witnesses; ++i) { + auto name = "init" + fc::to_string(i); + initial_state.initial_accounts.emplace_back(name, + nathan_key.get_public_key(), + nathan_key.get_public_key(), + true); + initial_state.initial_committee_candidates.push_back({name}); + initial_state.initial_witness_candidates.push_back({name, nathan_key.get_public_key()}); } - class application_impl : public net::node_delegate - { - public: - fc::optional _lock_file; - bool _is_block_producer = false; - bool _force_validate = false; + initial_state.initial_accounts.emplace_back("nathan", nathan_key.get_public_key()); + initial_state.initial_balances.push_back({nathan_key.get_public_key(), + GRAPHENE_SYMBOL, + GRAPHENE_MAX_SHARE_SUPPLY}); + initial_state.initial_chain_id = fc::sha256::hash("BOGUS"); - void reset_p2p_node(const fc::path& data_dir) - { try { + return initial_state; +} + +class application_impl : public net::node_delegate { +public: + fc::optional _lock_file; + bool _is_block_producer = false; + bool _force_validate = false; + + void reset_p2p_node(const fc::path &data_dir) { + try { _p2p_network = std::make_shared("PeerPlays Reference Implementation"); _p2p_network->load_configuration(data_dir / "p2p"); _p2p_network->set_node_delegate(this); - if( _options->count("seed-node") ) - { + if (_options->count("seed-node")) { auto seeds = _options->at("seed-node").as>(); - for( const string& endpoint_string : seeds ) - { + for (const string &endpoint_string : seeds) { try { std::vector endpoints = resolve_string_to_ip_endpoints(endpoint_string); - for (const fc::ip::endpoint& endpoint : endpoints) - { + for (const fc::ip::endpoint &endpoint : endpoints) { ilog("Adding seed node ${endpoint}", ("endpoint", endpoint)); _p2p_network->add_node(endpoint); _p2p_network->connect_to_endpoint(endpoint); } - } catch( const fc::exception& e ) { - wlog( "caught exception ${e} while adding seed node ${endpoint}", - ("e", e.to_detail_string())("endpoint", endpoint_string) ); + } catch (const fc::exception &e) { + wlog("caught exception ${e} while adding seed node ${endpoint}", + ("e", e.to_detail_string())("endpoint", endpoint_string)); } } } - if( _options->count("seed-nodes") ) - { + if (_options->count("seed-nodes")) { auto seeds_str = _options->at("seed-nodes").as(); auto seeds = fc::json::from_string(seeds_str).as>(2); - for( const string& endpoint_string : seeds ) - { + for (const string &endpoint_string : seeds) { try { std::vector endpoints = resolve_string_to_ip_endpoints(endpoint_string); - for (const fc::ip::endpoint& endpoint : endpoints) - { + for (const fc::ip::endpoint &endpoint : endpoints) { ilog("Adding seed node ${endpoint}", ("endpoint", endpoint)); _p2p_network->add_node(endpoint); } - } catch( const fc::exception& e ) { - wlog( "caught exception ${e} while adding seed node ${endpoint}", - ("e", e.to_detail_string())("endpoint", endpoint_string) ); + } catch (const fc::exception &e) { + wlog("caught exception ${e} while adding seed node ${endpoint}", + ("e", e.to_detail_string())("endpoint", endpoint_string)); } } - } - else - { + } else { // t.me/peerplays #seednodes vector seeds = { - "173.249.23.108:9777", - "node.peerblock.trade:9777", - "peerplays.blockoperations.com:9777", - "pms.blockveritas.co:7777", - "seed.ppy.alex-pu.info:8888", - "seed.ppy.blckchnd.com:6116", - "seed01.eifos.org:7777" +#ifdef BUILD_PEERPLAYS_TESTNET + +#else + "51.222.110.110:9777", + "95.216.90.243:9777", + "96.46.48.98:19777", + "96.46.48.98:29777", + "96.46.48.98:39777", + "96.46.48.98:49777", + "96.46.48.98:59777", + "seed.i9networks.net.br:9777", + "witness.serverpit.com:9777" +#endif }; - for( const string& endpoint_string : seeds ) - { + for (const string &endpoint_string : seeds) { try { std::vector endpoints = resolve_string_to_ip_endpoints(endpoint_string); - for (const fc::ip::endpoint& endpoint : endpoints) - { + for (const fc::ip::endpoint &endpoint : endpoints) { ilog("Adding seed node ${endpoint}", ("endpoint", endpoint)); _p2p_network->add_node(endpoint); } - } catch( const fc::exception& e ) { - wlog( "caught exception ${e} while adding seed node ${endpoint}", - ("e", e.to_detail_string())("endpoint", endpoint_string) ); + } catch (const fc::exception &e) { + wlog("caught exception ${e} while adding seed node ${endpoint}", + ("e", e.to_detail_string())("endpoint", endpoint_string)); } } } - if( _options->count("p2p-endpoint") ) + if (_options->count("p2p-endpoint")) _p2p_network->listen_on_endpoint(fc::ip::endpoint::from_string(_options->at("p2p-endpoint").as()), true); else _p2p_network->listen_on_port(0, false); @@ -196,285 +190,256 @@ namespace detail { _p2p_network->sync_from(net::item_id(net::core_message_type_enum::block_message_type, _chain_db->head_block_id()), std::vector()); - } FC_CAPTURE_AND_RETHROW() } + } + FC_CAPTURE_AND_RETHROW() + } - std::vector resolve_string_to_ip_endpoints(const std::string& endpoint_string) - { - try - { - string::size_type colon_pos = endpoint_string.find(':'); - if (colon_pos == std::string::npos) - FC_THROW("Missing required port number in endpoint string \"${endpoint_string}\"", - ("endpoint_string", endpoint_string)); - std::string port_string = endpoint_string.substr(colon_pos + 1); - try - { - uint16_t port = boost::lexical_cast(port_string); + std::vector resolve_string_to_ip_endpoints(const std::string &endpoint_string) { + try { + string::size_type colon_pos = endpoint_string.find(':'); + if (colon_pos == std::string::npos) + FC_THROW("Missing required port number in endpoint string \"${endpoint_string}\"", + ("endpoint_string", endpoint_string)); + std::string port_string = endpoint_string.substr(colon_pos + 1); + try { + uint16_t port = boost::lexical_cast(port_string); - std::string hostname = endpoint_string.substr(0, colon_pos); - std::vector endpoints = fc::resolve(hostname, port); - if (endpoints.empty()) - FC_THROW_EXCEPTION(fc::unknown_host_exception, "The host name can not be resolved: ${hostname}", ("hostname", hostname)); - return endpoints; - } - catch (const boost::bad_lexical_cast&) - { - FC_THROW("Bad port: ${port}", ("port", port_string)); - } + std::string hostname = endpoint_string.substr(0, colon_pos); + std::vector endpoints = fc::resolve(hostname, port); + if (endpoints.empty()) + FC_THROW_EXCEPTION(fc::unknown_host_exception, "The host name can not be resolved: ${hostname}", ("hostname", hostname)); + return endpoints; + } catch (const boost::bad_lexical_cast &) { + FC_THROW("Bad port: ${port}", ("port", port_string)); } - FC_CAPTURE_AND_RETHROW((endpoint_string)) + } + FC_CAPTURE_AND_RETHROW((endpoint_string)) + } + + void new_connection(const fc::http::websocket_connection_ptr &c) { + auto wsc = std::make_shared(c, GRAPHENE_MAX_NESTED_OBJECTS); + auto login = std::make_shared(std::ref(*_self)); + login->enable_api("database_api"); + + wsc->register_api(login->database()); + wsc->register_api(fc::api(login)); + + wsc->register_api(fc::api(login)); + + c->set_session_data(wsc); + + std::string username = "*"; + std::string password = "*"; + + // Try to extract login information from "Authorization" header if present + std::string auth = c->get_request_header("Authorization"); + if (boost::starts_with(auth, "Basic ")) { + + FC_ASSERT(auth.size() > 6); + auto user_pass = fc::base64_decode(auth.substr(6)); + + std::vector parts; + boost::split(parts, user_pass, boost::is_any_of(":")); + + FC_ASSERT(parts.size() == 2); + + username = parts[0]; + password = parts[1]; } - void new_connection( const fc::http::websocket_connection_ptr& c ) - { - auto wsc = std::make_shared(c, GRAPHENE_MAX_NESTED_OBJECTS); - auto login = std::make_shared( std::ref(*_self) ); - login->enable_api("database_api"); + login->login(username, password); + } - wsc->register_api(login->database()); - wsc->register_api(fc::api(login)); - - wsc->register_api(fc::api(login)); - - c->set_session_data( wsc ); - - std::string username = "*"; - std::string password = "*"; - - // Try to extract login information from "Authorization" header if present - std::string auth = c->get_request_header("Authorization"); - if( boost::starts_with(auth, "Basic ") ) { - - FC_ASSERT( auth.size() > 6 ); - auto user_pass = fc::base64_decode(auth.substr(6)); - - std::vector parts; - boost::split( parts, user_pass, boost::is_any_of(":") ); - - FC_ASSERT(parts.size() == 2); - - username = parts[0]; - password = parts[1]; - } - - login->login(username, password); - } - - void reset_websocket_server() - { try { - if( !_options->count("rpc-endpoint") ) + void reset_websocket_server() { + try { + if (!_options->count("rpc-endpoint")) return; _websocket_server = std::make_shared(); - _websocket_server->on_connection( std::bind(&application_impl::new_connection, this, std::placeholders::_1) ); + _websocket_server->on_connection(std::bind(&application_impl::new_connection, this, std::placeholders::_1)); - ilog("Configured websocket rpc to listen on ${ip}", ("ip",_options->at("rpc-endpoint").as())); - _websocket_server->listen( fc::ip::endpoint::from_string(_options->at("rpc-endpoint").as()) ); + ilog("Configured websocket rpc to listen on ${ip}", ("ip", _options->at("rpc-endpoint").as())); + _websocket_server->listen(fc::ip::endpoint::from_string(_options->at("rpc-endpoint").as())); _websocket_server->start_accept(); - } FC_CAPTURE_AND_RETHROW() } + } + FC_CAPTURE_AND_RETHROW() + } - - void reset_websocket_tls_server() - { try { - if( !_options->count("rpc-tls-endpoint") ) + void reset_websocket_tls_server() { + try { + if (!_options->count("rpc-tls-endpoint")) return; - if( !_options->count("server-pem") ) - { - wlog( "Please specify a server-pem to use rpc-tls-endpoint" ); + if (!_options->count("server-pem")) { + wlog("Please specify a server-pem to use rpc-tls-endpoint"); return; } string password = _options->count("server-pem-password") ? _options->at("server-pem-password").as() : ""; - _websocket_tls_server = std::make_shared( _options->at("server-pem").as(), password ); - _websocket_tls_server->on_connection( std::bind(&application_impl::new_connection, this, std::placeholders::_1) ); + _websocket_tls_server = std::make_shared(_options->at("server-pem").as(), password); + _websocket_tls_server->on_connection(std::bind(&application_impl::new_connection, this, std::placeholders::_1)); - ilog("Configured websocket TLS rpc to listen on ${ip}", ("ip",_options->at("rpc-tls-endpoint").as())); - _websocket_tls_server->listen( fc::ip::endpoint::from_string(_options->at("rpc-tls-endpoint").as()) ); + ilog("Configured websocket TLS rpc to listen on ${ip}", ("ip", _options->at("rpc-tls-endpoint").as())); + _websocket_tls_server->listen(fc::ip::endpoint::from_string(_options->at("rpc-tls-endpoint").as())); _websocket_tls_server->start_accept(); - } FC_CAPTURE_AND_RETHROW() } - - explicit application_impl(application* self) - : _self(self), - _chain_db(std::make_shared()) - { } + FC_CAPTURE_AND_RETHROW() + } - ~application_impl() - { - } + explicit application_impl(application *self) : + _self(self), + _chain_db(std::make_shared()) { + } - void set_dbg_init_key( genesis_state_type& genesis, const std::string& init_key ) - { - flat_set< std::string > initial_witness_names; - public_key_type init_pubkey( init_key ); - for( uint64_t i=0; i initial_witness_names; + 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; + } + + void startup() { + try { fc::create_directories(_data_dir / "blockchain"); auto initial_state = [this] { ilog("Initializing database..."); - if( _options->count("genesis-json") ) - { + if (_options->count("genesis-json")) { std::string genesis_str; - fc::read_file_contents( _options->at("genesis-json").as(), genesis_str ); - genesis_state_type genesis = fc::json::from_string( genesis_str ).as( 20 ); + fc::read_file_contents(_options->at("genesis-json").as(), genesis_str); + genesis_state_type genesis = fc::json::from_string(genesis_str).as(20); bool modified_genesis = false; - if( _options->count("genesis-timestamp") ) - { - genesis.initial_timestamp = fc::time_point_sec( fc::time_point::now() ) + genesis.initial_parameters.block_interval + _options->at("genesis-timestamp").as(); + if (_options->count("genesis-timestamp")) { + genesis.initial_timestamp = fc::time_point_sec(fc::time_point::now()) + genesis.initial_parameters.block_interval + _options->at("genesis-timestamp").as(); genesis.initial_timestamp -= genesis.initial_timestamp.sec_since_epoch() % genesis.initial_parameters.block_interval; modified_genesis = true; std::cerr << "Used genesis timestamp: " << genesis.initial_timestamp.to_iso_string() << " (PLEASE RECORD THIS)\n"; } - if( _options->count("dbg-init-key") ) - { - std::string init_key = _options->at( "dbg-init-key" ).as(); - FC_ASSERT( genesis.initial_witness_candidates.size() >= genesis.initial_active_witnesses ); - set_dbg_init_key( genesis, init_key ); + if (_options->count("dbg-init-key")) { + std::string init_key = _options->at("dbg-init-key").as(); + FC_ASSERT(genesis.initial_witness_candidates.size() >= genesis.initial_active_witnesses); + set_dbg_init_key(genesis, init_key); modified_genesis = true; std::cerr << "Set init witness key to " << init_key << "\n"; } - if( modified_genesis ) - { + if (modified_genesis) { std::cerr << "WARNING: GENESIS WAS MODIFIED, YOUR CHAIN ID MAY BE DIFFERENT\n"; genesis_str += "BOGUS"; - genesis.initial_chain_id = fc::sha256::hash( genesis_str ); - } - else - genesis.initial_chain_id = fc::sha256::hash( genesis_str ); + genesis.initial_chain_id = fc::sha256::hash(genesis_str); + } else + genesis.initial_chain_id = fc::sha256::hash(genesis_str); return genesis; - } - else - { + } else { std::string egenesis_json; - 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( 20 ); - genesis.initial_chain_id = fc::sha256::hash( egenesis_json ); + 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(20); + genesis.initial_chain_id = fc::sha256::hash(egenesis_json); return genesis; } }; - if( _options->count("resync-blockchain") ) + if (_options->count("resync-blockchain")) _chain_db->wipe(_data_dir / "blockchain", true); - flat_map loaded_checkpoints; - if( _options->count("checkpoint") ) - { + flat_map loaded_checkpoints; + if (_options->count("checkpoint")) { auto cps = _options->at("checkpoint").as>(); - loaded_checkpoints.reserve( cps.size() ); - for( auto cp : cps ) - { - auto item = fc::json::from_string(cp).as >( 2 ); + loaded_checkpoints.reserve(cps.size()); + for (auto cp : cps) { + auto item = fc::json::from_string(cp).as>(2); loaded_checkpoints[item.first] = item.second; } } - _chain_db->add_checkpoints( loaded_checkpoints ); + _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() ); + if (_options->count("enable-standby-votes-tracking")) { + _chain_db->enable_standby_votes_tracking(_options->at("enable-standby-votes-tracking").as()); } - - bool replay = false; + std::string replay_reason = "reason not provided"; - if( _options->count("replay-blockchain") ) - _chain_db->wipe( _data_dir / "blockchain", false ); + if (_options->count("replay-blockchain")) + _chain_db->wipe(_data_dir / "blockchain", false); - try - { - _chain_db->open( _data_dir / "blockchain", initial_state, GRAPHENE_CURRENT_DB_VERSION ); - } - catch( const fc::exception& e ) - { - elog( "Caught exception ${e} in open(), you might want to force a replay", ("e", e.to_detail_string()) ); + try { + _chain_db->open(_data_dir / "blockchain", initial_state, GRAPHENE_CURRENT_DB_VERSION); + } catch (const fc::exception &e) { + elog("Caught exception ${e} in open(), you might want to force a replay", ("e", e.to_detail_string())); throw; } - if( _options->count("force-validate") ) - { - ilog( "All transaction signatures will be validated" ); + if (_options->count("force-validate")) { + ilog("All transaction signatures will be validated"); _force_validate = true; } - if( _options->count("api-access") ) { + if (_options->count("api-access")) { - if(fc::exists(_options->at("api-access").as())) - { - _apiaccess = fc::json::from_file( _options->at("api-access").as() ).as( 20 ); - ilog( "Using api access file from ${path}", - ("path", _options->at("api-access").as().string()) ); - } - else - { + if (fc::exists(_options->at("api-access").as())) { + _apiaccess = fc::json::from_file(_options->at("api-access").as()).as(20); + ilog("Using api access file from ${path}", + ("path", _options->at("api-access").as().string())); + } else { elog("Failed to load file from ${path}", - ("path", _options->at("api-access").as().string())); + ("path", _options->at("api-access").as().string())); std::exit(EXIT_FAILURE); } - } - else - { + } else { // TODO: Remove this generous default access policy // when the UI logs in properly _apiaccess = api_access(); api_access_info wild_access; wild_access.password_hash_b64 = "*"; wild_access.password_salt_b64 = "*"; - wild_access.allowed_apis.push_back( "database_api" ); - wild_access.allowed_apis.push_back( "network_broadcast_api" ); - wild_access.allowed_apis.push_back( "history_api" ); - wild_access.allowed_apis.push_back( "crypto_api" ); - wild_access.allowed_apis.push_back( "bookie_api" ); - wild_access.allowed_apis.push_back( "affiliate_stats_api" ); + wild_access.allowed_apis.push_back("database_api"); + wild_access.allowed_apis.push_back("network_broadcast_api"); + wild_access.allowed_apis.push_back("history_api"); + wild_access.allowed_apis.push_back("crypto_api"); + wild_access.allowed_apis.push_back("bookie_api"); + wild_access.allowed_apis.push_back("affiliate_stats_api"); _apiaccess.permission_map["*"] = wild_access; } reset_p2p_node(_data_dir); reset_websocket_server(); reset_websocket_tls_server(); - } FC_LOG_AND_RETHROW() } - - - optional< api_access_info > get_api_access_info(const string& username)const - { - optional< api_access_info > result; - auto it = _apiaccess.permission_map.find(username); - if( it == _apiaccess.permission_map.end() ) - { - it = _apiaccess.permission_map.find("*"); - if( it == _apiaccess.permission_map.end() ) - return result; - } - return it->second; } + FC_LOG_AND_RETHROW() + } - void set_api_access_info(const string& username, api_access_info&& permissions) - { - _apiaccess.permission_map.insert(std::make_pair(username, std::move(permissions))); + optional get_api_access_info(const string &username) const { + optional result; + auto it = _apiaccess.permission_map.find(username); + if (it == _apiaccess.permission_map.end()) { + it = _apiaccess.permission_map.find("*"); + if (it == _apiaccess.permission_map.end()) + return result; } + return it->second; + } - /** + void set_api_access_info(const string &username, api_access_info &&permissions) { + _apiaccess.permission_map.insert(std::make_pair(username, std::move(permissions))); + } + + /** * If delegate has the item, the network has no need to fetch it. */ - virtual bool has_item(const net::item_id& id) override - { - try - { - if( id.item_type == graphene::net::block_message_type ) - return _chain_db->is_known_block(id.item_hash); - else - return _chain_db->is_known_transaction(id.item_hash); - } - FC_CAPTURE_AND_RETHROW( (id) ) + virtual bool has_item(const net::item_id &id) override { + try { + if (id.item_type == graphene::net::block_message_type) + return _chain_db->is_known_block(id.item_hash); + else + return _chain_db->is_known_transaction(id.item_hash); } + FC_CAPTURE_AND_RETHROW((id)) + } - /** + /** * @brief allows the application to validate an item prior to broadcasting to peers. * * @param sync_mode true if the message was fetched through the sync process, false during normal operation @@ -482,24 +447,19 @@ namespace detail { * * @throws exception if error validating the item, otherwise the item is safe to broadcast on. */ - virtual bool handle_block(const graphene::net::block_message& blk_msg, bool sync_mode, - std::vector& contained_transaction_message_ids) override - { try { + virtual bool handle_block(const graphene::net::block_message &blk_msg, bool sync_mode, + std::vector &contained_transaction_message_ids) override { + try { auto latency = fc::time_point::now() - blk_msg.block.timestamp; - FC_ASSERT( (latency.count()/1000) > -5000, "Rejecting block with timestamp in the future" ); - if (!sync_mode || blk_msg.block.block_num() % 10000 == 0) - { - const auto& witness = blk_msg.block.witness(*_chain_db); - const auto& witness_account = witness.witness_account(*_chain_db); + FC_ASSERT((latency.count() / 1000) > -5000, "Rejecting block with timestamp in the future"); + if (!sync_mode || blk_msg.block.block_num() % 10000 == 0) { + const auto &witness = blk_msg.block.witness(*_chain_db); + const auto &witness_account = witness.witness_account(*_chain_db); auto last_irr = _chain_db->get_dynamic_global_properties().last_irreversible_block_num; ilog("Got block: #${n} time: ${t} latency: ${l} ms from: ${w} irreversible: ${i} (-${d})", - ("t",blk_msg.block.timestamp) - ("n", blk_msg.block.block_num()) - ("l", (latency.count()/1000)) - ("w",witness_account.name) - ("i",last_irr)("d",blk_msg.block.block_num()-last_irr) ); + ("t", blk_msg.block.timestamp)("n", blk_msg.block.block_num())("l", (latency.count() / 1000))("w", witness_account.name)("i", last_irr)("d", blk_msg.block.block_num() - last_irr)); } - FC_ASSERT( (latency.count()/1000) > -5000, "Rejecting block with timestamp in the future" ); + FC_ASSERT((latency.count() / 1000) > -5000, "Rejecting block with timestamp in the future"); try { // TODO: in the case where this block is valid but on a fork that's too old for us to switch to, @@ -509,66 +469,65 @@ namespace detail { bool result = _chain_db->push_block(blk_msg.block, (_is_block_producer | _force_validate) ? database::skip_nothing : database::skip_transaction_signatures); // the block was accepted, so we now know all of the transactions contained in the block - if (!sync_mode) - { + if (!sync_mode) { // if we're not in sync mode, there's a chance we will be seeing some transactions // included in blocks before we see the free-floating transaction itself. If that // happens, there's no reason to fetch the transactions, so construct a list of the // transaction message ids we no longer need. // during sync, it is unlikely that we'll see any old - for (const processed_transaction& transaction : blk_msg.block.transactions) - { + for (const processed_transaction &transaction : blk_msg.block.transactions) { graphene::net::trx_message transaction_message(transaction); contained_transaction_message_ids.push_back(graphene::net::message(transaction_message).id()); } } return result; - } catch ( const graphene::chain::unlinkable_block_exception& e ) { + } catch (const graphene::chain::unlinkable_block_exception &e) { // translate to a graphene::net exception elog("Error when pushing block:\n${e}", ("e", e.to_detail_string())); FC_THROW_EXCEPTION(graphene::net::unlinkable_block_exception, "Error when pushing block:\n${e}", ("e", e.to_detail_string())); - } catch( const fc::exception& e ) { + } catch (const fc::exception &e) { elog("Error when pushing block:\n${e}", ("e", e.to_detail_string())); throw; } - if( !_is_finished_syncing && !sync_mode ) - { + if (!_is_finished_syncing && !sync_mode) { _is_finished_syncing = true; _self->syncing_finished(); } - } FC_CAPTURE_AND_RETHROW( (blk_msg)(sync_mode) ) } + } + FC_CAPTURE_AND_RETHROW((blk_msg)(sync_mode)) + } - virtual void handle_transaction(const graphene::net::trx_message& transaction_message) override - { try { + virtual void handle_transaction(const graphene::net::trx_message &transaction_message) override { + try { static fc::time_point last_call; static int trx_count = 0; ++trx_count; auto now = fc::time_point::now(); - if( now - last_call > fc::seconds(1) ) { - ilog("Got ${c} transactions from network", ("c",trx_count) ); + if (now - last_call > fc::seconds(1)) { + ilog("Got ${c} transactions from network", ("c", trx_count)); last_call = now; trx_count = 0; } - _chain_db->push_transaction( transaction_message.trx ); - } FC_CAPTURE_AND_RETHROW( (transaction_message) ) } - - virtual void handle_message(const message& message_to_process) override - { - // not a transaction, not a block - FC_THROW( "Invalid Message Type" ); + _chain_db->push_transaction(transaction_message.trx); } + FC_CAPTURE_AND_RETHROW((transaction_message)) + } - bool is_included_block(const block_id_type& block_id) - { - uint32_t block_num = block_header::num_from_id(block_id); - block_id_type block_id_in_preferred_chain = _chain_db->get_block_id_for_num(block_num); - return block_id == block_id_in_preferred_chain; - } + virtual void handle_message(const message &message_to_process) override { + // not a transaction, not a block + FC_THROW("Invalid Message Type"); + } - /** + bool is_included_block(const block_id_type &block_id) { + uint32_t block_num = block_header::num_from_id(block_id); + block_id_type block_id_in_preferred_chain = _chain_db->get_block_id_for_num(block_num); + return block_id == block_id_in_preferred_chain; + } + + /** * Assuming all data elements are ordered in some way, this method should * return up to limit ids that occur *after* the last ID in synopsis that * we recognize. @@ -577,78 +536,76 @@ namespace detail { * in our blockchain after the last item returned in the result, * or 0 if the result contains the last item in the blockchain */ - virtual std::vector get_block_ids(const std::vector& blockchain_synopsis, - uint32_t& remaining_item_count, - uint32_t limit) override - { try { + virtual std::vector get_block_ids(const std::vector &blockchain_synopsis, + uint32_t &remaining_item_count, + uint32_t limit) override { + try { vector result; remaining_item_count = 0; - if( _chain_db->head_block_num() == 0 ) + if (_chain_db->head_block_num() == 0) return result; result.reserve(limit); block_id_type last_known_block_id; if (blockchain_synopsis.empty() || - (blockchain_synopsis.size() == 1 && blockchain_synopsis[0] == block_id_type())) - { - // peer has sent us an empty synopsis meaning they have no blocks. - // A bug in old versions would cause them to send a synopsis containing block 000000000 - // when they had an empty blockchain, so pretend they sent the right thing here. + (blockchain_synopsis.size() == 1 && blockchain_synopsis[0] == block_id_type())) { + // peer has sent us an empty synopsis meaning they have no blocks. + // A bug in old versions would cause them to send a synopsis containing block 000000000 + // when they had an empty blockchain, so pretend they sent the right thing here. - // do nothing, leave last_known_block_id set to zero + // do nothing, leave last_known_block_id set to zero + } else { + bool found_a_block_in_synopsis = false; + for (const item_hash_t &block_id_in_synopsis : boost::adaptors::reverse(blockchain_synopsis)) + if (block_id_in_synopsis == block_id_type() || + (_chain_db->is_known_block(block_id_in_synopsis) && is_included_block(block_id_in_synopsis))) { + last_known_block_id = block_id_in_synopsis; + found_a_block_in_synopsis = true; + break; + } + if (!found_a_block_in_synopsis) + FC_THROW_EXCEPTION(graphene::net::peer_is_on_an_unreachable_fork, "Unable to provide a list of blocks starting at any of the blocks in peer's synopsis"); } - else - { - bool found_a_block_in_synopsis = false; - for (const item_hash_t& block_id_in_synopsis : boost::adaptors::reverse(blockchain_synopsis)) - if (block_id_in_synopsis == block_id_type() || - (_chain_db->is_known_block(block_id_in_synopsis) && is_included_block(block_id_in_synopsis))) - { - last_known_block_id = block_id_in_synopsis; - found_a_block_in_synopsis = true; - break; - } - if (!found_a_block_in_synopsis) - FC_THROW_EXCEPTION(graphene::net::peer_is_on_an_unreachable_fork, "Unable to provide a list of blocks starting at any of the blocks in peer's synopsis"); - } - for( uint32_t num = block_header::num_from_id(last_known_block_id); + for (uint32_t num = block_header::num_from_id(last_known_block_id); num <= _chain_db->head_block_num() && result.size() < limit; - ++num ) - if( num > 0 ) + ++num) + if (num > 0) result.push_back(_chain_db->get_block_id_for_num(num)); - if( !result.empty() && block_header::num_from_id(result.back()) < _chain_db->head_block_num() ) + if (!result.empty() && block_header::num_from_id(result.back()) < _chain_db->head_block_num()) remaining_item_count = _chain_db->head_block_num() - block_header::num_from_id(result.back()); return result; - } FC_CAPTURE_AND_RETHROW( (blockchain_synopsis)(remaining_item_count)(limit) ) } + } + FC_CAPTURE_AND_RETHROW((blockchain_synopsis)(remaining_item_count)(limit)) + } - /** + /** * Given the hash of the requested data, fetch the body. */ - virtual message get_item(const item_id& id) override - { try { - // ilog("Request for item ${id}", ("id", id)); - if( id.item_type == graphene::net::block_message_type ) - { + virtual message get_item(const item_id &id) override { + try { + // ilog("Request for item ${id}", ("id", id)); + if (id.item_type == graphene::net::block_message_type) { auto opt_block = _chain_db->fetch_block_by_id(id.item_hash); - if( !opt_block ) + if (!opt_block) elog("Couldn't find block ${id} -- corresponding ID in our chain is ${id2}", ("id", id.item_hash)("id2", _chain_db->get_block_id_for_num(block_header::num_from_id(id.item_hash)))); - FC_ASSERT( opt_block.valid() ); + FC_ASSERT(opt_block.valid()); // ilog("Serving up block #${num}", ("num", opt_block->block_num())); return block_message(std::move(*opt_block)); } - return trx_message( _chain_db->get_recent_transaction( id.item_hash ) ); - } FC_CAPTURE_AND_RETHROW( (id) ) } - - virtual chain_id_type get_chain_id()const override - { - return _chain_db->get_chain_id(); + return trx_message(_chain_db->get_recent_transaction(id.item_hash)); } + FC_CAPTURE_AND_RETHROW((id)) + } - /** + virtual chain_id_type get_chain_id() const override { + return _chain_db->get_chain_id(); + } + + /** * Returns a synopsis of the blockchain used for syncing. This consists of a list of * block hashes at intervals exponentially increasing towards the genesis block. * When syncing to a peer, the peer uses this data to determine if we're on the same @@ -706,270 +663,248 @@ namespace detail { * successfully pushed to the blockchain, so that tells us whether the peer is on a fork or on * the main chain. */ - virtual std::vector get_blockchain_synopsis(const item_hash_t& reference_point, - uint32_t number_of_blocks_after_reference_point) override - { try { - std::vector synopsis; - synopsis.reserve(30); - uint32_t high_block_num; - uint32_t non_fork_high_block_num; - uint32_t low_block_num = _chain_db->last_non_undoable_block_num(); - std::vector fork_history; + virtual std::vector get_blockchain_synopsis(const item_hash_t &reference_point, + uint32_t number_of_blocks_after_reference_point) override { + try { + std::vector synopsis; + synopsis.reserve(30); + uint32_t high_block_num; + uint32_t non_fork_high_block_num; + uint32_t low_block_num = _chain_db->last_non_undoable_block_num(); + std::vector fork_history; - if (reference_point != item_hash_t()) - { + if (reference_point != item_hash_t()) { // the node is asking for a summary of the block chain up to a specified // block, which may or may not be on a fork // for now, assume it's not on a fork - if (is_included_block(reference_point)) - { - // reference_point is a block we know about and is on the main chain - uint32_t reference_point_block_num = block_header::num_from_id(reference_point); - assert(reference_point_block_num > 0); - high_block_num = reference_point_block_num; - non_fork_high_block_num = high_block_num; + if (is_included_block(reference_point)) { + // reference_point is a block we know about and is on the main chain + uint32_t reference_point_block_num = block_header::num_from_id(reference_point); + assert(reference_point_block_num > 0); + high_block_num = reference_point_block_num; + non_fork_high_block_num = high_block_num; - if (reference_point_block_num < low_block_num) - { - // we're on the same fork (at least as far as reference_point) but we've passed - // reference point and could no longer undo that far if we diverged after that - // block. This should probably only happen due to a race condition where - // the network thread calls this function, and then immediately pushes a bunch of blocks, - // then the main thread finally processes this function. - // with the current framework, there's not much we can do to tell the network - // thread what our current head block is, so we'll just pretend that - // our head is actually the reference point. - // this *may* enable us to fetch blocks that we're unable to push, but that should - // be a rare case (and correctly handled) - low_block_num = reference_point_block_num; - } + if (reference_point_block_num < low_block_num) { + // we're on the same fork (at least as far as reference_point) but we've passed + // reference point and could no longer undo that far if we diverged after that + // block. This should probably only happen due to a race condition where + // the network thread calls this function, and then immediately pushes a bunch of blocks, + // then the main thread finally processes this function. + // with the current framework, there's not much we can do to tell the network + // thread what our current head block is, so we'll just pretend that + // our head is actually the reference point. + // this *may* enable us to fetch blocks that we're unable to push, but that should + // be a rare case (and correctly handled) + low_block_num = reference_point_block_num; + } + } else { + // block is a block we know about, but it is on a fork + try { + fork_history = _chain_db->get_block_ids_on_fork(reference_point); + // returns a vector where the last element is the common ancestor with the preferred chain, + // and the first element is the reference point you passed in + assert(fork_history.size() >= 2); + + if (fork_history.front() != reference_point) { + edump((fork_history)(reference_point)); + assert(fork_history.front() == reference_point); + } + block_id_type last_non_fork_block = fork_history.back(); + fork_history.pop_back(); // remove the common ancestor + boost::reverse(fork_history); + + if (last_non_fork_block == block_id_type()) // if the fork goes all the way back to genesis (does graphene's fork db allow this?) + non_fork_high_block_num = 0; + else + non_fork_high_block_num = block_header::num_from_id(last_non_fork_block); + + high_block_num = non_fork_high_block_num + fork_history.size(); + assert(high_block_num == block_header::num_from_id(fork_history.back())); + } catch (const fc::exception &e) { + // unable to get fork history for some reason. maybe not linked? + // we can't return a synopsis of its chain + elog("Unable to construct a blockchain synopsis for reference hash ${hash}: ${exception}", ("hash", reference_point)("exception", e)); + throw; + } + if (non_fork_high_block_num < low_block_num) { + wlog("Unable to generate a usable synopsis because the peer we're generating it for forked too long ago " + "(our chains diverge after block #${non_fork_high_block_num} but only undoable to block #${low_block_num})", + ("low_block_num", low_block_num)("non_fork_high_block_num", non_fork_high_block_num)); + FC_THROW_EXCEPTION(graphene::net::block_older_than_undo_history, "Peer is are on a fork I'm unable to switch to"); + } } - else - { - // block is a block we know about, but it is on a fork - try - { - fork_history = _chain_db->get_block_ids_on_fork(reference_point); - // returns a vector where the last element is the common ancestor with the preferred chain, - // and the first element is the reference point you passed in - assert(fork_history.size() >= 2); - - if( fork_history.front() != reference_point ) - { - edump( (fork_history)(reference_point) ); - assert(fork_history.front() == reference_point); - } - block_id_type last_non_fork_block = fork_history.back(); - fork_history.pop_back(); // remove the common ancestor - boost::reverse(fork_history); - - if (last_non_fork_block == block_id_type()) // if the fork goes all the way back to genesis (does graphene's fork db allow this?) - non_fork_high_block_num = 0; - else - non_fork_high_block_num = block_header::num_from_id(last_non_fork_block); - - high_block_num = non_fork_high_block_num + fork_history.size(); - assert(high_block_num == block_header::num_from_id(fork_history.back())); - } - catch (const fc::exception& e) - { - // unable to get fork history for some reason. maybe not linked? - // we can't return a synopsis of its chain - elog("Unable to construct a blockchain synopsis for reference hash ${hash}: ${exception}", ("hash", reference_point)("exception", e)); - throw; - } - if (non_fork_high_block_num < low_block_num) - { - wlog("Unable to generate a usable synopsis because the peer we're generating it for forked too long ago " - "(our chains diverge after block #${non_fork_high_block_num} but only undoable to block #${low_block_num})", - ("low_block_num", low_block_num) - ("non_fork_high_block_num", non_fork_high_block_num)); - FC_THROW_EXCEPTION(graphene::net::block_older_than_undo_history, "Peer is are on a fork I'm unable to switch to"); - } - } - } - else - { + } else { // no reference point specified, summarize the whole block chain high_block_num = _chain_db->head_block_num(); non_fork_high_block_num = high_block_num; if (high_block_num == 0) - return synopsis; // we have no blocks - } - - if( low_block_num == 0) - low_block_num = 1; + return synopsis; // we have no blocks + } - // at this point: - // low_block_num is the block before the first block we can undo, - // non_fork_high_block_num is the block before the fork (if the peer is on a fork, or otherwise it is the same as high_block_num) - // high_block_num is the block number of the reference block, or the end of the chain if no reference provided + if (low_block_num == 0) + low_block_num = 1; - // true_high_block_num is the ending block number after the network code appends any item ids it - // knows about that we don't - uint32_t true_high_block_num = high_block_num + number_of_blocks_after_reference_point; - do - { + // at this point: + // low_block_num is the block before the first block we can undo, + // non_fork_high_block_num is the block before the fork (if the peer is on a fork, or otherwise it is the same as high_block_num) + // high_block_num is the block number of the reference block, or the end of the chain if no reference provided + + // true_high_block_num is the ending block number after the network code appends any item ids it + // knows about that we don't + uint32_t true_high_block_num = high_block_num + number_of_blocks_after_reference_point; + do { // for each block in the synopsis, figure out where to pull the block id from. // if it's <= non_fork_high_block_num, we grab it from the main blockchain; // if it's not, we pull it from the fork history if (low_block_num <= non_fork_high_block_num) - synopsis.push_back(_chain_db->get_block_id_for_num(low_block_num)); + synopsis.push_back(_chain_db->get_block_id_for_num(low_block_num)); else - synopsis.push_back(fork_history[low_block_num - non_fork_high_block_num - 1]); + synopsis.push_back(fork_history[low_block_num - non_fork_high_block_num - 1]); low_block_num += (true_high_block_num - low_block_num + 2) / 2; - } - while (low_block_num <= high_block_num); + } while (low_block_num <= high_block_num); - //idump((synopsis)); - return synopsis; - } FC_CAPTURE_AND_RETHROW() } + //idump((synopsis)); + return synopsis; + } + FC_CAPTURE_AND_RETHROW() + } - /** + /** * Call this after the call to handle_message succeeds. * * @param item_type the type of the item we're synchronizing, will be the same as item passed to the sync_from() call * @param item_count the number of items known to the node that haven't been sent to handle_item() yet. * After `item_count` more calls to handle_item(), the node will be in sync */ - virtual void sync_status(uint32_t item_type, uint32_t item_count) override - { - // any status reports to GUI go here - } + virtual void sync_status(uint32_t item_type, uint32_t item_count) override { + // any status reports to GUI go here + } - /** + /** * Call any time the number of connected peers changes. */ - virtual void connection_count_changed(uint32_t c) override - { - // any status reports to GUI go here - } + virtual void connection_count_changed(uint32_t c) override { + // any status reports to GUI go here + } - virtual uint32_t get_block_number(const item_hash_t& block_id) override - { try { + virtual uint32_t get_block_number(const item_hash_t &block_id) override { + try { return block_header::num_from_id(block_id); - } FC_CAPTURE_AND_RETHROW( (block_id) ) } + } + FC_CAPTURE_AND_RETHROW((block_id)) + } - /** + /** * Returns the time a block was produced (if block_id = 0, returns genesis time). * If we don't know about the block, returns time_point_sec::min() */ - virtual fc::time_point_sec get_block_time(const item_hash_t& block_id) override - { try { - auto opt_block = _chain_db->fetch_block_by_id( block_id ); - if( opt_block.valid() ) return opt_block->timestamp; + virtual fc::time_point_sec get_block_time(const item_hash_t &block_id) override { + try { + auto opt_block = _chain_db->fetch_block_by_id(block_id); + if (opt_block.valid()) + return opt_block->timestamp; return fc::time_point_sec::min(); - } FC_CAPTURE_AND_RETHROW( (block_id) ) } - - virtual item_hash_t get_head_block_id() const override - { - return _chain_db->head_block_id(); } + FC_CAPTURE_AND_RETHROW((block_id)) + } - virtual uint32_t estimate_last_known_fork_from_git_revision_timestamp(uint32_t unix_timestamp) const override - { - return 0; // there are no forks in graphene - } + virtual item_hash_t get_head_block_id() const override { + return _chain_db->head_block_id(); + } - virtual void error_encountered(const std::string& message, const fc::oexception& error) override - { - // notify GUI or something cool - } + virtual uint32_t estimate_last_known_fork_from_git_revision_timestamp(uint32_t unix_timestamp) const override { + return 0; // there are no forks in graphene + } - uint8_t get_current_block_interval_in_seconds() const override - { - return _chain_db->get_global_properties().parameters.block_interval; - } + virtual void error_encountered(const std::string &message, const fc::oexception &error) override { + // notify GUI or something cool + } - application* _self; + uint8_t get_current_block_interval_in_seconds() const override { + return _chain_db->get_global_properties().parameters.block_interval; + } - fc::path _data_dir; - const bpo::variables_map* _options = nullptr; - api_access _apiaccess; + application *_self; - std::shared_ptr _chain_db; - std::shared_ptr _p2p_network; - std::shared_ptr _websocket_server; - std::shared_ptr _websocket_tls_server; + fc::path _data_dir; + const bpo::variables_map *_options = nullptr; + api_access _apiaccess; - std::map> _active_plugins; - std::map> _available_plugins; + std::shared_ptr _chain_db; + std::shared_ptr _p2p_network; + std::shared_ptr _websocket_server; + std::shared_ptr _websocket_tls_server; - bool _is_finished_syncing = false; - }; + std::map> _active_plugins; + std::map> _available_plugins; + bool _is_finished_syncing = false; +}; + +} // namespace detail + +application::application() : + my(new detail::application_impl(this)) { } -application::application() - : my(new detail::application_impl(this)) -{} - -application::~application() -{ - if( my->_p2p_network ) - { +application::~application() { + if (my->_p2p_network) { my->_p2p_network->close(); my->_p2p_network.reset(); } - if( my->_chain_db ) - { + if (my->_chain_db) { my->_chain_db->close(); } } -void application::set_program_options(boost::program_options::options_description& command_line_options, - boost::program_options::options_description& configuration_file_options) const -{ - configuration_file_options.add_options() - ("p2p-endpoint", bpo::value(), "Endpoint for P2P node to listen on") - ("seed-node,s", bpo::value>()->composing(), "P2P nodes to connect to on startup (may specify multiple times)") - ("seed-nodes", bpo::value()->composing(), "JSON array of P2P nodes to connect to on startup") - ("checkpoint,c", bpo::value>()->composing(), "Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints.") - ("rpc-endpoint", bpo::value()->implicit_value("127.0.0.1:8090"), "Endpoint for websocket RPC to listen on") - ("rpc-tls-endpoint", bpo::value()->implicit_value("127.0.0.1:8089"), "Endpoint for TLS websocket RPC to listen on") - ("server-pem,p", bpo::value()->implicit_value("server.pem"), "The TLS certificate file for this server") - ("server-pem-password,P", bpo::value()->implicit_value(""), "Password for this certificate") - ("genesis-json", bpo::value(), "File to read Genesis State from") - ("dbg-init-key", bpo::value(), "Block signing key to use for init witnesses, overrides genesis file") - ("api-access", bpo::value(), "JSON file specifying API permissions") - ("enable-standby-votes-tracking", bpo::value()->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.") - ("plugins", bpo::value(), "Space-separated list of plugins to activate") - ; - command_line_options.add(configuration_file_options); - command_line_options.add_options() - ("create-genesis-json", bpo::value(), - "Path to create a Genesis State at. If a well-formed JSON file exists at the path, it will be parsed and any " - "missing fields in a Genesis State will be added, and any unknown fields will be removed. If no file or an " - "invalid file is found, it will be replaced with an example Genesis State.") - ("replay-blockchain", "Rebuild object graph by replaying all blocks") - ("resync-blockchain", "Delete all blocks and re-sync with network from scratch") - ("force-validate", "Force validation of all transactions") - ("genesis-timestamp", bpo::value(), "Replace timestamp from genesis.json with current time plus this many seconds (experts only!)") - ; - command_line_options.add(_cli_options); - configuration_file_options.add(_cfg_options); +void application::set_program_options(boost::program_options::options_description &cli, + boost::program_options::options_description &cfg) const { + cfg.add_options()("p2p-endpoint", bpo::value(), "Endpoint for P2P node to listen on"); + cfg.add_options()("seed-node,s", bpo::value>()->composing(), "P2P nodes to connect to on startup (may specify multiple times)"); + cfg.add_options()("seed-nodes", bpo::value()->composing(), "JSON array of P2P nodes to connect to on startup"); + cfg.add_options()("checkpoint,c", bpo::value>()->composing(), "Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints."); + cfg.add_options()("rpc-endpoint", bpo::value()->implicit_value("127.0.0.1:8090"), "Endpoint for websocket RPC to listen on"); + cfg.add_options()("rpc-tls-endpoint", bpo::value()->implicit_value("127.0.0.1:8089"), "Endpoint for TLS websocket RPC to listen on"); + cfg.add_options()("server-pem,p", bpo::value()->implicit_value("server.pem"), "The TLS certificate file for this server"); + cfg.add_options()("server-pem-password,P", bpo::value()->implicit_value(""), "Password for this certificate"); + cfg.add_options()("genesis-json", bpo::value(), "File to read Genesis State from"); + cfg.add_options()("dbg-init-key", bpo::value(), "Block signing key to use for init witnesses, overrides genesis file"); + cfg.add_options()("api-access", bpo::value(), "JSON file specifying API permissions"); + cfg.add_options()("enable-standby-votes-tracking", bpo::value()->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."); + cfg.add_options()("plugins", bpo::value()->default_value("account_history accounts_list affiliate_stats bookie market_history witness"), + "Space-separated list of plugins to activate"); + + cli.add(cfg); + cli.add_options()("create-genesis-json", bpo::value(), + "Path to create a Genesis State at. If a well-formed JSON file exists at the path, it will be parsed and any " + "missing fields in a Genesis State will be added, and any unknown fields will be removed. If no file or an " + "invalid file is found, it will be replaced with an example Genesis State."); + cli.add_options()("replay-blockchain", "Rebuild object graph by replaying all blocks"); + cli.add_options()("resync-blockchain", "Delete all blocks and re-sync with network from scratch"); + cli.add_options()("force-validate", "Force validation of all transactions"); + cli.add_options()("genesis-timestamp", bpo::value(), "Replace timestamp from genesis.json with current time plus this many seconds (experts only!)"); + cli.add(_cli_options); + cfg.add(_cfg_options); } -void application::initialize(const fc::path& data_dir, const boost::program_options::variables_map& options) -{ +void application::initialize(const fc::path &data_dir, const boost::program_options::variables_map &options) { my->_data_dir = data_dir; my->_options = &options; - if( options.count("create-genesis-json") ) - { + if (options.count("create-genesis-json")) { fc::path genesis_out = options.at("create-genesis-json").as(); genesis_state_type genesis_state = detail::create_example_genesis(); - if( fc::exists(genesis_out) ) - { + if (fc::exists(genesis_out)) { try { - genesis_state = fc::json::from_file(genesis_out).as( 20 ); - } catch(const fc::exception& e) { - std::cerr << "Unable to parse existing genesis file:\n" << e.to_string() + genesis_state = fc::json::from_file(genesis_out).as(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] "; char response = std::cin.get(); - if( toupper(response) != 'Y' ) + if (toupper(response) != 'Y') return; } @@ -983,12 +918,11 @@ void application::initialize(const fc::path& data_dir, const boost::program_opti } std::set wanted; - if( options.count("plugins") ) - { - boost::split(wanted, options.at("plugins").as(), [](char c){return c == ' ';}); - } - else - { + if (options.count("plugins")) { + boost::split(wanted, options.at("plugins").as(), [](char c) { + return c == ' '; + }); + } else { wanted.insert("account_history"); wanted.insert("market_history"); wanted.insert("accounts_list"); @@ -998,113 +932,97 @@ void application::initialize(const fc::path& data_dir, const boost::program_opti wanted.insert("bookie"); int es_ah_conflict_counter = 0; - for (auto& it : wanted) - { - if(it == "account_history") + for (auto &it : wanted) { + if (it == "account_history") ++es_ah_conflict_counter; - if(it == "elasticsearch") + if (it == "elasticsearch") ++es_ah_conflict_counter; - if(es_ah_conflict_counter > 1) { + if (es_ah_conflict_counter > 1) { elog("Can't start program with elasticsearch and account_history plugin at the same time"); std::exit(EXIT_FAILURE); } - if (!it.empty()) enable_plugin(it); + if (!it.empty()) + enable_plugin(it); } } -void application::startup() -{ +void application::startup() { try { - my->startup(); - } catch ( const fc::exception& e ) { - elog( "${e}", ("e",e.to_detail_string()) ); + my->startup(); + } catch (const fc::exception &e) { + elog("${e}", ("e", e.to_detail_string())); throw; - } catch ( ... ) { - elog( "unexpected exception" ); + } catch (...) { + elog("unexpected exception"); throw; } } -std::shared_ptr application::get_plugin(const string& name) const -{ +std::shared_ptr application::get_plugin(const string &name) const { return my->_active_plugins[name]; } -bool application::is_plugin_enabled(const string& name) const -{ +bool application::is_plugin_enabled(const string &name) const { return !(my->_active_plugins.find(name) == my->_active_plugins.end()); } -net::node_ptr application::p2p_node() -{ +net::node_ptr application::p2p_node() { return my->_p2p_network; } -std::shared_ptr application::chain_database() const -{ +std::shared_ptr application::chain_database() const { return my->_chain_db; } -void application::set_block_production(bool producing_blocks) -{ +void application::set_block_production(bool producing_blocks) { my->_is_block_producer = producing_blocks; } -optional< api_access_info > application::get_api_access_info( const string& username )const -{ - return my->get_api_access_info( username ); +optional application::get_api_access_info(const string &username) const { + return my->get_api_access_info(username); } -void application::set_api_access_info(const string& username, api_access_info&& permissions) -{ +void application::set_api_access_info(const string &username, api_access_info &&permissions) { my->set_api_access_info(username, std::move(permissions)); } -bool application::is_finished_syncing() const -{ +bool application::is_finished_syncing() const { return my->_is_finished_syncing; } -void graphene::app::application::enable_plugin(const string& name) -{ +void graphene::app::application::enable_plugin(const string &name) { FC_ASSERT(my->_available_plugins[name], "Unknown plugin '" + name + "'"); my->_active_plugins[name] = my->_available_plugins[name]; my->_active_plugins[name]->plugin_set_app(this); } -void graphene::app::application::add_available_plugin(std::shared_ptr p) -{ +void graphene::app::application::add_available_plugin(std::shared_ptr p) { my->_available_plugins[p->plugin_name()] = p; } -void application::shutdown_plugins() -{ - for( auto& entry : my->_active_plugins ) +void application::shutdown_plugins() { + for (auto &entry : my->_active_plugins) entry.second->plugin_shutdown(); return; } -void application::shutdown() -{ - if( my->_p2p_network ) +void application::shutdown() { + if (my->_p2p_network) my->_p2p_network->close(); - if( my->_chain_db ) + if (my->_chain_db) my->_chain_db->close(); } -void application::initialize_plugins( const boost::program_options::variables_map& options ) -{ - for( auto& entry : my->_active_plugins ) - entry.second->plugin_initialize( options ); +void application::initialize_plugins(const boost::program_options::variables_map &options) { + for (auto &entry : my->_active_plugins) + entry.second->plugin_initialize(options); return; } -void application::startup_plugins() -{ - for( auto& entry : my->_active_plugins ) +void application::startup_plugins() { + for (auto &entry : my->_active_plugins) entry.second->plugin_startup(); return; } -// namespace detail -} } +}} // namespace graphene::app diff --git a/libraries/app/config_util.cpp b/libraries/app/config_util.cpp index f06291b7..c6dc2375 100644 --- a/libraries/app/config_util.cpp +++ b/libraries/app/config_util.cpp @@ -25,36 +25,36 @@ #include #include -#include -#include #include #include #include #include +#include +#include -#include -#include +#include #include #include -#include -#include +#include +#include #include namespace bpo = boost::program_options; -class deduplicator -{ +class deduplicator { public: - deduplicator() : modifier(nullptr) {} + deduplicator() : + modifier(nullptr) { + } - deduplicator(const boost::shared_ptr (*mod_fn)(const boost::shared_ptr&)) - : modifier(mod_fn) {} + deduplicator(const boost::shared_ptr (*mod_fn)(const boost::shared_ptr &)) : + modifier(mod_fn) { + } - const boost::shared_ptr next(const boost::shared_ptr& o) - { + const boost::shared_ptr next(const boost::shared_ptr &o) { const std::string name = o->long_name(); - if( seen.find( name ) != seen.end() ) + if (seen.find(name) != seen.end()) return nullptr; seen.insert(name); return modifier ? modifier(o) : o; @@ -62,15 +62,14 @@ public: private: boost::container::flat_set seen; - const boost::shared_ptr (*modifier)(const boost::shared_ptr&); + const boost::shared_ptr (*modifier)(const boost::shared_ptr &); }; // 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) -{ +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" @@ -115,26 +114,22 @@ static void write_default_logging_config_to_stream(std::ostream& out) // logging config is too complicated to be parsed by boost::program_options, // so we do it by hand -static fc::optional load_logging_config_from_ini_file(const fc::path& config_ini_filename) -{ - try - { +static fc::optional 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; + for (const auto §ion : config_ini_tree) { + const std::string §ion_name = section.first; + const boost::property_tree::ptree §ion_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)) - { + 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("stream"); @@ -142,20 +137,18 @@ static fc::optional load_logging_config_from_ini_file(const // 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)); + 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)); + 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)); + fc::console_appender::level_color(fc::log_level::error, + fc::console_appender::color::cyan)); console_appender_config.stream = fc::variant(stream_name).as(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)) - { + } 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("filename"); if (file_name.is_relative()) @@ -174,9 +167,7 @@ static fc::optional load_logging_config_from_ini_file(const 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)) - { + } 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("level"); std::string appenders_string = section_tree.get("appenders"); @@ -197,74 +188,66 @@ static fc::optional load_logging_config_from_ini_file(const FC_RETHROW_EXCEPTIONS(warn, "") } -static const boost::shared_ptr new_option_description( const std::string& name, const bpo::value_semantic* value, const std::string& description ) -{ +static const boost::shared_ptr 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() ); + 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 ) -{ +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 opt : cfg_options.options() ) - { + for (const boost::shared_ptr opt : cfg_options.options()) { const boost::shared_ptr od = dedup.next(opt); - if( !od ) continue; - unique_options.add( od ); + if (!od) + continue; + unique_options.add(od); } // get the basic options bpo::store(bpo::parse_config_file(config_ini_path.preferred_string().c_str(), - unique_options, true), options); + unique_options, true), + options); } -static bool load_logging_config_file(const fc::path& config_ini_path) -{ +static bool load_logging_config_file(const fc::path &config_ini_path) { // try to get logging options from the config file. - try - { + try { fc::optional logging_config = load_logging_config_from_ini_file(config_ini_path); - if (logging_config) - { + if (logging_config) { fc::configure_logging(*logging_config); return true; } - } - catch (const fc::exception& ex) - { + } 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 ) -{ +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) ) + if (!fc::exists(data_dir)) fc::create_directories(data_dir); - auto modify_option_defaults = [](const boost::shared_ptr& o) -> const boost::shared_ptr { - const std::string& name = o->long_name(); - if( name == "partial-operations" ) - return new_option_description(name, bpo::value()->default_value(true), o->description() ); - if( name == "max-ops-per-account" ) - return new_option_description(name, bpo::value()->default_value(100), o->description() ); - return o; + auto modify_option_defaults = [](const boost::shared_ptr &o) -> const boost::shared_ptr { + const std::string &name = o->long_name(); + if (name == "partial-operations") + return new_option_description(name, bpo::value()->default_value(true), o->description()); + if (name == "max-ops-per-account") + return new_option_description(name, bpo::value()->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 opt : cfg_options.options() ) - { + std::string plugin_header_surrounding(78, '='); + for (const boost::shared_ptr opt : cfg_options.options()) { const boost::shared_ptr od = dedup.next(opt); - if( !od ) continue; + if (!od) + continue; - if( od->long_name().find("plugin-cfg-header-") == 0 ) // it's a plugin header + if (od->long_name().find("plugin-cfg-header-") == 0) // it's a plugin header { out_cfg << "\n"; out_cfg << "# " << plugin_header_surrounding << "\n"; @@ -274,20 +257,21 @@ static void create_new_config_file(const fc::path& config_ini_path, const fc::pa continue; } - if( !od->description().empty() ) + if (!od->description().empty()) out_cfg << "# " << od->description() << "\n"; boost::any store; - if( !od->semantic()->apply_default(store) ) + if (!od->semantic()->apply_default(store)) out_cfg << "# " << od->long_name() << " = \n"; else { auto example = od->format_parameter(); - if( example.empty() ) + if (example.empty()) // This is a boolean switch - out_cfg << od->long_name() << " = " << "false\n"; + out_cfg << od->long_name() << " = " + << "false\n"; else { // The string is formatted "arg (=)" example.erase(0, 6); - example.erase(example.length()-1); + example.erase(example.length() - 1); out_cfg << od->long_name() << " = " << example << "\n"; } } @@ -304,11 +288,9 @@ static void create_new_config_file(const fc::path& config_ini_path, const fc::pa out_cfg.close(); } -static void create_logging_config_file(const fc::path& config_ini_path, const fc::path& data_dir) -{ +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)) - { + if (!exists(data_dir)) { create_directories(data_dir); } @@ -319,36 +301,29 @@ static void create_logging_config_file(const fc::path& config_ini_path, const fc 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"; +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); - } + 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); } -} } // graphene::app + // 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); + } +} + +}} // namespace graphene::app diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 836af71e..77582222 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -23,11 +23,11 @@ */ #include -#include -#include #include +#include #include #include +#include #include @@ -35,9 +35,9 @@ #include #include +#include #include #include -#include #include @@ -46,273 +46,278 @@ #define GET_REQUIRED_FEES_MAX_RECURSION 4 -typedef std::map< std::pair, std::vector > market_queue_type; +typedef std::map, std::vector> market_queue_type; template class fc::api; namespace graphene { namespace app { -class database_api_impl : public std::enable_shared_from_this -{ - public: - database_api_impl( graphene::chain::database& db ); - ~database_api_impl(); +class database_api_impl : public std::enable_shared_from_this { +public: + database_api_impl(graphene::chain::database &db); + ~database_api_impl(); - // Objects - fc::variants get_objects(const vector& ids)const; + // Objects + fc::variants get_objects(const vector &ids) const; - // Subscriptions - void set_subscribe_callback( std::function cb, bool notify_remove_create ); - void set_pending_transaction_callback( std::function cb ); - void set_block_applied_callback( std::function cb ); - void cancel_all_subscriptions(); + // Subscriptions + void set_subscribe_callback(std::function cb, bool notify_remove_create); + void set_pending_transaction_callback(std::function cb); + void set_block_applied_callback(std::function cb); + void cancel_all_subscriptions(); - // Blocks and transactions - optional get_block_header(uint32_t block_num)const; - map> get_block_header_batch(const vector block_nums)const; - optional get_block(uint32_t block_num)const; - vector> get_blocks(uint32_t block_num_from, uint32_t block_num_to)const; - processed_transaction get_transaction( uint32_t block_num, uint32_t trx_in_block )const; + // Blocks and transactions + optional get_block_header(uint32_t block_num) const; + map> get_block_header_batch(const vector block_nums) const; + optional get_block(uint32_t block_num) const; + vector> get_blocks(uint32_t block_num_from, uint32_t block_num_to) const; + processed_transaction get_transaction(uint32_t block_num, uint32_t trx_in_block) const; - // Globals - chain_property_object get_chain_properties()const; - global_property_object get_global_properties()const; - fc::variant_object get_config()const; - chain_id_type get_chain_id()const; - dynamic_global_property_object get_dynamic_global_properties()const; - global_betting_statistics_object get_global_betting_statistics() const; + // Globals + chain_property_object get_chain_properties() const; + global_property_object get_global_properties() const; + fc::variant_object get_config() const; + chain_id_type get_chain_id() const; + dynamic_global_property_object get_dynamic_global_properties() const; + global_betting_statistics_object get_global_betting_statistics() const; - // Keys - vector> get_key_references( vector key )const; - bool is_public_key_registered(string public_key) const; + // Keys + vector> get_key_references(vector key) const; + bool is_public_key_registered(string public_key) const; - // Accounts - account_id_type get_account_id_from_string(const std::string& name_or_id)const; - vector> get_accounts(const vector& account_names_or_ids)const; - std::map get_full_accounts( const vector& names_or_ids, bool subscribe ); - optional get_account_by_name( string name )const; - vector get_account_references( const std::string account_id_or_name )const; - vector> lookup_account_names(const vector& account_names)const; - map lookup_accounts(const string& lower_bound_name, uint32_t limit)const; - uint64_t get_account_count()const; + // Accounts + account_id_type get_account_id_from_string(const std::string &name_or_id) const; + vector> get_accounts(const vector &account_names_or_ids) const; + std::map get_full_accounts(const vector &names_or_ids, bool subscribe); + optional get_account_by_name(string name) const; + vector get_account_references(const std::string account_id_or_name) const; + vector> lookup_account_names(const vector &account_names) const; + map lookup_accounts(const string &lower_bound_name, uint32_t limit) const; + uint64_t get_account_count() const; - // Balances - vector get_account_balances(const std::string& account_name_or_id, const flat_set& assets)const; - vector get_balance_objects( const vector
& addrs )const; - vector get_vested_balances( const vector& objs )const; - vector get_vesting_balances( const std::string account_id_or_name )const; + // Balances + vector get_account_balances(const std::string &account_name_or_id, const flat_set &assets) const; + vector get_balance_objects(const vector
&addrs) const; + vector get_vested_balances(const vector &objs) const; + vector get_vesting_balances(const std::string account_id_or_name) const; - // Assets - asset_id_type get_asset_id_from_string(const std::string& symbol_or_id)const; - vector> get_assets(const vector& asset_symbols_or_ids)const; - // helper function - vector> get_assets( const vector& asset_ids )const; - vector list_assets(const string& lower_bound_symbol, uint32_t limit)const; - vector> lookup_asset_symbols(const vector& symbols_or_ids)const; - uint64_t get_asset_count()const; + // Assets + asset_id_type get_asset_id_from_string(const std::string &symbol_or_id) const; + vector> get_assets(const vector &asset_symbols_or_ids) const; + // helper function + vector> get_assets(const vector &asset_ids) const; + vector list_assets(const string &lower_bound_symbol, uint32_t limit) const; + vector> lookup_asset_symbols(const vector &symbols_or_ids) const; + uint64_t get_asset_count() const; - // Peerplays - vector list_sports() const; - vector list_event_groups(sport_id_type sport_id) const; - vector list_events_in_group(event_group_id_type event_group_id) const; - vector list_betting_market_groups(event_id_type) const; - vector list_betting_markets(betting_market_group_id_type) const; - vector get_unmatched_bets_for_bettor(betting_market_id_type, account_id_type) const; - vector get_all_unmatched_bets_for_bettor(account_id_type) const; + // Peerplays + vector list_sports() const; + vector list_event_groups(sport_id_type sport_id) const; + vector list_events_in_group(event_group_id_type event_group_id) const; + vector list_betting_market_groups(event_id_type) const; + vector list_betting_markets(betting_market_group_id_type) const; + vector get_unmatched_bets_for_bettor(betting_market_id_type, account_id_type) const; + vector get_all_unmatched_bets_for_bettor(account_id_type) const; - // Lottery Assets - vector get_lotteries( asset_id_type stop = asset_id_type(), - unsigned limit = 100, - asset_id_type start = asset_id_type() )const; - vector get_account_lotteries( account_id_type issuer, - asset_id_type stop, - unsigned limit, - asset_id_type start )const; - asset get_lottery_balance( asset_id_type lottery_id )const; - sweeps_vesting_balance_object get_sweeps_vesting_balance_object( account_id_type account )const; - asset get_sweeps_vesting_balance_available_for_claim( account_id_type account )const; + // Lottery Assets + vector get_lotteries(asset_id_type stop = asset_id_type(), + unsigned limit = 100, + asset_id_type start = asset_id_type()) const; + vector get_account_lotteries(account_id_type issuer, + asset_id_type stop, + unsigned limit, + asset_id_type start) const; + asset get_lottery_balance(asset_id_type lottery_id) const; + sweeps_vesting_balance_object get_sweeps_vesting_balance_object(account_id_type account) const; + asset get_sweeps_vesting_balance_available_for_claim(account_id_type account) const; - // Markets / feeds - vector get_limit_orders( const asset_id_type a, const asset_id_type b, const uint32_t limit )const; - vector get_limit_orders( const std::string& a, const std::string& b, const uint32_t limit)const; - vector get_call_orders(const std::string& a, uint32_t limit)const; - vector get_settle_orders(const std::string& a, uint32_t limit)const; - vector get_margin_positions( const std::string account_id_or_name )const; - void subscribe_to_market(std::function 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; - vector get_trade_history( const string& base, const string& quote, fc::time_point_sec start, fc::time_point_sec stop, unsigned limit = 100 )const; + // Markets / feeds + vector get_limit_orders(const asset_id_type a, const asset_id_type b, const uint32_t limit) const; + vector get_limit_orders(const std::string &a, const std::string &b, const uint32_t limit) const; + vector get_call_orders(const std::string &a, uint32_t limit) const; + vector get_settle_orders(const std::string &a, uint32_t limit) const; + vector get_margin_positions(const std::string account_id_or_name) const; + void subscribe_to_market(std::function 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 "e) const; + market_volume get_24_volume(const string &base, const string "e) const; + order_book get_order_book(const string &base, const string "e, unsigned limit = 50) const; + vector get_trade_history(const string &base, const string "e, fc::time_point_sec start, fc::time_point_sec stop, unsigned limit = 100) const; - // Witnesses - vector> get_witnesses(const vector& witness_ids)const; - fc::optional get_witness_by_account(const std::string account_id_or_name)const; - map lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const; - uint64_t get_witness_count()const; + // Witnesses + vector> get_witnesses(const vector &witness_ids) const; + fc::optional get_witness_by_account(const std::string account_id_or_name) const; + map lookup_witness_accounts(const string &lower_bound_name, uint32_t limit) const; + uint64_t get_witness_count() const; - // Committee members - vector> get_committee_members(const vector& committee_member_ids)const; - fc::optional get_committee_member_by_account(const std::string account_id_or_name)const; - map lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const; + // Committee members + vector> get_committee_members(const vector &committee_member_ids) const; + fc::optional get_committee_member_by_account(const std::string account_id_or_name) const; + map lookup_committee_member_accounts(const string &lower_bound_name, uint32_t limit) const; - // SON members - vector> get_sons(const vector& son_ids)const; - fc::optional get_son_by_account(account_id_type account)const; - map lookup_son_accounts(const string& lower_bound_name, uint32_t limit)const; - uint64_t get_son_count()const; + // SON members + vector> get_sons(const vector &son_ids) const; + fc::optional get_son_by_account(account_id_type account) const; + map lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const; + uint64_t get_son_count() const; - // SON wallets - optional get_active_son_wallet(); - optional get_son_wallet_by_time_point(time_point_sec time_point); - vector> get_son_wallets(uint32_t limit); + // SON wallets + optional get_active_son_wallet(); + optional get_son_wallet_by_time_point(time_point_sec time_point); + vector> get_son_wallets(uint32_t limit); - // Sidechain addresses - vector> get_sidechain_addresses(const vector& sidechain_address_ids)const; - vector> get_sidechain_addresses_by_account(account_id_type account)const; - vector> get_sidechain_addresses_by_sidechain(sidechain_type sidechain)const; - fc::optional get_sidechain_address_by_account_and_sidechain(account_id_type account, sidechain_type sidechain)const; - uint64_t get_sidechain_addresses_count()const; + // Sidechain addresses + vector> get_sidechain_addresses(const vector &sidechain_address_ids) const; + vector> get_sidechain_addresses_by_account(account_id_type account) const; + vector> get_sidechain_addresses_by_sidechain(sidechain_type sidechain) const; + fc::optional get_sidechain_address_by_account_and_sidechain(account_id_type account, sidechain_type sidechain) const; + uint64_t get_sidechain_addresses_count() const; - // Votes - vector lookup_vote_ids( const vector& votes )const; + // Votes + vector lookup_vote_ids(const vector &votes) const; - // Authority / validation - std::string get_transaction_hex(const signed_transaction& trx)const; - set get_required_signatures( const signed_transaction& trx, const flat_set& available_keys )const; - set get_potential_signatures( const signed_transaction& trx )const; - set
get_potential_address_signatures( const signed_transaction& trx )const; - bool verify_authority( const signed_transaction& trx )const; - bool verify_account_authority( const string& name_or_id, const flat_set& signers )const; - processed_transaction validate_transaction( const signed_transaction& trx )const; - vector< fc::variant > get_required_fees( const vector& ops, const std::string& asset_id_or_symbol )const; + // Authority / validation + std::string get_transaction_hex(const signed_transaction &trx) const; + set get_required_signatures(const signed_transaction &trx, const flat_set &available_keys) const; + set get_potential_signatures(const signed_transaction &trx) const; + set
get_potential_address_signatures(const signed_transaction &trx) const; + bool verify_authority(const signed_transaction &trx) const; + bool verify_account_authority(const string &name_or_id, const flat_set &signers) const; + processed_transaction validate_transaction(const signed_transaction &trx) const; + vector get_required_fees(const vector &ops, const std::string &asset_id_or_symbol) const; - // Proposed transactions - vector get_proposed_transactions( const std::string account_id_or_name )const; + // Proposed transactions + vector get_proposed_transactions(const std::string account_id_or_name) const; - // Blinded balances - vector get_blinded_balances( const flat_set& commitments )const; + // Blinded balances + vector get_blinded_balances(const flat_set &commitments) const; - // Tournaments - vector get_tournaments_in_state(tournament_state state, uint32_t limit) const; - vector get_tournaments(tournament_id_type stop, unsigned limit, tournament_id_type start); - vector get_tournaments_by_state(tournament_id_type stop, unsigned limit, tournament_id_type start, tournament_state state); - vector get_registered_tournaments(account_id_type account_filter, uint32_t limit) const; + // Tournaments + vector get_tournaments_in_state(tournament_state state, uint32_t limit) const; + vector get_tournaments(tournament_id_type stop, unsigned limit, tournament_id_type start); + vector get_tournaments_by_state(tournament_id_type stop, unsigned limit, tournament_id_type start, tournament_state state); + vector get_registered_tournaments(account_id_type account_filter, uint32_t limit) const; - // gpos - gpos_info get_gpos_info(const account_id_type account) const; + // gpos + gpos_info get_gpos_info(const account_id_type account) const; - // rbac - vector get_custom_permissions(const account_id_type account) const; - fc::optional get_custom_permission_by_name(const account_id_type account, const string& permission_name) const; - vector get_custom_account_authorities(const account_id_type account) const; - vector get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const; - vector get_custom_account_authorities_by_permission_name(const account_id_type account, const string& permission_name) const; - vector get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const; + // rbac + vector get_custom_permissions(const account_id_type account) const; + fc::optional get_custom_permission_by_name(const account_id_type account, const string &permission_name) const; + vector get_custom_account_authorities(const account_id_type account) const; + vector get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const; + vector get_custom_account_authorities_by_permission_name(const account_id_type account, const string &permission_name) const; + vector get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const; - // NFT - uint64_t nft_get_balance(const account_id_type owner) const; - optional nft_owner_of(const nft_id_type token_id) const; - optional nft_get_approved(const nft_id_type token_id) const; - bool nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const; - string nft_get_name(const nft_metadata_id_type nft_metadata_id) const; - string nft_get_symbol(const nft_metadata_id_type nft_metadata_id) const; - string nft_get_token_uri(const nft_id_type token_id) const; - uint64_t nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const; - nft_object nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const; - nft_object nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const; - vector nft_get_all_tokens() const; - vector nft_get_tokens_by_owner(const account_id_type owner) const; + // NFT + uint64_t nft_get_balance(const account_id_type owner) const; + optional nft_owner_of(const nft_id_type token_id) const; + optional nft_get_approved(const nft_id_type token_id) const; + bool nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const; + string nft_get_name(const nft_metadata_id_type nft_metadata_id) const; + string nft_get_symbol(const nft_metadata_id_type nft_metadata_id) const; + string nft_get_token_uri(const nft_id_type token_id) const; + uint64_t nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const; + nft_object nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const; + nft_object nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const; + vector nft_get_all_tokens() const; + vector nft_get_tokens_by_owner(const account_id_type owner) const; - // Marketplace - vector list_offers(const offer_id_type lower_id, uint32_t limit) const; - vector list_sell_offers(const offer_id_type lower_id, uint32_t limit) const; - vector list_buy_offers(const offer_id_type lower_id, uint32_t limit) const; - vector list_offer_history(const offer_history_id_type lower_id, uint32_t limit) const; - vector get_offers_by_issuer(const offer_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const; - vector get_offers_by_item(const offer_id_type lower_id, const nft_id_type item, uint32_t limit) const; - vector get_offer_history_by_issuer(const offer_history_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const; - vector get_offer_history_by_item(const offer_history_id_type lower_id, const nft_id_type item, uint32_t limit) const; - vector get_offer_history_by_bidder(const offer_history_id_type lower_id, const account_id_type bidder_account_id, uint32_t limit) const; + // Marketplace + vector list_offers(const offer_id_type lower_id, uint32_t limit) const; + vector list_sell_offers(const offer_id_type lower_id, uint32_t limit) const; + vector list_buy_offers(const offer_id_type lower_id, uint32_t limit) const; + vector list_offer_history(const offer_history_id_type lower_id, uint32_t limit) const; + vector get_offers_by_issuer(const offer_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const; + vector get_offers_by_item(const offer_id_type lower_id, const nft_id_type item, uint32_t limit) const; + vector get_offer_history_by_issuer(const offer_history_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const; + vector get_offer_history_by_item(const offer_history_id_type lower_id, const nft_id_type item, uint32_t limit) const; + vector get_offer_history_by_bidder(const offer_history_id_type lower_id, const account_id_type bidder_account_id, uint32_t limit) const; - // Account Role - vector get_account_roles_by_owner(account_id_type owner) const; + uint32_t api_limit_get_lower_bound_symbol = 100; + uint32_t api_limit_get_limit_orders = 300; + uint32_t api_limit_get_limit_orders_by_account = 101; + uint32_t api_limit_get_order_book = 50; + uint32_t api_limit_all_offers_count = 100; + uint32_t api_limit_lookup_accounts = 1000; + uint32_t api_limit_lookup_witness_accounts = 1000; + uint32_t api_limit_lookup_committee_member_accounts = 1000; + uint32_t api_limit_get_trade_history = 100; + uint32_t api_limit_get_trade_history_by_sequence = 100; + + // Account Role + vector get_account_roles_by_owner(account_id_type owner) 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 - void subscribe_to_item( const T& i )const - { - auto vec = fc::raw::pack(i); - if( !_subscribe_callback ) - return; + 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 + void subscribe_to_item(const T &i) const { + auto vec = fc::raw::pack(i); + if (!_subscribe_callback) + return; - if( !is_subscribed_to_item(i) ) - { - _subscribe_filter.insert( vec.data(), vec.size() );//(vecconst char*)&i, sizeof(i) ); - } + if (!is_subscribed_to_item(i)) { + _subscribe_filter.insert(vec.data(), vec.size()); //(vecconst char*)&i, sizeof(i) ); } + } - template - bool is_subscribed_to_item( const T& i )const - { - if( !_subscribe_callback ) - return false; + template + bool is_subscribed_to_item(const T &i) const { + if (!_subscribe_callback) + return false; - return _subscribe_filter.contains( i ); + return _subscribe_filter.contains(i); + } + + bool is_impacted_account(const flat_set &accounts) { + if (!_subscribed_accounts.size() || !accounts.size()) + return false; + + return std::any_of(accounts.begin(), accounts.end(), [this](const account_id_type &account) { + return _subscribed_accounts.find(account) != _subscribed_accounts.end(); + }); + } + + template + void enqueue_if_subscribed_to_market(const object *obj, market_queue_type &queue, bool full_object = true) { + const T *order = dynamic_cast(obj); + FC_ASSERT(order != nullptr); + + auto market = order->get_market(); + + auto sub = _market_subscriptions.find(market); + if (sub != _market_subscriptions.end()) { + queue[market].emplace_back(full_object ? obj->to_variant() : fc::variant(obj->id, 1)); } + } - bool is_impacted_account( const flat_set& accounts) - { - if( !_subscribed_accounts.size() || !accounts.size() ) - return false; + void broadcast_updates(const vector &updates); + void broadcast_market_updates(const market_queue_type &queue); + void handle_object_changed(bool force_notify, bool full_object, const vector &ids, const flat_set &impacted_accounts, std::function find_object); - return std::any_of(accounts.begin(), accounts.end(), [this](const account_id_type& account) { - return _subscribed_accounts.find(account) != _subscribed_accounts.end(); - }); - } + /** called every time a block is applied to report the objects that were changed */ + void on_objects_new(const vector &ids, const flat_set &impacted_accounts); + void on_objects_changed(const vector &ids, const flat_set &impacted_accounts); + void on_objects_removed(const vector &ids, const vector &objs, const flat_set &impacted_accounts); + void on_applied_block(); - template - void enqueue_if_subscribed_to_market(const object* obj, market_queue_type& queue, bool full_object=true) - { - const T* order = dynamic_cast(obj); - FC_ASSERT( order != nullptr); + bool _notify_remove_create = false; + mutable fc::bloom_filter _subscribe_filter; + std::set _subscribed_accounts; + std::function _subscribe_callback; + std::function _pending_trx_callback; + std::function _block_applied_callback; - auto market = order->get_market(); - - auto sub = _market_subscriptions.find( market ); - if( sub != _market_subscriptions.end() ) { - queue[market].emplace_back( full_object ? obj->to_variant() : fc::variant(obj->id, 1) ); - } - } - - void broadcast_updates( const vector& updates ); - void broadcast_market_updates( const market_queue_type& queue); - void handle_object_changed(bool force_notify, bool full_object, const vector& ids, const flat_set& impacted_accounts, std::function find_object); - - /** called every time a block is applied to report the objects that were changed */ - void on_objects_new(const vector& ids, const flat_set& impacted_accounts); - void on_objects_changed(const vector& ids, const flat_set& impacted_accounts); - void on_objects_removed(const vector& ids, const vector& objs, const flat_set& impacted_accounts); - void on_applied_block(); - - bool _notify_remove_create = false; - mutable fc::bloom_filter _subscribe_filter; - std::set _subscribed_accounts; - std::function _subscribe_callback; - std::function _pending_trx_callback; - std::function _block_applied_callback; - - boost::signals2::scoped_connection _new_connection; - boost::signals2::scoped_connection _change_connection; - boost::signals2::scoped_connection _removed_connection; - boost::signals2::scoped_connection _applied_block_connection; - boost::signals2::scoped_connection _pending_trx_connection; - map< pair, std::function > _market_subscriptions; - graphene::chain::database& _db; + boost::signals2::scoped_connection _new_connection; + boost::signals2::scoped_connection _change_connection; + boost::signals2::scoped_connection _removed_connection; + boost::signals2::scoped_connection _applied_block_connection; + boost::signals2::scoped_connection _pending_trx_connection; + map, std::function> _market_subscriptions; + graphene::chain::database &_db; }; ////////////////////////////////////////////////////////////////////// @@ -321,33 +326,37 @@ class database_api_impl : public std::enable_shared_from_this // // ////////////////////////////////////////////////////////////////////// -database_api::database_api( graphene::chain::database& db ) - : my( new database_api_impl( db ) ) {} - -database_api::~database_api() {} - -database_api_impl::database_api_impl( graphene::chain::database& db ):_db(db) -{ - wlog("creating database api ${x}", ("x",int64_t(this)) ); - _new_connection = _db.new_objects.connect([this](const vector& ids, const flat_set& impacted_accounts) { - on_objects_new(ids, impacted_accounts); - }); - _change_connection = _db.changed_objects.connect([this](const vector& ids, const flat_set& impacted_accounts) { - on_objects_changed(ids, impacted_accounts); - }); - _removed_connection = _db.removed_objects.connect([this](const vector& ids, const vector& objs, const flat_set& impacted_accounts) { - on_objects_removed(ids, objs, impacted_accounts); - }); - _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, GRAPHENE_MAX_NESTED_OBJECTS) ); - }); +database_api::database_api(graphene::chain::database &db) : + my(new database_api_impl(db)) { } -database_api_impl::~database_api_impl() -{ - elog("freeing database api ${x}", ("x",int64_t(this)) ); +database_api::~database_api() { +} + +database_api_impl::database_api_impl(graphene::chain::database &db) : + _db(db) { + wlog("creating database api ${x}", ("x", int64_t(this))); + _new_connection = _db.new_objects.connect([this](const vector &ids, const flat_set &impacted_accounts) { + on_objects_new(ids, impacted_accounts); + }); + _change_connection = _db.changed_objects.connect([this](const vector &ids, const flat_set &impacted_accounts) { + on_objects_changed(ids, impacted_accounts); + }); + _removed_connection = _db.removed_objects.connect([this](const vector &ids, const vector &objs, const flat_set &impacted_accounts) { + on_objects_removed(ids, objs, impacted_accounts); + }); + _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, GRAPHENE_MAX_NESTED_OBJECTS)); + }); +} + +database_api_impl::~database_api_impl() { + elog("freeing database api ${x}", ("x", int64_t(this))); } ////////////////////////////////////////////////////////////////////// @@ -356,20 +365,19 @@ database_api_impl::~database_api_impl() // // ////////////////////////////////////////////////////////////////////// -fc::variants database_api::get_objects(const vector& ids)const -{ - return my->get_objects( ids ); +fc::variants database_api::get_objects(const vector &ids) const { + return my->get_objects(ids); } -fc::variants database_api_impl::get_objects(const vector& ids)const -{ - if( _subscribe_callback ) { - for( auto id : ids ) - { - if( id.type() == operation_history_object_type && id.space() == protocol_ids ) continue; - if( id.type() == impl_account_transaction_history_object_type && id.space() == implementation_ids ) continue; +fc::variants database_api_impl::get_objects(const vector &ids) const { + if (_subscribe_callback) { + for (auto id : ids) { + if (id.type() == operation_history_object_type && id.space() == protocol_ids) + continue; + if (id.type() == impl_account_transaction_history_object_type && id.space() == implementation_ids) + continue; - this->subscribe_to_item( id ); + this->subscribe_to_item(id); } } @@ -378,10 +386,10 @@ fc::variants database_api_impl::get_objects(const vector& ids)co std::transform(ids.begin(), ids.end(), std::back_inserter(result), [this](object_id_type id) -> fc::variant { - if(auto obj = _db.find_object(id)) - return obj->to_variant(); - return {}; - }); + if (auto obj = _db.find_object(id)) + return obj->to_variant(); + return {}; + }); return result; } @@ -392,54 +400,46 @@ fc::variants database_api_impl::get_objects(const vector& ids)co // // ////////////////////////////////////////////////////////////////////// -void database_api::set_subscribe_callback( std::function cb, bool notify_remove_create ) -{ - my->set_subscribe_callback( cb, notify_remove_create ); +void database_api::set_subscribe_callback(std::function cb, bool notify_remove_create) { + my->set_subscribe_callback(cb, notify_remove_create); } -void database_api_impl::set_subscribe_callback( std::function cb, bool notify_remove_create ) -{ +void database_api_impl::set_subscribe_callback(std::function cb, bool notify_remove_create) { //edump((clear_filter)); _subscribe_callback = cb; _notify_remove_create = notify_remove_create; _subscribed_accounts.clear(); static fc::bloom_parameters param; - param.projected_element_count = 10000; - param.false_positive_probability = 1.0/100; - param.maximum_size = 1024*8*8*2; + param.projected_element_count = 10000; + param.false_positive_probability = 1.0 / 100; + param.maximum_size = 1024 * 8 * 8 * 2; param.compute_optimal_parameters(); _subscribe_filter = fc::bloom_filter(param); } -void database_api::set_pending_transaction_callback( std::function cb ) -{ - my->set_pending_transaction_callback( cb ); +void database_api::set_pending_transaction_callback(std::function cb) { + my->set_pending_transaction_callback(cb); } -void database_api_impl::set_pending_transaction_callback( std::function cb ) -{ +void database_api_impl::set_pending_transaction_callback(std::function cb) { _pending_trx_callback = cb; } -void database_api::set_block_applied_callback( std::function cb ) -{ - my->set_block_applied_callback( cb ); +void database_api::set_block_applied_callback(std::function cb) { + my->set_block_applied_callback(cb); } -void database_api_impl::set_block_applied_callback( std::function cb ) -{ +void database_api_impl::set_block_applied_callback(std::function cb) { _block_applied_callback = cb; } -void database_api::cancel_all_subscriptions() -{ +void database_api::cancel_all_subscriptions() { my->cancel_all_subscriptions(); } -void database_api_impl::cancel_all_subscriptions() -{ - set_subscribe_callback( std::function(), true); +void database_api_impl::cancel_all_subscriptions() { + set_subscribe_callback(std::function(), true); _market_subscriptions.clear(); } @@ -449,77 +449,65 @@ void database_api_impl::cancel_all_subscriptions() // // ////////////////////////////////////////////////////////////////////// -optional database_api::get_block_header(uint32_t block_num)const -{ - return my->get_block_header( block_num ); +optional database_api::get_block_header(uint32_t block_num) const { + return my->get_block_header(block_num); } -optional database_api_impl::get_block_header(uint32_t block_num) const -{ +optional database_api_impl::get_block_header(uint32_t block_num) const { auto result = _db.fetch_block_by_number(block_num); - if(result) + if (result) return *result; return {}; } -map> database_api::get_block_header_batch(const vector block_nums)const -{ - return my->get_block_header_batch( block_nums ); +map> database_api::get_block_header_batch(const vector block_nums) const { + return my->get_block_header_batch(block_nums); } -map> database_api_impl::get_block_header_batch(const vector block_nums) const -{ +map> database_api_impl::get_block_header_batch(const vector block_nums) const { map> results; - for (const uint32_t block_num : block_nums) - { + for (const uint32_t block_num : block_nums) { results[block_num] = get_block_header(block_num); } return results; } -optional database_api::get_block(uint32_t block_num)const -{ - return my->get_block( block_num ); +optional database_api::get_block(uint32_t block_num) const { + return my->get_block(block_num); } -optional database_api_impl::get_block(uint32_t block_num)const -{ +optional database_api_impl::get_block(uint32_t block_num) const { return _db.fetch_block_by_number(block_num); } -vector> database_api::get_blocks(uint32_t block_num_from, uint32_t block_num_to)const -{ - return my->get_blocks( block_num_from, block_num_to ); +vector> database_api::get_blocks(uint32_t block_num_from, uint32_t block_num_to) const { + return my->get_blocks(block_num_from, block_num_to); } -vector> database_api_impl::get_blocks(uint32_t block_num_from, uint32_t block_num_to)const -{ - FC_ASSERT( block_num_to >= block_num_from && block_num_to - block_num_from <= 100, "Total blocks to be returned should be less than 100"); +vector> database_api_impl::get_blocks(uint32_t block_num_from, uint32_t block_num_to) const { + FC_ASSERT(block_num_to >= block_num_from && block_num_to - block_num_from <= 100, "Total blocks to be returned should be less than 100"); vector> res; - for(uint32_t block_num=block_num_from; block_num<=block_num_to; block_num++) { + for (uint32_t block_num = block_num_from; block_num <= block_num_to; block_num++) { res.push_back(_db.fetch_block_by_number(block_num)); } return res; } -processed_transaction database_api::get_transaction( uint32_t block_num, uint32_t trx_in_block )const -{ - return my->get_transaction( block_num, trx_in_block ); +processed_transaction database_api::get_transaction(uint32_t block_num, uint32_t trx_in_block) const { + return my->get_transaction(block_num, trx_in_block); } -optional database_api::get_recent_transaction_by_id( const transaction_id_type& id )const -{ +optional database_api::get_recent_transaction_by_id(const transaction_id_type &id) const { try { - return my->_db.get_recent_transaction( id ); - } catch ( ... ) { + return my->_db.get_recent_transaction(id); + } catch (...) { return optional(); } } -processed_transaction database_api_impl::get_transaction(uint32_t block_num, uint32_t trx_num)const -{ +processed_transaction database_api_impl::get_transaction(uint32_t block_num, uint32_t trx_num) const { auto opt_block = _db.fetch_block_by_number(block_num); - FC_ASSERT( opt_block ); - FC_ASSERT( opt_block->transactions.size() > trx_num ); + FC_ASSERT(opt_block); + FC_ASSERT(opt_block->transactions.size() > trx_num); return opt_block->transactions[trx_num]; } @@ -529,166 +517,145 @@ processed_transaction database_api_impl::get_transaction(uint32_t block_num, uin // // ////////////////////////////////////////////////////////////////////// -chain_property_object database_api::get_chain_properties()const -{ +chain_property_object database_api::get_chain_properties() const { return my->get_chain_properties(); } -chain_property_object database_api_impl::get_chain_properties()const -{ +chain_property_object database_api_impl::get_chain_properties() const { return _db.get(chain_property_id_type()); } -global_property_object database_api::get_global_properties()const -{ +global_property_object database_api::get_global_properties() const { return my->get_global_properties(); } -global_property_object database_api_impl::get_global_properties()const -{ +global_property_object database_api_impl::get_global_properties() const { return _db.get(global_property_id_type()); } -fc::variant_object database_api::get_config()const -{ +fc::variant_object database_api::get_config() const { return my->get_config(); } -fc::variant_object database_api_impl::get_config()const -{ +fc::variant_object database_api_impl::get_config() const { return graphene::chain::get_config(); } -chain_id_type database_api::get_chain_id()const -{ +chain_id_type database_api::get_chain_id() const { return my->get_chain_id(); } -chain_id_type database_api_impl::get_chain_id()const -{ +chain_id_type database_api_impl::get_chain_id() const { return _db.get_chain_id(); } -dynamic_global_property_object database_api::get_dynamic_global_properties()const -{ +dynamic_global_property_object database_api::get_dynamic_global_properties() const { return my->get_dynamic_global_properties(); } -dynamic_global_property_object database_api_impl::get_dynamic_global_properties()const -{ +dynamic_global_property_object database_api_impl::get_dynamic_global_properties() const { return _db.get(dynamic_global_property_id_type()); } -global_betting_statistics_object database_api::get_global_betting_statistics() const -{ - return my->get_global_betting_statistics(); +global_betting_statistics_object database_api::get_global_betting_statistics() const { + return my->get_global_betting_statistics(); } -global_betting_statistics_object database_api_impl::get_global_betting_statistics() const -{ +global_betting_statistics_object database_api_impl::get_global_betting_statistics() const { return _db.get(global_betting_statistics_id_type()); } - ////////////////////////////////////////////////////////////////////// // // // Keys // // // ////////////////////////////////////////////////////////////////////// -vector> database_api::get_key_references( vector key )const -{ - return my->get_key_references( key ); +vector> database_api::get_key_references(vector key) const { + return my->get_key_references(key); } /** * @return all accounts that referr to the key or account id in their owner or active authorities. */ -vector> database_api_impl::get_key_references( vector keys )const -{ - wdump( (keys) ); +vector> database_api_impl::get_key_references(vector keys) const { + wdump((keys)); - const auto& idx = _db.get_index_type(); - const auto& aidx = dynamic_cast(idx); - const auto& refs = aidx.get_secondary_index(); + const auto &idx = _db.get_index_type(); + const auto &aidx = dynamic_cast(idx); + const auto &refs = aidx.get_secondary_index(); - vector< vector > final_result; + vector> final_result; final_result.reserve(keys.size()); - for( auto& key : keys ) - { + for (auto &key : keys) { - address a1( pts_address(key, false, 56) ); - address a2( pts_address(key, true, 56) ); - address a3( pts_address(key, false, 0) ); - address a4( pts_address(key, true, 0) ); - address a5( key ); + address a1(pts_address(key, false, 56)); + address a2(pts_address(key, true, 56)); + address a3(pts_address(key, false, 0)); + address a4(pts_address(key, true, 0)); + address a5(key); - subscribe_to_item( key ); - subscribe_to_item( a1 ); - subscribe_to_item( a2 ); - subscribe_to_item( a3 ); - subscribe_to_item( a4 ); - subscribe_to_item( a5 ); + subscribe_to_item(key); + subscribe_to_item(a1); + subscribe_to_item(a2); + subscribe_to_item(a3); + subscribe_to_item(a4); + subscribe_to_item(a5); vector result; - for( auto& a : {a1,a2,a3,a4,a5} ) - { - auto itr = refs.account_to_address_memberships.find(a); - if( itr != refs.account_to_address_memberships.end() ) - { - result.reserve( result.size() + itr->second.size() ); - for( auto item : itr->second ) - { - wdump((a)(item)(item(_db).name)); - result.push_back(item); - } - } + for (auto &a : {a1, a2, a3, a4, a5}) { + auto itr = refs.account_to_address_memberships.find(a); + if (itr != refs.account_to_address_memberships.end()) { + result.reserve(result.size() + itr->second.size()); + for (auto item : itr->second) { + wdump((a)(item)(item(_db).name)); + result.push_back(item); + } + } } auto itr = refs.account_to_key_memberships.find(key); - if( itr != refs.account_to_key_memberships.end() ) - { - result.reserve( result.size() + itr->second.size() ); - for( auto item : itr->second ) result.push_back(item); + if (itr != refs.account_to_key_memberships.end()) { + result.reserve(result.size() + itr->second.size()); + for (auto item : itr->second) + result.push_back(item); } - final_result.emplace_back( std::move(result) ); + final_result.emplace_back(std::move(result)); } - for( auto i : final_result ) + for (auto i : final_result) subscribe_to_item(i); return final_result; } -bool database_api::is_public_key_registered(string public_key) const -{ - return my->is_public_key_registered(public_key); +bool database_api::is_public_key_registered(string public_key) const { + return my->is_public_key_registered(public_key); } -bool database_api_impl::is_public_key_registered(string public_key) const -{ - // Short-circuit - if (public_key.empty()) { - return false; - } +bool database_api_impl::is_public_key_registered(string public_key) const { + // Short-circuit + if (public_key.empty()) { + return false; + } - // Search among all keys using an existing map of *current* account keys - public_key_type key; - try { - key = public_key_type(public_key); - } catch ( ... ) { - // An invalid public key was detected - return false; - } - const auto& idx = _db.get_index_type(); - const auto& aidx = dynamic_cast(idx); - const auto& refs = aidx.get_secondary_index(); - auto itr = refs.account_to_key_memberships.find(key); - bool is_known = itr != refs.account_to_key_memberships.end(); + // Search among all keys using an existing map of *current* account keys + public_key_type key; + try { + key = public_key_type(public_key); + } catch (...) { + // An invalid public key was detected + return false; + } + const auto &idx = _db.get_index_type(); + const auto &aidx = dynamic_cast(idx); + const auto &refs = aidx.get_secondary_index(); + auto itr = refs.account_to_key_memberships.find(key); + bool is_known = itr != refs.account_to_key_memberships.end(); - return is_known; + return is_known; } ////////////////////////////////////////////////////////////////////// @@ -697,52 +664,46 @@ bool database_api_impl::is_public_key_registered(string public_key) const // // ////////////////////////////////////////////////////////////////////// -account_id_type database_api::get_account_id_from_string(const std::string& name_or_id)const -{ - return my->get_account_from_string( name_or_id )->id; +account_id_type database_api::get_account_id_from_string(const std::string &name_or_id) const { + return my->get_account_from_string(name_or_id)->id; } -vector> database_api::get_accounts(const vector& account_names_or_ids)const -{ - return my->get_accounts( account_names_or_ids ); +vector> database_api::get_accounts(const vector &account_names_or_ids) const { + return my->get_accounts(account_names_or_ids); } -vector> database_api_impl::get_accounts(const vector& account_names_or_ids)const -{ - vector> result; result.reserve(account_names_or_ids.size()); +vector> database_api_impl::get_accounts(const vector &account_names_or_ids) const { + vector> 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 { - const account_object *account = get_account_from_string(id_or_name, false); - if(account == nullptr) - return {}; + const account_object *account = get_account_from_string(id_or_name, false); + if (account == nullptr) + return {}; - subscribe_to_item( account->id ); - return *account; - }); + subscribe_to_item(account->id); + return *account; + }); return result; } -std::map database_api::get_full_accounts( const vector& names_or_ids, bool subscribe ) -{ - return my->get_full_accounts( names_or_ids, subscribe ); +std::map database_api::get_full_accounts(const vector &names_or_ids, bool subscribe) { + return my->get_full_accounts(names_or_ids, subscribe); } -std::map database_api_impl::get_full_accounts( const vector& names_or_ids, bool subscribe) -{ - const auto& proposal_idx = _db.get_index_type(); - const auto& pidx = dynamic_cast(proposal_idx); - const auto& proposals_by_account = pidx.get_secondary_index(); +std::map database_api_impl::get_full_accounts(const vector &names_or_ids, bool subscribe) { + const auto &proposal_idx = _db.get_index_type(); + const auto &pidx = dynamic_cast(proposal_idx); + const auto &proposals_by_account = pidx.get_secondary_index(); std::map results; - for (const std::string& account_name_or_id : names_or_ids) - { - const account_object* account = nullptr; + 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, 1).as(1)); - else - { - const auto& idx = _db.get_index_type().indices().get(); + else { + const auto &idx = _db.get_index_type().indices().get(); auto itr = idx.find(account_name_or_id); if (itr != idx.end()) account = &*itr; @@ -750,11 +711,10 @@ std::map database_api_impl::get_full_accounts( const if (account == nullptr) continue; - if( subscribe ) - { - FC_ASSERT( std::distance(_subscribed_accounts.begin(), _subscribed_accounts.end()) <= 100 ); - _subscribed_accounts.insert( account->get_id() ); - subscribe_to_item( account->id ); + if (subscribe) { + FC_ASSERT(std::distance(_subscribed_accounts.begin(), _subscribed_accounts.end()) <= 100); + _subscribed_accounts.insert(account->get_id()); + subscribe_to_item(account->id); } full_account acnt; @@ -763,67 +723,64 @@ std::map database_api_impl::get_full_accounts( const acnt.registrar_name = account->registrar(_db).name; acnt.referrer_name = account->referrer(_db).name; acnt.lifetime_referrer_name = account->lifetime_referrer(_db).name; - acnt.votes = lookup_vote_ids( vector(account->options.votes.begin(),account->options.votes.end()) ); + acnt.votes = lookup_vote_ids(vector(account->options.votes.begin(), account->options.votes.end())); - if (account->cashback_vb) - { + if (account->cashback_vb) { acnt.cashback_balance = account->cashback_balance(_db); } // Add the account's proposals - auto required_approvals_itr = proposals_by_account._account_to_proposals.find( account->id ); - if( required_approvals_itr != proposals_by_account._account_to_proposals.end() ) - { - acnt.proposals.reserve( required_approvals_itr->second.size() ); - for( auto proposal_id : required_approvals_itr->second ) - acnt.proposals.push_back( proposal_id(_db) ); + auto required_approvals_itr = proposals_by_account._account_to_proposals.find(account->id); + if (required_approvals_itr != proposals_by_account._account_to_proposals.end()) { + acnt.proposals.reserve(required_approvals_itr->second.size()); + for (auto proposal_id : required_approvals_itr->second) + acnt.proposals.push_back(proposal_id(_db)); } - // Add the account's balances - 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 ); + const auto &balances = _db.get_index_type>().get_secondary_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().indices().get().equal_range(account->id); std::for_each(vesting_range.first, vesting_range.second, - [&acnt](const vesting_balance_object& balance) { + [&acnt](const vesting_balance_object &balance) { acnt.vesting_balances.emplace_back(balance); }); // Add the account's orders auto order_range = _db.get_index_type().indices().get().equal_range(account->id); std::for_each(order_range.first, order_range.second, - [&acnt] (const limit_order_object& order) { + [&acnt](const limit_order_object &order) { acnt.limit_orders.emplace_back(order); }); auto call_range = _db.get_index_type().indices().get().equal_range(account->id); std::for_each(call_range.first, call_range.second, - [&acnt] (const call_order_object& call) { + [&acnt](const call_order_object &call) { acnt.call_orders.emplace_back(call); }); auto settle_range = _db.get_index_type().indices().get().equal_range(account->id); std::for_each(settle_range.first, settle_range.second, - [&acnt] (const force_settlement_object& settle) { + [&acnt](const force_settlement_object &settle) { acnt.settle_orders.emplace_back(settle); }); // get assets issued by user auto asset_range = _db.get_index_type().indices().get().equal_range(account->id); std::for_each(asset_range.first, asset_range.second, - [&acnt] (const asset_object& asset) { + [&acnt](const asset_object &asset) { acnt.assets.emplace_back(asset.id); }); // get withdraws permissions auto withdraw_range = _db.get_index_type().indices().get().equal_range(account->id); std::for_each(withdraw_range.first, withdraw_range.second, - [&acnt] (const withdraw_permission_object& withdraw) { + [&acnt](const withdraw_permission_object &withdraw) { acnt.withdraws.emplace_back(withdraw); }); auto pending_payouts_range = - _db.get_index_type().indices().get().equal_range(boost::make_tuple(account->id)); + _db.get_index_type().indices().get().equal_range(boost::make_tuple(account->id)); std::copy(pending_payouts_range.first, pending_payouts_range.second, std::back_inserter(acnt.pending_dividend_payments)); @@ -832,90 +789,81 @@ std::map database_api_impl::get_full_accounts( const return results; } -optional database_api::get_account_by_name( string name )const -{ - return my->get_account_by_name( name ); +optional database_api::get_account_by_name(string name) const { + return my->get_account_by_name(name); } -optional database_api_impl::get_account_by_name( string name )const -{ - const auto& idx = _db.get_index_type().indices().get(); +optional database_api_impl::get_account_by_name(string name) const { + const auto &idx = _db.get_index_type().indices().get(); auto itr = idx.find(name); if (itr != idx.end()) return *itr; return optional(); } -vector database_api::get_account_references( const std::string account_id_or_name )const -{ - return my->get_account_references( account_id_or_name ); +vector database_api::get_account_references(const std::string account_id_or_name) const { + return my->get_account_references(account_id_or_name); } -vector database_api_impl::get_account_references( const std::string account_id_or_name )const -{ - const auto& idx = _db.get_index_type(); - const auto& aidx = dynamic_cast(idx); - const auto& refs = aidx.get_secondary_index(); +vector database_api_impl::get_account_references(const std::string account_id_or_name) const { + const auto &idx = _db.get_index_type(); + const auto &aidx = dynamic_cast(idx); + const auto &refs = aidx.get_secondary_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 result; - if( itr != refs.account_to_account_memberships.end() ) - { - result.reserve( itr->second.size() ); - for( auto item : itr->second ) result.push_back(item); + if (itr != refs.account_to_account_memberships.end()) { + result.reserve(itr->second.size()); + for (auto item : itr->second) + result.push_back(item); } return result; } -vector> database_api::lookup_account_names(const vector& account_names)const -{ - return my->lookup_account_names( account_names ); +vector> database_api::lookup_account_names(const vector &account_names) const { + return my->lookup_account_names(account_names); } -vector> database_api_impl::lookup_account_names(const vector& account_names)const -{ - const auto& accounts_by_name = _db.get_index_type().indices().get(); - vector > result; +vector> database_api_impl::lookup_account_names(const vector &account_names) const { + const auto &accounts_by_name = _db.get_index_type().indices().get(); + vector> result; result.reserve(account_names.size()); std::transform(account_names.begin(), account_names.end(), std::back_inserter(result), - [&accounts_by_name](const string& name) -> optional { - auto itr = accounts_by_name.find(name); - return itr == accounts_by_name.end()? optional() : *itr; - }); + [&accounts_by_name](const string &name) -> optional { + auto itr = accounts_by_name.find(name); + return itr == accounts_by_name.end() ? optional() : *itr; + }); return result; } -map database_api::lookup_accounts(const string& lower_bound_name, uint32_t limit)const -{ - return my->lookup_accounts( lower_bound_name, limit ); +map database_api::lookup_accounts(const string &lower_bound_name, uint32_t limit) const { + return my->lookup_accounts(lower_bound_name, limit); } -map database_api_impl::lookup_accounts(const string& lower_bound_name, uint32_t limit)const -{ - FC_ASSERT( limit <= 1000 ); - const auto& accounts_by_name = _db.get_index_type().indices().get(); - map result; +map database_api_impl::lookup_accounts(const string &lower_bound_name, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_lookup_accounts, + "Number of querying accounts can not be greater than ${configured_limit}", + ("configured_limit", api_limit_lookup_accounts)); + const auto &accounts_by_name = _db.get_index_type().indices().get(); + map result; - for( auto itr = accounts_by_name.lower_bound(lower_bound_name); + for (auto itr = accounts_by_name.lower_bound(lower_bound_name); limit-- && itr != accounts_by_name.end(); - ++itr ) - { + ++itr) { result.insert(make_pair(itr->name, itr->get_id())); - if( limit == 1 ) - subscribe_to_item( itr->get_id() ); + if (limit == 1) + subscribe_to_item(itr->get_id()); } return result; } -uint64_t database_api::get_account_count()const -{ +uint64_t database_api::get_account_count() const { return my->get_account_count(); } -uint64_t database_api_impl::get_account_count()const -{ +uint64_t database_api_impl::get_account_count() const { return _db.get_index_type().indices().size(); } @@ -925,108 +873,94 @@ uint64_t database_api_impl::get_account_count()const // // ////////////////////////////////////////////////////////////////////// -vector database_api::get_account_balances(const std::string& account_name_or_id, const flat_set& assets)const -{ - return my->get_account_balances( account_name_or_id, assets ); +vector database_api::get_account_balances(const std::string &account_name_or_id, const flat_set &assets) const { + return my->get_account_balances(account_name_or_id, assets); } -vector database_api_impl::get_account_balances( const std::string& account_name_or_id, - const flat_set& assets)const -{ - const account_object* account = get_account_from_string(account_name_or_id); +vector database_api_impl::get_account_balances(const std::string &account_name_or_id, + const flat_set &assets) const { + const account_object *account = get_account_from_string(account_name_or_id); account_id_type acnt = account->id; vector result; - if (assets.empty()) - { + if (assets.empty()) { // if the caller passes in an empty list of assets, return balances for all assets the account owns - 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 - { + const auto &balance_index = _db.get_index_type>(); + const auto &balances = balance_index.get_secondary_index().get_account_balances(acnt); + for (const auto balance : balances) + result.push_back(balance.second->get_balance()); + } else { result.reserve(assets.size()); std::transform(assets.begin(), assets.end(), std::back_inserter(result), - [this, acnt](asset_id_type id) { return _db.get_balance(acnt, id); }); + [this, acnt](asset_id_type id) { + return _db.get_balance(acnt, id); + }); } return result; } -vector database_api::get_named_account_balances(const std::string& name, const flat_set& assets)const -{ - return my->get_account_balances( name, assets ); +vector database_api::get_named_account_balances(const std::string &name, const flat_set &assets) const { + return my->get_account_balances(name, assets); } -vector database_api::get_balance_objects( const vector
& addrs )const -{ - return my->get_balance_objects( addrs ); +vector database_api::get_balance_objects(const vector
&addrs) const { + return my->get_balance_objects(addrs); } -vector database_api_impl::get_balance_objects( const vector
& addrs )const -{ - try - { - const auto& bal_idx = _db.get_index_type(); - const auto& by_owner_idx = bal_idx.indices().get(); +vector database_api_impl::get_balance_objects(const vector
&addrs) const { + try { + const auto &bal_idx = _db.get_index_type(); + const auto &by_owner_idx = bal_idx.indices().get(); vector result; - for( const auto& owner : addrs ) - { - subscribe_to_item( owner ); - auto itr = by_owner_idx.lower_bound( boost::make_tuple( owner, asset_id_type(0) ) ); - while( itr != by_owner_idx.end() && itr->owner == owner ) - { - result.push_back( *itr ); + for (const auto &owner : addrs) { + subscribe_to_item(owner); + auto itr = by_owner_idx.lower_bound(boost::make_tuple(owner, asset_id_type(0))); + while (itr != by_owner_idx.end() && itr->owner == owner) { + result.push_back(*itr); ++itr; } } return result; } - FC_CAPTURE_AND_RETHROW( (addrs) ) + FC_CAPTURE_AND_RETHROW((addrs)) } -vector database_api::get_vested_balances( const vector& objs )const -{ - return my->get_vested_balances( objs ); +vector database_api::get_vested_balances(const vector &objs) const { + return my->get_vested_balances(objs); } -vector database_api_impl::get_vested_balances( const vector& objs )const -{ - try - { +vector database_api_impl::get_vested_balances(const vector &objs) const { + try { vector result; - result.reserve( objs.size() ); + result.reserve(objs.size()); auto now = _db.head_block_time(); - for( auto obj : objs ) - result.push_back( obj(_db).available( now ) ); + for (auto obj : objs) + result.push_back(obj(_db).available(now)); return result; - } FC_CAPTURE_AND_RETHROW( (objs) ) + } + FC_CAPTURE_AND_RETHROW((objs)) } -vector database_api::get_vesting_balances( const std::string account_id_or_name )const -{ - return my->get_vesting_balances( account_id_or_name ); +vector database_api::get_vesting_balances(const std::string account_id_or_name) const { + return my->get_vesting_balances(account_id_or_name); } -vector database_api_impl::get_vesting_balances( const std::string account_id_or_name )const -{ - try - { +vector 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 result; auto vesting_range = _db.get_index_type().indices().get().equal_range(account_id); std::for_each(vesting_range.first, vesting_range.second, - [&result](const vesting_balance_object& balance) { - if(balance.balance.amount > 0) - result.emplace_back(balance); + [&result](const vesting_balance_object &balance) { + if (balance.balance.amount > 0) + result.emplace_back(balance); }); return result; } - FC_CAPTURE_AND_RETHROW( (account_id_or_name) ); + FC_CAPTURE_AND_RETHROW((account_id_or_name)); } ////////////////////////////////////////////////////////////////////// @@ -1035,295 +969,260 @@ vector database_api_impl::get_vesting_balances( const st // // ////////////////////////////////////////////////////////////////////// -asset_id_type database_api::get_asset_id_from_string(const std::string& symbol_or_id)const -{ - return my->get_asset_from_string( symbol_or_id )->id; +asset_id_type database_api::get_asset_id_from_string(const std::string &symbol_or_id) const { + 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 -{ +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; + 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(1)); - else - { - const auto& idx = _db.get_index_type().indices().get(); + else { + const auto &idx = _db.get_index_type().indices().get(); auto itr = idx.find(symbol_or_id); if (itr != idx.end()) asset = &*itr; } - if(throw_if_not_found) - FC_ASSERT( asset, "no such asset" ); + if (throw_if_not_found) + FC_ASSERT(asset, "no such asset"); return asset; } -vector> database_api::get_assets(const vector& asset_symbols_or_ids)const -{ - return my->get_assets( asset_symbols_or_ids ); +vector> database_api::get_assets(const vector &asset_symbols_or_ids) const { + return my->get_assets(asset_symbols_or_ids); } -vector> database_api_impl::get_assets(const vector& asset_symbols_or_ids)const -{ - vector> result; result.reserve(asset_symbols_or_ids.size()); +vector> database_api_impl::get_assets(const vector &asset_symbols_or_ids) const { + vector> 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 { - 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 ); - }); + 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> database_api_impl::get_assets(const vector& asset_ids)const -{ - vector> result; result.reserve(asset_ids.size()); +vector> database_api_impl::get_assets(const vector &asset_ids) const { + vector> result; + result.reserve(asset_ids.size()); std::transform(asset_ids.begin(), asset_ids.end(), std::back_inserter(result), [this](asset_id_type id) -> optional { - if(auto o = _db.find(id)) - { - subscribe_to_item( id ); - return *o; - } - return {}; - }); + if (auto o = _db.find(id)) { + subscribe_to_item(id); + return *o; + } + return {}; + }); return result; } -vector database_api::list_assets(const string& lower_bound_symbol, uint32_t limit)const -{ - return my->list_assets( lower_bound_symbol, limit ); +vector database_api::list_assets(const string &lower_bound_symbol, uint32_t limit) const { + return my->list_assets(lower_bound_symbol, limit); } -vector database_api_impl::list_assets(const string& lower_bound_symbol, uint32_t limit)const -{ - FC_ASSERT( limit <= 100 ); - const auto& assets_by_symbol = _db.get_index_type().indices().get(); +vector database_api_impl::list_assets(const string &lower_bound_symbol, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_get_lower_bound_symbol, + "Number of querying accounts can not be greater than ${configured_limit}", + ("configured_limit", api_limit_get_lower_bound_symbol)); + const auto &assets_by_symbol = _db.get_index_type().indices().get(); vector result; result.reserve(limit); auto itr = assets_by_symbol.lower_bound(lower_bound_symbol); - if( lower_bound_symbol == "" ) + if (lower_bound_symbol == "") itr = assets_by_symbol.begin(); - while(limit-- && itr != assets_by_symbol.end()) + while (limit-- && itr != assets_by_symbol.end()) result.emplace_back(*itr++); return result; } -vector> database_api::lookup_asset_symbols(const vector& symbols_or_ids)const -{ - return my->lookup_asset_symbols( symbols_or_ids ); +vector> database_api::lookup_asset_symbols(const vector &symbols_or_ids) const { + return my->lookup_asset_symbols(symbols_or_ids); } -vector> database_api_impl::lookup_asset_symbols(const vector& symbols_or_ids)const -{ - const auto& assets_by_symbol = _db.get_index_type().indices().get(); - vector > result; +vector> database_api_impl::lookup_asset_symbols(const vector &symbols_or_ids) const { + const auto &assets_by_symbol = _db.get_index_type().indices().get(); + vector> result; result.reserve(symbols_or_ids.size()); std::transform(symbols_or_ids.begin(), symbols_or_ids.end(), std::back_inserter(result), - [this, &assets_by_symbol](const string& symbol_or_id) -> optional { - if( !symbol_or_id.empty() && std::isdigit(symbol_or_id[0]) ) - { - auto ptr = _db.find(variant(symbol_or_id, 1).as(1)); - return ptr == nullptr? optional() : *ptr; - } - auto itr = assets_by_symbol.find(symbol_or_id); - return itr == assets_by_symbol.end()? optional() : *itr; - }); + [this, &assets_by_symbol](const string &symbol_or_id) -> optional { + if (!symbol_or_id.empty() && std::isdigit(symbol_or_id[0])) { + auto ptr = _db.find(variant(symbol_or_id, 1).as(1)); + return ptr == nullptr ? optional() : *ptr; + } + auto itr = assets_by_symbol.find(symbol_or_id); + return itr == assets_by_symbol.end() ? optional() : *itr; + }); return result; } -uint64_t database_api::get_asset_count()const -{ +uint64_t database_api::get_asset_count() const { return my->get_asset_count(); } -uint64_t database_api_impl::get_asset_count()const -{ +uint64_t database_api_impl::get_asset_count() const { return _db.get_index_type().indices().size(); } //////////////////// // Lottery Assets // //////////////////// - -vector database_api::get_lotteries( asset_id_type stop, - unsigned limit, - asset_id_type start )const -{ - return my->get_lotteries( stop, limit, start ); +vector database_api::get_lotteries(asset_id_type stop, + unsigned limit, + asset_id_type start) const { + return my->get_lotteries(stop, limit, start); } -vector database_api_impl::get_lotteries( asset_id_type stop, - unsigned limit, - asset_id_type start )const -{ +vector database_api_impl::get_lotteries(asset_id_type stop, + unsigned limit, + asset_id_type start) const { vector result; - if( limit > 100 ) limit = 100; - const auto& assets = _db.get_index_type().indices().get(); + if (limit > 100) + limit = 100; + const auto &assets = _db.get_index_type().indices().get(); - const auto range = assets.equal_range( boost::make_tuple( true ) ); - for( const auto& a : boost::make_iterator_range( range.first, range.second ) ) - { - if( start == asset_id_type() || (a.get_id().instance.value <= start.instance.value) ) - result.push_back( a ); - if( a.get_id().instance.value < stop.instance.value || result.size() >= limit ) + const auto range = assets.equal_range(boost::make_tuple(true)); + for (const auto &a : boost::make_iterator_range(range.first, range.second)) { + if (start == asset_id_type() || (a.get_id().instance.value <= start.instance.value)) + result.push_back(a); + if (a.get_id().instance.value < stop.instance.value || result.size() >= limit) break; } return result; } -vector database_api::get_account_lotteries( account_id_type issuer, - asset_id_type stop, - unsigned limit, - asset_id_type start )const -{ - return my->get_account_lotteries( issuer, stop, limit, start ); +vector database_api::get_account_lotteries(account_id_type issuer, + asset_id_type stop, + unsigned limit, + asset_id_type start) const { + return my->get_account_lotteries(issuer, stop, limit, start); } -vector database_api_impl::get_account_lotteries( account_id_type issuer, - asset_id_type stop, - unsigned limit, - asset_id_type start )const -{ +vector database_api_impl::get_account_lotteries(account_id_type issuer, + asset_id_type stop, + unsigned limit, + asset_id_type start) const { vector result; - if( limit > 100 ) limit = 100; - const auto& assets = _db.get_index_type().indices().get(); + if (limit > 100) + limit = 100; + const auto &assets = _db.get_index_type().indices().get(); - const auto range = assets.equal_range( boost::make_tuple( true, issuer.instance.value ) ); - for( const auto& a : boost::make_iterator_range( range.first, range.second ) ) - { - if( start == asset_id_type() || (a.get_id().instance.value <= start.instance.value) ) - result.push_back( a ); - if( a.get_id().instance.value < stop.instance.value || result.size() >= limit ) + const auto range = assets.equal_range(boost::make_tuple(true, issuer.instance.value)); + for (const auto &a : boost::make_iterator_range(range.first, range.second)) { + if (start == asset_id_type() || (a.get_id().instance.value <= start.instance.value)) + result.push_back(a); + if (a.get_id().instance.value < stop.instance.value || result.size() >= limit) break; } return result; } -asset database_api::get_lottery_balance( asset_id_type lottery_id )const -{ - return my->get_lottery_balance( lottery_id ); +asset database_api::get_lottery_balance(asset_id_type lottery_id) const { + return my->get_lottery_balance(lottery_id); } -asset database_api_impl::get_lottery_balance( asset_id_type lottery_id )const -{ - auto lottery_asset = lottery_id( _db ); - FC_ASSERT( lottery_asset.is_lottery() ); - return _db.get_balance( lottery_id ); +asset database_api_impl::get_lottery_balance(asset_id_type lottery_id) const { + auto lottery_asset = lottery_id(_db); + FC_ASSERT(lottery_asset.is_lottery()); + return _db.get_balance(lottery_id); } -sweeps_vesting_balance_object database_api::get_sweeps_vesting_balance_object( account_id_type account )const -{ - return my->get_sweeps_vesting_balance_object( account ); +sweeps_vesting_balance_object database_api::get_sweeps_vesting_balance_object(account_id_type account) const { + return my->get_sweeps_vesting_balance_object(account); } -sweeps_vesting_balance_object database_api_impl::get_sweeps_vesting_balance_object( account_id_type account )const -{ - const auto& vesting_idx = _db.get_index_type().indices().get(); +sweeps_vesting_balance_object database_api_impl::get_sweeps_vesting_balance_object(account_id_type account) const { + const auto &vesting_idx = _db.get_index_type().indices().get(); auto account_balance = vesting_idx.find(account); - FC_ASSERT( account_balance != vesting_idx.end(), "NO SWEEPS VESTING BALANCE" ); + FC_ASSERT(account_balance != vesting_idx.end(), "NO SWEEPS VESTING BALANCE"); return *account_balance; } -asset database_api::get_sweeps_vesting_balance_available_for_claim( account_id_type account )const -{ - return my->get_sweeps_vesting_balance_available_for_claim( account ); +asset database_api::get_sweeps_vesting_balance_available_for_claim(account_id_type account) const { + return my->get_sweeps_vesting_balance_available_for_claim(account); } -asset database_api_impl::get_sweeps_vesting_balance_available_for_claim( account_id_type account )const -{ - const auto& vesting_idx = _db.get_index_type().indices().get(); +asset database_api_impl::get_sweeps_vesting_balance_available_for_claim(account_id_type account) const { + const auto &vesting_idx = _db.get_index_type().indices().get(); auto account_balance = vesting_idx.find(account); - FC_ASSERT( account_balance != vesting_idx.end(), "NO SWEEPS VESTING BALANCE" ); + FC_ASSERT(account_balance != vesting_idx.end(), "NO SWEEPS VESTING BALANCE"); return account_balance->available_for_claim(); } ////////////////////////////////////////////////////////////////////// // Peerplays // ////////////////////////////////////////////////////////////////////// -vector database_api::list_sports() const -{ +vector database_api::list_sports() const { return my->list_sports(); } -vector database_api_impl::list_sports() const -{ - const auto& sport_object_idx = _db.get_index_type().indices().get(); - return boost::copy_range >(sport_object_idx); +vector database_api_impl::list_sports() const { + const auto &sport_object_idx = _db.get_index_type().indices().get(); + return boost::copy_range>(sport_object_idx); } -vector database_api::list_event_groups(sport_id_type sport_id) const -{ +vector database_api::list_event_groups(sport_id_type sport_id) const { return my->list_event_groups(sport_id); } -vector database_api_impl::list_event_groups(sport_id_type sport_id) const -{ - const auto& event_group_idx = _db.get_index_type().indices().get(); - return boost::copy_range >(event_group_idx.equal_range(sport_id)); +vector database_api_impl::list_event_groups(sport_id_type sport_id) const { + const auto &event_group_idx = _db.get_index_type().indices().get(); + return boost::copy_range>(event_group_idx.equal_range(sport_id)); } -vector database_api::list_events_in_group(event_group_id_type event_group_id) const -{ +vector database_api::list_events_in_group(event_group_id_type event_group_id) const { return my->list_events_in_group(event_group_id); } -vector database_api_impl::list_events_in_group(event_group_id_type event_group_id) const -{ - const auto& event_idx = _db.get_index_type().indices().get(); - return boost::copy_range >(event_idx.equal_range(event_group_id)); +vector database_api_impl::list_events_in_group(event_group_id_type event_group_id) const { + const auto &event_idx = _db.get_index_type().indices().get(); + return boost::copy_range>(event_idx.equal_range(event_group_id)); } -vector database_api::list_betting_market_groups(event_id_type event_id) const -{ - return my->list_betting_market_groups(event_id); +vector database_api::list_betting_market_groups(event_id_type event_id) const { + return my->list_betting_market_groups(event_id); } -vector database_api_impl::list_betting_market_groups(event_id_type event_id) const -{ - const auto& betting_market_group_idx = _db.get_index_type().indices().get(); - return boost::copy_range >(betting_market_group_idx.equal_range(event_id)); +vector database_api_impl::list_betting_market_groups(event_id_type event_id) const { + const auto &betting_market_group_idx = _db.get_index_type().indices().get(); + return boost::copy_range>(betting_market_group_idx.equal_range(event_id)); } -vector database_api::list_betting_markets(betting_market_group_id_type betting_market_group_id) const -{ +vector database_api::list_betting_markets(betting_market_group_id_type betting_market_group_id) const { return my->list_betting_markets(betting_market_group_id); } -vector database_api_impl::list_betting_markets(betting_market_group_id_type betting_market_group_id) const -{ - const auto& betting_market_idx = _db.get_index_type().indices().get(); - return boost::copy_range >(betting_market_idx.equal_range(betting_market_group_id)); +vector database_api_impl::list_betting_markets(betting_market_group_id_type betting_market_group_id) const { + const auto &betting_market_idx = _db.get_index_type().indices().get(); + return boost::copy_range>(betting_market_idx.equal_range(betting_market_group_id)); } -vector database_api::get_unmatched_bets_for_bettor(betting_market_id_type betting_market_id, account_id_type bettor_id) const -{ +vector database_api::get_unmatched_bets_for_bettor(betting_market_id_type betting_market_id, account_id_type bettor_id) const { return my->get_unmatched_bets_for_bettor(betting_market_id, bettor_id); } -vector database_api_impl::get_unmatched_bets_for_bettor(betting_market_id_type betting_market_id, account_id_type bettor_id) const -{ - const auto& bet_idx = _db.get_index_type().indices().get(); - return boost::copy_range >(bet_idx.equal_range(std::make_tuple(bettor_id, betting_market_id))); +vector database_api_impl::get_unmatched_bets_for_bettor(betting_market_id_type betting_market_id, account_id_type bettor_id) const { + const auto &bet_idx = _db.get_index_type().indices().get(); + return boost::copy_range>(bet_idx.equal_range(std::make_tuple(bettor_id, betting_market_id))); } -vector database_api::get_all_unmatched_bets_for_bettor(account_id_type bettor_id) const -{ +vector database_api::get_all_unmatched_bets_for_bettor(account_id_type bettor_id) const { return my->get_all_unmatched_bets_for_bettor(bettor_id); } -vector database_api_impl::get_all_unmatched_bets_for_bettor(account_id_type bettor_id) const -{ - const auto& bet_idx = _db.get_index_type().indices().get(); - return boost::copy_range >(bet_idx.equal_range(std::make_tuple(bettor_id))); +vector database_api_impl::get_all_unmatched_bets_for_bettor(account_id_type bettor_id) const { + const auto &bet_idx = _db.get_index_type().indices().get(); + return boost::copy_range>(bet_idx.equal_range(std::make_tuple(bettor_id))); } ////////////////////////////////////////////////////////////////////// @@ -1332,45 +1231,40 @@ vector database_api_impl::get_all_unmatched_bets_for_bettor(account_ // // ////////////////////////////////////////////////////////////////////// -vector 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 ); +vector 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); } /** * @return the limit orders for both sides of the book for the two assets specified up to limit number on each side. */ -vector database_api_impl::get_limit_orders(const std::string& a, const std::string& b, const uint32_t limit)const -{ +vector 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 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(); - const auto& limit_price_idx = limit_order_idx.indices().get(); +vector 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(); + const auto &limit_price_idx = limit_order_idx.indices().get(); vector result; - result.reserve(limit*2); + result.reserve(limit * 2); uint32_t count = 0; - auto limit_itr = limit_price_idx.lower_bound(price::max(a,b)); - auto limit_end = limit_price_idx.upper_bound(price::min(a,b)); - while(limit_itr != limit_end && count < limit) - { + auto limit_itr = limit_price_idx.lower_bound(price::max(a, b)); + auto limit_end = limit_price_idx.upper_bound(price::min(a, b)); + while (limit_itr != limit_end && count < limit) { result.push_back(*limit_itr); ++limit_itr; ++count; } count = 0; - limit_itr = limit_price_idx.lower_bound(price::max(b,a)); - limit_end = limit_price_idx.upper_bound(price::min(b,a)); - while(limit_itr != limit_end && count < limit) - { + limit_itr = limit_price_idx.lower_bound(price::max(b, a)); + limit_end = limit_price_idx.upper_bound(price::min(b, a)); + while (limit_itr != limit_end && count < limit) { result.push_back(*limit_itr); ++limit_itr; ++count; @@ -1379,286 +1273,264 @@ vector database_api_impl::get_limit_orders( const asset_id_t return result; } -vector database_api::get_call_orders(const std::string& a, uint32_t limit)const -{ - return my->get_call_orders( a, limit ); +vector database_api::get_call_orders(const std::string &a, uint32_t limit) const { + return my->get_call_orders(a, limit); } -vector database_api_impl::get_call_orders(const std::string& a, uint32_t limit)const -{ - const auto& call_index = _db.get_index_type().indices().get(); - const asset_object* mia = get_asset_from_string(a); +vector database_api_impl::get_call_orders(const std::string &a, uint32_t limit) const { + const auto &call_index = _db.get_index_type().indices().get(); + 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_index.lower_bound(index_price.min()), call_index.lower_bound(index_price.max())); } -vector database_api::get_settle_orders(const std::string& a, uint32_t limit)const -{ - return my->get_settle_orders( a, limit ); +vector database_api::get_settle_orders(const std::string &a, uint32_t limit) const { + return my->get_settle_orders(a, limit); } -vector database_api_impl::get_settle_orders(const std::string& a, uint32_t limit)const -{ - const auto& settle_index = _db.get_index_type().indices().get(); - const asset_object* mia = get_asset_from_string(a); +vector database_api_impl::get_settle_orders(const std::string &a, uint32_t limit) const { + const auto &settle_index = _db.get_index_type().indices().get(); + const asset_object *mia = get_asset_from_string(a); return vector(settle_index.lower_bound(mia->get_id()), settle_index.upper_bound(mia->get_id())); } -vector database_api::get_margin_positions( const std::string account_id_or_name )const -{ - return my->get_margin_positions( account_id_or_name ); +vector database_api::get_margin_positions(const std::string account_id_or_name) const { + return my->get_margin_positions(account_id_or_name); } -vector database_api_impl::get_margin_positions( const std::string account_id_or_name )const -{ - try - { - const auto& idx = _db.get_index_type(); - const auto& aidx = idx.indices().get(); +vector database_api_impl::get_margin_positions(const std::string account_id_or_name) const { + try { + const auto &idx = _db.get_index_type(); + const auto &aidx = idx.indices().get(); 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) ) ); + 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 result; - while( start != end ) - { + while (start != end) { result.push_back(*start); ++start; } return result; - } FC_CAPTURE_AND_RETHROW( (account_id_or_name) ) + } + FC_CAPTURE_AND_RETHROW((account_id_or_name)) } -void database_api::subscribe_to_market(std::function callback, const std::string& a, const std::string& b) -{ - my->subscribe_to_market( callback, a, b ); +void database_api::subscribe_to_market(std::function 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 callback, const std::string& a, const std::string& b) -{ +void database_api_impl::subscribe_to_market(std::function callback, const std::string &a, const std::string &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); + 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; + _market_subscriptions[std::make_pair(asset_a_id, asset_b_id)] = callback; } -void database_api::unsubscribe_from_market(const std::string& a, const std::string& b) -{ - my->unsubscribe_from_market( a, 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(const std::string& a, const std::string& b) -{ +void database_api_impl::unsubscribe_from_market(const std::string &a, const std::string &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); + 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_subscriptions.erase(std::make_pair(asset_a_id, asset_b_id)); } -market_ticker database_api::get_ticker( const string& base, const string& quote )const -{ - return my->get_ticker( base, quote ); +market_ticker database_api::get_ticker(const string &base, const string "e) const { + return my->get_ticker(base, quote); } -market_ticker database_api_impl::get_ticker( const string& base, const string& quote )const -{ - const auto assets = lookup_asset_symbols( {base, quote} ); - FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) ); - FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) ); +market_ticker database_api_impl::get_ticker(const string &base, const string "e) const { + const auto assets = lookup_asset_symbols({base, quote}); + FC_ASSERT(assets[0], "Invalid base asset symbol: ${s}", ("s", base)); + FC_ASSERT(assets[1], "Invalid quote asset symbol: ${s}", ("s", quote)); - market_ticker result; - result.base = base; - result.quote = quote; - result.latest = 0; - result.lowest_ask = 0; - result.highest_bid = 0; - result.percent_change = 0; - result.base_volume = 0; - result.quote_volume = 0; + market_ticker result; + result.base = base; + result.quote = quote; + result.latest = 0; + result.lowest_ask = 0; + result.highest_bid = 0; + result.percent_change = 0; + result.base_volume = 0; + result.quote_volume = 0; - try { - const fc::time_point_sec now = fc::time_point::now(); - const fc::time_point_sec yesterday = fc::time_point_sec( now.sec_since_epoch() - 86400 ); - const auto batch_size = 100; + try { + const fc::time_point_sec now = fc::time_point::now(); + const fc::time_point_sec yesterday = fc::time_point_sec(now.sec_since_epoch() - 86400); + const auto batch_size = 100; - vector trades = get_trade_history( base, quote, now, yesterday, batch_size ); - if( !trades.empty() ) - { - result.latest = trades[0].price; + vector trades = get_trade_history(base, quote, now, yesterday, batch_size); + if (!trades.empty()) { + result.latest = trades[0].price; - while( !trades.empty() ) - { - for( const market_trade& t: trades ) - { - result.base_volume += t.value; - result.quote_volume += t.amount; - } - - trades = get_trade_history( base, quote, trades.back().date, yesterday, batch_size ); + while (!trades.empty()) { + for (const market_trade &t : trades) { + result.base_volume += t.value; + result.quote_volume += t.amount; } - const auto last_trade_yesterday = get_trade_history( base, quote, yesterday, fc::time_point_sec(), 1 ); - if( !last_trade_yesterday.empty() ) - { - const auto price_yesterday = last_trade_yesterday[0].price; - result.percent_change = ( (result.latest / price_yesterday) - 1 ) * 100; - } - } - else - { - const auto last_trade = get_trade_history( base, quote, now, fc::time_point_sec(), 1 ); - if( !last_trade.empty() ) - result.latest = last_trade[0].price; - } + trades = get_trade_history(base, quote, trades.back().date, yesterday, batch_size); + } - const auto orders = get_order_book( base, quote, 1 ); - if( !orders.asks.empty() ) result.lowest_ask = orders.asks[0].price; - if( !orders.bids.empty() ) result.highest_bid = orders.bids[0].price; - } FC_CAPTURE_AND_RETHROW( (base)(quote) ) + const auto last_trade_yesterday = get_trade_history(base, quote, yesterday, fc::time_point_sec(), 1); + if (!last_trade_yesterday.empty()) { + const auto price_yesterday = last_trade_yesterday[0].price; + result.percent_change = ((result.latest / price_yesterday) - 1) * 100; + } + } else { + const auto last_trade = get_trade_history(base, quote, now, fc::time_point_sec(), 1); + if (!last_trade.empty()) + result.latest = last_trade[0].price; + } - return result; + const auto orders = get_order_book(base, quote, 1); + if (!orders.asks.empty()) + result.lowest_ask = orders.asks[0].price; + if (!orders.bids.empty()) + result.highest_bid = orders.bids[0].price; + } + FC_CAPTURE_AND_RETHROW((base)(quote)) + + return result; } -market_volume database_api::get_24_volume( const string& base, const string& quote )const -{ - return my->get_24_volume( base, quote ); +market_volume database_api::get_24_volume(const string &base, const string "e) const { + return my->get_24_volume(base, quote); } -market_volume database_api_impl::get_24_volume( const string& base, const string& quote )const -{ - const auto ticker = get_ticker( base, quote ); +market_volume database_api_impl::get_24_volume(const string &base, const string "e) const { + const auto ticker = get_ticker(base, quote); - market_volume result; - result.base = ticker.base; - result.quote = ticker.quote; - result.base_volume = ticker.base_volume; - result.quote_volume = ticker.quote_volume; + market_volume result; + result.base = ticker.base; + result.quote = ticker.quote; + result.base_volume = ticker.base_volume; + result.quote_volume = ticker.quote_volume; - return result; + return result; } -order_book database_api::get_order_book( const string& base, const string& quote, unsigned limit )const -{ - return my->get_order_book( base, quote, limit); +order_book database_api::get_order_book(const string &base, const string "e, unsigned limit) const { + return my->get_order_book(base, quote, limit); } -order_book database_api_impl::get_order_book( const string& base, const string& quote, unsigned limit )const -{ +order_book database_api_impl::get_order_book(const string &base, const string "e, unsigned limit) const { using boost::multiprecision::uint128_t; - FC_ASSERT( limit <= 50 ); + FC_ASSERT(limit <= api_limit_get_order_book, + "Number of querying accounts can not be greater than ${configured_limit}", + ("configured_limit", api_limit_get_order_book)); order_book result; result.base = base; result.quote = quote; - auto assets = lookup_asset_symbols( {base, quote} ); - FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) ); - FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) ); + auto assets = lookup_asset_symbols({base, quote}); + FC_ASSERT(assets[0], "Invalid base asset symbol: ${s}", ("s", base)); + FC_ASSERT(assets[1], "Invalid quote asset symbol: ${s}", ("s", quote)); auto base_id = assets[0]->id; auto quote_id = assets[1]->id; - auto orders = get_limit_orders( base_id, quote_id, limit ); + auto orders = get_limit_orders(base_id, quote_id, limit); - - auto asset_to_real = [&]( const asset& a, int p ) { return double(a.amount.value)/pow( 10, p ); }; - auto price_to_real = [&]( const price& p ) - { - if( p.base.asset_id == base_id ) - return asset_to_real( p.base, assets[0]->precision ) / asset_to_real( p.quote, assets[1]->precision ); + auto asset_to_real = [&](const asset &a, int p) { + return double(a.amount.value) / pow(10, p); + }; + auto price_to_real = [&](const price &p) { + if (p.base.asset_id == base_id) + return asset_to_real(p.base, assets[0]->precision) / asset_to_real(p.quote, assets[1]->precision); else - return asset_to_real( p.quote, assets[0]->precision ) / asset_to_real( p.base, assets[1]->precision ); + return asset_to_real(p.quote, assets[0]->precision) / asset_to_real(p.base, assets[1]->precision); }; - for( const auto& o : orders ) - { - if( o.sell_price.base.asset_id == base_id ) - { + for (const auto &o : orders) { + if (o.sell_price.base.asset_id == base_id) { order ord; - ord.price = price_to_real( o.sell_price ); - ord.quote = asset_to_real( share_type( ( uint128_t( o.for_sale.value ) * o.sell_price.quote.amount.value ) / o.sell_price.base.amount.value ), assets[1]->precision ); - ord.base = asset_to_real( o.for_sale, assets[0]->precision ); - result.bids.push_back( ord ); - } - else - { + ord.price = price_to_real(o.sell_price); + ord.quote = asset_to_real(share_type((uint128_t(o.for_sale.value) * o.sell_price.quote.amount.value) / o.sell_price.base.amount.value), assets[1]->precision); + ord.base = asset_to_real(o.for_sale, assets[0]->precision); + result.bids.push_back(ord); + } else { order ord; - ord.price = price_to_real( o.sell_price ); - ord.quote = asset_to_real( o.for_sale, assets[1]->precision ); - ord.base = asset_to_real( share_type( ( uint128_t( o.for_sale.value ) * o.sell_price.quote.amount.value ) / o.sell_price.base.amount.value ), assets[0]->precision ); - result.asks.push_back( ord ); + ord.price = price_to_real(o.sell_price); + ord.quote = asset_to_real(o.for_sale, assets[1]->precision); + ord.base = asset_to_real(share_type((uint128_t(o.for_sale.value) * o.sell_price.quote.amount.value) / o.sell_price.base.amount.value), assets[0]->precision); + result.asks.push_back(ord); } } return result; } -vector database_api::get_trade_history( const string& base, - const string& quote, - fc::time_point_sec start, - fc::time_point_sec stop, - unsigned limit )const -{ - return my->get_trade_history( base, quote, start, stop, limit ); +vector database_api::get_trade_history(const string &base, + const string "e, + fc::time_point_sec start, + fc::time_point_sec stop, + unsigned limit) const { + return my->get_trade_history(base, quote, start, stop, limit); } -vector database_api_impl::get_trade_history( const string& base, - const string& quote, - fc::time_point_sec start, - fc::time_point_sec stop, - unsigned limit )const -{ - FC_ASSERT( limit <= 100 ); +vector database_api_impl::get_trade_history(const string &base, + const string "e, + fc::time_point_sec start, + fc::time_point_sec stop, + unsigned limit) const { + FC_ASSERT(limit <= api_limit_get_trade_history, + "Number of querying accounts can not be greater than ${configured_limit}", + ("configured_limit", api_limit_get_trade_history)); - auto assets = lookup_asset_symbols( {base, quote} ); - FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) ); - FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) ); + auto assets = lookup_asset_symbols({base, quote}); + FC_ASSERT(assets[0], "Invalid base asset symbol: ${s}", ("s", base)); + FC_ASSERT(assets[1], "Invalid quote asset symbol: ${s}", ("s", quote)); auto base_id = assets[0]->id; auto quote_id = assets[1]->id; - if( base_id > quote_id ) std::swap( base_id, quote_id ); - const auto& history_idx = _db.get_index_type().indices().get(); + if (base_id > quote_id) + std::swap(base_id, quote_id); + const auto &history_idx = _db.get_index_type().indices().get(); history_key hkey; hkey.base = base_id; hkey.quote = quote_id; hkey.sequence = std::numeric_limits::min(); - auto price_to_real = [&]( const share_type a, int p ) { return double( a.value ) / pow( 10, p ); }; + auto price_to_real = [&](const share_type a, int p) { + return double(a.value) / pow(10, p); + }; - if ( start.sec_since_epoch() == 0 ) - start = fc::time_point_sec( fc::time_point::now() ); + if (start.sec_since_epoch() == 0) + start = fc::time_point_sec(fc::time_point::now()); uint32_t count = 0; - auto itr = history_idx.lower_bound( hkey ); + auto itr = history_idx.lower_bound(hkey); vector result; - while( itr != history_idx.end() && count < limit && !( itr->key.base != base_id || itr->key.quote != quote_id || itr->time < stop ) ) - { - if( itr->time < start ) - { + while (itr != history_idx.end() && count < limit && !(itr->key.base != base_id || itr->key.quote != quote_id || itr->time < stop)) { + if (itr->time < start) { market_trade trade; - if( assets[0]->id == itr->op.receives.asset_id ) - { - trade.amount = price_to_real( itr->op.pays.amount, assets[1]->precision ); - trade.value = price_to_real( itr->op.receives.amount, assets[0]->precision ); - } - else - { - trade.amount = price_to_real( itr->op.receives.amount, assets[1]->precision ); - trade.value = price_to_real( itr->op.pays.amount, assets[0]->precision ); + if (assets[0]->id == itr->op.receives.asset_id) { + trade.amount = price_to_real(itr->op.pays.amount, assets[1]->precision); + trade.value = price_to_real(itr->op.receives.amount, assets[0]->precision); + } else { + trade.amount = price_to_real(itr->op.receives.amount, assets[1]->precision); + trade.value = price_to_real(itr->op.pays.amount, assets[0]->precision); } trade.date = itr->time; trade.price = trade.value / trade.amount; - result.push_back( trade ); + result.push_back(trade); ++count; } @@ -1676,64 +1548,58 @@ vector database_api_impl::get_trade_history( const string& base, // // ////////////////////////////////////////////////////////////////////// -vector> database_api::get_witnesses(const vector& witness_ids)const -{ - return my->get_witnesses( witness_ids ); +vector> database_api::get_witnesses(const vector &witness_ids) const { + return my->get_witnesses(witness_ids); } -vector database_api::get_workers_by_account(const std::string account_id_or_name)const -{ - const auto& idx = my->_db.get_index_type().indices().get(); - const account_id_type account = my->get_account_from_string(account_id_or_name)->id; - auto itr = idx.find(account); - vector result; +vector database_api::get_workers_by_account(const std::string account_id_or_name) const { + const auto &idx = my->_db.get_index_type().indices().get(); + const account_id_type account = my->get_account_from_string(account_id_or_name)->id; + auto itr = idx.find(account); + vector result; - if( itr != idx.end() && itr->worker_account == account ) - { - result.emplace_back( *itr ); - ++itr; - } + if (itr != idx.end() && itr->worker_account == account) { + result.emplace_back(*itr); + ++itr; + } - return result; -} - - -vector> database_api_impl::get_witnesses(const vector& witness_ids)const -{ - vector> result; result.reserve(witness_ids.size()); - std::transform(witness_ids.begin(), witness_ids.end(), std::back_inserter(result), - [this](witness_id_type id) -> optional { - if(auto o = _db.find(id)) - return *o; - return {}; - }); return result; } -fc::optional database_api::get_witness_by_account(const std::string account_id_or_name)const -{ - return my->get_witness_by_account( account_id_or_name ); +vector> database_api_impl::get_witnesses(const vector &witness_ids) const { + vector> result; + result.reserve(witness_ids.size()); + std::transform(witness_ids.begin(), witness_ids.end(), std::back_inserter(result), + [this](witness_id_type id) -> optional { + if (auto o = _db.find(id)) + return *o; + return {}; + }); + return result; } -fc::optional database_api_impl::get_witness_by_account(const std::string account_id_or_name) const -{ - const auto& idx = _db.get_index_type().indices().get(); +fc::optional database_api::get_witness_by_account(const std::string account_id_or_name) const { + return my->get_witness_by_account(account_id_or_name); +} + +fc::optional database_api_impl::get_witness_by_account(const std::string account_id_or_name) const { + const auto &idx = _db.get_index_type().indices().get(); const account_id_type account = get_account_from_string(account_id_or_name)->id; auto itr = idx.find(account); - if( itr != idx.end() ) + if (itr != idx.end()) return *itr; return {}; } -map database_api::lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const -{ - return my->lookup_witness_accounts( lower_bound_name, limit ); +map database_api::lookup_witness_accounts(const string &lower_bound_name, uint32_t limit) const { + return my->lookup_witness_accounts(lower_bound_name, limit); } -map database_api_impl::lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const -{ - FC_ASSERT( limit <= 1000 ); - const auto& witnesses_by_id = _db.get_index_type().indices().get(); +map database_api_impl::lookup_witness_accounts(const string &lower_bound_name, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_lookup_witness_accounts, + "Number of querying accounts can not be greater than ${configured_limit}", + ("configured_limit", api_limit_lookup_witness_accounts)); + const auto &witnesses_by_id = _db.get_index_type().indices().get(); // we want to order witnesses by account name, but that name is in the account object // so the witness_index doesn't have a quick way to access it. @@ -1741,25 +1607,23 @@ map database_api_impl::lookup_witness_accounts(const st // records to return. This could be optimized, but we expect the // number of witnesses to be few and the frequency of calls to be rare std::map witnesses_by_account_name; - for (const witness_object& witness : witnesses_by_id) - if (auto account_iter = _db.find(witness.witness_account)) - if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name - witnesses_by_account_name.insert(std::make_pair(account_iter->name, witness.id)); + for (const witness_object &witness : witnesses_by_id) + if (auto account_iter = _db.find(witness.witness_account)) + if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name + witnesses_by_account_name.insert(std::make_pair(account_iter->name, witness.id)); auto end_iter = witnesses_by_account_name.begin(); while (end_iter != witnesses_by_account_name.end() && limit--) - ++end_iter; + ++end_iter; witnesses_by_account_name.erase(end_iter, witnesses_by_account_name.end()); return witnesses_by_account_name; } -uint64_t database_api::get_witness_count()const -{ +uint64_t database_api::get_witness_count() const { return my->get_witness_count(); } -uint64_t database_api_impl::get_witness_count()const -{ +uint64_t database_api_impl::get_witness_count() const { return _db.get_index_type().indices().size(); } @@ -1769,47 +1633,44 @@ uint64_t database_api_impl::get_witness_count()const // // ////////////////////////////////////////////////////////////////////// -vector> database_api::get_committee_members(const vector& committee_member_ids)const -{ - return my->get_committee_members( committee_member_ids ); +vector> database_api::get_committee_members(const vector &committee_member_ids) const { + return my->get_committee_members(committee_member_ids); } -vector> database_api_impl::get_committee_members(const vector& committee_member_ids)const -{ - vector> result; result.reserve(committee_member_ids.size()); +vector> database_api_impl::get_committee_members(const vector &committee_member_ids) const { + vector> result; + result.reserve(committee_member_ids.size()); std::transform(committee_member_ids.begin(), committee_member_ids.end(), std::back_inserter(result), [this](committee_member_id_type id) -> optional { - if(auto o = _db.find(id)) - return *o; - return {}; - }); + if (auto o = _db.find(id)) + return *o; + return {}; + }); return result; } -fc::optional database_api::get_committee_member_by_account(const std::string account_id_or_name)const -{ - return my->get_committee_member_by_account( account_id_or_name ); +fc::optional database_api::get_committee_member_by_account(const std::string account_id_or_name) const { + return my->get_committee_member_by_account(account_id_or_name); } -fc::optional database_api_impl::get_committee_member_by_account(const std::string account_id_or_name) const -{ - const auto& idx = _db.get_index_type().indices().get(); +fc::optional database_api_impl::get_committee_member_by_account(const std::string account_id_or_name) const { + const auto &idx = _db.get_index_type().indices().get(); const account_id_type account = get_account_from_string(account_id_or_name)->id; auto itr = idx.find(account); - if( itr != idx.end() ) + if (itr != idx.end()) return *itr; return {}; } -map database_api::lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const -{ - return my->lookup_committee_member_accounts( lower_bound_name, limit ); +map database_api::lookup_committee_member_accounts(const string &lower_bound_name, uint32_t limit) const { + return my->lookup_committee_member_accounts(lower_bound_name, limit); } -map database_api_impl::lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const -{ - FC_ASSERT( limit <= 1000 ); - const auto& committee_members_by_id = _db.get_index_type().indices().get(); +map database_api_impl::lookup_committee_member_accounts(const string &lower_bound_name, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_lookup_committee_member_accounts, + "Number of querying accounts can not be greater than ${configured_limit}", + ("configured_limit", api_limit_lookup_committee_member_accounts)); + const auto &committee_members_by_id = _db.get_index_type().indices().get(); // we want to order committee_members by account name, but that name is in the account object // so the committee_member_index doesn't have a quick way to access it. @@ -1817,14 +1678,14 @@ map database_api_impl::lookup_committee_member // records to return. This could be optimized, but we expect the // number of committee_members to be few and the frequency of calls to be rare std::map committee_members_by_account_name; - for (const committee_member_object& committee_member : committee_members_by_id) - if (auto account_iter = _db.find(committee_member.committee_member_account)) - if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name - committee_members_by_account_name.insert(std::make_pair(account_iter->name, committee_member.id)); + for (const committee_member_object &committee_member : committee_members_by_id) + if (auto account_iter = _db.find(committee_member.committee_member_account)) + if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name + committee_members_by_account_name.insert(std::make_pair(account_iter->name, committee_member.id)); auto end_iter = committee_members_by_account_name.begin(); while (end_iter != committee_members_by_account_name.end() && limit--) - ++end_iter; + ++end_iter; committee_members_by_account_name.erase(end_iter, committee_members_by_account_name.end()); return committee_members_by_account_name; } @@ -1835,46 +1696,41 @@ map database_api_impl::lookup_committee_member // // ////////////////////////////////////////////////////////////////////// -vector> database_api::get_sons(const vector& son_ids)const -{ - return my->get_sons( son_ids ); +vector> database_api::get_sons(const vector &son_ids) const { + return my->get_sons(son_ids); } -vector> database_api_impl::get_sons(const vector& son_ids)const -{ - vector> result; result.reserve(son_ids.size()); +vector> database_api_impl::get_sons(const vector &son_ids) const { + vector> result; + result.reserve(son_ids.size()); std::transform(son_ids.begin(), son_ids.end(), std::back_inserter(result), [this](son_id_type id) -> optional { - if(auto o = _db.find(id)) - return *o; - return {}; - }); + if (auto o = _db.find(id)) + return *o; + return {}; + }); return result; } -fc::optional database_api::get_son_by_account(account_id_type account)const -{ - return my->get_son_by_account( account ); +fc::optional database_api::get_son_by_account(account_id_type account) const { + return my->get_son_by_account(account); } -fc::optional database_api_impl::get_son_by_account(account_id_type account) const -{ - const auto& idx = _db.get_index_type().indices().get(); +fc::optional database_api_impl::get_son_by_account(account_id_type account) const { + const auto &idx = _db.get_index_type().indices().get(); auto itr = idx.find(account); - if( itr != idx.end() ) + if (itr != idx.end()) return *itr; return {}; } -map database_api::lookup_son_accounts(const string& lower_bound_name, uint32_t limit)const -{ - return my->lookup_son_accounts( lower_bound_name, limit ); +map database_api::lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const { + return my->lookup_son_accounts(lower_bound_name, limit); } -map database_api_impl::lookup_son_accounts(const string& lower_bound_name, uint32_t limit)const -{ - FC_ASSERT( limit <= 1000 ); - const auto& sons_by_id = _db.get_index_type().indices().get(); +map database_api_impl::lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const { + FC_ASSERT(limit <= 1000); + const auto &sons_by_id = _db.get_index_type().indices().get(); // we want to order sons by account name, but that name is in the account object // so the son_index doesn't have a quick way to access it. @@ -1882,25 +1738,23 @@ map database_api_impl::lookup_son_accounts(const string& lo // records to return. This could be optimized, but we expect the // number of witnesses to be few and the frequency of calls to be rare std::map sons_by_account_name; - for (const son_object& son : sons_by_id) - if (auto account_iter = _db.find(son.son_account)) - if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name - sons_by_account_name.insert(std::make_pair(account_iter->name, son.id)); + for (const son_object &son : sons_by_id) + if (auto account_iter = _db.find(son.son_account)) + if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name + sons_by_account_name.insert(std::make_pair(account_iter->name, son.id)); auto end_iter = sons_by_account_name.begin(); while (end_iter != sons_by_account_name.end() && limit--) - ++end_iter; + ++end_iter; sons_by_account_name.erase(end_iter, sons_by_account_name.end()); return sons_by_account_name; } -uint64_t database_api::get_son_count()const -{ +uint64_t database_api::get_son_count() const { return my->get_son_count(); } -uint64_t database_api_impl::get_son_count()const -{ +uint64_t database_api_impl::get_son_count() const { return _db.get_index_type().indices().size(); } @@ -1910,47 +1764,41 @@ uint64_t database_api_impl::get_son_count()const // // ////////////////////////////////////////////////////////////////////// -optional database_api::get_active_son_wallet() -{ +optional database_api::get_active_son_wallet() { return my->get_active_son_wallet(); } -optional database_api_impl::get_active_son_wallet() -{ - const auto& idx = _db.get_index_type().indices().get(); +optional database_api_impl::get_active_son_wallet() { + const auto &idx = _db.get_index_type().indices().get(); auto obj = idx.rbegin(); if (obj != idx.rend()) { - return *obj; + return *obj; } return {}; } -optional database_api::get_son_wallet_by_time_point(time_point_sec time_point) -{ +optional database_api::get_son_wallet_by_time_point(time_point_sec time_point) { return my->get_son_wallet_by_time_point(time_point); } -optional database_api_impl::get_son_wallet_by_time_point(time_point_sec time_point) -{ - const auto& son_wallets_by_id = _db.get_index_type().indices().get(); - for (const son_wallet_object& swo : son_wallets_by_id) { +optional database_api_impl::get_son_wallet_by_time_point(time_point_sec time_point) { + const auto &son_wallets_by_id = _db.get_index_type().indices().get(); + for (const son_wallet_object &swo : son_wallets_by_id) { if ((time_point >= swo.valid_from) && (time_point < swo.expires)) return swo; } return {}; } -vector> database_api::get_son_wallets(uint32_t limit) -{ +vector> database_api::get_son_wallets(uint32_t limit) { return my->get_son_wallets(limit); } -vector> database_api_impl::get_son_wallets(uint32_t limit) -{ - FC_ASSERT( limit <= 1000 ); +vector> database_api_impl::get_son_wallets(uint32_t limit) { + FC_ASSERT(limit <= 1000); vector> result; - const auto& son_wallets_by_id = _db.get_index_type().indices().get(); - for (const son_wallet_object& swo : son_wallets_by_id) + const auto &son_wallets_by_id = _db.get_index_type().indices().get(); + for (const son_wallet_object &swo : son_wallets_by_id) result.push_back(swo); return result; } @@ -1961,78 +1809,69 @@ vector> database_api_impl::get_son_wallets(uint32_t // // ////////////////////////////////////////////////////////////////////// -vector> database_api::get_sidechain_addresses(const vector& sidechain_address_ids)const -{ - return my->get_sidechain_addresses( sidechain_address_ids ); +vector> database_api::get_sidechain_addresses(const vector &sidechain_address_ids) const { + return my->get_sidechain_addresses(sidechain_address_ids); } -vector> database_api_impl::get_sidechain_addresses(const vector& sidechain_address_ids)const -{ - vector> result; result.reserve(sidechain_address_ids.size()); +vector> database_api_impl::get_sidechain_addresses(const vector &sidechain_address_ids) const { + vector> result; + result.reserve(sidechain_address_ids.size()); std::transform(sidechain_address_ids.begin(), sidechain_address_ids.end(), std::back_inserter(result), [this](sidechain_address_id_type id) -> optional { - if(auto o = _db.find(id)) - return *o; - return {}; - }); + if (auto o = _db.find(id)) + return *o; + return {}; + }); return result; } -vector> database_api::get_sidechain_addresses_by_account(account_id_type account)const -{ - return my->get_sidechain_addresses_by_account( account ); +vector> database_api::get_sidechain_addresses_by_account(account_id_type account) const { + return my->get_sidechain_addresses_by_account(account); } -vector> database_api_impl::get_sidechain_addresses_by_account(account_id_type account)const -{ +vector> database_api_impl::get_sidechain_addresses_by_account(account_id_type account) const { vector> result; - const auto& sidechain_addresses_range = _db.get_index_type().indices().get().equal_range(account); + const auto &sidechain_addresses_range = _db.get_index_type().indices().get().equal_range(account); std::for_each(sidechain_addresses_range.first, sidechain_addresses_range.second, - [&result] (const sidechain_address_object& sao) { - if( sao.expires == time_point_sec::maximum() ) - result.push_back(sao); - }); + [&result](const sidechain_address_object &sao) { + if (sao.expires == time_point_sec::maximum()) + result.push_back(sao); + }); return result; } -vector> database_api::get_sidechain_addresses_by_sidechain(sidechain_type sidechain)const -{ - return my->get_sidechain_addresses_by_sidechain( sidechain ); +vector> database_api::get_sidechain_addresses_by_sidechain(sidechain_type sidechain) const { + return my->get_sidechain_addresses_by_sidechain(sidechain); } -vector> database_api_impl::get_sidechain_addresses_by_sidechain(sidechain_type sidechain)const -{ +vector> database_api_impl::get_sidechain_addresses_by_sidechain(sidechain_type sidechain) const { vector> result; - const auto& sidechain_addresses_range = _db.get_index_type().indices().get().equal_range(sidechain); + const auto &sidechain_addresses_range = _db.get_index_type().indices().get().equal_range(sidechain); std::for_each(sidechain_addresses_range.first, sidechain_addresses_range.second, - [&result] (const sidechain_address_object& sao) { - if( sao.expires == time_point_sec::maximum() ) - result.push_back(sao); - }); + [&result](const sidechain_address_object &sao) { + if (sao.expires == time_point_sec::maximum()) + result.push_back(sao); + }); return result; } -fc::optional database_api::get_sidechain_address_by_account_and_sidechain(account_id_type account, sidechain_type sidechain)const -{ - return my->get_sidechain_address_by_account_and_sidechain( account, sidechain ); +fc::optional database_api::get_sidechain_address_by_account_and_sidechain(account_id_type account, sidechain_type sidechain) const { + return my->get_sidechain_address_by_account_and_sidechain(account, sidechain); } -fc::optional database_api_impl::get_sidechain_address_by_account_and_sidechain(account_id_type account, sidechain_type sidechain)const -{ - const auto& idx = _db.get_index_type().indices().get(); - auto itr = idx.find( boost::make_tuple( account, sidechain, time_point_sec::maximum() ) ); - if( itr != idx.end() ) +fc::optional database_api_impl::get_sidechain_address_by_account_and_sidechain(account_id_type account, sidechain_type sidechain) const { + const auto &idx = _db.get_index_type().indices().get(); + auto itr = idx.find(boost::make_tuple(account, sidechain, time_point_sec::maximum())); + if (itr != idx.end()) return *itr; return {}; } -uint64_t database_api::get_sidechain_addresses_count()const -{ +uint64_t database_api::get_sidechain_addresses_count() const { return my->get_sidechain_addresses_count(); } -uint64_t database_api_impl::get_sidechain_addresses_count()const -{ +uint64_t database_api_impl::get_sidechain_addresses_count() const { return _db.get_index_type().indices().size(); } @@ -2042,75 +1881,66 @@ uint64_t database_api_impl::get_sidechain_addresses_count()const // // ////////////////////////////////////////////////////////////////////// -vector database_api::lookup_vote_ids( const vector& votes )const -{ - return my->lookup_vote_ids( votes ); +vector database_api::lookup_vote_ids(const vector &votes) const { + return my->lookup_vote_ids(votes); } -vector database_api_impl::lookup_vote_ids( const vector& votes )const -{ - FC_ASSERT( votes.size() < 1000, "Only 1000 votes can be queried at a time" ); +vector database_api_impl::lookup_vote_ids(const vector &votes) const { + FC_ASSERT(votes.size() < 1000, "Only 1000 votes can be queried at a time"); - const auto& witness_idx = _db.get_index_type().indices().get(); - const auto& committee_idx = _db.get_index_type().indices().get(); - const auto& for_worker_idx = _db.get_index_type().indices().get(); - const auto& against_worker_idx = _db.get_index_type().indices().get(); - const auto& son_idx = _db.get_index_type().indices().get(); + const auto &witness_idx = _db.get_index_type().indices().get(); + const auto &committee_idx = _db.get_index_type().indices().get(); + const auto &for_worker_idx = _db.get_index_type().indices().get(); + const auto &against_worker_idx = _db.get_index_type().indices().get(); + const auto &son_idx = _db.get_index_type().indices().get(); vector result; - result.reserve( votes.size() ); - for( auto id : votes ) - { - switch( id.type() ) - { - case vote_id_type::committee: - { - auto itr = committee_idx.find( id ); - if( itr != committee_idx.end() ) - result.emplace_back( variant( *itr, 1 ) ); - else - result.emplace_back( variant() ); - break; - } - case vote_id_type::witness: - { - auto itr = witness_idx.find( id ); - if( itr != witness_idx.end() ) - result.emplace_back( variant( *itr, 1 ) ); - else - result.emplace_back( variant() ); - break; - } - case vote_id_type::worker: - { - auto itr = for_worker_idx.find( id ); - if( itr != for_worker_idx.end() ) { - result.emplace_back( variant( *itr, 1 ) ); + result.reserve(votes.size()); + for (auto id : votes) { + switch (id.type()) { + case vote_id_type::committee: { + auto itr = committee_idx.find(id); + if (itr != committee_idx.end()) + result.emplace_back(variant(*itr, 1)); + else + result.emplace_back(variant()); + break; + } + case vote_id_type::witness: { + auto itr = witness_idx.find(id); + if (itr != witness_idx.end()) + result.emplace_back(variant(*itr, 1)); + else + result.emplace_back(variant()); + break; + } + case vote_id_type::worker: { + auto itr = for_worker_idx.find(id); + if (itr != for_worker_idx.end()) { + 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, 1)); + } else { + result.emplace_back(variant()); } - else { - auto itr = against_worker_idx.find( id ); - if( itr != against_worker_idx.end() ) { - result.emplace_back( variant( *itr, 1 ) ); - } - else { - result.emplace_back( variant() ); - } - } - break; - } - case vote_id_type::son: - { - auto itr = son_idx.find( id ); - if( itr != son_idx.end() ) - result.emplace_back( variant( *itr, 5 ) ); - else - result.emplace_back( variant() ); - break; } + break; + } + case vote_id_type::son: { + auto itr = son_idx.find(id); + if (itr != son_idx.end()) + result.emplace_back(variant(*itr, 5)); + else + result.emplace_back(variant()); + 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) ); + 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; @@ -2122,148 +1952,137 @@ vector database_api_impl::lookup_vote_ids( const vector& // // ////////////////////////////////////////////////////////////////////// -std::string database_api::get_transaction_hex(const signed_transaction& trx)const -{ - return my->get_transaction_hex( trx ); +std::string database_api::get_transaction_hex(const signed_transaction &trx) const { + return my->get_transaction_hex(trx); } -std::string database_api_impl::get_transaction_hex(const signed_transaction& trx)const -{ +std::string database_api_impl::get_transaction_hex(const signed_transaction &trx) const { return fc::to_hex(fc::raw::pack(trx)); } -set database_api::get_required_signatures( const signed_transaction& trx, const flat_set& available_keys )const -{ - return my->get_required_signatures( trx, available_keys ); +set database_api::get_required_signatures(const signed_transaction &trx, const flat_set &available_keys) const { + return my->get_required_signatures(trx, available_keys); } -set database_api_impl::get_required_signatures( const signed_transaction& trx, const flat_set& available_keys )const -{ +set database_api_impl::get_required_signatures(const signed_transaction &trx, const flat_set &available_keys) const { wdump((trx)(available_keys)); - auto result = trx.get_required_signatures( _db.get_chain_id(), - available_keys, - [&]( account_id_type id ){ return &id(_db).active; }, - [&]( account_id_type id ){ return &id(_db).owner; }, - [&]( account_id_type id, const operation& op ) { - return _db.get_account_custom_authorities(id, op); - }, - _db.get_global_properties().parameters.max_authority_depth ); + auto result = trx.get_required_signatures( + _db.get_chain_id(), + available_keys, + [&](account_id_type id) { + return &id(_db).active; + }, + [&](account_id_type id) { + return &id(_db).owner; + }, + [&](account_id_type id, const operation &op) { + return _db.get_account_custom_authorities(id, op); + }, + _db.get_global_properties().parameters.max_authority_depth); wdump((result)); return result; } -set database_api::get_potential_signatures( const signed_transaction& trx )const -{ - return my->get_potential_signatures( trx ); +set database_api::get_potential_signatures(const signed_transaction &trx) const { + return my->get_potential_signatures(trx); } -set
database_api::get_potential_address_signatures( const signed_transaction& trx )const -{ - return my->get_potential_address_signatures( trx ); +set
database_api::get_potential_address_signatures(const signed_transaction &trx) const { + return my->get_potential_address_signatures(trx); } -set database_api_impl::get_potential_signatures( const signed_transaction& trx )const -{ +set database_api_impl::get_potential_signatures(const signed_transaction &trx) const { wdump((trx)); set result; trx.get_required_signatures( - _db.get_chain_id(), - flat_set(), - [&]( account_id_type id ) - { - const auto& auth = id(_db).active; - for( const auto& k : auth.get_keys() ) - result.insert(k); - return &auth; - }, - [&]( account_id_type id ) - { - const auto& auth = id(_db).owner; - for( const auto& k : auth.get_keys() ) - result.insert(k); - return &auth; - }, - [&]( account_id_type id, const operation& op ) { - vector custom_auths = _db.get_account_custom_authorities(id, op); - for (const auto& cauth: custom_auths) - { - for (const auto& k : cauth.get_keys()) - { + _db.get_chain_id(), + flat_set(), + [&](account_id_type id) { + const auto &auth = id(_db).active; + for (const auto &k : auth.get_keys()) result.insert(k); + return &auth; + }, + [&](account_id_type id) { + const auto &auth = id(_db).owner; + for (const auto &k : auth.get_keys()) + result.insert(k); + return &auth; + }, + [&](account_id_type id, const operation &op) { + vector custom_auths = _db.get_account_custom_authorities(id, op); + for (const auto &cauth : custom_auths) { + for (const auto &k : cauth.get_keys()) { + result.insert(k); + } } - } - return custom_auths; - }, - _db.get_global_properties().parameters.max_authority_depth - ); + return custom_auths; + }, + _db.get_global_properties().parameters.max_authority_depth); wdump((result)); return result; } -set
database_api_impl::get_potential_address_signatures( const signed_transaction& trx )const -{ +set
database_api_impl::get_potential_address_signatures(const signed_transaction &trx) const { set
result; trx.get_required_signatures( - _db.get_chain_id(), - flat_set(), - [&]( account_id_type id ) - { - const auto& auth = id(_db).active; - for( const auto& k : auth.get_addresses() ) - result.insert(k); - return &auth; - }, - [&]( account_id_type id ) - { - const auto& auth = id(_db).owner; - for( const auto& k : auth.get_addresses() ) - result.insert(k); - return &auth; - }, - [&]( account_id_type id, const operation& op ) { - return _db.get_account_custom_authorities(id, op); - }, - _db.get_global_properties().parameters.max_authority_depth - ); + _db.get_chain_id(), + flat_set(), + [&](account_id_type id) { + const auto &auth = id(_db).active; + for (const auto &k : auth.get_addresses()) + result.insert(k); + return &auth; + }, + [&](account_id_type id) { + const auto &auth = id(_db).owner; + for (const auto &k : auth.get_addresses()) + result.insert(k); + return &auth; + }, + [&](account_id_type id, const operation &op) { + return _db.get_account_custom_authorities(id, op); + }, + _db.get_global_properties().parameters.max_authority_depth); return result; } -bool database_api::verify_authority( const signed_transaction& trx )const -{ - return my->verify_authority( trx ); +bool database_api::verify_authority(const signed_transaction &trx) const { + return my->verify_authority(trx); } -bool database_api_impl::verify_authority( const signed_transaction& trx )const -{ - trx.verify_authority( _db.get_chain_id(), - [this]( account_id_type id ){ return &id(_db).active; }, - [this]( account_id_type id ){ return &id(_db).owner; }, - [this]( account_id_type id, const operation& op ) { - return _db.get_account_custom_authorities(id, op); }, - _db.get_global_properties().parameters.max_authority_depth ); +bool database_api_impl::verify_authority(const signed_transaction &trx) const { + trx.verify_authority( + _db.get_chain_id(), + [this](account_id_type id) { + return &id(_db).active; + }, + [this](account_id_type id) { + return &id(_db).owner; + }, + [this](account_id_type id, const operation &op) { + return _db.get_account_custom_authorities(id, op); + }, + _db.get_global_properties().parameters.max_authority_depth); return true; } -bool database_api::verify_account_authority( const string& name_or_id, const flat_set& signers )const -{ - return my->verify_account_authority( name_or_id, signers ); +bool database_api::verify_account_authority(const string &name_or_id, const flat_set &signers) const { + return my->verify_account_authority(name_or_id, signers); } -bool database_api_impl::verify_account_authority( const string& name_or_id, const flat_set& keys )const -{ - FC_ASSERT( name_or_id.size() > 0); - const account_object* account = nullptr; +bool database_api_impl::verify_account_authority(const string &name_or_id, const flat_set &keys) const { + 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(1)); - else - { - const auto& idx = _db.get_index_type().indices().get(); + else { + const auto &idx = _db.get_index_type().indices().get(); auto itr = idx.find(name_or_id); if (itr != idx.end()) account = &*itr; } - FC_ASSERT( account, "no such account" ); - + FC_ASSERT(account, "no such account"); /// reuse trx.verify_authority by creating a dummy transfer signed_transaction trx; @@ -2271,98 +2090,85 @@ bool database_api_impl::verify_account_authority( const string& name_or_id, cons op.from = account->id; trx.operations.emplace_back(op); - return verify_authority( trx ); + return verify_authority(trx); } -processed_transaction database_api::validate_transaction( const signed_transaction& trx )const -{ - return my->validate_transaction( trx ); +processed_transaction database_api::validate_transaction(const signed_transaction &trx) const { + return my->validate_transaction(trx); } -processed_transaction database_api_impl::validate_transaction( const signed_transaction& trx )const -{ +processed_transaction database_api_impl::validate_transaction(const signed_transaction &trx) const { return _db.validate_transaction(trx); } -vector< fc::variant > database_api::get_required_fees( const vector& ops, const std::string& asset_id_or_symbol )const -{ - return my->get_required_fees( ops, asset_id_or_symbol ); +vector database_api::get_required_fees(const vector &ops, const std::string &asset_id_or_symbol) const { + return my->get_required_fees(ops, asset_id_or_symbol); } /** * Container method for mutually recursive functions used to * implement get_required_fees() with potentially nested proposals. */ -struct get_required_fees_helper -{ +struct get_required_fees_helper { get_required_fees_helper( - const fee_schedule& _current_fee_schedule, - const price& _core_exchange_rate, - uint32_t _max_recursion - ) - : current_fee_schedule(_current_fee_schedule), - core_exchange_rate(_core_exchange_rate), - max_recursion(_max_recursion) - {} + const fee_schedule &_current_fee_schedule, + const price &_core_exchange_rate, + uint32_t _max_recursion) : + current_fee_schedule(_current_fee_schedule), + core_exchange_rate(_core_exchange_rate), + max_recursion(_max_recursion) { + } - fc::variant set_op_fees( operation& op ) - { - if( op.which() == operation::tag::value ) - { - return set_proposal_create_op_fees( op ); - } - else - { - asset fee = current_fee_schedule.set_fee( op, core_exchange_rate ); + fc::variant set_op_fees(operation &op) { + if (op.which() == operation::tag::value) { + return set_proposal_create_op_fees(op); + } else { + asset fee = current_fee_schedule.set_fee(op, core_exchange_rate); fc::variant result; - fc::to_variant( fee, result, GRAPHENE_NET_MAX_NESTED_OBJECTS ); + fc::to_variant(fee, result, GRAPHENE_NET_MAX_NESTED_OBJECTS); return result; } } - fc::variant set_proposal_create_op_fees( operation& proposal_create_op ) - { - proposal_create_operation& op = proposal_create_op.get(); - std::pair< asset, fc::variants > result; - for( op_wrapper& prop_op : op.proposed_ops ) - { - FC_ASSERT( current_recursion < max_recursion ); + fc::variant set_proposal_create_op_fees(operation &proposal_create_op) { + proposal_create_operation &op = proposal_create_op.get(); + std::pair result; + for (op_wrapper &prop_op : op.proposed_ops) { + FC_ASSERT(current_recursion < max_recursion); ++current_recursion; - result.second.push_back( set_op_fees( prop_op.op ) ); + result.second.push_back(set_op_fees(prop_op.op)); --current_recursion; } // we need to do this on the boxed version, which is why we use // two mutually recursive functions instead of a visitor - result.first = current_fee_schedule.set_fee( proposal_create_op, core_exchange_rate ); + result.first = current_fee_schedule.set_fee(proposal_create_op, core_exchange_rate); fc::variant vresult; - fc::to_variant( result, vresult, GRAPHENE_NET_MAX_NESTED_OBJECTS ); + fc::to_variant(result, vresult, GRAPHENE_NET_MAX_NESTED_OBJECTS); return vresult; } - const fee_schedule& current_fee_schedule; - const price& core_exchange_rate; + const fee_schedule ¤t_fee_schedule; + const price &core_exchange_rate; uint32_t max_recursion; uint32_t current_recursion = 0; }; -vector< fc::variant > database_api_impl::get_required_fees( const vector& ops, const std::string& asset_id_or_symbol )const -{ - vector< operation > _ops = ops; +vector database_api_impl::get_required_fees(const vector &ops, const std::string &asset_id_or_symbol) const { + vector _ops = ops; // // we copy the ops because we need to mutate an operation to reliably // determine its fee, see #435 // - vector< fc::variant > result; + vector result; result.reserve(ops.size()); - const asset_object& a = *get_asset_from_string(asset_id_or_symbol); + 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, - GET_REQUIRED_FEES_MAX_RECURSION ); - for( operation& op : _ops ) - { - result.push_back( helper.set_op_fees( op ) ); + _db.current_fee_schedule(), + a.options.core_exchange_rate, + GET_REQUIRED_FEES_MAX_RECURSION); + for (operation &op : _ops) { + result.push_back(helper.set_op_fees(op)); } return result; } @@ -2373,26 +2179,24 @@ vector< fc::variant > database_api_impl::get_required_fees( const vector database_api::get_proposed_transactions( const std::string account_id_or_name )const -{ - return my->get_proposed_transactions( account_id_or_name ); +vector database_api::get_proposed_transactions(const std::string account_id_or_name) const { + return my->get_proposed_transactions(account_id_or_name); } /** TODO: add secondary index that will accelerate this process */ -vector database_api_impl::get_proposed_transactions( const std::string account_id_or_name )const -{ - const auto& idx = _db.get_index_type(); +vector database_api_impl::get_proposed_transactions(const std::string account_id_or_name) const { + const auto &idx = _db.get_index_type(); vector 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(obj); - if( p.required_active_approvals.find( id ) != p.required_active_approvals.end() ) - result.push_back(p); - else if ( p.required_owner_approvals.find( id ) != p.required_owner_approvals.end() ) - result.push_back(p); - else if ( p.available_active_approvals.find( id ) != p.available_active_approvals.end() ) - result.push_back(p); + idx.inspect_all_objects([&](const object &obj) { + const proposal_object &p = static_cast(obj); + if (p.required_active_approvals.find(id) != p.required_active_approvals.end()) + result.push_back(p); + else if (p.required_owner_approvals.find(id) != p.required_owner_approvals.end()) + result.push_back(p); + else if (p.available_active_approvals.find(id) != p.available_active_approvals.end()) + result.push_back(p); }); return result; } @@ -2403,21 +2207,19 @@ vector database_api_impl::get_proposed_transactions( const std: // // ////////////////////////////////////////////////////////////////////// -vector database_api::get_blinded_balances( const flat_set& commitments )const -{ - return my->get_blinded_balances( commitments ); +vector database_api::get_blinded_balances(const flat_set &commitments) const { + return my->get_blinded_balances(commitments); } -vector database_api_impl::get_blinded_balances( const flat_set& commitments )const -{ - vector result; result.reserve(commitments.size()); - const auto& bal_idx = _db.get_index_type(); - const auto& by_commitment_idx = bal_idx.indices().get(); - for( const auto& c : commitments ) - { - auto itr = by_commitment_idx.find( c ); - if( itr != by_commitment_idx.end() ) - result.push_back( *itr ); +vector database_api_impl::get_blinded_balances(const flat_set &commitments) const { + vector result; + result.reserve(commitments.size()); + const auto &bal_idx = _db.get_index_type(); + const auto &by_commitment_idx = bal_idx.indices().get(); + for (const auto &c : commitments) { + auto itr = by_commitment_idx.find(c); + if (itr != by_commitment_idx.end()) + result.push_back(*itr); } return result; } @@ -2427,20 +2229,17 @@ vector database_api_impl::get_blinded_balances( const fl // Tournament methods // // // ////////////////////////////////////////////////////////////////////// -vector database_api::get_tournaments_in_state(tournament_state state, uint32_t limit) const -{ +vector database_api::get_tournaments_in_state(tournament_state state, uint32_t limit) const { return my->get_tournaments_in_state(state, limit); } -vector database_api_impl::get_tournaments_in_state(tournament_state state, uint32_t limit) const -{ +vector database_api_impl::get_tournaments_in_state(tournament_state state, uint32_t limit) const { vector result; - const auto& registration_deadline_index = _db.get_index_type().indices().get(); + const auto ®istration_deadline_index = _db.get_index_type().indices().get(); const auto range = registration_deadline_index.equal_range(boost::make_tuple(state)); - for (const tournament_object& tournament_obj : boost::make_iterator_range(range.first, range.second)) - { + for (const tournament_object &tournament_obj : boost::make_iterator_range(range.first, range.second)) { result.emplace_back(tournament_obj); - subscribe_to_item( tournament_obj.id ); + subscribe_to_item(tournament_obj.id); if (result.size() >= limit) break; @@ -2450,84 +2249,77 @@ vector database_api_impl::get_tournaments_in_state(tournament vector database_api::get_tournaments(tournament_id_type stop, unsigned limit, - tournament_id_type start) -{ + tournament_id_type start) { return my->get_tournaments(stop, limit, start); } vector database_api_impl::get_tournaments(tournament_id_type stop, unsigned limit, - tournament_id_type start) -{ + tournament_id_type start) { vector result; - const auto& tournament_idx = _db.get_index_type().indices().get(); - for (auto elem: tournament_idx) { - if( result.size() >= limit ) break; - if( ( (elem.get_id().instance.value <= start.instance.value) || start == tournament_id_type()) && - ( (elem.get_id().instance.value >= stop.instance.value) || stop == tournament_id_type())) - result.push_back( elem ); + const auto &tournament_idx = _db.get_index_type().indices().get(); + for (auto elem : tournament_idx) { + if (result.size() >= limit) + break; + if (((elem.get_id().instance.value <= start.instance.value) || start == tournament_id_type()) && + ((elem.get_id().instance.value >= stop.instance.value) || stop == tournament_id_type())) + result.push_back(elem); } return result; } - vector database_api::get_tournaments_by_state(tournament_id_type stop, unsigned limit, tournament_id_type start, - tournament_state state) -{ + tournament_state state) { return my->get_tournaments_by_state(stop, limit, start, state); } vector database_api_impl::get_tournaments_by_state(tournament_id_type stop, unsigned limit, tournament_id_type start, - tournament_state state) -{ + tournament_state state) { vector result; - const auto& tournament_idx = _db.get_index_type().indices().get(); - for (auto elem: tournament_idx) { - if( result.size() >= limit ) break; - if( ( (elem.get_id().instance.value <= start.instance.value) || start == tournament_id_type()) && - ( (elem.get_id().instance.value >= stop.instance.value) || stop == tournament_id_type()) && - elem.get_state() == state ) - result.push_back( elem ); + const auto &tournament_idx = _db.get_index_type().indices().get(); + for (auto elem : tournament_idx) { + if (result.size() >= limit) + break; + if (((elem.get_id().instance.value <= start.instance.value) || start == tournament_id_type()) && + ((elem.get_id().instance.value >= stop.instance.value) || stop == tournament_id_type()) && + elem.get_state() == state) + result.push_back(elem); } return result; } -const account_object* database_api_impl::get_account_from_string( const std::string& name_or_id, - bool throw_if_not_found ) const -{ +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; + 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(1)); - else - { - const auto& idx = _db.get_index_type().indices().get(); + else { + const auto &idx = _db.get_index_type().indices().get(); auto itr = idx.find(name_or_id); if (itr != idx.end()) account = &*itr; } - if(throw_if_not_found) - FC_ASSERT( account, "no such account" ); + if (throw_if_not_found) + FC_ASSERT(account, "no such account"); return account; } -vector database_api::get_registered_tournaments(account_id_type account_filter, uint32_t limit) const -{ +vector database_api::get_registered_tournaments(account_id_type account_filter, uint32_t limit) const { return my->get_registered_tournaments(account_filter, limit); } -vector database_api_impl::get_registered_tournaments(account_id_type account_filter, uint32_t limit) const -{ - const auto& tournament_details_idx = _db.get_index_type(); - const auto& tournament_details_primary_idx = dynamic_cast&>(tournament_details_idx); - const auto& players_idx = tournament_details_primary_idx.get_secondary_index(); +vector database_api_impl::get_registered_tournaments(account_id_type account_filter, uint32_t limit) const { + const auto &tournament_details_idx = _db.get_index_type(); + const auto &tournament_details_primary_idx = dynamic_cast &>(tournament_details_idx); + const auto &players_idx = tournament_details_primary_idx.get_secondary_index(); vector tournament_ids = players_idx.get_registered_tournaments_for_account(account_filter); if (tournament_ids.size() >= limit) @@ -2541,66 +2333,48 @@ vector database_api_impl::get_registered_tournaments(account // // ////////////////////////////////////////////////////////////////////// -graphene::app::gpos_info database_api::get_gpos_info(const account_id_type account) const -{ +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 +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); + const auto ÷nd_data = asset_id_type()(_db).dividend_data(_db); + const account_object ÷nd_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().lower_bound(boost::make_tuple(asset_id_type(), balance_type)); - auto vesting_balances_end = - vesting_index.indices().get().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(); - const auto& vesting_balances = vesting_index.indices().get(); - 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) - { + // get only once a collection of accounts that hold nonzero vesting balances of the dividend asset + const vesting_balance_index &vesting_index = _db.get_index_type(); + const auto &vesting_balances = vesting_index.indices().get(); + 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 account_vbos; const time_point_sec now = _db.head_block_time(); auto vesting_range = _db.get_index_type().indices().get().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); - }); - + [&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) - { + + 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)) + if (vesting_balance_obj.is_withdraw_allowed(_db.head_block_time(), vesting_balance_obj.balance.amount)) allowed_withdraw_amount += vesting_balance_obj.balance.amount; } @@ -2616,34 +2390,28 @@ graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type // // ////////////////////////////////////////////////////////////////////// -vector database_api::get_custom_permissions(const account_id_type account) const -{ +vector database_api::get_custom_permissions(const account_id_type account) const { return my->get_custom_permissions(account); } -vector database_api_impl::get_custom_permissions(const account_id_type account) const -{ - const auto& pindex = _db.get_index_type().indices().get(); +vector database_api_impl::get_custom_permissions(const account_id_type account) const { + const auto &pindex = _db.get_index_type().indices().get(); auto prange = pindex.equal_range(boost::make_tuple(account)); vector custom_permissions; - for(const custom_permission_object& pobj : boost::make_iterator_range(prange.first, prange.second)) - { + for (const custom_permission_object &pobj : boost::make_iterator_range(prange.first, prange.second)) { custom_permissions.push_back(pobj); } return custom_permissions; } -fc::optional database_api::get_custom_permission_by_name(const account_id_type account, const string& permission_name) const -{ +fc::optional database_api::get_custom_permission_by_name(const account_id_type account, const string &permission_name) const { return my->get_custom_permission_by_name(account, permission_name); } -fc::optional database_api_impl::get_custom_permission_by_name(const account_id_type account, const string& permission_name) const -{ - const auto& pindex = _db.get_index_type().indices().get(); +fc::optional database_api_impl::get_custom_permission_by_name(const account_id_type account, const string &permission_name) const { + const auto &pindex = _db.get_index_type().indices().get(); auto prange = pindex.equal_range(boost::make_tuple(account, permission_name)); - for(const custom_permission_object& pobj : boost::make_iterator_range(prange.first, prange.second)) - { + for (const custom_permission_object &pobj : boost::make_iterator_range(prange.first, prange.second)) { return pobj; } return {}; @@ -2655,59 +2423,51 @@ fc::optional database_api_impl::get_custom_permission_ // // ////////////////////////////////////////////////////////////////////// -uint64_t database_api::nft_get_balance(const account_id_type owner) const -{ +uint64_t database_api::nft_get_balance(const account_id_type owner) const { return my->nft_get_balance(owner); } -uint64_t database_api_impl::nft_get_balance(const account_id_type owner) const -{ +uint64_t database_api_impl::nft_get_balance(const account_id_type owner) const { const auto &idx_nft = _db.get_index_type().indices().get(); const auto &idx_nft_range = idx_nft.equal_range(owner); return std::distance(idx_nft_range.first, idx_nft_range.second); } -optional database_api::nft_owner_of(const nft_id_type token_id) const -{ +optional database_api::nft_owner_of(const nft_id_type token_id) const { return my->nft_owner_of(token_id); } -optional database_api_impl::nft_owner_of(const nft_id_type token_id) const -{ +optional database_api_impl::nft_owner_of(const nft_id_type token_id) const { const auto &idx_nft = _db.get_index_type().indices().get(); auto itr_nft = idx_nft.find(token_id); if (itr_nft != idx_nft.end()) { - return itr_nft->owner; + return itr_nft->owner; } return {}; } -optional database_api::nft_get_approved(const nft_id_type token_id) const -{ +optional database_api::nft_get_approved(const nft_id_type token_id) const { return my->nft_get_approved(token_id); } -optional database_api_impl::nft_get_approved(const nft_id_type token_id) const -{ +optional database_api_impl::nft_get_approved(const nft_id_type token_id) const { const auto &idx_nft = _db.get_index_type().indices().get(); auto itr_nft = idx_nft.find(token_id); if (itr_nft != idx_nft.end()) { - return itr_nft->approved; + return itr_nft->approved; } return {}; } -bool database_api::nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const -{ +bool database_api::nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const { return my->nft_is_approved_for_all(owner, operator_); } -bool database_api_impl::nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const -{ +bool database_api_impl::nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const { const auto &idx_nft = _db.get_index_type().indices().get(); const auto &idx_nft_range = idx_nft.equal_range(owner); if (std::distance(idx_nft_range.first, idx_nft_range.second) == 0) { - return false; + return false; } bool result = true; std::for_each(idx_nft_range.first, idx_nft_range.second, [&](const nft_object &obj) { @@ -2716,43 +2476,37 @@ bool database_api_impl::nft_is_approved_for_all(const account_id_type owner, con return result; } -string database_api::nft_get_name(const nft_metadata_id_type nft_metadata_id) const -{ +string database_api::nft_get_name(const nft_metadata_id_type nft_metadata_id) const { return my->nft_get_name(nft_metadata_id); } -string database_api_impl::nft_get_name(const nft_metadata_id_type nft_metadata_id) const -{ +string database_api_impl::nft_get_name(const nft_metadata_id_type nft_metadata_id) const { const auto &idx_nft_md = _db.get_index_type().indices().get(); auto itr_nft_md = idx_nft_md.find(nft_metadata_id); if (itr_nft_md != idx_nft_md.end()) { - return itr_nft_md->name; + return itr_nft_md->name; } return ""; } -string database_api::nft_get_symbol(const nft_metadata_id_type nft_metadata_id) const -{ +string database_api::nft_get_symbol(const nft_metadata_id_type nft_metadata_id) const { return my->nft_get_symbol(nft_metadata_id); } -string database_api_impl::nft_get_symbol(const nft_metadata_id_type nft_metadata_id) const -{ +string database_api_impl::nft_get_symbol(const nft_metadata_id_type nft_metadata_id) const { const auto &idx_nft_md = _db.get_index_type().indices().get(); auto itr_nft_md = idx_nft_md.find(nft_metadata_id); if (itr_nft_md != idx_nft_md.end()) { - return itr_nft_md->symbol; + return itr_nft_md->symbol; } return ""; } -string database_api::nft_get_token_uri(const nft_id_type token_id) const -{ +string database_api::nft_get_token_uri(const nft_id_type token_id) const { return my->nft_get_token_uri(token_id); } -string database_api_impl::nft_get_token_uri(const nft_id_type token_id) const -{ +string database_api_impl::nft_get_token_uri(const nft_id_type token_id) const { string result = ""; const auto &idx_nft = _db.get_index_type().indices().get(); auto itr_nft = idx_nft.find(token_id); @@ -2767,62 +2521,54 @@ string database_api_impl::nft_get_token_uri(const nft_id_type token_id) const return result; } -uint64_t database_api::nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const -{ +uint64_t database_api::nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const { return my->nft_get_total_supply(nft_metadata_id); } -uint64_t database_api_impl::nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const -{ +uint64_t database_api_impl::nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const { const auto &idx_nft_md = _db.get_index_type().indices().get(); return idx_nft_md.size(); } -nft_object database_api::nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const -{ +nft_object database_api::nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const { return my->nft_token_by_index(nft_metadata_id, token_idx); } -nft_object database_api_impl::nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const -{ +nft_object database_api_impl::nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const { const auto &idx_nft = _db.get_index_type().indices().get(); auto idx_nft_range = idx_nft.equal_range(nft_metadata_id); uint64_t tmp_idx = token_idx; for (auto itr = idx_nft_range.first; itr != idx_nft_range.second; ++itr) { if (tmp_idx == 0) { - return *itr; + return *itr; } tmp_idx = tmp_idx - 1; } return {}; } -nft_object database_api::nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const -{ +nft_object database_api::nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const { return my->nft_token_of_owner_by_index(nft_metadata_id, owner, token_idx); } -nft_object database_api_impl::nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const -{ +nft_object database_api_impl::nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const { const auto &idx_nft = _db.get_index_type().indices().get(); auto idx_nft_range = idx_nft.equal_range(std::make_tuple(nft_metadata_id, owner)); uint64_t tmp_idx = token_idx; for (auto itr = idx_nft_range.first; itr != idx_nft_range.second; ++itr) { if (tmp_idx == 0) { - return *itr; + return *itr; } tmp_idx = tmp_idx - 1; } return {}; } -vector database_api::nft_get_all_tokens() const -{ +vector database_api::nft_get_all_tokens() const { return my->nft_get_all_tokens(); } -vector database_api_impl::nft_get_all_tokens() const -{ +vector database_api_impl::nft_get_all_tokens() const { const auto &idx_nft = _db.get_index_type().indices().get(); vector result; for (auto itr = idx_nft.begin(); itr != idx_nft.end(); ++itr) { @@ -2831,13 +2577,11 @@ vector database_api_impl::nft_get_all_tokens() const return result; } -vector database_api::nft_get_tokens_by_owner(const account_id_type owner) const -{ +vector database_api::nft_get_tokens_by_owner(const account_id_type owner) const { return my->nft_get_tokens_by_owner(owner); } -vector database_api_impl::nft_get_tokens_by_owner(const account_id_type owner) const -{ +vector database_api_impl::nft_get_tokens_by_owner(const account_id_type owner) const { const auto &idx_nft = _db.get_index_type().indices().get(); auto idx_nft_range = idx_nft.equal_range(owner); vector result; @@ -2847,118 +2591,103 @@ vector database_api_impl::nft_get_tokens_by_owner(const account_id_t return result; } -vector database_api::get_custom_account_authorities(const account_id_type account) const -{ +vector database_api::get_custom_account_authorities(const account_id_type account) const { return my->get_custom_account_authorities(account); } -vector database_api_impl::get_custom_account_authorities(const account_id_type account) const -{ - const auto& pindex = _db.get_index_type().indices().get(); - const auto& cindex = _db.get_index_type().indices().get(); +vector database_api_impl::get_custom_account_authorities(const account_id_type account) const { + const auto &pindex = _db.get_index_type().indices().get(); + const auto &cindex = _db.get_index_type().indices().get(); vector custom_account_auths; auto prange = pindex.equal_range(boost::make_tuple(account)); - for(const custom_permission_object& pobj : boost::make_iterator_range(prange.first, prange.second)) - { + for (const custom_permission_object &pobj : boost::make_iterator_range(prange.first, prange.second)) { auto crange = cindex.equal_range(boost::make_tuple(pobj.id)); - for(const custom_account_authority_object& cobj : boost::make_iterator_range(crange.first, crange.second)) - { + for (const custom_account_authority_object &cobj : boost::make_iterator_range(crange.first, crange.second)) { custom_account_auths.push_back(cobj); } } return custom_account_auths; } -vector database_api::get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const -{ +vector database_api::get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const { return my->get_custom_account_authorities_by_permission_id(permission_id); } -vector database_api_impl::get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const -{ - const auto& cindex = _db.get_index_type().indices().get(); +vector database_api_impl::get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const { + const auto &cindex = _db.get_index_type().indices().get(); vector custom_account_auths; auto crange = cindex.equal_range(boost::make_tuple(permission_id)); - for(const custom_account_authority_object& cobj : boost::make_iterator_range(crange.first, crange.second)) - { + for (const custom_account_authority_object &cobj : boost::make_iterator_range(crange.first, crange.second)) { custom_account_auths.push_back(cobj); } return custom_account_auths; } -vector database_api::get_custom_account_authorities_by_permission_name(const account_id_type account, const string& permission_name) const -{ +vector database_api::get_custom_account_authorities_by_permission_name(const account_id_type account, const string &permission_name) const { return my->get_custom_account_authorities_by_permission_name(account, permission_name); } -vector database_api_impl::get_custom_account_authorities_by_permission_name(const account_id_type account, const string& permission_name) const -{ +vector database_api_impl::get_custom_account_authorities_by_permission_name(const account_id_type account, const string &permission_name) const { vector custom_account_auths; fc::optional pobj = get_custom_permission_by_name(account, permission_name); - if(!pobj) - { + if (!pobj) { return custom_account_auths; } - const auto& cindex = _db.get_index_type().indices().get(); + const auto &cindex = _db.get_index_type().indices().get(); auto crange = cindex.equal_range(boost::make_tuple(pobj->id)); - for(const custom_account_authority_object& cobj : boost::make_iterator_range(crange.first, crange.second)) - { + for (const custom_account_authority_object &cobj : boost::make_iterator_range(crange.first, crange.second)) { custom_account_auths.push_back(cobj); } return custom_account_auths; } -vector database_api::get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const -{ +vector database_api::get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const { return my->get_active_custom_account_authorities_by_operation(account, operation_type); } -vector database_api_impl::get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const -{ +vector database_api_impl::get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const { operation op; op.set_which(operation_type); return _db.get_account_custom_authorities(account, op); } // Marketplace -vector database_api::list_offers(const offer_id_type lower_id, uint32_t limit) const -{ +vector database_api::list_offers(const offer_id_type lower_id, uint32_t limit) const { return my->list_offers(lower_id, limit); } -vector database_api_impl::list_offers(const offer_id_type lower_id, uint32_t limit) const -{ - FC_ASSERT( limit <= 100 ); - const auto& offers_idx = _db.get_index_type().indices().get(); +vector database_api_impl::list_offers(const offer_id_type lower_id, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_all_offers_count, + "Number of querying offers can not be greater than ${configured_limit}", + ("configured_limit", api_limit_all_offers_count)); + const auto &offers_idx = _db.get_index_type().indices().get(); vector result; result.reserve(limit); auto itr = offers_idx.lower_bound(lower_id); - while(limit-- && itr != offers_idx.end()) + while (limit-- && itr != offers_idx.end()) result.emplace_back(*itr++); return result; } -vector database_api::list_sell_offers(const offer_id_type lower_id, uint32_t limit) const -{ +vector database_api::list_sell_offers(const offer_id_type lower_id, uint32_t limit) const { return my->list_sell_offers(lower_id, limit); } -vector database_api_impl::list_sell_offers(const offer_id_type lower_id, uint32_t limit) const -{ - FC_ASSERT( limit <= 100 ); - const auto& offers_idx = _db.get_index_type().indices().get(); +vector database_api_impl::list_sell_offers(const offer_id_type lower_id, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_all_offers_count, + "Number of querying offers can not be greater than ${configured_limit}", + ("configured_limit", api_limit_all_offers_count)); + const auto &offers_idx = _db.get_index_type().indices().get(); vector result; result.reserve(limit); auto itr = offers_idx.lower_bound(lower_id); - while(limit && itr != offers_idx.end()) - { - if(itr->buying_item == false) - { + while (limit && itr != offers_idx.end()) { + if (itr->buying_item == false) { result.emplace_back(*itr); limit--; } @@ -2967,24 +2696,22 @@ vector database_api_impl::list_sell_offers(const offer_id_type low return result; } -vector database_api::list_buy_offers(const offer_id_type lower_id, uint32_t limit) const -{ +vector database_api::list_buy_offers(const offer_id_type lower_id, uint32_t limit) const { return my->list_buy_offers(lower_id, limit); } -vector database_api_impl::list_buy_offers(const offer_id_type lower_id, uint32_t limit) const -{ - FC_ASSERT( limit <= 100 ); - const auto& offers_idx = _db.get_index_type().indices().get(); +vector database_api_impl::list_buy_offers(const offer_id_type lower_id, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_all_offers_count, + "Number of querying offers can not be greater than ${configured_limit}", + ("configured_limit", api_limit_all_offers_count)); + const auto &offers_idx = _db.get_index_type().indices().get(); vector result; result.reserve(limit); auto itr = offers_idx.lower_bound(lower_id); - while(limit && itr != offers_idx.end()) - { - if(itr->buying_item == true) - { + while (limit && itr != offers_idx.end()) { + if (itr->buying_item == true) { result.emplace_back(*itr); limit--; } @@ -2994,42 +2721,40 @@ vector database_api_impl::list_buy_offers(const offer_id_type lowe return result; } -vector database_api::list_offer_history(const offer_history_id_type lower_id, uint32_t limit) const -{ +vector database_api::list_offer_history(const offer_history_id_type lower_id, uint32_t limit) const { return my->list_offer_history(lower_id, limit); } -vector database_api_impl::list_offer_history(const offer_history_id_type lower_id, uint32_t limit) const -{ - FC_ASSERT( limit <= 100 ); - const auto& oh_idx = _db.get_index_type().indices().get(); +vector database_api_impl::list_offer_history(const offer_history_id_type lower_id, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_all_offers_count, + "Number of querying offers can not be greater than ${configured_limit}", + ("configured_limit", api_limit_all_offers_count)); + const auto &oh_idx = _db.get_index_type().indices().get(); vector result; result.reserve(limit); auto itr = oh_idx.lower_bound(lower_id); - while(limit-- && itr != oh_idx.end()) + while (limit-- && itr != oh_idx.end()) result.emplace_back(*itr++); return result; } -vector database_api::get_offers_by_issuer(const offer_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const -{ +vector database_api::get_offers_by_issuer(const offer_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const { return my->get_offers_by_issuer(lower_id, issuer_account_id, limit); } -vector database_api_impl::get_offers_by_issuer(const offer_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const -{ - FC_ASSERT( limit <= 100 ); - const auto& offers_idx = _db.get_index_type().indices().get(); +vector database_api_impl::get_offers_by_issuer(const offer_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_all_offers_count, + "Number of querying offers can not be greater than ${configured_limit}", + ("configured_limit", api_limit_all_offers_count)); + const auto &offers_idx = _db.get_index_type().indices().get(); vector result; result.reserve(limit); auto itr = offers_idx.lower_bound(lower_id); - while(limit && itr != offers_idx.end()) - { - if(itr->issuer == issuer_account_id) - { + while (limit && itr != offers_idx.end()) { + if (itr->issuer == issuer_account_id) { result.emplace_back(*itr); limit--; } @@ -3038,23 +2763,21 @@ vector database_api_impl::get_offers_by_issuer(const offer_id_type return result; } -vector database_api::get_offers_by_item(const offer_id_type lower_id, const nft_id_type item, uint32_t limit) const -{ +vector database_api::get_offers_by_item(const offer_id_type lower_id, const nft_id_type item, uint32_t limit) const { return my->get_offers_by_item(lower_id, item, limit); } -vector database_api_impl::get_offers_by_item(const offer_id_type lower_id, const nft_id_type item, uint32_t limit) const -{ - FC_ASSERT( limit <= 100 ); - const auto& offers_idx = _db.get_index_type().indices().get(); +vector database_api_impl::get_offers_by_item(const offer_id_type lower_id, const nft_id_type item, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_all_offers_count, + "Number of querying offers can not be greater than ${configured_limit}", + ("configured_limit", api_limit_all_offers_count)); + const auto &offers_idx = _db.get_index_type().indices().get(); vector result; result.reserve(limit); auto itr = offers_idx.lower_bound(lower_id); - while(limit && itr != offers_idx.end()) - { - if(itr->item_ids.find(item) != itr->item_ids.end()) - { + while (limit && itr != offers_idx.end()) { + if (itr->item_ids.find(item) != itr->item_ids.end()) { result.emplace_back(*itr); limit--; } @@ -3063,34 +2786,30 @@ vector database_api_impl::get_offers_by_item(const offer_id_type l return result; } -vector database_api::get_offer_history_by_issuer(const offer_history_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const -{ +vector database_api::get_offer_history_by_issuer(const offer_history_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const { return my->get_offer_history_by_issuer(lower_id, issuer_account_id, limit); } -vector database_api::get_offer_history_by_item(const offer_history_id_type lower_id, const nft_id_type item, uint32_t limit) const -{ +vector database_api::get_offer_history_by_item(const offer_history_id_type lower_id, const nft_id_type item, uint32_t limit) const { return my->get_offer_history_by_item(lower_id, item, limit); } -vector database_api::get_offer_history_by_bidder(const offer_history_id_type lower_id, const account_id_type bidder_account_id, uint32_t limit) const -{ +vector database_api::get_offer_history_by_bidder(const offer_history_id_type lower_id, const account_id_type bidder_account_id, uint32_t limit) const { return my->get_offer_history_by_bidder(lower_id, bidder_account_id, limit); } -vector database_api_impl::get_offer_history_by_issuer(const offer_history_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const -{ - FC_ASSERT( limit <= 100 ); - const auto& oh_idx = _db.get_index_type().indices().get(); +vector database_api_impl::get_offer_history_by_issuer(const offer_history_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_all_offers_count, + "Number of querying offers can not be greater than ${configured_limit}", + ("configured_limit", api_limit_all_offers_count)); + const auto &oh_idx = _db.get_index_type().indices().get(); vector result; result.reserve(limit); auto itr = oh_idx.lower_bound(lower_id); - while(limit && itr != oh_idx.end()) - { - if(itr->issuer == issuer_account_id) - { + while (limit && itr != oh_idx.end()) { + if (itr->issuer == issuer_account_id) { result.emplace_back(*itr); limit--; } @@ -3099,19 +2818,18 @@ vector database_api_impl::get_offer_history_by_issuer(cons return result; } -vector database_api_impl::get_offer_history_by_item(const offer_history_id_type lower_id, const nft_id_type item, uint32_t limit) const -{ - FC_ASSERT( limit <= 100 ); - const auto& oh_idx = _db.get_index_type().indices().get(); +vector database_api_impl::get_offer_history_by_item(const offer_history_id_type lower_id, const nft_id_type item, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_all_offers_count, + "Number of querying offers can not be greater than ${configured_limit}", + ("configured_limit", api_limit_all_offers_count)); + const auto &oh_idx = _db.get_index_type().indices().get(); vector result; result.reserve(limit); auto itr = oh_idx.lower_bound(lower_id); - while(limit && itr != oh_idx.end()) - { - if(itr->item_ids.find(item) != itr->item_ids.end()) - { + while (limit && itr != oh_idx.end()) { + if (itr->item_ids.find(item) != itr->item_ids.end()) { result.emplace_back(*itr); limit--; } @@ -3121,19 +2839,18 @@ vector database_api_impl::get_offer_history_by_item(const return result; } -vector database_api_impl::get_offer_history_by_bidder(const offer_history_id_type lower_id, const account_id_type bidder_account_id, uint32_t limit) const -{ - FC_ASSERT( limit <= 100 ); - const auto& oh_idx = _db.get_index_type().indices().get(); +vector database_api_impl::get_offer_history_by_bidder(const offer_history_id_type lower_id, const account_id_type bidder_account_id, uint32_t limit) const { + FC_ASSERT(limit <= api_limit_all_offers_count, + "Number of querying offers can not be greater than ${configured_limit}", + ("configured_limit", api_limit_all_offers_count)); + const auto &oh_idx = _db.get_index_type().indices().get(); vector result; result.reserve(limit); auto itr = oh_idx.lower_bound(lower_id); - while(limit && itr != oh_idx.end()) - { - if(itr->bidder && *itr->bidder == bidder_account_id) - { + while (limit && itr != oh_idx.end()) { + if (itr->bidder && *itr->bidder == bidder_account_id) { result.emplace_back(*itr); limit--; } @@ -3143,18 +2860,15 @@ vector database_api_impl::get_offer_history_by_bidder(cons return result; } -vector database_api::get_account_roles_by_owner(account_id_type owner) const -{ +vector database_api::get_account_roles_by_owner(account_id_type owner) const { return my->get_account_roles_by_owner(owner); } -vector database_api_impl::get_account_roles_by_owner(account_id_type owner) const -{ +vector database_api_impl::get_account_roles_by_owner(account_id_type owner) const { const auto &idx_aro = _db.get_index_type().indices().get(); auto idx_aro_range = idx_aro.equal_range(owner); vector result; - for (auto itr = idx_aro_range.first; itr != idx_aro_range.second; ++itr) - { + for (auto itr = idx_aro_range.first; itr != idx_aro_range.second; ++itr) { result.push_back(*itr); } return result; @@ -3166,84 +2880,68 @@ vector database_api_impl::get_account_roles_by_owner(accoun // // ////////////////////////////////////////////////////////////////////// -void database_api_impl::broadcast_updates( const vector& updates ) -{ - if( updates.size() && _subscribe_callback ) { +void database_api_impl::broadcast_updates(const vector &updates) { + if (updates.size() && _subscribe_callback) { auto capture_this = shared_from_this(); - fc::async([capture_this,updates](){ - if(capture_this->_subscribe_callback) - capture_this->_subscribe_callback( fc::variant(updates) ); + fc::async([capture_this, updates]() { + if (capture_this->_subscribe_callback) + capture_this->_subscribe_callback(fc::variant(updates)); }); } } -void database_api_impl::broadcast_market_updates( const market_queue_type& queue) -{ - if( queue.size() ) - { +void database_api_impl::broadcast_market_updates(const market_queue_type &queue) { + if (queue.size()) { auto capture_this = shared_from_this(); - fc::async([capture_this, this, queue](){ - for( const auto& item : queue ) - { + fc::async([capture_this, this, queue]() { + for (const auto &item : queue) { auto sub = _market_subscriptions.find(item.first); - if( sub != _market_subscriptions.end() ) - sub->second( fc::variant(item.second ) ); - } + if (sub != _market_subscriptions.end()) + sub->second(fc::variant(item.second)); + } }); } } -void database_api_impl::on_objects_removed( const vector& ids, const vector& objs, const flat_set& impacted_accounts) -{ +void database_api_impl::on_objects_removed(const vector &ids, const vector &objs, const flat_set &impacted_accounts) { handle_object_changed(_notify_remove_create, false, ids, impacted_accounts, - [objs](object_id_type id) -> const object* { - auto it = std::find_if( - objs.begin(), objs.end(), - [id](const object* o) {return o != nullptr && o->id == id;}); + [objs](object_id_type id) -> const object * { + auto it = std::find_if( + objs.begin(), objs.end(), + [id](const object *o) { + return o != nullptr && o->id == id; + }); - if (it != objs.end()) - return *it; + if (it != objs.end()) + return *it; - return nullptr; - } - ); + return nullptr; + }); } -void database_api_impl::on_objects_new(const vector& ids, const flat_set& impacted_accounts) -{ +void database_api_impl::on_objects_new(const vector &ids, const flat_set &impacted_accounts) { handle_object_changed(_notify_remove_create, true, ids, impacted_accounts, - std::bind(&object_database::find_object, &_db, std::placeholders::_1) - ); + std::bind(&object_database::find_object, &_db, std::placeholders::_1)); } -void database_api_impl::on_objects_changed(const vector& ids, const flat_set& impacted_accounts) -{ +void database_api_impl::on_objects_changed(const vector &ids, const flat_set &impacted_accounts) { handle_object_changed(false, true, ids, impacted_accounts, - std::bind(&object_database::find_object, &_db, std::placeholders::_1) - ); + std::bind(&object_database::find_object, &_db, std::placeholders::_1)); } -void database_api_impl::handle_object_changed(bool force_notify, bool full_object, const vector& ids, const flat_set& impacted_accounts, std::function find_object) -{ - if( _subscribe_callback ) - { +void database_api_impl::handle_object_changed(bool force_notify, bool full_object, const vector &ids, const flat_set &impacted_accounts, std::function find_object) { + if (_subscribe_callback) { vector updates; - for(auto id : ids) - { - if( force_notify || is_subscribed_to_item(id) || is_impacted_account(impacted_accounts) ) - { - if( full_object ) - { + for (auto id : ids) { + if (force_notify || is_subscribed_to_item(id) || is_impacted_account(impacted_accounts)) { + if (full_object) { auto obj = find_object(id); - if( obj ) - { - updates.emplace_back( obj->to_variant() ); + if (obj) { + updates.emplace_back(obj->to_variant()); } - } - else - { - updates.emplace_back( fc::variant( id, 1 ) ); + } else { + updates.emplace_back(fc::variant(id, 1)); } } } @@ -3251,25 +2949,20 @@ void database_api_impl::handle_object_changed(bool force_notify, bool full_objec broadcast_updates(updates); } - if( _market_subscriptions.size() ) - { + if (_market_subscriptions.size()) { market_queue_type broadcast_queue; - /// pushing the future back / popping the prior future if it is complete. - /// if a connection hangs then this could get backed up and result in - /// a failure to exit cleanly. - //fc::async([capture_this,this,updates,market_broadcast_queue](){ - //if( _subscribe_callback ) - // _subscribe_callback( updates ); + /// pushing the future back / popping the prior future if it is complete. + /// if a connection hangs then this could get backed up and result in + /// a failure to exit cleanly. + //fc::async([capture_this,this,updates,market_broadcast_queue](){ + //if( _subscribe_callback ) + // _subscribe_callback( updates ); - for(auto id : ids) - { - if( id.is() ) - { - enqueue_if_subscribed_to_market( find_object(id), broadcast_queue, full_object ); - } - else if( id.is() ) - { - enqueue_if_subscribed_to_market( find_object(id), broadcast_queue, full_object ); + for (auto id : ids) { + if (id.is()) { + enqueue_if_subscribed_to_market(find_object(id), broadcast_queue, full_object); + } else if (id.is()) { + enqueue_if_subscribed_to_market(find_object(id), broadcast_queue, full_object); } } @@ -3280,57 +2973,53 @@ void database_api_impl::handle_object_changed(bool force_notify, bool full_objec /** note: this method cannot yield because it is called in the middle of * apply a block. */ -void database_api_impl::on_applied_block() -{ - if (_block_applied_callback) - { +void database_api_impl::on_applied_block() { + if (_block_applied_callback) { auto capture_this = shared_from_this(); block_id_type block_id = _db.head_block_id(); - fc::async([this,capture_this,block_id](){ + fc::async([this, capture_this, block_id]() { _block_applied_callback(fc::variant(block_id, 1)); }); } - if(_market_subscriptions.size() == 0) + if (_market_subscriptions.size() == 0) return; - const auto& ops = _db.get_applied_operations(); - map< std::pair, vector> > subscribed_markets_ops; - for(const optional< operation_history_object >& o_op : ops) - { - if( !o_op.valid() ) + const auto &ops = _db.get_applied_operations(); + map, vector>> subscribed_markets_ops; + for (const optional &o_op : ops) { + if (!o_op.valid()) continue; - const operation_history_object& op = *o_op; + const operation_history_object &op = *o_op; - std::pair market; - switch(op.op.which()) - { - /* This is sent via the object_changed callback + std::pair market; + switch (op.op.which()) { + /* This is sent via the object_changed callback case operation::tag::value: market = op.op.get().get_market(); break; */ - case operation::tag::value: - market = op.op.get().get_market(); - break; - /* + case operation::tag::value: + market = op.op.get().get_market(); + break; + /* case operation::tag::value: */ - default: break; + default: + break; } - if(_market_subscriptions.count(market)) + if (_market_subscriptions.count(market)) subscribed_markets_ops[market].push_back(std::make_pair(op.op, op.result)); } /// we need to ensure the database_api is not deleted for the life of the async operation auto capture_this = shared_from_this(); - fc::async([this,capture_this,subscribed_markets_ops](){ - for(auto item : subscribed_markets_ops) - { + fc::async([this, capture_this, subscribed_markets_ops]() { + for (auto item : subscribed_markets_ops) { auto itr = _market_subscriptions.find(item.first); - if(itr != _market_subscriptions.end()) + if (itr != _market_subscriptions.end()) itr->second(fc::variant(item.second, GRAPHENE_NET_MAX_NESTED_OBJECTS)); } }); } -} } // graphene::app +}} // namespace graphene::app diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index 4adf73a3..c12d45bf 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -25,24 +25,24 @@ #include -#include #include +#include -#include #include +#include #include -#include #include #include +#include #include #include -#include #include #include +#include #include @@ -52,55 +52,52 @@ #include namespace graphene { namespace app { - using namespace graphene::chain; - using namespace graphene::market_history; - using namespace graphene::accounts_list; - using namespace fc::ecc; - using namespace std; +using namespace graphene::chain; +using namespace graphene::market_history; +using namespace graphene::accounts_list; +using namespace fc::ecc; +using namespace std; - class application; +class application; - struct verify_range_result - { - bool success; - uint64_t min_val; - uint64_t max_val; - }; - - struct verify_range_proof_rewind_result - { - bool success; - uint64_t min_val; - uint64_t max_val; - uint64_t value_out; - fc::ecc::blind_factor_type blind_out; - string message_out; - }; +struct verify_range_result { + bool success; + uint64_t min_val; + uint64_t max_val; +}; - struct account_asset_balance - { - string name; - account_id_type account_id; - share_type amount; - }; - struct asset_holders - { - asset_id_type asset_id; - int count; - }; - - /** +struct verify_range_proof_rewind_result { + bool success; + uint64_t min_val; + uint64_t max_val; + uint64_t value_out; + fc::ecc::blind_factor_type blind_out; + string message_out; +}; + +struct account_asset_balance { + string name; + account_id_type account_id; + share_type amount; +}; +struct asset_holders { + asset_id_type asset_id; + int count; +}; + +/** * @brief The history_api class implements the RPC API for account history * * This API contains methods to access account histories */ - class history_api - { - public: - history_api(application& app) - :_app(app), database_api( std::ref(*app.chain_database())) {} +class history_api { +public: + history_api(application &app) : + _app(app), + database_api(std::ref(*app.chain_database())) { + } - /** + /** * @brief Get operations relevant to the specificed account * @param account_id_or_name The account ID or name whose history should be queried * @param stop ID of the earliest operation to retrieve @@ -108,12 +105,12 @@ namespace graphene { namespace app { * @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 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; + vector 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_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, ...) @@ -122,13 +119,13 @@ namespace graphene { namespace app { * @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 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(), - unsigned limit = 100)const; + vector 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(), + unsigned limit = 100) const; - /** + /** * @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). @@ -140,79 +137,79 @@ 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 get_relative_account_history( const std::string account_id_or_name, - uint32_t stop = 0, - unsigned limit = 100, - uint32_t start = 0) const; + vector get_relative_account_history(const std::string account_id_or_name, + uint32_t stop = 0, + unsigned limit = 100, + uint32_t start = 0) const; - vector get_fill_order_history( std::string asset_a, std::string asset_b, uint32_t limit )const; - vector 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 list_core_accounts()const; - flat_set get_market_history_buckets()const; - private: - application& _app; - graphene::app::database_api database_api; - }; + vector get_fill_order_history(std::string asset_a, std::string asset_b, uint32_t limit) const; + vector 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 list_core_accounts() const; + flat_set get_market_history_buckets() const; + uint32_t api_limit_get_account_history_operations = 100; + uint32_t api_limit_get_account_history = 100; + uint32_t api_limit_get_relative_account_history = 100; - /** +private: + application &_app; + graphene::app::database_api database_api; +}; + +/** * @brief Block api */ - class block_api - { - public: - block_api(graphene::chain::database& db); - ~block_api(); +class block_api { +public: + block_api(graphene::chain::database &db); + ~block_api(); - vector> get_blocks(uint32_t block_num_from, uint32_t block_num_to)const; + vector> get_blocks(uint32_t block_num_from, uint32_t block_num_to) const; - private: - graphene::chain::database& _db; - }; +private: + graphene::chain::database &_db; +}; - - /** +/** * @brief The network_broadcast_api class allows broadcasting of transactions. */ - class network_broadcast_api : public std::enable_shared_from_this - { - public: - network_broadcast_api(application& a); +class network_broadcast_api : public std::enable_shared_from_this { +public: + network_broadcast_api(application &a); - struct transaction_confirmation - { - transaction_id_type id; - uint32_t block_num; - uint32_t trx_num; - processed_transaction trx; - }; + struct transaction_confirmation { + transaction_id_type id; + uint32_t block_num; + uint32_t trx_num; + processed_transaction trx; + }; - typedef std::function confirmation_callback; + typedef std::function confirmation_callback; - /** + /** * @brief Broadcast a transaction to the network * @param trx The transaction to broadcast * * The transaction will be checked for validity in the local database prior to broadcasting. If it fails to * apply locally, an error will be thrown and the transaction will not be broadcast. */ - void broadcast_transaction(const signed_transaction& trx); + void broadcast_transaction(const signed_transaction &trx); - /** this version of broadcast transaction registers a callback method that will be called when the transaction is + /** this version of broadcast transaction registers a callback method that will be called when the transaction is * included into a block. The callback method includes the transaction id, block number, and transaction number in the * block. */ - void broadcast_transaction_with_callback( confirmation_callback cb, const signed_transaction& trx); + void broadcast_transaction_with_callback(confirmation_callback cb, const signed_transaction &trx); - /** this version of broadcast transaction registers a callback method that will be called when the transaction is + /** this version of broadcast transaction registers a callback method that will be called when the transaction is * included into a block. The callback method includes the transaction id, block number, and transaction number in the * block. */ - fc::variant broadcast_transaction_synchronous(const signed_transaction& trx); + fc::variant broadcast_transaction_synchronous(const signed_transaction &trx); - void broadcast_block( const signed_block& block ); + void broadcast_block(const signed_block &block); - /** + /** * @brief Not reflected, thus not accessible to API clients. * * This function is registered to receive the applied_block @@ -220,146 +217,144 @@ namespace graphene { namespace app { * It then dispatches callbacks to clients who have requested * to be notified when a particular txid is included in a block. */ - void on_applied_block( const signed_block& b ); - private: - boost::signals2::scoped_connection _applied_block_connection; - map _callbacks; - application& _app; - }; + void on_applied_block(const signed_block &b); - /** +private: + boost::signals2::scoped_connection _applied_block_connection; + map _callbacks; + application &_app; +}; + +/** * @brief The network_node_api class allows maintenance of p2p connections. */ - class network_node_api - { - public: - network_node_api(application& a); +class network_node_api { +public: + network_node_api(application &a); - /** + /** * @brief Return general network information, such as p2p port */ - fc::variant_object get_info() const; + fc::variant_object get_info() const; - /** + /** * @brief add_node Connect to a new peer * @param ep The IP/Port of the peer to connect to */ - void add_node(const fc::ip::endpoint& ep); + void add_node(const fc::ip::endpoint &ep); - /** + /** * @brief Get status of all current connections to peers */ - std::vector get_connected_peers() const; + std::vector get_connected_peers() const; - /** + /** * @brief Get advanced node parameters, such as desired and max * number of connections */ - fc::variant_object get_advanced_node_parameters() const; + fc::variant_object get_advanced_node_parameters() const; - /** + /** * @brief Set advanced node parameters, such as desired and max * number of connections * @param params a JSON object containing the name/value pairs for the parameters to set */ - void set_advanced_node_parameters(const fc::variant_object& params); - - /** - * @brief Return list of potential peers - */ - std::vector get_potential_peers() const; - - /** - * @brief Return list of pending transactions. - */ - map list_pending_transactions() const; - - /** - * @brief Subscribes caller for notifications about pending transactions. - * @param callback a functional object which will be called when new transaction is created. - */ - void subscribe_to_pending_transactions(std::function callback); - - /** - * @brief Unsubscribes caller from notifications about pending transactions. - */ - void unsubscribe_from_pending_transactions(); - - private: - application& _app; - map _pending_transactions; - boost::signals2::scoped_connection _pending_trx_connection; - boost::signals2::scoped_connection _applied_block_connection; - std::function _on_pending_transaction; - }; - - class crypto_api - { - public: - crypto_api(); - - fc::ecc::commitment_type blind( const fc::ecc::blind_factor_type& blind, uint64_t value ); - - fc::ecc::blind_factor_type blind_sum( const std::vector& blinds_in, uint32_t non_neg ); - - bool verify_sum( const std::vector& commits_in, const std::vector& neg_commits_in, int64_t excess ); - - verify_range_result verify_range( const fc::ecc::commitment_type& commit, const std::vector& proof ); - - std::vector range_proof_sign( uint64_t min_value, - const commitment_type& commit, - const blind_factor_type& commit_blind, - const blind_factor_type& nonce, - int8_t base10_exp, - uint8_t min_bits, - uint64_t actual_value ); - - - verify_range_proof_rewind_result verify_range_proof_rewind( const blind_factor_type& nonce, - const fc::ecc::commitment_type& commit, - const std::vector& proof ); - - - range_proof_info range_get_info( const std::vector& proof ); - }; + void set_advanced_node_parameters(const fc::variant_object ¶ms); /** + * @brief Return list of potential peers + */ + std::vector get_potential_peers() const; + + /** + * @brief Return list of pending transactions. + */ + map list_pending_transactions() const; + + /** + * @brief Subscribes caller for notifications about pending transactions. + * @param callback a functional object which will be called when new transaction is created. + */ + void subscribe_to_pending_transactions(std::function callback); + + /** + * @brief Unsubscribes caller from notifications about pending transactions. + */ + void unsubscribe_from_pending_transactions(); + +private: + application &_app; + map _pending_transactions; + boost::signals2::scoped_connection _pending_trx_connection; + boost::signals2::scoped_connection _applied_block_connection; + std::function _on_pending_transaction; +}; + +class crypto_api { +public: + crypto_api(); + + fc::ecc::commitment_type blind(const fc::ecc::blind_factor_type &blind, uint64_t value); + + fc::ecc::blind_factor_type blind_sum(const std::vector &blinds_in, uint32_t non_neg); + + bool verify_sum(const std::vector &commits_in, const std::vector &neg_commits_in, int64_t excess); + + verify_range_result verify_range(const fc::ecc::commitment_type &commit, const std::vector &proof); + + std::vector range_proof_sign(uint64_t min_value, + const commitment_type &commit, + const blind_factor_type &commit_blind, + const blind_factor_type &nonce, + int8_t base10_exp, + uint8_t min_bits, + uint64_t actual_value); + + verify_range_proof_rewind_result verify_range_proof_rewind(const blind_factor_type &nonce, + const fc::ecc::commitment_type &commit, + const std::vector &proof); + + range_proof_info range_get_info(const std::vector &proof); +}; + +/** * @brief */ - class asset_api - { - public: - asset_api(graphene::app::application& app); - ~asset_api(); +class asset_api { +public: + asset_api(graphene::app::application &app); + ~asset_api(); - /** + /** * @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 get_asset_holders( std::string asset, uint32_t start, uint32_t limit )const; + vector 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; + int get_asset_holders_count(std::string asset) const; - /** + /** * @brief Get all asset holders * @return A list of all asset holders */ - vector get_all_asset_holders() const; + vector get_all_asset_holders() const; - private: - graphene::app::application& _app; - graphene::chain::database& _db; - graphene::app::database_api database_api; - }; -} } // graphene::app + uint32_t api_limit_get_asset_holders = 100; + +private: + graphene::app::application &_app; + graphene::chain::database &_db; + graphene::app::database_api database_api; +}; +}} // namespace graphene::app extern template class fc::api; extern template class fc::api; @@ -370,18 +365,17 @@ extern template class fc::api; extern template class fc::api; namespace graphene { namespace app { - /** +/** * @brief The login_api class implements the bottom layer of the RPC API * * All other APIs must be requested from this API. */ - class login_api - { - public: - login_api(application& a); - ~login_api(); +class login_api { +public: + login_api(application &a); + ~login_api(); - /** + /** * @brief Authenticate to the RPC server * @param user Username to login with * @param password Password to login with @@ -390,114 +384,120 @@ namespace graphene { namespace app { * @note This must be called prior to requesting other APIs. Other APIs may not be accessible until the client * has sucessfully authenticated. */ - bool login(const string& user, const string& password); - /// @brief Retrieve the network block API - fc::api block()const; - /// @brief Retrieve the network broadcast API - fc::api network_broadcast()const; - /// @brief Retrieve the database API - fc::api database()const; - /// @brief Retrieve the history API - fc::api history()const; - /// @brief Retrieve the network node API - fc::api network_node()const; - /// @brief Retrieve the cryptography API - fc::api crypto()const; - /// @brief Retrieve the asset API - fc::api asset()const; - /// @brief Retrieve the debug API (if available) - fc::api debug()const; - /// @brief Retrieve the bookie API (if available) - fc::api bookie()const; - /// @brief Retrieve the affiliate_stats API (if available) - fc::api affiliate_stats()const; + bool login(const string &user, const string &password); + /// @brief Retrieve the network block API + fc::api block() const; + /// @brief Retrieve the network broadcast API + fc::api network_broadcast() const; + /// @brief Retrieve the database API + fc::api database() const; + /// @brief Retrieve the history API + fc::api history() const; + /// @brief Retrieve the network node API + fc::api network_node() const; + /// @brief Retrieve the cryptography API + fc::api crypto() const; + /// @brief Retrieve the asset API + fc::api asset() const; + /// @brief Retrieve the debug API (if available) + fc::api debug() const; + /// @brief Retrieve the bookie API (if available) + fc::api bookie() const; + /// @brief Retrieve the affiliate_stats API (if available) + fc::api affiliate_stats() const; - /// @brief Called to enable an API, not reflected. - void enable_api( const string& api_name ); - private: + /// @brief Called to enable an API, not reflected. + void enable_api(const string &api_name); - application& _app; - optional< fc::api > _block_api; - optional< fc::api > _database_api; - optional< fc::api > _network_broadcast_api; - optional< fc::api > _network_node_api; - optional< fc::api > _history_api; - optional< fc::api > _crypto_api; - optional< fc::api > _asset_api; - optional< fc::api > _debug_api; - optional< fc::api > _bookie_api; - optional< fc::api > _affiliate_stats_api; - }; +private: + application &_app; + optional> _block_api; + optional> _database_api; + optional> _network_broadcast_api; + optional> _network_node_api; + optional> _history_api; + optional> _crypto_api; + optional> _asset_api; + optional> _debug_api; + optional> _bookie_api; + optional> _affiliate_stats_api; +}; -}} // graphene::app +}} // namespace graphene::app extern template class fc::api; -FC_REFLECT( graphene::app::network_broadcast_api::transaction_confirmation, - (id)(block_num)(trx_num)(trx) ) -FC_REFLECT( graphene::app::verify_range_result, - (success)(min_val)(max_val) ) -FC_REFLECT( graphene::app::verify_range_proof_rewind_result, - (success)(min_val)(max_val)(value_out)(blind_out)(message_out) ) -//FC_REFLECT_TYPENAME( fc::ecc::compact_signature ); -//FC_REFLECT_TYPENAME( fc::ecc::commitment_type ); +// clang-format off -FC_REFLECT( graphene::app::account_asset_balance, (name)(account_id)(amount) ); -FC_REFLECT( graphene::app::asset_holders, (asset_id)(count) ); +FC_REFLECT(graphene::app::network_broadcast_api::transaction_confirmation, + (id)(block_num)(trx_num)(trx)) + +FC_REFLECT(graphene::app::verify_range_result, + (success)(min_val)(max_val)) + +FC_REFLECT(graphene::app::verify_range_proof_rewind_result, + (success)(min_val)(max_val)(value_out)(blind_out)(message_out)) + +FC_REFLECT(graphene::app::account_asset_balance, + (name)(account_id)(amount)); + +FC_REFLECT(graphene::app::asset_holders, + (asset_id)(count)); FC_API(graphene::app::history_api, - (get_account_history) - (get_account_history_operations) - (get_relative_account_history) - (get_fill_order_history) - (get_market_history) - (get_market_history_buckets) - (list_core_accounts) - ) + (get_account_history) + (get_account_history_operations) + (get_relative_account_history) + (get_fill_order_history) + (get_market_history) + (get_market_history_buckets) + (list_core_accounts)) + FC_API(graphene::app::block_api, - (get_blocks) - ) + (get_blocks)) + FC_API(graphene::app::network_broadcast_api, - (broadcast_transaction) - (broadcast_transaction_with_callback) - (broadcast_transaction_synchronous) - (broadcast_block) - ) + (broadcast_transaction) + (broadcast_transaction_with_callback) + (broadcast_transaction_synchronous) + (broadcast_block)) + FC_API(graphene::app::network_node_api, - (get_info) - (add_node) - (get_connected_peers) - (get_potential_peers) - (get_advanced_node_parameters) - (set_advanced_node_parameters) - (list_pending_transactions) - (subscribe_to_pending_transactions) - (unsubscribe_from_pending_transactions) - ) + (get_info) + (add_node) + (get_connected_peers) + (get_potential_peers) + (get_advanced_node_parameters) + (set_advanced_node_parameters) + (list_pending_transactions) + (subscribe_to_pending_transactions) + (unsubscribe_from_pending_transactions)) + FC_API(graphene::app::crypto_api, - (blind) - (blind_sum) - (verify_sum) - (verify_range) - (range_proof_sign) - (verify_range_proof_rewind) - (range_get_info) - ) + (blind) + (blind_sum) + (verify_sum) + (verify_range) + (range_proof_sign) + (verify_range_proof_rewind) + (range_get_info)) + FC_API(graphene::app::asset_api, - (get_asset_holders) - (get_asset_holders_count) - (get_all_asset_holders) - ) + (get_asset_holders) + (get_asset_holders_count) + (get_all_asset_holders)) + FC_API(graphene::app::login_api, - (login) - (block) - (network_broadcast) - (database) - (history) - (network_node) - (crypto) - (asset) - (debug) - (bookie) - (affiliate_stats) - ) + (login) + (block) + (network_broadcast) + (database) + (history) + (network_node) + (crypto) + (asset) + (debug) + (bookie) + (affiliate_stats)) + +// clang-format on diff --git a/libraries/app/include/graphene/app/api_access.hpp b/libraries/app/include/graphene/app/api_access.hpp index 8dbad1a1..df79a88f 100644 --- a/libraries/app/include/graphene/app/api_access.hpp +++ b/libraries/app/include/graphene/app/api_access.hpp @@ -31,26 +31,26 @@ namespace graphene { namespace app { -struct api_access_info -{ +struct api_access_info { std::string password_hash_b64; std::string password_salt_b64; - std::vector< std::string > allowed_apis; + std::vector allowed_apis; }; -struct api_access -{ - std::map< std::string, api_access_info > permission_map; +struct api_access { + std::map permission_map; }; -} } // graphene::app +}} // namespace graphene::app + +// clang-format off FC_REFLECT( graphene::app::api_access_info, - (password_hash_b64) - (password_salt_b64) - (allowed_apis) - ) + (password_hash_b64) + (password_salt_b64) + (allowed_apis)) FC_REFLECT( graphene::app::api_access, - (permission_map) - ) + (permission_map)) + +// clang-format on diff --git a/libraries/app/include/graphene/app/application.hpp b/libraries/app/include/graphene/app/application.hpp index a436aacd..7bf52212 100644 --- a/libraries/app/include/graphene/app/application.hpp +++ b/libraries/app/include/graphene/app/application.hpp @@ -24,89 +24,86 @@ #pragma once #include -#include #include +#include #include namespace graphene { namespace app { - namespace detail { class application_impl; } - using std::string; +namespace detail { +class application_impl; +} +using std::string; - class abstract_plugin; +class abstract_plugin; - class application - { - public: - application(); - ~application(); +class application { +public: + application(); + ~application(); - void set_program_options( boost::program_options::options_description& command_line_options, - boost::program_options::options_description& configuration_file_options )const; - void initialize(const fc::path& data_dir, const boost::program_options::variables_map&options); - void initialize_plugins( const boost::program_options::variables_map& options ); - void startup(); - void shutdown(); - void startup_plugins(); - void shutdown_plugins(); + void set_program_options(boost::program_options::options_description &cli, + boost::program_options::options_description &cfg) const; + void initialize(const fc::path &data_dir, const boost::program_options::variables_map &options); + void initialize_plugins(const boost::program_options::variables_map &options); + void startup(); + void shutdown(); + void startup_plugins(); + void shutdown_plugins(); - template - std::shared_ptr register_plugin() - { - auto plug = std::make_shared(); - plug->plugin_set_app(this); + template + std::shared_ptr register_plugin() { + auto plug = std::make_shared(); + plug->plugin_set_app(this); - boost::program_options::options_description plugin_cli_options(plug->plugin_name() + " plugin. " + plug->plugin_description() + "\nOptions"), plugin_cfg_options; - //boost::program_options::options_description plugin_cli_options("Options for plugin " + plug->plugin_name()), plugin_cfg_options; - plug->plugin_set_program_options(plugin_cli_options, plugin_cfg_options); - if( !plugin_cli_options.options().empty() ) - _cli_options.add(plugin_cli_options); + boost::program_options::options_description plugin_cli_options(plug->plugin_name() + " plugin. " + plug->plugin_description() + "\nOptions"), plugin_cfg_options; + plug->plugin_set_program_options(plugin_cli_options, plugin_cfg_options); + if (!plugin_cli_options.options().empty()) + _cli_options.add(plugin_cli_options); - if( !plugin_cfg_options.options().empty() ) - { - std::string header_name = "plugin-cfg-header-" + plug->plugin_name(); - std::string header_desc = plug->plugin_name() + " plugin options"; - _cfg_options.add_options()(header_name.c_str(), header_desc.c_str()); - _cfg_options.add(plugin_cfg_options); - } + if (!plugin_cfg_options.options().empty()) { + std::string header_name = "plugin-cfg-header-" + plug->plugin_name(); + std::string header_desc = plug->plugin_name() + " plugin options"; + _cfg_options.add_options()(header_name.c_str(), header_desc.c_str()); + _cfg_options.add(plugin_cfg_options); + } - add_available_plugin( plug ); - return plug; - } - std::shared_ptr get_plugin( const string& name )const; + add_available_plugin(plug); + return plug; + } + std::shared_ptr get_plugin(const string &name) const; - template - std::shared_ptr get_plugin( const string& name ) const - { - std::shared_ptr abs_plugin = get_plugin( name ); - std::shared_ptr result = std::dynamic_pointer_cast( abs_plugin ); - FC_ASSERT( result != std::shared_ptr() ); - return result; - } + template + std::shared_ptr get_plugin(const string &name) const { + std::shared_ptr abs_plugin = get_plugin(name); + std::shared_ptr result = std::dynamic_pointer_cast(abs_plugin); + FC_ASSERT(result != std::shared_ptr()); + return result; + } - net::node_ptr p2p_node(); - std::shared_ptr chain_database()const; + net::node_ptr p2p_node(); + std::shared_ptr chain_database() const; - void set_block_production(bool producing_blocks); - fc::optional< api_access_info > get_api_access_info( const string& username )const; - void set_api_access_info(const string& username, api_access_info&& permissions); + void set_block_production(bool producing_blocks); + fc::optional get_api_access_info(const string &username) const; + void set_api_access_info(const string &username, api_access_info &&permissions); - bool is_finished_syncing()const; - /// Emitted when syncing finishes (is_finished_syncing will return true) - boost::signals2::signal syncing_finished; + bool is_finished_syncing() const; + /// Emitted when syncing finishes (is_finished_syncing will return true) + boost::signals2::signal syncing_finished; - void enable_plugin( const string& name ); + void enable_plugin(const string &name); - bool is_plugin_enabled(const string& name) const; + bool is_plugin_enabled(const string &name) const; - std::shared_ptr elasticsearch_thread; + std::shared_ptr elasticsearch_thread; - private: - void add_available_plugin( std::shared_ptr p ); - std::shared_ptr my; +private: + void add_available_plugin(std::shared_ptr p); + std::shared_ptr my; - boost::program_options::options_description _cli_options; - boost::program_options::options_description _cfg_options; - }; + boost::program_options::options_description _cli_options; + boost::program_options::options_description _cfg_options; +}; -} } +}} // namespace graphene::app diff --git a/libraries/app/include/graphene/app/config_util.hpp b/libraries/app/include/graphene/app/config_util.hpp index d7358f22..3d31e506 100644 --- a/libraries/app/include/graphene/app/config_util.hpp +++ b/libraries/app/include/graphene/app/config_util.hpp @@ -23,12 +23,12 @@ */ #pragma once -#include #include +#include 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); +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 \ No newline at end of file +}} // namespace graphene::app diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index b6461635..695eae7a 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -32,30 +32,30 @@ #include #include #include +#include #include #include #include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include +#include #include #include -#include +#include -#include -#include #include +#include +#include -#include +#include #include +#include #include #include -#include #include @@ -80,47 +80,42 @@ using namespace std; class database_api_impl; -struct order -{ - double price; - double quote; - double base; +struct order { + double price; + double quote; + double base; }; -struct order_book -{ - string base; - string quote; - vector< order > bids; - vector< order > asks; +struct order_book { + string base; + string quote; + vector bids; + vector asks; }; -struct market_ticker -{ - string base; - string quote; - double latest; - double lowest_ask; - double highest_bid; - double percent_change; - double base_volume; - double quote_volume; +struct market_ticker { + string base; + string quote; + double latest; + double lowest_ask; + double highest_bid; + double percent_change; + double base_volume; + double quote_volume; }; -struct market_volume -{ - string base; - string quote; - double base_volume; - double quote_volume; +struct market_volume { + string base; + string quote; + double base_volume; + double quote_volume; }; -struct market_trade -{ - fc::time_point_sec date; - double price; - double amount; - double value; +struct market_trade { + fc::time_point_sec date; + double price; + double amount; + double value; }; struct gpos_info { @@ -140,824 +135,819 @@ struct gpos_info { * read-only; all modifications to the database must be performed via transactions. Transactions are broadcast via * the @ref network_broadcast_api. */ -class database_api -{ - public: - database_api(graphene::chain::database& db); - ~database_api(); +class database_api { +public: + database_api(graphene::chain::database &db); + ~database_api(); - ///////////// - // Objects // - ///////////// + ///////////// + // Objects // + ///////////// - /** - * @brief Get the objects corresponding to the provided IDs - * @param ids IDs of the objects to retrieve - * @return The objects retrieved, in the order they are mentioned in ids - * - * If any of the provided IDs does not map to an object, a null variant is returned in its position. - */ - fc::variants get_objects(const vector& ids)const; + /** + * @brief Get the objects corresponding to the provided IDs + * @param ids IDs of the objects to retrieve + * @return The objects retrieved, in the order they are mentioned in ids + * + * If any of the provided IDs does not map to an object, a null variant is returned in its position. + */ + fc::variants get_objects(const vector &ids) const; - /////////////////// - // Subscriptions // - /////////////////// + /////////////////// + // Subscriptions // + /////////////////// - void set_subscribe_callback( std::function cb, bool clear_filter ); - void set_pending_transaction_callback( std::function cb ); - void set_block_applied_callback( std::function cb ); - /** - * @brief Stop receiving any notifications - * - * This unsubscribes from all subscribed markets and objects. - */ - void cancel_all_subscriptions(); + void set_subscribe_callback(std::function cb, bool clear_filter); + void set_pending_transaction_callback(std::function cb); + void set_block_applied_callback(std::function cb); + /** + * @brief Stop receiving any notifications + * + * This unsubscribes from all subscribed markets and objects. + */ + void cancel_all_subscriptions(); - ///////////////////////////// - // Blocks and transactions // - ///////////////////////////// + ///////////////////////////// + // Blocks and transactions // + ///////////////////////////// - /** - * @brief Retrieve a block header - * @param block_num Height of the block whose header should be returned - * @return header of the referenced block, or null if no matching block was found - */ - optional get_block_header(uint32_t block_num)const; + /** + * @brief Retrieve a block header + * @param block_num Height of the block whose header should be returned + * @return header of the referenced block, or null if no matching block was found + */ + optional get_block_header(uint32_t block_num) const; - /** + /** * @brief Retrieve multiple block header by block numbers * @param block_num vector containing heights of the block whose header should be returned * @return array of headers of the referenced blocks, or null if no matching block was found */ - map> get_block_header_batch(const vector block_nums)const; + map> get_block_header_batch(const vector block_nums) const; + /** + * @brief Retrieve a full, signed block + * @param block_num Height of the block to be returned + * @return the referenced block, or null if no matching block was found + */ + optional get_block(uint32_t block_num) const; - /** - * @brief Retrieve a full, signed block - * @param block_num Height of the block to be returned - * @return the referenced block, or null if no matching block was found - */ - optional get_block(uint32_t block_num)const; + /** + * @brief Retrieve a list of signed blocks + * @param block_num_from start + * @param block_num_to end + * @return list of referenced blocks + */ + vector> get_blocks(uint32_t block_num_from, uint32_t block_num_to) const; - /** - * @brief Retrieve a list of signed blocks - * @param block_num_from start - * @param block_num_to end - * @return list of referenced blocks - */ - vector> get_blocks(uint32_t block_num_from, uint32_t block_num_to)const; + /** + * @brief used to fetch an individual transaction. + */ + processed_transaction get_transaction(uint32_t block_num, uint32_t trx_in_block) const; - /** - * @brief used to fetch an individual transaction. - */ - processed_transaction get_transaction( uint32_t block_num, uint32_t trx_in_block )const; + /** + * If the transaction has not expired, this method will return the transaction for the given ID or + * it will return NULL if it is not known. Just because it is not known does not mean it wasn't + * included in the blockchain. + */ + optional get_recent_transaction_by_id(const transaction_id_type &id) const; - /** - * If the transaction has not expired, this method will return the transaction for the given ID or - * it will return NULL if it is not known. Just because it is not known does not mean it wasn't - * included in the blockchain. - */ - optional get_recent_transaction_by_id( const transaction_id_type& id )const; + ///////////// + // Globals // + ///////////// - ///////////// - // Globals // - ///////////// + /** + * @brief Retrieve the @ref chain_property_object associated with the chain + */ + chain_property_object get_chain_properties() const; - /** - * @brief Retrieve the @ref chain_property_object associated with the chain - */ - chain_property_object get_chain_properties()const; + /** + * @brief Retrieve the current @ref global_property_object + */ + global_property_object get_global_properties() const; - /** - * @brief Retrieve the current @ref global_property_object - */ - global_property_object get_global_properties()const; + /** + * @brief Retrieve compile-time constants + */ + fc::variant_object get_config() const; - /** - * @brief Retrieve compile-time constants - */ - fc::variant_object get_config()const; + /** + * @brief Get the chain ID + */ + chain_id_type get_chain_id() const; - /** - * @brief Get the chain ID - */ - chain_id_type get_chain_id()const; + /** + * @brief Retrieve the current @ref dynamic_global_property_object + */ + dynamic_global_property_object get_dynamic_global_properties() const; - /** - * @brief Retrieve the current @ref dynamic_global_property_object - */ - dynamic_global_property_object get_dynamic_global_properties()const; + ////////// + // Keys // + ////////// - ////////// - // Keys // - ////////// + vector> get_key_references(vector key) const; - vector> get_key_references( vector key )const; - - /** + /** * Determine whether a textual representation of a public key * (in Base-58 format) is *currently* linked * to any *registered* (i.e. non-stealth) account on the blockchain * @param public_key Public key * @return Whether a public key is known */ - bool is_public_key_registered(string public_key) const; - - ////////////// - // Accounts // - ////////////// - - /** - * @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> get_accounts(const vector& account_names_or_ids)const; - - /** - * @brief Fetch all objects relevant to the specified accounts and subscribe to updates - * @param callback Function to call with updates - * @param names_or_ids Each item must be the name or ID of an account to retrieve - * @return Map of string from @ref names_or_ids to the corresponding account - * - * This function fetches all relevant objects for the given accounts, and subscribes to updates to the given - * accounts. If any of the strings in @ref names_or_ids cannot be tied to an account, that input will be - * ignored. All other accounts will be retrieved and subscribed. - * - */ - std::map get_full_accounts( const vector& names_or_ids, bool subscribe ); - - optional get_account_by_name( string name )const; - - /** - * @return all accounts that referr to the key or account id in their owner or active authorities. - */ - vector get_account_references( const std::string account_name_or_id )const; - - /** - * @brief Get a list of accounts by name - * @param account_names Names of the accounts to retrieve - * @return The accounts holding the provided names - * - * This function has semantics identical to @ref get_objects - */ - vector> lookup_account_names(const vector& account_names)const; - - /** - * @brief Get names and IDs for registered accounts - * @param lower_bound_name Lower bound of the first name to return - * @param limit Maximum number of results to return -- must not exceed 1000 - * @return Map of account names to corresponding IDs - */ - map lookup_accounts(const string& lower_bound_name, uint32_t limit)const; - - ////////////// - // Balances // - ////////////// - - /** - * @brief Get an account's balances in various assets - * @param id ID of the account to get balances for - * @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 get_account_balances( const std::string& account_name_or_id, - const flat_set& assets )const; - - /// Semantically equivalent to @ref get_account_balances, but takes a name instead of an ID. - vector get_named_account_balances(const std::string& name, const flat_set& assets)const; - - /** @return all unclaimed balance objects for a set of addresses */ - vector get_balance_objects( const vector
& addrs )const; - - vector get_vested_balances( const vector& objs )const; - - vector get_vesting_balances( const std::string account_id_or_name )const; - - /** - * @brief Get the total number of accounts registered with the blockchain - */ - uint64_t get_account_count()const; - - //////////// - // 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_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> get_assets(const vector& asset_symbols_or_ids)const; - - /** - * @brief Get assets alphabetically by symbol name - * @param lower_bound_symbol Lower bound of symbol names to retrieve - * @param limit Maximum number of assets to fetch (must not exceed 100) - * @return The assets found - */ - vector list_assets(const string& lower_bound_symbol, uint32_t limit)const; - - /** - * @brief Get a list of assets by symbol - * @param asset_symbols Symbols or stringified IDs of the assets to retrieve - * @return The assets corresponding to the provided symbols or IDs - * - * This function has semantics identical to @ref get_objects - */ - vector> lookup_asset_symbols(const vector& symbols_or_ids)const; - - /** - * @brief Get assets count - * @return The assets count - */ - uint64_t get_asset_count()const; - - //////////////////// - // Lottery Assets // - //////////////////// - /** - * @brief Get a list of lottery assets - * @return The lottery assets between start and stop ids - */ - vector get_lotteries( asset_id_type stop = asset_id_type(), - unsigned limit = 100, - asset_id_type start = asset_id_type() )const; - vector get_account_lotteries( account_id_type issuer, - asset_id_type stop, - unsigned limit, - asset_id_type start )const; - sweeps_vesting_balance_object get_sweeps_vesting_balance_object( account_id_type account )const; - asset get_sweeps_vesting_balance_available_for_claim( account_id_type account )const; - /** - * @brief Get balance of lottery assets - */ - asset get_lottery_balance( asset_id_type lottery_id ) const; - - - ///////////////////// - // Peerplays // - ///////////////////// - - /** - * @brief Get global betting statistics - */ - global_betting_statistics_object get_global_betting_statistics() const; - - /** - * @brief Get a list of all sports - */ - vector list_sports() const; - - /** - * @brief Return a list of all event groups for a sport (e.g. all soccer leagues in soccer) - */ - vector list_event_groups(sport_id_type sport_id) const; - - /** - * @brief Return a list of all events in an event group - */ - vector list_events_in_group(event_group_id_type event_group_id) const; - - /** - * @brief Return a list of all betting market groups for an event - */ - vector list_betting_market_groups(event_id_type) const; - - /** - * @brief Return a list of all betting markets for a betting market group - */ - vector list_betting_markets(betting_market_group_id_type) const; - - /** - * @brief Return a list of all unmatched bets for a given account on a specific betting market - */ - vector get_unmatched_bets_for_bettor(betting_market_id_type, account_id_type) const; - - /** - * @brief Return a list of all unmatched bets for a given account (includes bets on all markets) - */ - vector get_all_unmatched_bets_for_bettor(account_id_type) const; - - ///////////////////// - // Markets / feeds // - ///////////////////// - - /** - * @brief Get limit orders in a given market - * @param a ID of asset being sold - * @param b ID of asset being purchased - * @param limit Maximum number of orders to retrieve - * @return The limit orders, ordered from least price to greatest - */ - vector 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 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 get_call_orders(const std::string& a, uint32_t limit)const; - - /** - * @brief Get forced settlement orders in a given asset - * @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 get_settle_orders(const std::string& a, uint32_t limit)const; - - /** - * @return all open margin positions for a given account id. - */ - vector 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 or name - * @param b Second asset ID or name - * - * Callback will be passed a variant containing a vector>. The vector will - * contain, in order, the operations which changed the market, and their results. - */ - void subscribe_to_market(std::function callback, - const std::string& a, const std::string& b); - - /** - * @brief Unsubscribe from updates to a given market - * @param a First asset ID or name - * @param b Second asset ID or name - */ - void unsubscribe_from_market( const std::string& a, const std::string& b ); - - /** - * @brief Returns the ticker for the market assetA:assetB - * @param a String name of the first asset - * @param b String name of the second asset - * @return The market ticker for the past 24 hours. - */ - market_ticker get_ticker( const string& base, const string& quote )const; - - /** - * @brief Returns the 24 hour volume for the market assetA:assetB - * @param a String name of the first asset - * @param b String name of the second asset - * @return The market volume over the past 24 hours - */ - market_volume get_24_volume( const string& base, const string& quote )const; - - /** - * @brief Returns the order book for the market base:quote - * @param base String name of the first asset - * @param quote String name of the second asset - * @param depth of the order book. Up to depth of each asks and bids, capped at 50. Prioritizes most moderate of each - * @return Order book of the market - */ - order_book get_order_book( const string& base, const string& quote, unsigned limit = 50 )const; - - /** - * @brief Returns recent trades for the market assetA:assetB - * Note: Currentlt, timezone offsets are not supported. The time must be UTC. - * @param a String name of the first asset - * @param b String name of the second asset - * @param stop Stop time as a UNIX timestamp - * @param limit Number of trasactions to retrieve, capped at 100 - * @param start Start time as a UNIX timestamp - * @return Recent transactions in the market - */ - vector get_trade_history( const string& base, const string& quote, fc::time_point_sec start, fc::time_point_sec stop, unsigned limit = 100 )const; - - - - /////////////// - // Witnesses // - /////////////// - - /** - * @brief Get a list of witnesses by ID - * @param witness_ids IDs of the witnesses to retrieve - * @return The witnesses corresponding to the provided IDs - * - * This function has semantics identical to @ref get_objects - */ - vector> get_witnesses(const vector& witness_ids)const; - - /** - * @brief Get the witness owned by a given account - * @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 get_witness_by_account(const std::string account_name_or_id)const; - - /** - * @brief Get names and IDs for registered witnesses - * @param lower_bound_name Lower bound of the first name to return - * @param limit Maximum number of results to return -- must not exceed 1000 - * @return Map of witness names to corresponding IDs - */ - map lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const; - - /** - * @brief Get the total number of witnesses registered with the blockchain - */ - uint64_t get_witness_count()const; - - /////////////////////// - // Committee members // - /////////////////////// - - /** - * @brief Get a list of committee_members by ID - * @param committee_member_ids IDs of the committee_members to retrieve - * @return The committee_members corresponding to the provided IDs - * - * This function has semantics identical to @ref get_objects - */ - vector> get_committee_members(const vector& committee_member_ids)const; - - /** - * @brief Get the committee_member owned by a given account - * @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 get_committee_member_by_account(const std::string account_id_or_name)const; - - /** - * @brief Get names and IDs for registered committee_members - * @param lower_bound_name Lower bound of the first name to return - * @param limit Maximum number of results to return -- must not exceed 1000 - * @return Map of committee_member names to corresponding IDs - */ - map lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const; - - ///////////////// - // SON members // - ///////////////// - - /** - * @brief Get a list of SONs by ID - * @param son_ids IDs of the SONs to retrieve - * @return The SONs corresponding to the provided IDs - * - * This function has semantics identical to @ref get_objects - */ - vector> get_sons(const vector& son_ids)const; - - /** - * @brief Get the SON owned by a given account - * @param account The ID of the account whose SON should be retrieved - * @return The SON object, or null if the account does not have a SON - */ - fc::optional get_son_by_account(account_id_type account)const; - - /** - * @brief Get names and IDs for registered SONs - * @param lower_bound_name Lower bound of the first name to return - * @param limit Maximum number of results to return -- must not exceed 1000 - * @return Map of SON names to corresponding IDs - */ - map lookup_son_accounts(const string& lower_bound_name, uint32_t limit)const; - - /** - * @brief Get the total number of SONs registered with the blockchain - */ - uint64_t get_son_count()const; - - ///////////////////////// - // SON Wallets // - ///////////////////////// - - /** - * @brief Get active SON wallet - * @return Active SON wallet object - */ - optional get_active_son_wallet(); - - /** - * @brief Get SON wallet that was active for a given time point - * @param time_point Time point - * @return SON wallet object, for the wallet that was active for a given time point - */ - optional get_son_wallet_by_time_point(time_point_sec time_point); - - /** - * @brief Get full list of SON wallets - * @param limit Maximum number of results to return - * @return A list of SON wallet objects - */ - vector> get_son_wallets(uint32_t limit); - - ///////////////////////// - // Sidechain Addresses // - ///////////////////////// - - /** - * @brief Get a list of sidechain addresses - * @param sidechain_address_ids IDs of the sidechain addresses to retrieve - * @return The sidechain accounts corresponding to the provided IDs - * - * This function has semantics identical to @ref get_objects - */ - vector> get_sidechain_addresses(const vector& sidechain_address_ids)const; - - /** - * @brief Get the sidechain addresses for a given account - * @param account The ID of the account whose sidechain addresses should be retrieved - * @return The sidechain addresses objects, or null if the account does not have a sidechain addresses - */ - vector> get_sidechain_addresses_by_account(account_id_type account)const; - - /** - * @brief Get the sidechain addresses for a given sidechain - * @param sidechain Sidechain for which addresses should be retrieved - * @return The sidechain addresses objects, or null if the sidechain does not have any addresses - */ - vector> get_sidechain_addresses_by_sidechain(sidechain_type sidechain)const; - - /** - * @brief Get the sidechain addresses for a given account and sidechain - * @param account The ID of the account whose sidechain addresses should be retrieved - * @param sidechain Sidechain for which address should be retrieved - * @return The sidechain addresses objects, or null if the account does not have a sidechain addresses for a given sidechain - */ - fc::optional get_sidechain_address_by_account_and_sidechain(account_id_type account, sidechain_type sidechain)const; - - /** - * @brief Get the total number of sidechain addresses registered with the blockchain - */ - uint64_t get_sidechain_addresses_count()const; - - /// WORKERS - - /** - * @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 get_workers_by_account(const std::string account_id_or_name)const; - - - /////////// - // Votes // - /////////// - - /** - * @brief Given a set of votes, return the objects they are voting for. - * - * This will be a mixture of committee_member_object, witness_objects, and worker_objects - * - * The results will be in the same order as the votes. Null will be returned for - * any vote ids that are not found. - */ - vector lookup_vote_ids( const vector& votes )const; - - //////////////////////////// - // Authority / validation // - //////////////////////////// - - /// @brief Get a hexdump of the serialized binary form of a transaction - std::string get_transaction_hex(const signed_transaction& trx)const; - - /** - * This API will take a partially signed transaction and a set of public keys that the owner has the ability to sign for - * and return the minimal subset of public keys that should add signatures to the transaction. - */ - set get_required_signatures( const signed_transaction& trx, const flat_set& available_keys )const; - - /** - * This method will return the set of all public keys that could possibly sign for a given transaction. This call can - * be used by wallets to filter their set of public keys to just the relevant subset prior to calling @ref get_required_signatures - * to get the minimum subset. - */ - set get_potential_signatures( const signed_transaction& trx )const; - set
get_potential_address_signatures( const signed_transaction& trx )const; - - /** - * @return true of the @ref trx has all of the required signatures, otherwise throws an exception - */ - bool verify_authority( const signed_transaction& trx )const; - - /** - * @return true if the signers have enough authority to authorize an account - */ - bool verify_account_authority( const string& name_or_id, const flat_set& signers )const; - - /** - * Validates a transaction against the current state without broadcasting it on the network. - */ - processed_transaction validate_transaction( const signed_transaction& trx )const; - - /** - * 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& ops, const std::string& asset_id_or_symbol )const; - - /////////////////////////// - // Proposed transactions // - /////////////////////////// - - /** - * @return the set of proposed transactions relevant to the specified account id. - */ - vector get_proposed_transactions( const std::string account_id_or_name )const; - - ////////////////////// - // Blinded balances // - ////////////////////// - - /** - * @return the set of blinded balance objects by commitment ID - */ - vector get_blinded_balances( const flat_set& commitments )const; - - ///////////////// - // Tournaments // - ///////////////// - /** - * @return the list of tournaments in the given state - */ - vector get_tournaments_in_state(tournament_state state, uint32_t limit) const; - - vector get_tournaments(tournament_id_type stop = tournament_id_type(), - unsigned limit = 100, - tournament_id_type start = tournament_id_type()); - - vector get_tournaments_by_state(tournament_id_type stop = tournament_id_type(), - unsigned limit = 100, - tournament_id_type start = tournament_id_type(), - tournament_state state = tournament_state::accepting_registrations); - - /** - * @return the list of tournaments that a given account is registered to play in - */ - vector get_registered_tournaments(account_id_type account_filter, uint32_t limit) const; - - ////////// - // GPOS // - ////////// - /** - * @return account and network GPOS information - */ - gpos_info get_gpos_info(const account_id_type account) const; - - ////////// - // RBAC // - ////////// - /** - * @return account and custom permissions/account-authorities info - */ - vector get_custom_permissions(const account_id_type account) const; - fc::optional get_custom_permission_by_name(const account_id_type account, const string& permission_name) const; - vector get_custom_account_authorities(const account_id_type account) const; - vector get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const; - vector get_custom_account_authorities_by_permission_name(const account_id_type account, const string& permission_name) const; - vector get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const; - - ///////// - // NFT // - ///////// - /** - * @brief Returns the number of NFT owned by account - * @param owner Owner account ID - * @return Number of NFTs owned by account - */ - uint64_t nft_get_balance(const account_id_type owner) const; - - /** - * @brief Returns the NFT owner - * @param token_id NFT ID - * @return NFT owner account ID - */ - optional nft_owner_of(const nft_id_type token_id) const; - - /** - * @brief Returns the NFT approved account ID - * @param token_id NFT ID - * @return NFT approved account ID - */ - optional nft_get_approved(const nft_id_type token_id) const; - - /** - * @brief Returns operator approved state for all NFT owned by owner - * @param owner NFT owner account ID - * @param token_id NFT ID - * @return True if operator is approved for all NFT owned by owner, else False - */ - bool nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const; - - /** - * @brief Returns NFT name from NFT metadata - * @param nft_metadata_id NFT metadata ID - * @return NFT name - */ - string nft_get_name(const nft_metadata_id_type nft_metadata_id) const; - - /** - * @brief Returns NFT symbol from NFT metadata - * @param nft_metadata_id NFT metadata ID - * @return NFT symbol - */ - string nft_get_symbol(const nft_metadata_id_type nft_metadata_id) const; - - /** - * @brief Returns NFT URI - * @param token_id NFT ID - * @return NFT URI - */ - string nft_get_token_uri(const nft_id_type token_id) const; - - /** - * @brief Returns total number of NFTs assigned to NFT metadata - * @param nft_metadata_id NFT metadata ID - * @return Total number of NFTs assigned to NFT metadata - */ - uint64_t nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const; - - /** - * @brief Returns NFT by index from NFT metadata - * @param nft_metadata_id NFT metadata ID - * @param token_idx NFT index in the list of tokens - * @return NFT symbol - */ - nft_object nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const; - - /** - * @brief Returns NFT by owner and index - * @param nft_metadata_id NFT metadata ID - * @param owner NFT owner - * @param token_idx NFT index in the list of tokens - * @return NFT object - */ - nft_object nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const; - - /** - * @brief Returns list of all available NTF's - * @return List of all available NFT's - */ - vector nft_get_all_tokens() const; - - /** - * @brief Returns NFT's owned by owner - * @param owner NFT owner - * @return List of NFT owned by owner - */ - vector nft_get_tokens_by_owner(const account_id_type owner) const; - - ////////////////// - // MARKET PLACE // - ////////////////// - vector list_offers(const offer_id_type lower_id, uint32_t limit) const; - vector list_sell_offers(const offer_id_type lower_id, uint32_t limit) const; - vector list_buy_offers(const offer_id_type lower_id, uint32_t limit) const; - vector list_offer_history(const offer_history_id_type lower_id, uint32_t limit) const; - vector get_offers_by_issuer(const offer_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const; - vector get_offers_by_item(const offer_id_type lower_id, const nft_id_type item, uint32_t limit) const; - vector get_offer_history_by_issuer(const offer_history_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const; - vector get_offer_history_by_item(const offer_history_id_type lower_id, const nft_id_type item, uint32_t limit) const; - vector get_offer_history_by_bidder(const offer_history_id_type lower_id, const account_id_type bidder_account_id, uint32_t limit) const; - - ////////////////// - // ACCOUNT ROLE // - ////////////////// - vector get_account_roles_by_owner(account_id_type owner) const; - - private: - std::shared_ptr< database_api_impl > my; + bool is_public_key_registered(string public_key) const; + + ////////////// + // Accounts // + ////////////// + + /** + * @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> get_accounts(const vector &account_names_or_ids) const; + + /** + * @brief Fetch all objects relevant to the specified accounts and subscribe to updates + * @param callback Function to call with updates + * @param names_or_ids Each item must be the name or ID of an account to retrieve + * @return Map of string from @ref names_or_ids to the corresponding account + * + * This function fetches all relevant objects for the given accounts, and subscribes to updates to the given + * accounts. If any of the strings in @ref names_or_ids cannot be tied to an account, that input will be + * ignored. All other accounts will be retrieved and subscribed. + * + */ + std::map get_full_accounts(const vector &names_or_ids, bool subscribe); + + optional get_account_by_name(string name) const; + + /** + * @return all accounts that referr to the key or account id in their owner or active authorities. + */ + vector get_account_references(const std::string account_name_or_id) const; + + /** + * @brief Get a list of accounts by name + * @param account_names Names of the accounts to retrieve + * @return The accounts holding the provided names + * + * This function has semantics identical to @ref get_objects + */ + vector> lookup_account_names(const vector &account_names) const; + + /** + * @brief Get names and IDs for registered accounts + * @param lower_bound_name Lower bound of the first name to return + * @param limit Maximum number of results to return -- must not exceed 1000 + * @return Map of account names to corresponding IDs + */ + map lookup_accounts(const string &lower_bound_name, uint32_t limit) const; + + ////////////// + // Balances // + ////////////// + + /** + * @brief Get an account's balances in various assets + * @param id ID of the account to get balances for + * @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 get_account_balances(const std::string &account_name_or_id, + const flat_set &assets) const; + + /// Semantically equivalent to @ref get_account_balances, but takes a name instead of an ID. + vector get_named_account_balances(const std::string &name, const flat_set &assets) const; + + /** @return all unclaimed balance objects for a set of addresses */ + vector get_balance_objects(const vector
&addrs) const; + + vector get_vested_balances(const vector &objs) const; + + vector get_vesting_balances(const std::string account_id_or_name) const; + + /** + * @brief Get the total number of accounts registered with the blockchain + */ + uint64_t get_account_count() const; + + //////////// + // 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_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> get_assets(const vector &asset_symbols_or_ids) const; + + /** + * @brief Get assets alphabetically by symbol name + * @param lower_bound_symbol Lower bound of symbol names to retrieve + * @param limit Maximum number of assets to fetch (must not exceed 100) + * @return The assets found + */ + vector list_assets(const string &lower_bound_symbol, uint32_t limit) const; + + /** + * @brief Get a list of assets by symbol + * @param asset_symbols Symbols or stringified IDs of the assets to retrieve + * @return The assets corresponding to the provided symbols or IDs + * + * This function has semantics identical to @ref get_objects + */ + vector> lookup_asset_symbols(const vector &symbols_or_ids) const; + + /** + * @brief Get assets count + * @return The assets count + */ + uint64_t get_asset_count() const; + + //////////////////// + // Lottery Assets // + //////////////////// + /** + * @brief Get a list of lottery assets + * @return The lottery assets between start and stop ids + */ + vector get_lotteries(asset_id_type stop = asset_id_type(), + unsigned limit = 100, + asset_id_type start = asset_id_type()) const; + vector get_account_lotteries(account_id_type issuer, + asset_id_type stop, + unsigned limit, + asset_id_type start) const; + sweeps_vesting_balance_object get_sweeps_vesting_balance_object(account_id_type account) const; + asset get_sweeps_vesting_balance_available_for_claim(account_id_type account) const; + /** + * @brief Get balance of lottery assets + */ + asset get_lottery_balance(asset_id_type lottery_id) const; + + ///////////////////// + // Peerplays // + ///////////////////// + + /** + * @brief Get global betting statistics + */ + global_betting_statistics_object get_global_betting_statistics() const; + + /** + * @brief Get a list of all sports + */ + vector list_sports() const; + + /** + * @brief Return a list of all event groups for a sport (e.g. all soccer leagues in soccer) + */ + vector list_event_groups(sport_id_type sport_id) const; + + /** + * @brief Return a list of all events in an event group + */ + vector list_events_in_group(event_group_id_type event_group_id) const; + + /** + * @brief Return a list of all betting market groups for an event + */ + vector list_betting_market_groups(event_id_type) const; + + /** + * @brief Return a list of all betting markets for a betting market group + */ + vector list_betting_markets(betting_market_group_id_type) const; + + /** + * @brief Return a list of all unmatched bets for a given account on a specific betting market + */ + vector get_unmatched_bets_for_bettor(betting_market_id_type, account_id_type) const; + + /** + * @brief Return a list of all unmatched bets for a given account (includes bets on all markets) + */ + vector get_all_unmatched_bets_for_bettor(account_id_type) const; + + ///////////////////// + // Markets / feeds // + ///////////////////// + + /** + * @brief Get limit orders in a given market + * @param a ID of asset being sold + * @param b ID of asset being purchased + * @param limit Maximum number of orders to retrieve + * @return The limit orders, ordered from least price to greatest + */ + vector 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 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 get_call_orders(const std::string &a, uint32_t limit) const; + + /** + * @brief Get forced settlement orders in a given asset + * @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 get_settle_orders(const std::string &a, uint32_t limit) const; + + /** + * @return all open margin positions for a given account id. + */ + vector 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 or name + * @param b Second asset ID or name + * + * Callback will be passed a variant containing a vector>. The vector will + * contain, in order, the operations which changed the market, and their results. + */ + void subscribe_to_market(std::function callback, + const std::string &a, const std::string &b); + + /** + * @brief Unsubscribe from updates to a given market + * @param a First asset ID or name + * @param b Second asset ID or name + */ + void unsubscribe_from_market(const std::string &a, const std::string &b); + + /** + * @brief Returns the ticker for the market assetA:assetB + * @param a String name of the first asset + * @param b String name of the second asset + * @return The market ticker for the past 24 hours. + */ + market_ticker get_ticker(const string &base, const string "e) const; + + /** + * @brief Returns the 24 hour volume for the market assetA:assetB + * @param a String name of the first asset + * @param b String name of the second asset + * @return The market volume over the past 24 hours + */ + market_volume get_24_volume(const string &base, const string "e) const; + + /** + * @brief Returns the order book for the market base:quote + * @param base String name of the first asset + * @param quote String name of the second asset + * @param depth of the order book. Up to depth of each asks and bids, capped at 50. Prioritizes most moderate of each + * @return Order book of the market + */ + order_book get_order_book(const string &base, const string "e, unsigned limit = 50) const; + + /** + * @brief Returns recent trades for the market assetA:assetB + * Note: Currentlt, timezone offsets are not supported. The time must be UTC. + * @param a String name of the first asset + * @param b String name of the second asset + * @param stop Stop time as a UNIX timestamp + * @param limit Number of trasactions to retrieve, capped at 100 + * @param start Start time as a UNIX timestamp + * @return Recent transactions in the market + */ + vector get_trade_history(const string &base, const string "e, fc::time_point_sec start, fc::time_point_sec stop, unsigned limit = 100) const; + + /////////////// + // Witnesses // + /////////////// + + /** + * @brief Get a list of witnesses by ID + * @param witness_ids IDs of the witnesses to retrieve + * @return The witnesses corresponding to the provided IDs + * + * This function has semantics identical to @ref get_objects + */ + vector> get_witnesses(const vector &witness_ids) const; + + /** + * @brief Get the witness owned by a given account + * @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 get_witness_by_account(const std::string account_name_or_id) const; + + /** + * @brief Get names and IDs for registered witnesses + * @param lower_bound_name Lower bound of the first name to return + * @param limit Maximum number of results to return -- must not exceed 1000 + * @return Map of witness names to corresponding IDs + */ + map lookup_witness_accounts(const string &lower_bound_name, uint32_t limit) const; + + /** + * @brief Get the total number of witnesses registered with the blockchain + */ + uint64_t get_witness_count() const; + + /////////////////////// + // Committee members // + /////////////////////// + + /** + * @brief Get a list of committee_members by ID + * @param committee_member_ids IDs of the committee_members to retrieve + * @return The committee_members corresponding to the provided IDs + * + * This function has semantics identical to @ref get_objects + */ + vector> get_committee_members(const vector &committee_member_ids) const; + + /** + * @brief Get the committee_member owned by a given account + * @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 get_committee_member_by_account(const std::string account_id_or_name) const; + + /** + * @brief Get names and IDs for registered committee_members + * @param lower_bound_name Lower bound of the first name to return + * @param limit Maximum number of results to return -- must not exceed 1000 + * @return Map of committee_member names to corresponding IDs + */ + map lookup_committee_member_accounts(const string &lower_bound_name, uint32_t limit) const; + + ///////////////// + // SON members // + ///////////////// + + /** + * @brief Get a list of SONs by ID + * @param son_ids IDs of the SONs to retrieve + * @return The SONs corresponding to the provided IDs + * + * This function has semantics identical to @ref get_objects + */ + vector> get_sons(const vector &son_ids) const; + + /** + * @brief Get the SON owned by a given account + * @param account The ID of the account whose SON should be retrieved + * @return The SON object, or null if the account does not have a SON + */ + fc::optional get_son_by_account(account_id_type account) const; + + /** + * @brief Get names and IDs for registered SONs + * @param lower_bound_name Lower bound of the first name to return + * @param limit Maximum number of results to return -- must not exceed 1000 + * @return Map of SON names to corresponding IDs + */ + map lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const; + + /** + * @brief Get the total number of SONs registered with the blockchain + */ + uint64_t get_son_count() const; + + ///////////////////////// + // SON Wallets // + ///////////////////////// + + /** + * @brief Get active SON wallet + * @return Active SON wallet object + */ + optional get_active_son_wallet(); + + /** + * @brief Get SON wallet that was active for a given time point + * @param time_point Time point + * @return SON wallet object, for the wallet that was active for a given time point + */ + optional get_son_wallet_by_time_point(time_point_sec time_point); + + /** + * @brief Get full list of SON wallets + * @param limit Maximum number of results to return + * @return A list of SON wallet objects + */ + vector> get_son_wallets(uint32_t limit); + + ///////////////////////// + // Sidechain Addresses // + ///////////////////////// + + /** + * @brief Get a list of sidechain addresses + * @param sidechain_address_ids IDs of the sidechain addresses to retrieve + * @return The sidechain accounts corresponding to the provided IDs + * + * This function has semantics identical to @ref get_objects + */ + vector> get_sidechain_addresses(const vector &sidechain_address_ids) const; + + /** + * @brief Get the sidechain addresses for a given account + * @param account The ID of the account whose sidechain addresses should be retrieved + * @return The sidechain addresses objects, or null if the account does not have a sidechain addresses + */ + vector> get_sidechain_addresses_by_account(account_id_type account) const; + + /** + * @brief Get the sidechain addresses for a given sidechain + * @param sidechain Sidechain for which addresses should be retrieved + * @return The sidechain addresses objects, or null if the sidechain does not have any addresses + */ + vector> get_sidechain_addresses_by_sidechain(sidechain_type sidechain) const; + + /** + * @brief Get the sidechain addresses for a given account and sidechain + * @param account The ID of the account whose sidechain addresses should be retrieved + * @param sidechain Sidechain for which address should be retrieved + * @return The sidechain addresses objects, or null if the account does not have a sidechain addresses for a given sidechain + */ + fc::optional get_sidechain_address_by_account_and_sidechain(account_id_type account, sidechain_type sidechain) const; + + /** + * @brief Get the total number of sidechain addresses registered with the blockchain + */ + uint64_t get_sidechain_addresses_count() const; + + /// WORKERS + + /** + * @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 get_workers_by_account(const std::string account_id_or_name) const; + + /////////// + // Votes // + /////////// + + /** + * @brief Given a set of votes, return the objects they are voting for. + * + * This will be a mixture of committee_member_object, witness_objects, and worker_objects + * + * The results will be in the same order as the votes. Null will be returned for + * any vote ids that are not found. + */ + vector lookup_vote_ids(const vector &votes) const; + + //////////////////////////// + // Authority / validation // + //////////////////////////// + + /// @brief Get a hexdump of the serialized binary form of a transaction + std::string get_transaction_hex(const signed_transaction &trx) const; + + /** + * This API will take a partially signed transaction and a set of public keys that the owner has the ability to sign for + * and return the minimal subset of public keys that should add signatures to the transaction. + */ + set get_required_signatures(const signed_transaction &trx, const flat_set &available_keys) const; + + /** + * This method will return the set of all public keys that could possibly sign for a given transaction. This call can + * be used by wallets to filter their set of public keys to just the relevant subset prior to calling @ref get_required_signatures + * to get the minimum subset. + */ + set get_potential_signatures(const signed_transaction &trx) const; + set
get_potential_address_signatures(const signed_transaction &trx) const; + + /** + * @return true of the @ref trx has all of the required signatures, otherwise throws an exception + */ + bool verify_authority(const signed_transaction &trx) const; + + /** + * @return true if the signers have enough authority to authorize an account + */ + bool verify_account_authority(const string &name_or_id, const flat_set &signers) const; + + /** + * Validates a transaction against the current state without broadcasting it on the network. + */ + processed_transaction validate_transaction(const signed_transaction &trx) const; + + /** + * 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 get_required_fees(const vector &ops, const std::string &asset_id_or_symbol) const; + + /////////////////////////// + // Proposed transactions // + /////////////////////////// + + /** + * @return the set of proposed transactions relevant to the specified account id. + */ + vector get_proposed_transactions(const std::string account_id_or_name) const; + + ////////////////////// + // Blinded balances // + ////////////////////// + + /** + * @return the set of blinded balance objects by commitment ID + */ + vector get_blinded_balances(const flat_set &commitments) const; + + ///////////////// + // Tournaments // + ///////////////// + /** + * @return the list of tournaments in the given state + */ + vector get_tournaments_in_state(tournament_state state, uint32_t limit) const; + + vector get_tournaments(tournament_id_type stop = tournament_id_type(), + unsigned limit = 100, + tournament_id_type start = tournament_id_type()); + + vector get_tournaments_by_state(tournament_id_type stop = tournament_id_type(), + unsigned limit = 100, + tournament_id_type start = tournament_id_type(), + tournament_state state = tournament_state::accepting_registrations); + + /** + * @return the list of tournaments that a given account is registered to play in + */ + vector get_registered_tournaments(account_id_type account_filter, uint32_t limit) const; + + ////////// + // GPOS // + ////////// + /** + * @return account and network GPOS information + */ + gpos_info get_gpos_info(const account_id_type account) const; + + ////////// + // RBAC // + ////////// + /** + * @return account and custom permissions/account-authorities info + */ + vector get_custom_permissions(const account_id_type account) const; + fc::optional get_custom_permission_by_name(const account_id_type account, const string &permission_name) const; + vector get_custom_account_authorities(const account_id_type account) const; + vector get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const; + vector get_custom_account_authorities_by_permission_name(const account_id_type account, const string &permission_name) const; + vector get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const; + + ///////// + // NFT // + ///////// + /** + * @brief Returns the number of NFT owned by account + * @param owner Owner account ID + * @return Number of NFTs owned by account + */ + uint64_t nft_get_balance(const account_id_type owner) const; + + /** + * @brief Returns the NFT owner + * @param token_id NFT ID + * @return NFT owner account ID + */ + optional nft_owner_of(const nft_id_type token_id) const; + + /** + * @brief Returns the NFT approved account ID + * @param token_id NFT ID + * @return NFT approved account ID + */ + optional nft_get_approved(const nft_id_type token_id) const; + + /** + * @brief Returns operator approved state for all NFT owned by owner + * @param owner NFT owner account ID + * @param token_id NFT ID + * @return True if operator is approved for all NFT owned by owner, else False + */ + bool nft_is_approved_for_all(const account_id_type owner, const account_id_type operator_) const; + + /** + * @brief Returns NFT name from NFT metadata + * @param nft_metadata_id NFT metadata ID + * @return NFT name + */ + string nft_get_name(const nft_metadata_id_type nft_metadata_id) const; + + /** + * @brief Returns NFT symbol from NFT metadata + * @param nft_metadata_id NFT metadata ID + * @return NFT symbol + */ + string nft_get_symbol(const nft_metadata_id_type nft_metadata_id) const; + + /** + * @brief Returns NFT URI + * @param token_id NFT ID + * @return NFT URI + */ + string nft_get_token_uri(const nft_id_type token_id) const; + + /** + * @brief Returns total number of NFTs assigned to NFT metadata + * @param nft_metadata_id NFT metadata ID + * @return Total number of NFTs assigned to NFT metadata + */ + uint64_t nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const; + + /** + * @brief Returns NFT by index from NFT metadata + * @param nft_metadata_id NFT metadata ID + * @param token_idx NFT index in the list of tokens + * @return NFT symbol + */ + nft_object nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const; + + /** + * @brief Returns NFT by owner and index + * @param nft_metadata_id NFT metadata ID + * @param owner NFT owner + * @param token_idx NFT index in the list of tokens + * @return NFT object + */ + nft_object nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const; + + /** + * @brief Returns list of all available NTF's + * @return List of all available NFT's + */ + vector nft_get_all_tokens() const; + + /** + * @brief Returns NFT's owned by owner + * @param owner NFT owner + * @return List of NFT owned by owner + */ + vector nft_get_tokens_by_owner(const account_id_type owner) const; + + ////////////////// + // MARKET PLACE // + ////////////////// + vector list_offers(const offer_id_type lower_id, uint32_t limit) const; + vector list_sell_offers(const offer_id_type lower_id, uint32_t limit) const; + vector list_buy_offers(const offer_id_type lower_id, uint32_t limit) const; + vector list_offer_history(const offer_history_id_type lower_id, uint32_t limit) const; + vector get_offers_by_issuer(const offer_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const; + vector get_offers_by_item(const offer_id_type lower_id, const nft_id_type item, uint32_t limit) const; + vector get_offer_history_by_issuer(const offer_history_id_type lower_id, const account_id_type issuer_account_id, uint32_t limit) const; + vector get_offer_history_by_item(const offer_history_id_type lower_id, const nft_id_type item, uint32_t limit) const; + vector get_offer_history_by_bidder(const offer_history_id_type lower_id, const account_id_type bidder_account_id, uint32_t limit) const; + + ////////////////// + // ACCOUNT ROLE // + ////////////////// + vector get_account_roles_by_owner(account_id_type owner) const; + +private: + std::shared_ptr my; }; -} } +}} // namespace graphene::app extern template class fc::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) ); +// clang-format off +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 @@ -1136,3 +1126,5 @@ FC_API(graphene::app::database_api, // Account Roles (get_account_roles_by_owner) ) + +// clang-format on diff --git a/libraries/app/include/graphene/app/full_account.hpp b/libraries/app/include/graphene/app/full_account.hpp index dc83adb6..2106e83b 100644 --- a/libraries/app/include/graphene/app/full_account.hpp +++ b/libraries/app/include/graphene/app/full_account.hpp @@ -24,51 +24,53 @@ #pragma once #include -#include #include +#include #include namespace graphene { namespace app { - using namespace graphene::chain; +using namespace graphene::chain; - struct full_account - { - account_object account; - account_statistics_object statistics; - string registrar_name; - string referrer_name; - string lifetime_referrer_name; - vector votes; - optional cashback_balance; - vector balances; - vector vesting_balances; - vector limit_orders; - vector call_orders; - vector settle_orders; - vector proposals; - vector assets; - vector withdraws; -// vector pending_dividend_payments; - vector pending_dividend_payments; - }; +struct full_account { + account_object account; + account_statistics_object statistics; + string registrar_name; + string referrer_name; + string lifetime_referrer_name; + vector votes; + optional cashback_balance; + vector balances; + vector vesting_balances; + vector limit_orders; + vector call_orders; + vector settle_orders; + vector proposals; + vector assets; + vector withdraws; + // vector pending_dividend_payments; + vector pending_dividend_payments; +}; -} } +}} // namespace graphene::app -FC_REFLECT( graphene::app::full_account, - (account) - (statistics) - (registrar_name) - (referrer_name) - (lifetime_referrer_name) - (votes) - (cashback_balance) - (balances) - (vesting_balances) - (limit_orders) - (call_orders) - (settle_orders) - (proposals) - (assets) - (withdraws) - (pending_dividend_payments) - ) +// clang-format off + +FC_REFLECT(graphene::app::full_account, + (account) + (statistics) + (registrar_name) + (referrer_name) + (lifetime_referrer_name) + (votes) + (cashback_balance) + (balances) + (vesting_balances) + (limit_orders) + (call_orders) + (settle_orders) + (proposals) + (assets) + (withdraws) + (pending_dividend_payments)) + +// clang-format on diff --git a/libraries/app/include/graphene/app/plugin.hpp b/libraries/app/include/graphene/app/plugin.hpp index 45336f67..044f779b 100644 --- a/libraries/app/include/graphene/app/plugin.hpp +++ b/libraries/app/include/graphene/app/plugin.hpp @@ -30,118 +30,119 @@ namespace graphene { namespace app { -class abstract_plugin -{ - public: - virtual ~abstract_plugin(){} - virtual std::string plugin_name()const = 0; - virtual std::string plugin_description()const = 0; +class abstract_plugin { +public: + virtual ~abstract_plugin() { + } + virtual std::string plugin_name() const = 0; + virtual std::string plugin_description() const = 0; - /** - * @brief Perform early startup routines and register plugin indexes, callbacks, etc. - * - * Plugins MUST supply a method initialize() which will be called early in the application startup. This method - * should contain early setup code such as initializing variables, adding indexes to the database, registering - * callback methods from the database, adding APIs, etc., as well as applying any options in the @ref options map - * - * This method is called BEFORE the database is open, therefore any routines which require any chain state MUST - * NOT be called by this method. These routines should be performed in startup() instead. - * - * @param options The options passed to the application, via configuration files or command line - */ - virtual void plugin_initialize( const boost::program_options::variables_map& options ) = 0; + /** + * @brief Perform early startup routines and register plugin indexes, callbacks, etc. + * + * Plugins MUST supply a method initialize() which will be called early in the application startup. This method + * should contain early setup code such as initializing variables, adding indexes to the database, registering + * callback methods from the database, adding APIs, etc., as well as applying any options in the @ref options map + * + * This method is called BEFORE the database is open, therefore any routines which require any chain state MUST + * NOT be called by this method. These routines should be performed in startup() instead. + * + * @param options The options passed to the application, via configuration files or command line + */ + virtual void plugin_initialize(const boost::program_options::variables_map &options) = 0; - /** - * @brief Begin normal runtime operations - * - * Plugins MUST supply a method startup() which will be called at the end of application startup. This method - * should contain code which schedules any tasks, or requires chain state. - */ - virtual void plugin_startup() = 0; + /** + * @brief Begin normal runtime operations + * + * Plugins MUST supply a method startup() which will be called at the end of application startup. This method + * should contain code which schedules any tasks, or requires chain state. + */ + virtual void plugin_startup() = 0; - /** - * @brief Cleanly shut down the plugin. - * - * This is called to request a clean shutdown (e.g. due to SIGINT or SIGTERM). - */ - virtual void plugin_shutdown() = 0; + /** + * @brief Cleanly shut down the plugin. + * + * This is called to request a clean shutdown (e.g. due to SIGINT or SIGTERM). + */ + virtual void plugin_shutdown() = 0; - /** - * @brief Register the application instance with the plugin. - * - * This is called by the framework to set the application. - */ - virtual void plugin_set_app( application* a ) = 0; + /** + * @brief Register the application instance with the plugin. + * + * This is called by the framework to set the application. + */ + virtual void plugin_set_app(application *a) = 0; - /** - * @brief Fill in command line parameters used by the plugin. - * - * @param command_line_options All options this plugin supports taking on the command-line - * @param config_file_options All options this plugin supports storing in a configuration file - * - * This method populates its arguments with any - * command-line and configuration file options the plugin supports. - * If a plugin does not need these options, it - * may simply provide an empty implementation of this method. - */ - virtual void plugin_set_program_options( - boost::program_options::options_description& command_line_options, - boost::program_options::options_description& config_file_options - ) = 0; + /** + * @brief Fill in command line parameters used by the plugin. + * + * @param command_line_options All options this plugin supports taking on the command-line + * @param config_file_options All options this plugin supports storing in a configuration file + * + * This method populates its arguments with any + * command-line and configuration file options the plugin supports. + * If a plugin does not need these options, it + * may simply provide an empty implementation of this method. + */ + virtual void plugin_set_program_options(boost::program_options::options_description &command_line_options, + boost::program_options::options_description &config_file_options) = 0; }; /** * Provides basic default implementations of abstract_plugin functions. */ -class plugin : public abstract_plugin -{ - public: - plugin(); - virtual ~plugin() override; +class plugin : public abstract_plugin { +public: + plugin(); + virtual ~plugin() override; - virtual std::string plugin_name()const override; - virtual std::string plugin_description()const override; - virtual void plugin_initialize( const boost::program_options::variables_map& options ) override; - virtual void plugin_startup() override; - virtual void plugin_shutdown() override; - virtual void plugin_set_app( application* app ) override; - virtual void plugin_set_program_options( - boost::program_options::options_description& command_line_options, - boost::program_options::options_description& config_file_options - ) override; + virtual std::string plugin_name() const override; + virtual std::string plugin_description() const override; + virtual void plugin_initialize(const boost::program_options::variables_map &options) override; + virtual void plugin_startup() override; + virtual void plugin_shutdown() override; + virtual void plugin_set_app(application *app) override; + virtual void plugin_set_program_options(boost::program_options::options_description &command_line_options, + boost::program_options::options_description &config_file_options) override; - chain::database& database() { return *app().chain_database(); } - application& app()const { assert(_app); return *_app; } - protected: - net::node& p2p_node() { return *app().p2p_node(); } + chain::database &database() { + return *app().chain_database(); + } + application &app() const { + assert(_app); + return *_app; + } - private: - application* _app = nullptr; +protected: + net::node &p2p_node() { + return *app().p2p_node(); + } + +private: + application *_app = nullptr; }; /// @group Some useful tools for boost::program_options arguments using vectors of JSON strings /// @{ -template -T dejsonify(const string& s, uint32_t max_depth) -{ +template +T dejsonify(const string &s, uint32_t max_depth) { return fc::json::from_string(s).as(max_depth); } namespace impl { - template - T dejsonify( const string& s ) - { - return graphene::app::dejsonify( s, GRAPHENE_MAX_NESTED_OBJECTS ); - } +template +T dejsonify(const string &s) { + return graphene::app::dejsonify(s, GRAPHENE_MAX_NESTED_OBJECTS); } +} // namespace impl #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& ops = options[name].as>(); \ +#define LOAD_VALUE_SET(options, name, container, type) \ + if (options.count(name)) { \ + const std::vector &ops = options[name].as>(); \ std::transform(ops.begin(), ops.end(), std::inserter(container, container.end()), &graphene::app::impl::dejsonify); \ -} + } /// @} -} } //graphene::app +}} // namespace graphene::app diff --git a/libraries/app/plugin.cpp b/libraries/app/plugin.cpp index cae488a6..5155986b 100644 --- a/libraries/app/plugin.cpp +++ b/libraries/app/plugin.cpp @@ -27,54 +27,44 @@ namespace graphene { namespace app { -plugin::plugin() -{ +plugin::plugin() { _app = nullptr; return; } -plugin::~plugin() -{ +plugin::~plugin() { return; } -std::string plugin::plugin_name()const -{ +std::string plugin::plugin_name() const { return ""; } -std::string plugin::plugin_description()const -{ +std::string plugin::plugin_description() const { return ""; } -void plugin::plugin_initialize( const boost::program_options::variables_map& options ) -{ +void plugin::plugin_initialize(const boost::program_options::variables_map &options) { return; } -void plugin::plugin_startup() -{ +void plugin::plugin_startup() { return; } -void plugin::plugin_shutdown() -{ +void plugin::plugin_shutdown() { return; } -void plugin::plugin_set_app( application* app ) -{ +void plugin::plugin_set_app(application *app) { _app = app; return; } void plugin::plugin_set_program_options( - boost::program_options::options_description& command_line_options, - boost::program_options::options_description& config_file_options -) -{ + boost::program_options::options_description &cli, + boost::program_options::options_description &cfg) { return; } -} } // graphene::app +}} // namespace graphene::app diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 0a0e9c56..4054878c 100755 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -8,143 +8,29 @@ add_dependencies( build_hardfork_hpp cat-parts ) file(GLOB HEADERS "include/graphene/chain/*.hpp") file(GLOB PROTOCOL_HEADERS "include/graphene/chain/protocol/*.hpp") -if( GRAPHENE_DISABLE_UNITY_BUILD ) - set( GRAPHENE_DB_FILES - db_balance.cpp - db_bet.cpp - db_block.cpp - db_debug.cpp - db_getter.cpp - db_init.cpp - db_maint.cpp - db_management.cpp - db_market.cpp - db_update.cpp - db_witness_schedule.cpp - ) +file(GLOB CPP_FILES "*.cpp") +file(GLOB PROTOCOL_CPP_FILES "protocol/*.cpp") + +#if( GRAPHENE_DISABLE_UNITY_BUILD ) + list(FILTER CPP_FILES EXCLUDE REGEX "[/]database[.]cpp$") + #message ("--- ${CPP_FILES}") message( STATUS "Graphene database unity build disabled" ) -else( GRAPHENE_DISABLE_UNITY_BUILD ) - set( GRAPHENE_DB_FILES - database.cpp ) - message( STATUS "Graphene database unity build enabled" ) -endif( GRAPHENE_DISABLE_UNITY_BUILD ) +#else( GRAPHENE_DISABLE_UNITY_BUILD ) +# list(FILTER CPP_FILES EXCLUDE REGEX ".*db_.*[.]cpp$") +# #message ("--- ${CPP_FILES}") +# message( STATUS "Graphene database unity build enabled" ) +#endif( GRAPHENE_DISABLE_UNITY_BUILD ) -## SORT .cpp by most likely to change / break compile add_library( graphene_chain - - # As database takes the longest to compile, start it first - ${GRAPHENE_DB_FILES} - fork_database.cpp - - protocol/types.cpp - protocol/address.cpp - protocol/authority.cpp - protocol/asset.cpp - protocol/assert.cpp - protocol/account.cpp - protocol/transfer.cpp - protocol/chain_parameters.cpp - protocol/committee_member.cpp - protocol/witness.cpp - protocol/market.cpp - protocol/proposal.cpp - protocol/withdraw_permission.cpp - protocol/asset_ops.cpp - protocol/lottery_ops.cpp - protocol/memo.cpp - protocol/worker.cpp - protocol/custom.cpp - protocol/operations.cpp - protocol/transaction.cpp - protocol/block.cpp - protocol/fee_schedule.cpp - protocol/confidential.cpp - protocol/vote.cpp - protocol/tournament.cpp - protocol/small_ops.cpp - protocol/custom_permission.cpp - protocol/custom_account_authority.cpp - protocol/offer.cpp - - genesis_state.cpp - get_config.cpp - - pts_address.cpp - - evaluator.cpp - balance_evaluator.cpp - account_evaluator.cpp - assert_evaluator.cpp - witness_evaluator.cpp - committee_member_evaluator.cpp - asset_evaluator.cpp - lottery_evaluator.cpp - transfer_evaluator.cpp - proposal_evaluator.cpp - market_evaluator.cpp - vesting_balance_evaluator.cpp - tournament_evaluator.cpp - tournament_object.cpp - match_object.cpp - game_object.cpp - withdraw_permission_evaluator.cpp - worker_evaluator.cpp - confidential_evaluator.cpp - special_authority.cpp - buyback.cpp - - account_object.cpp - asset_object.cpp - fba_object.cpp - proposal_object.cpp - vesting_balance_object.cpp - small_objects.cpp - - block_database.cpp - - is_authorized_asset.cpp - - protocol/sport.cpp - sport_evaluator.cpp - protocol/event_group.cpp - event_group_evaluator.cpp - event_group_object.cpp - protocol/event.cpp - event_evaluator.cpp - event_object.cpp - protocol/betting_market.cpp - betting_market_evaluator.cpp - betting_market_object.cpp - betting_market_group_object.cpp - custom_permission_evaluator.cpp - custom_account_authority_evaluator.cpp - - affiliate_payout.cpp - - offer_object.cpp - offer_evaluator.cpp - nft_evaluator.cpp - protocol/nft.cpp - protocol/account_role.cpp - account_role_evaluator.cpp - - son_evaluator.cpp - son_object.cpp - - son_wallet_evaluator.cpp - son_wallet_deposit_evaluator.cpp - son_wallet_withdraw_evaluator.cpp - - sidechain_address_evaluator.cpp - sidechain_transaction_evaluator.cpp - + ${CPP_FILES} + ${PROTOCOL_CPP_FILES} ${HEADERS} ${PROTOCOL_HEADERS} "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) add_dependencies( graphene_chain build_hardfork_hpp ) -target_link_libraries( graphene_chain fc graphene_db ) +target_link_libraries( graphene_chain graphene_db ) target_include_directories( graphene_chain PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include" ) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 0c7a458d..0591da54 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -597,7 +597,6 @@ void_result asset_update_dividend_evaluator::do_apply( const asset_update_divide obj.referrer = op.issuer; obj.lifetime_referrer = op.issuer(db()).lifetime_referrer; - auto& params = db().get_global_properties().parameters; obj.network_fee_percentage = GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; obj.lifetime_referrer_fee_percentage = GRAPHENE_DEFAULT_LIFETIME_REFERRER_PERCENT_OF_FEE; obj.referrer_rewards_percentage = GRAPHENE_DEFAULT_LIFETIME_REFERRER_PERCENT_OF_FEE; diff --git a/libraries/chain/asset_object.cpp b/libraries/chain/asset_object.cpp index 79ad88ad..70adbde8 100644 --- a/libraries/chain/asset_object.cpp +++ b/libraries/chain/asset_object.cpp @@ -266,7 +266,7 @@ map< account_id_type, vector< uint16_t > > asset_object::distribute_winners_part *t += percents_to_distribute / holders.size(); } auto sweeps_distribution_percentage = db.get_global_properties().parameters.sweeps_distribution_percentage(); - for( int c = 0; c < winner_numbers.size(); ++c ) { + for( size_t c = 0; c < winner_numbers.size(); ++c ) { auto winner_num = winner_numbers[c]; lottery_reward_operation reward_op; reward_op.lottery = get_id(); diff --git a/libraries/chain/block_database.cpp b/libraries/chain/block_database.cpp index 2dd9b7a2..7675871e 100644 --- a/libraries/chain/block_database.cpp +++ b/libraries/chain/block_database.cpp @@ -76,6 +76,10 @@ void block_database::flush() void block_database::store( const block_id_type& _id, const signed_block& b ) { + if (true == replay_mode){ + return; + } + block_id_type id = _id; if( id == block_id_type() ) { @@ -99,8 +103,15 @@ void block_database::remove( const block_id_type& id ) 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 ) + + std::streampos s_pos = _block_num_to_pos.tellg(); + if (-1 == s_pos){ + FC_THROW_EXCEPTION(fc::key_not_found_exception, "Block ${id} not contained in block database, _block_num_to_pos.tellg failed", ("id", id)); + } + + if ( static_cast(s_pos) <= index_pos ){ FC_THROW_EXCEPTION(fc::key_not_found_exception, "Block ${id} not contained in block database", ("id", id)); + } _block_num_to_pos.seekg( index_pos ); _block_num_to_pos.read( (char*)&e, sizeof(e) ); @@ -114,20 +125,27 @@ void block_database::remove( const block_id_type& id ) } FC_CAPTURE_AND_RETHROW( (id) ) } bool block_database::contains( const block_id_type& id )const -{ +{ try { if( id == block_id_type() ) return false; 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 + sizeof(e) ) + + std::streampos s_pos = _block_num_to_pos.tellg(); + if (-1 == s_pos){ + FC_THROW_EXCEPTION(fc::key_not_found_exception, "Block ${id} not contained in block database, _block_num_to_pos.tellg failed", ("id", id)); + } + + if ( static_cast(s_pos) < index_pos + sizeof(e) ) return false; + _block_num_to_pos.seekg( index_pos ); _block_num_to_pos.read( (char*)&e, sizeof(e) ); return e.block_id == id && e.block_size > 0; -} +} FC_CAPTURE_AND_RETHROW( (id) ) } block_id_type block_database::fetch_block_id( uint32_t block_num )const { @@ -152,7 +170,13 @@ optional block_database::fetch_optional( const block_id_type& id ) 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 ) + std::streampos s_pos = _block_num_to_pos.tellg(); + + if (-1 == s_pos){ + FC_THROW_EXCEPTION(fc::key_not_found_exception, "Block ${id} not contained in block database, _block_num_to_pos.tellg failed", ("id", id)); + } + + if ( static_cast(s_pos) <= index_pos ) return {}; _block_num_to_pos.seekg( index_pos ); @@ -184,7 +208,12 @@ optional block_database::fetch_by_number( uint32_t block_num )cons index_entry e; auto index_pos = sizeof(e)*block_num; _block_num_to_pos.seekg( 0, _block_num_to_pos.end ); - if ( _block_num_to_pos.tellg() <= index_pos ) + std::streampos s_pos = _block_num_to_pos.tellg(); + if (-1 == s_pos){ + FC_THROW_EXCEPTION(fc::key_not_found_exception, "Block ${block_num} not contained in block database, _block_num_to_pos.tellg failed", ("block_num", block_num)); + } + + if ( static_cast(s_pos) <= index_pos ) return {}; _block_num_to_pos.seekg( index_pos, _block_num_to_pos.beg ); @@ -213,7 +242,11 @@ optional block_database::last_index_entry()const { _block_num_to_pos.seekg( 0, _block_num_to_pos.end ); std::streampos pos = _block_num_to_pos.tellg(); - if( pos < sizeof(index_entry) ) + if (-1 == pos){ + FC_THROW_EXCEPTION(fc::key_not_found_exception, "last_index_entry tellg failed"); + } + + if( static_cast(pos) < sizeof(index_entry) ) return optional(); pos -= pos % sizeof(index_entry); @@ -226,7 +259,7 @@ optional block_database::last_index_entry()const { _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 ) + && e.block_pos + static_cast(e.block_size) <= static_cast(blocks_size) ) try { vector data( e.block_size ); @@ -271,4 +304,9 @@ optional block_database::last_id()const return optional(); } +void block_database::set_replay_mode(bool mode) +{ + replay_mode = mode; +} + } } diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 1e124902..8c1287c3 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -30,6 +30,6 @@ #include "db_maint.cpp" #include "db_management.cpp" #include "db_market.cpp" +#include "db_notify.cpp" #include "db_update.cpp" #include "db_witness_schedule.cpp" -#include "db_notify.cpp" \ No newline at end of file diff --git a/libraries/chain/db_balance.cpp b/libraries/chain/db_balance.cpp index 55729050..27a7e79e 100644 --- a/libraries/chain/db_balance.cpp +++ b/libraries/chain/db_balance.cpp @@ -140,8 +140,10 @@ void database::adjust_sweeps_vesting_balance(account_id_type account, int64_t de b.balance = delta; }); } else { - if( delta < 0 ) - FC_ASSERT( itr->get_balance() >= -delta, "Insufficient Balance: ${a}'s balance of ${b} is less than required ${r}", ("a",account)("b",itr->get_balance())("r",-delta)); + if( delta < 0 ) { + uint64_t delta_uint64 = -delta; + FC_ASSERT( itr->get_balance() >= delta_uint64, "Insufficient Balance: ${a}'s balance of ${b} is less than required ${r}", ("a",account)("b",itr->get_balance())("r",-delta)); + } modify(*itr, [&delta,&asset_id,this](sweeps_vesting_balance_object& b) { b.adjust_balance( asset( delta, asset_id ) ); b.last_claim_date = head_block_time(); diff --git a/libraries/chain/db_bet.cpp b/libraries/chain/db_bet.cpp index 8c3e1357..6b14f4ff 100644 --- a/libraries/chain/db_bet.cpp +++ b/libraries/chain/db_bet.cpp @@ -303,8 +303,6 @@ void database::settle_betting_market_group(const betting_market_group_object& be remove(betting_market); } - const event_object& event = betting_market_group.event_id(*this); - fc_dlog(fc::logger::get("betting"), "removing betting market group ${id}", ("id", betting_market_group.id)); remove(betting_market_group); @@ -537,11 +535,9 @@ int match_bet(database& db, const bet_object& taker_bet, const bet_object& maker // because we matched at the maker's odds and not the taker's odds, the remaining amount to match // may not be an even multiple of the taker's odds; round it down. share_type taker_remaining_factor = unrounded_taker_remaining_amount_to_match / takers_odds_maker_odds_ratio; - share_type taker_remaining_maker_amount_to_match = taker_remaining_factor * takers_odds_maker_odds_ratio; share_type taker_remaining_bet_amount = taker_remaining_factor * takers_odds_taker_odds_ratio; taker_refund_amount = taker_bet.amount_to_bet.amount - taker_amount_to_match - taker_remaining_bet_amount; - //idump((taker_remaining_factor)(taker_remaining_maker_amount_to_match)(taker_remaining_bet_amount)(taker_refund_amount)); } if (taker_refund_amount > share_type()) diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 21701a25..67601c2e 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -715,7 +715,8 @@ void database::_apply_block( const signed_block& next_block ) perform_chain_maintenance(next_block, global_props); check_ending_lotteries(); - + check_ending_nft_lotteries(); + create_block_summary(next_block); place_delayed_bets(); // must happen after update_global_dynamic_data() updates the time clear_expired_transactions(); diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index 57a72e7f..78740c9b 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -109,7 +109,7 @@ uint32_t database::last_non_undoable_block_num() const return head_block_num() - _undo_db.size(); } -std::vector database::get_seeds(asset_id_type for_asset, uint8_t count_winners) const +std::vector database::get_seeds( asset_id_type for_asset, uint8_t count_winners ) const { FC_ASSERT( count_winners <= 64 ); std::string salted_string = std::string(_random_number_generator._seed) + std::to_string(for_asset.instance.value); @@ -315,6 +315,38 @@ bool database::is_son_active( son_id_type son_id ) return (it_son != active_son_ids.end()); } +vector database::get_random_numbers(uint64_t minimum, uint64_t maximum, uint64_t selections, bool duplicates) +{ + FC_ASSERT( selections <= 100000 ); + if (duplicates == false) { + FC_ASSERT( maximum - minimum >= selections ); + } + + vector v; + v.reserve(selections); + + if (duplicates) { + for (uint64_t i = 0; i < selections; i++) { + int64_t rnd = get_random_bits(maximum - minimum) + minimum; + v.push_back(rnd); + } + } else { + vector tmpv; + tmpv.reserve(selections); + for (uint64_t i = minimum; i < maximum; i++) { + tmpv.push_back(i); + } + + for (uint64_t i = 0; (i < selections) && (tmpv.size() > 0); i++) { + uint64_t idx = get_random_bits(tmpv.size()); + v.push_back(tmpv.at(idx)); + tmpv.erase(tmpv.begin() + idx); + } + } + + return v; +} + bool database::is_asset_creation_allowed(const string &symbol) { time_point_sec now = head_block_time(); diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 43ba381d..724cad85 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include @@ -94,12 +95,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include @@ -203,6 +206,12 @@ const uint8_t offer_history_object::type_id; const uint8_t account_role_object::space_id; const uint8_t account_role_object::type_id; +const uint8_t nft_lottery_balance_object::space_id; +const uint8_t nft_lottery_balance_object::type_id; + +const uint8_t random_number_object::space_id; +const uint8_t random_number_object::type_id; + void database::initialize_evaluators() { _operation_evaluators.resize(255); @@ -295,6 +304,9 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); + register_evaluator(); + register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); @@ -314,6 +326,7 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); } void database::initialize_indexes() @@ -403,7 +416,9 @@ void database::initialize_indexes() add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); + add_index< primary_index >(); add_index< primary_index >(); + add_index< primary_index >(); } @@ -933,7 +948,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) const auto& idx = get_index_type().indices().get(); auto it = idx.begin(); - bool has_imbalanced_assets = false; while( it != idx.end() ) { @@ -945,7 +959,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) FC_ASSERT( debt_itr != total_debts.end() ); if( supply_itr->second != debt_itr->second ) { - has_imbalanced_assets = true; elog( "Genesis for asset ${aname} is not balanced\n" " Debt is ${debt}\n" " Supply is ${supply}\n", @@ -957,10 +970,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) } ++it; } -// @romek -#if 0 - FC_ASSERT( !has_imbalanced_assets ); -#endif // Save tallied supplies for( const auto& item : total_supplies ) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 0d585605..3f68d598 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -32,24 +32,24 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include #include -#include - -#define USE_VESTING_OBJECT_BY_ASSET_BALANCE_INDEX // vesting_balance_object by_asset_balance index needed namespace graphene { namespace chain { @@ -84,7 +84,7 @@ vector> database::sort_votable_objects< std::vector> refs; for( auto& son : all_sons ) { - if(son.has_valid_config() && son.status != son_status::deregistered) + if(son.has_valid_config(head_block_time()) && son.status != son_status::deregistered) { refs.push_back(std::cref(son)); } @@ -210,20 +210,29 @@ void database::pay_sons() if( now < HARDFORK_SON2_TIME ) { son_weight = get_weight_before_son2_hf(_vote_tally_buffer[son_obj->vote_id]); } - weighted_total_txs_signed += (s.txs_signed * son_weight); + uint64_t txs_signed = 0; + for (const auto &ts : s.txs_signed) { + txs_signed = txs_signed + ts.second; + } + weighted_total_txs_signed += (txs_signed * son_weight); }); // Now pay off each SON proportional to the number of transactions signed. get_index_type().inspect_all_objects([this, &weighted_total_txs_signed, &dpo, &son_budget, &get_weight, &get_weight_before_son2_hf, &now](const object& o) { const son_statistics_object& s = static_cast(o); - if(s.txs_signed > 0){ + uint64_t txs_signed = 0; + for (const auto &ts : s.txs_signed) { + txs_signed = txs_signed + ts.second; + } + + if(txs_signed > 0){ const auto& idx = get_index_type().indices().get(); auto son_obj = idx.find( s.owner ); auto son_weight = get_weight(_vote_tally_buffer[son_obj->vote_id]); if( now < HARDFORK_SON2_TIME ) { son_weight = get_weight_before_son2_hf(_vote_tally_buffer[son_obj->vote_id]); } - share_type pay = (s.txs_signed * son_weight * son_budget.value)/weighted_total_txs_signed; + share_type pay = (txs_signed * son_weight * son_budget.value)/weighted_total_txs_signed; modify( *son_obj, [&]( son_object& _son_obj) { _son_obj.pay_son_fee(pay, *this); @@ -236,8 +245,9 @@ void database::pay_sons() //Reset the tx counter in each son statistics object modify( s, [&]( son_statistics_object& _s) { - _s.total_txs_signed += _s.txs_signed; - _s.txs_signed = 0; + for (const auto &ts : s.txs_signed) { + _s.txs_signed.at(ts.first) = 0; + } }); } }); @@ -267,11 +277,13 @@ void database::update_son_metrics(const vector& curr_active_sons) bool is_active_son = (std::find(current_sons.begin(), current_sons.end(), son.id) != current_sons.end()); modify( stats, [&]( son_statistics_object& _stats ) { + if(is_active_son) { + _stats.total_voted_time = _stats.total_voted_time + get_global_properties().parameters.maintenance_interval; + } _stats.total_downtime += _stats.current_interval_downtime; _stats.current_interval_downtime = 0; - if(is_active_son) - { - _stats.total_voted_time = _stats.total_voted_time + get_global_properties().parameters.maintenance_interval; + for (const auto &str : _stats.sidechain_txs_reported) { + _stats.sidechain_txs_reported.at(str.first) = 0; } }); } @@ -593,7 +605,7 @@ void database::update_active_committee_members() update_committee_member_total_votes( cm ); } } - + // Update committee authorities if( !committee_members.empty() ) { @@ -1206,7 +1218,6 @@ uint32_t database::get_gpos_current_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(); @@ -1244,13 +1255,13 @@ double database::calculate_vesting_factor(const account_object& stake_account) // 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, + // 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 @@ -1399,7 +1410,6 @@ void schedule_pending_dividend_balances(database& db, 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().lower_bound(boost::make_tuple(dividend_holder_asset_obj.id, balance_type)); @@ -1414,22 +1424,6 @@ void schedule_pending_dividend_balances(database& db, ("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(); - 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 && - 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)); - } - } -#endif auto current_distribution_account_balance_iter = current_distribution_account_balance_range.begin(); if(db.head_block_time() < HARDFORK_GPOS_TIME) @@ -1883,7 +1877,6 @@ void process_dividend_assets(database& db) { // if there was a previous payout, make our next payment one interval uint32_t current_time_sec = current_head_block_time.sec_since_epoch(); - fc::time_point_sec reference_time = *dividend_data_obj.last_scheduled_payout_time; uint32_t next_possible_time_sec = dividend_data_obj.last_scheduled_payout_time->sec_since_epoch(); do next_possible_time_sec += *dividend_data_obj.options.payout_interval; @@ -1944,10 +1937,7 @@ void database::perform_son_tasks() a.options.market_fee_percent = 500; // 5% a.options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK; a.options.flags = asset_issuer_permission_flags::charge_market_fee | - //asset_issuer_permission_flags::white_list | - asset_issuer_permission_flags::override_authority | - asset_issuer_permission_flags::transfer_restricted | - asset_issuer_permission_flags::disable_confidential; + asset_issuer_permission_flags::override_authority; a.options.core_exchange_rate.base.amount = 100000; a.options.core_exchange_rate.base.asset_id = asset_id_type(0); a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value @@ -1964,6 +1954,74 @@ void database::perform_son_tasks() gpo.pending_parameters->extensions.value.btc_asset = btc_asset.get_id(); }); } + // create HBD asset here because son_account is the issuer of the HBD + if (gpo.parameters.hbd_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME) + { + const asset_dynamic_data_object& dyn_asset = + create([](asset_dynamic_data_object& a) { + a.current_supply = 0; + }); + + const asset_object& hbd_asset = + create( [&gpo, &dyn_asset]( asset_object& a ) { + a.symbol = "HBD"; + a.precision = 3; + a.issuer = gpo.parameters.son_account(); + a.options.max_supply = GRAPHENE_MAX_SHARE_SUPPLY; + a.options.market_fee_percent = 500; // 5% + a.options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK; + a.options.flags = asset_issuer_permission_flags::charge_market_fee | + asset_issuer_permission_flags::override_authority; + a.options.core_exchange_rate.base.amount = 100000; + a.options.core_exchange_rate.base.asset_id = asset_id_type(0); + a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value + a.options.core_exchange_rate.quote.asset_id = a.id; + a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty + a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set + a.options.whitelist_markets.clear(); // might be traded with + a.options.blacklist_markets.clear(); // might not be traded with + a.dynamic_asset_data_id = dyn_asset.id; + }); + modify( gpo, [&hbd_asset]( global_property_object& gpo ) { + gpo.parameters.extensions.value.hbd_asset = hbd_asset.get_id(); + if( gpo.pending_parameters ) + gpo.pending_parameters->extensions.value.hbd_asset = hbd_asset.get_id(); + }); + } + // create HIVE asset here because son_account is the issuer of the HIVE + if (gpo.parameters.hive_asset() == asset_id_type() && head_block_time() >= HARDFORK_SON_FOR_HIVE_TIME) + { + const asset_dynamic_data_object& dyn_asset = + create([](asset_dynamic_data_object& a) { + a.current_supply = 0; + }); + + const asset_object& hive_asset = + create( [&gpo, &dyn_asset]( asset_object& a ) { + a.symbol = "HIVE"; + a.precision = 3; + a.issuer = gpo.parameters.son_account(); + a.options.max_supply = GRAPHENE_MAX_SHARE_SUPPLY; + a.options.market_fee_percent = 500; // 5% + a.options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK; + a.options.flags = asset_issuer_permission_flags::charge_market_fee | + asset_issuer_permission_flags::override_authority; + a.options.core_exchange_rate.base.amount = 100000; + a.options.core_exchange_rate.base.asset_id = asset_id_type(0); + a.options.core_exchange_rate.quote.amount = 2500; // CoinMarketCap approx value + a.options.core_exchange_rate.quote.asset_id = a.id; + a.options.whitelist_authorities.clear(); // accounts allowed to use asset, if not empty + a.options.blacklist_authorities.clear(); // accounts who can blacklist other accounts to use asset, if white_list flag is set + a.options.whitelist_markets.clear(); // might be traded with + a.options.blacklist_markets.clear(); // might not be traded with + a.dynamic_asset_data_id = dyn_asset.id; + }); + modify( gpo, [&hive_asset]( global_property_object& gpo ) { + gpo.parameters.extensions.value.hive_asset = hive_asset.get_id(); + if( gpo.pending_parameters ) + gpo.pending_parameters->extensions.value.hive_asset = hive_asset.get_id(); + }); + } // Pay the SONs if (head_block_time() >= HARDFORK_SON_TIME) { @@ -2024,7 +2082,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g balance_type = vesting_balance_type::gpos; const vesting_balance_index& vesting_index = d.get_index_type(); -#ifdef USE_VESTING_OBJECT_BY_ASSET_BALANCE_INDEX + auto vesting_balances_begin = vesting_index.indices().get().lower_bound(boost::make_tuple(asset_id_type(), balance_type)); auto vesting_balances_end = @@ -2036,19 +2094,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g ("owner", vesting_balance_obj.owner(d).name) ("amount", vesting_balance_obj.balance.amount)); } -#else - const auto& vesting_balances = vesting_index.indices().get(); - 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 && 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}", - ("owner", vesting_balance_obj.owner(d).name) - ("amount", vesting_balance_obj.balance.amount)); - } - } -#endif + } void operator()( const account_object& stake_account, const account_statistics_object& stats ) @@ -2145,7 +2191,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g } } } tally_helper(*this, gpo); - + perform_account_maintenance( tally_helper ); struct clear_canary { clear_canary(vector& target): target(target){} @@ -2191,7 +2237,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g 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.pending_parameters->extensions.value.gpos_vesting_lockin_period = p.parameters.extensions.value.gpos_vesting_lockin_period; if( !p.pending_parameters->extensions.value.rbac_max_permissions_per_account.valid() ) p.pending_parameters->extensions.value.rbac_max_permissions_per_account = p.parameters.extensions.value.rbac_max_permissions_per_account; if( !p.pending_parameters->extensions.value.rbac_max_account_authority_lifetime.valid() ) @@ -2224,6 +2270,10 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g p.pending_parameters->extensions.value.btc_asset = p.parameters.extensions.value.btc_asset; if( !p.pending_parameters->extensions.value.maximum_son_count.valid() ) p.pending_parameters->extensions.value.maximum_son_count = p.parameters.extensions.value.maximum_son_count; + if( !p.pending_parameters->extensions.value.hbd_asset.valid() ) + p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset; + if( !p.pending_parameters->extensions.value.hive_asset.valid() ) + p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset; p.parameters = std::move(*p.pending_parameters); p.pending_parameters.reset(); } diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index c6380b8c..cbf7f018 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -107,7 +108,6 @@ void database::reindex( fc::path data_dir ) 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, starting at ${next}...", ("next",head_block_num() + 1) ); @@ -123,8 +123,7 @@ void database::reindex( fc::path data_dir ) } 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 << "% "<= head_block_id(), "last block ID does not match current chain state", ("last_block->id", last_block)("head_block_id",head_block_num()) ); + + _block_id_to_block.set_replay_mode(true); + reindex( data_dir ); + + _block_id_to_block.set_replay_mode(false); } _opened = true; } @@ -244,7 +248,7 @@ void database::close(bool rewind) { if (!_opened) return; - + // TODO: Save pending tx's on close() clear_pending(); @@ -294,7 +298,7 @@ void database::force_slow_replays() void database::check_ending_lotteries() { try { - const auto& lotteries_idx = get_index_type().indices().get(); + const auto& lotteries_idx = get_index_type().indices().get(); for( auto checking_asset: lotteries_idx ) { FC_ASSERT( checking_asset.is_lottery() ); @@ -306,6 +310,24 @@ void database::check_ending_lotteries() } catch( ... ) {} } +void database::check_ending_nft_lotteries() +{ + try { + const auto &nft_lotteries_idx = get_index_type().indices().get(); + for (auto checking_token : nft_lotteries_idx) + { + FC_ASSERT(checking_token.is_lottery()); + const auto &lottery_options = checking_token.lottery_data->lottery_options; + FC_ASSERT(lottery_options.is_active); + // Check the current supply of lottery tokens + auto current_supply = checking_token.get_token_current_supply(*this); + if ((lottery_options.ending_on_soldout && (current_supply == checking_token.max_supply)) || + (lottery_options.end_date != time_point_sec() && (lottery_options.end_date <= head_block_time()))) + checking_token.end_lottery(*this); + } + } catch( ... ) {} +} + void database::check_lottery_end_by_participants( asset_id_type asset_id ) { try { diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 06ffdee5..c5986fad 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -24,6 +24,7 @@ #include +#include #include #include #include @@ -41,6 +42,10 @@ #include #include #include +#include +#include +#include +#include using namespace fc; @@ -359,6 +364,13 @@ struct get_impacted_account_visitor void operator()( const account_role_delete_operation& op ){ _impacted.insert( op.owner ); } + void operator()( const nft_lottery_token_purchase_operation& op ){ + _impacted.insert( op.buyer ); + } + void operator()( const nft_lottery_reward_operation& op ) { + _impacted.insert( op.winner ); + } + void operator()( const nft_lottery_end_operation& op ) {} void operator()( const son_create_operation& op ) { _impacted.insert( op.owner_account ); } @@ -416,6 +428,9 @@ struct get_impacted_account_visitor void operator()( const sidechain_transaction_settle_operation& op ) { _impacted.insert( op.payer ); } + void operator()( const random_number_store_operation& op ) { + _impacted.insert( op.account ); + } }; void graphene::chain::operation_get_impacted_accounts( const operation& op, flat_set& result, bool ignore_custom_operation_required_auths ) { @@ -528,6 +543,9 @@ void get_relevant_accounts( const object* obj, flat_set& accoun } case sidechain_transaction_object_type:{ break; } + default: { + break; + } } } else if( obj->id.space() == implementation_ids ) @@ -582,6 +600,10 @@ void get_relevant_accounts( const object* obj, flat_set& accoun break; case impl_fba_accumulator_object_type: break; + case impl_nft_lottery_balance_object_type: + break; + default: + break; } } } // end get_relevant_accounts( const object* obj, flat_set& accounts ) diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index 2e896070..0476982c 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -26,16 +26,18 @@ #include #include +#include +#include #include #include #include +#include #include +#include +#include #include #include #include -#include -#include -#include #include @@ -46,7 +48,6 @@ namespace graphene { namespace chain { void database::update_global_dynamic_data( const signed_block& b, const uint32_t missed_blocks ) { const dynamic_global_property_object& _dgp = get_dynamic_global_properties(); - const global_property_object& gpo = get_global_properties(); // dynamic global properties updating modify( _dgp, [&b,this,missed_blocks]( dynamic_global_property_object& dgp ){ diff --git a/libraries/chain/hardfork.d/1000.hf b/libraries/chain/hardfork.d/1000.hf index 2ce5237d..dea29c0f 100644 --- a/libraries/chain/hardfork.d/1000.hf +++ b/libraries/chain/hardfork.d/1000.hf @@ -1,3 +1,7 @@ #ifndef HARDFORK_1000_TIME -#define HARDFORK_1000_TIME (fc::time_point_sec( 1550491200 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_1000_TIME (fc::time_point_sec::from_iso_string("2018-10-20T01:46:40")) +#else +#define HARDFORK_1000_TIME (fc::time_point_sec::from_iso_string("2019-02-18T12:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/1001.hf b/libraries/chain/hardfork.d/1001.hf index 78b838cc..ec77eb0c 100644 --- a/libraries/chain/hardfork.d/1001.hf +++ b/libraries/chain/hardfork.d/1001.hf @@ -1,4 +1,8 @@ // added delete sport and delete event group operations #ifndef HARDFORK_1001_TIME -#define HARDFORK_1001_TIME (fc::time_point_sec( 1550491200 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_1001_TIME (fc::time_point_sec::from_iso_string("2018-10-20T01:46:40")) +#else +#define HARDFORK_1001_TIME (fc::time_point_sec::from_iso_string("2019-02-18T12:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/357.hf b/libraries/chain/hardfork.d/357.hf index 650b9a7a..35e3685c 100644 --- a/libraries/chain/hardfork.d/357.hf +++ b/libraries/chain/hardfork.d/357.hf @@ -1,4 +1,8 @@ // #357 Disallow publishing certain malformed price feeds #ifndef HARDFORK_357_TIME -#define HARDFORK_357_TIME (fc::time_point_sec( 1444416300 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_357_TIME (fc::time_point_sec::from_iso_string("2015-10-09T18:45:00")) +#else +#define HARDFORK_357_TIME (fc::time_point_sec::from_iso_string("2015-10-09T18:45:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/359.hf b/libraries/chain/hardfork.d/359.hf index c52576d0..6d81be15 100644 --- a/libraries/chain/hardfork.d/359.hf +++ b/libraries/chain/hardfork.d/359.hf @@ -1,4 +1,8 @@ // #359 Allow digits in asset name #ifndef HARDFORK_359_TIME -#define HARDFORK_359_TIME (fc::time_point_sec( 1444416300 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_359_TIME (fc::time_point_sec::from_iso_string("2015-10-09T18:45:00")) +#else +#define HARDFORK_359_TIME (fc::time_point_sec::from_iso_string("2015-10-09T18:45:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/385.hf b/libraries/chain/hardfork.d/385.hf index 43f8ead0..b6e04ce1 100644 --- a/libraries/chain/hardfork.d/385.hf +++ b/libraries/chain/hardfork.d/385.hf @@ -1,4 +1,8 @@ // #385 October 23 enforce PARENT.CHILD and allow short names #ifndef HARDFORK_385_TIME -#define HARDFORK_385_TIME (fc::time_point_sec( 1445558400 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_385_TIME (fc::time_point_sec::from_iso_string("2015-10-23T00:00:00")) +#else +#define HARDFORK_385_TIME (fc::time_point_sec::from_iso_string("2015-10-23T00:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/409.hf b/libraries/chain/hardfork.d/409.hf index 87629140..cef2369c 100644 --- a/libraries/chain/hardfork.d/409.hf +++ b/libraries/chain/hardfork.d/409.hf @@ -1,4 +1,8 @@ // #409 Allow creation of sub-assets #ifndef HARDFORK_409_TIME -#define HARDFORK_409_TIME (fc::time_point_sec( 1446652800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_409_TIME (fc::time_point_sec::from_iso_string("2015-11-04T16:00:00")) +#else +#define HARDFORK_409_TIME (fc::time_point_sec::from_iso_string("2015-11-04T16:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/413.hf b/libraries/chain/hardfork.d/413.hf index c0ce3690..b1a0b8b7 100644 --- a/libraries/chain/hardfork.d/413.hf +++ b/libraries/chain/hardfork.d/413.hf @@ -1,4 +1,8 @@ // #413 Add operation to claim asset fees #ifndef HARDFORK_413_TIME -#define HARDFORK_413_TIME (fc::time_point_sec( 1446652800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_413_TIME (fc::time_point_sec::from_iso_string("2015-11-04T16:00:00")) +#else +#define HARDFORK_413_TIME (fc::time_point_sec::from_iso_string("2015-11-04T16:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/415.hf b/libraries/chain/hardfork.d/415.hf index 94645270..d0a144c6 100644 --- a/libraries/chain/hardfork.d/415.hf +++ b/libraries/chain/hardfork.d/415.hf @@ -1,4 +1,8 @@ // #415 Default accept policy for asset with no whitelist authorities #ifndef HARDFORK_415_TIME -#define HARDFORK_415_TIME (fc::time_point_sec( 1446652800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_415_TIME (fc::time_point_sec::from_iso_string("2015-11-04T16:00:00")) +#else +#define HARDFORK_415_TIME (fc::time_point_sec::from_iso_string("2015-11-04T16:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/416.hf b/libraries/chain/hardfork.d/416.hf index 2c3319d1..677aede2 100644 --- a/libraries/chain/hardfork.d/416.hf +++ b/libraries/chain/hardfork.d/416.hf @@ -1,4 +1,8 @@ // #416 enforce_white_list is inconsistently applied #ifndef HARDFORK_416_TIME -#define HARDFORK_416_TIME (fc::time_point_sec( 1446652800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_416_TIME (fc::time_point_sec::from_iso_string("2015-11-04T16:00:00")) +#else +#define HARDFORK_416_TIME (fc::time_point_sec::from_iso_string("2015-11-04T16:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/419.hf b/libraries/chain/hardfork.d/419.hf index c5bbf68d..db97a0bd 100644 --- a/libraries/chain/hardfork.d/419.hf +++ b/libraries/chain/hardfork.d/419.hf @@ -1,4 +1,8 @@ // #419 Account can pay fees in blacklisted asset #ifndef HARDFORK_419_TIME -#define HARDFORK_419_TIME (fc::time_point_sec( 1446652800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_419_TIME (fc::time_point_sec::from_iso_string("2015-11-04T16:00:00")) +#else +#define HARDFORK_419_TIME (fc::time_point_sec::from_iso_string("2015-11-04T16:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/436.hf b/libraries/chain/hardfork.d/436.hf index 1c030eb6..cd4681b5 100644 --- a/libraries/chain/hardfork.d/436.hf +++ b/libraries/chain/hardfork.d/436.hf @@ -1,4 +1,8 @@ // #436 Prevent margin call from being triggered unless feed < call price #ifndef HARDFORK_436_TIME -#define HARDFORK_436_TIME (fc::time_point_sec( 1450288800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_436_TIME (fc::time_point_sec::from_iso_string("2015-12-16T18:00:00")) +#else +#define HARDFORK_436_TIME (fc::time_point_sec::from_iso_string("2015-12-16T18:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/445.hf b/libraries/chain/hardfork.d/445.hf index 30178b7a..1f33cad6 100644 --- a/libraries/chain/hardfork.d/445.hf +++ b/libraries/chain/hardfork.d/445.hf @@ -1,4 +1,8 @@ // #445 Refund create order fees on cancel #ifndef HARDFORK_445_TIME -#define HARDFORK_445_TIME (fc::time_point_sec( 1450288800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_445_TIME (fc::time_point_sec::from_iso_string("2015-12-16T18:00:00")) +#else +#define HARDFORK_445_TIME (fc::time_point_sec::from_iso_string("2015-12-16T18:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/453.hf b/libraries/chain/hardfork.d/453.hf index 6b5226c8..784903b7 100644 --- a/libraries/chain/hardfork.d/453.hf +++ b/libraries/chain/hardfork.d/453.hf @@ -1,4 +1,8 @@ // #453 Hardfork to retroactively correct referral percentages #ifndef HARDFORK_453_TIME -#define HARDFORK_453_TIME (fc::time_point_sec( 1450288800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_453_TIME (fc::time_point_sec::from_iso_string("2015-12-16T18:00:00")) +#else +#define HARDFORK_453_TIME (fc::time_point_sec::from_iso_string("2015-12-16T18:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/480.hf b/libraries/chain/hardfork.d/480.hf index a8283ba7..a996160e 100644 --- a/libraries/chain/hardfork.d/480.hf +++ b/libraries/chain/hardfork.d/480.hf @@ -1,4 +1,8 @@ // #480 Fix non-BTS MIA core_exchange_rate check #ifndef HARDFORK_480_TIME -#define HARDFORK_480_TIME (fc::time_point_sec( 1450378800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_480_TIME (fc::time_point_sec::from_iso_string("2015-12-17T19:00:00")) +#else +#define HARDFORK_480_TIME (fc::time_point_sec::from_iso_string("2015-12-17T19:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/483.hf b/libraries/chain/hardfork.d/483.hf index f242a74f..9ce88228 100644 --- a/libraries/chain/hardfork.d/483.hf +++ b/libraries/chain/hardfork.d/483.hf @@ -1,4 +1,8 @@ // #483 Operation history numbering change #ifndef HARDFORK_483_TIME -#define HARDFORK_483_TIME (fc::time_point_sec( 1450378800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_483_TIME (fc::time_point_sec::from_iso_string("2015-12-17T19:00:00")) +#else +#define HARDFORK_483_TIME (fc::time_point_sec::from_iso_string("2015-12-17T19:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/5050-1.hf b/libraries/chain/hardfork.d/5050-1.hf index 51c12732..d700b7a0 100644 --- a/libraries/chain/hardfork.d/5050-1.hf +++ b/libraries/chain/hardfork.d/5050-1.hf @@ -1,4 +1,7 @@ -// 5050_1 HARDFORK Thursday, 22 April 2020 20:00:00 GMT #ifndef HARDFORK_5050_1_TIME -#define HARDFORK_5050_1_TIME (fc::time_point_sec( 1587585600 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_5050_1_TIME (fc::time_point_sec::from_iso_string("2020-04-15T20:00:00")) +#else +#define HARDFORK_5050_1_TIME (fc::time_point_sec::from_iso_string("2020-04-22T20:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/516.hf b/libraries/chain/hardfork.d/516.hf index 80859724..04dac79f 100644 --- a/libraries/chain/hardfork.d/516.hf +++ b/libraries/chain/hardfork.d/516.hf @@ -1,4 +1,8 @@ // #516 Special authorities #ifndef HARDFORK_516_TIME -#define HARDFORK_516_TIME (fc::time_point_sec( 1456250400 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_516_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#else +#define HARDFORK_516_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/533.hf b/libraries/chain/hardfork.d/533.hf index 32d8ede8..f1ab1403 100644 --- a/libraries/chain/hardfork.d/533.hf +++ b/libraries/chain/hardfork.d/533.hf @@ -1,4 +1,8 @@ // #533 Improve vote counting implementation #ifndef HARDFORK_533_TIME -#define HARDFORK_533_TIME (fc::time_point_sec( 1456250400 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_533_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#else +#define HARDFORK_533_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/538.hf b/libraries/chain/hardfork.d/538.hf index 99a27537..67232a61 100644 --- a/libraries/chain/hardfork.d/538.hf +++ b/libraries/chain/hardfork.d/538.hf @@ -1,4 +1,8 @@ // #538 Buyback accounts #ifndef HARDFORK_538_TIME -#define HARDFORK_538_TIME (fc::time_point_sec( 1456250400 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_538_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#else +#define HARDFORK_538_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/555.hf b/libraries/chain/hardfork.d/555.hf index 45ef0473..822f6265 100644 --- a/libraries/chain/hardfork.d/555.hf +++ b/libraries/chain/hardfork.d/555.hf @@ -1,4 +1,8 @@ // #555 Buyback accounts #ifndef HARDFORK_555_TIME -#define HARDFORK_555_TIME (fc::time_point_sec( 1456250400 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_555_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#else +#define HARDFORK_555_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/563.hf b/libraries/chain/hardfork.d/563.hf index 001563ca..2ccdec02 100644 --- a/libraries/chain/hardfork.d/563.hf +++ b/libraries/chain/hardfork.d/563.hf @@ -1,4 +1,8 @@ // #563 Stealth fee routing #ifndef HARDFORK_563_TIME -#define HARDFORK_563_TIME (fc::time_point_sec( 1456250400 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_563_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#else +#define HARDFORK_563_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/572.hf b/libraries/chain/hardfork.d/572.hf index a466ef72..68f517ae 100644 --- a/libraries/chain/hardfork.d/572.hf +++ b/libraries/chain/hardfork.d/572.hf @@ -1,4 +1,8 @@ // #572 Allow asset to update permission flags when no supply exists #ifndef HARDFORK_572_TIME -#define HARDFORK_572_TIME (fc::time_point_sec( 1456250400 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_572_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#else +#define HARDFORK_572_TIME (fc::time_point_sec::from_iso_string("2016-02-23T18:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/599.hf b/libraries/chain/hardfork.d/599.hf index 6249101d..74503b01 100644 --- a/libraries/chain/hardfork.d/599.hf +++ b/libraries/chain/hardfork.d/599.hf @@ -1,4 +1,8 @@ // #599 Unpacking of extension is incorrect #ifndef HARDFORK_599_TIME -#define HARDFORK_599_TIME (fc::time_point_sec( 1459789200 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_599_TIME (fc::time_point_sec::from_iso_string("2016-04-04T17:00:00")) +#else +#define HARDFORK_599_TIME (fc::time_point_sec::from_iso_string("2016-04-04T17:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/607.hf b/libraries/chain/hardfork.d/607.hf index 77c8c9e0..a6dc7584 100644 --- a/libraries/chain/hardfork.d/607.hf +++ b/libraries/chain/hardfork.d/607.hf @@ -1,4 +1,8 @@ // #607 Disable negative voting on workers #ifndef HARDFORK_607_TIME -#define HARDFORK_607_TIME (fc::time_point_sec( 1458752400 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_607_TIME (fc::time_point_sec::from_iso_string("2016-03-23T17:00:00")) +#else +#define HARDFORK_607_TIME (fc::time_point_sec::from_iso_string("2016-03-23T17:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/613.hf b/libraries/chain/hardfork.d/613.hf index 9978d33c..67d9a304 100644 --- a/libraries/chain/hardfork.d/613.hf +++ b/libraries/chain/hardfork.d/613.hf @@ -1,4 +1,8 @@ // #613 Deprecate annual membership #ifndef HARDFORK_613_TIME -#define HARDFORK_613_TIME (fc::time_point_sec( 1458752400 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_613_TIME (fc::time_point_sec::from_iso_string("2016-03-23T17:00:00")) +#else +#define HARDFORK_613_TIME (fc::time_point_sec::from_iso_string("2016-03-23T17:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/615.hf b/libraries/chain/hardfork.d/615.hf index ac0535dc..19bdb7e1 100644 --- a/libraries/chain/hardfork.d/615.hf +++ b/libraries/chain/hardfork.d/615.hf @@ -1,4 +1,8 @@ // #615 Fix price feed expiration check, so websocket server will never spam too much data #ifndef HARDFORK_615_TIME -#define HARDFORK_615_TIME (fc::time_point_sec( 1458752400 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_615_TIME (fc::time_point_sec::from_iso_string("2016-03-23T17:00:00")) +#else +#define HARDFORK_615_TIME (fc::time_point_sec::from_iso_string("2016-03-23T17:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/999.hf b/libraries/chain/hardfork.d/999.hf index ed8d2e98..ba004e47 100644 --- a/libraries/chain/hardfork.d/999.hf +++ b/libraries/chain/hardfork.d/999.hf @@ -1,4 +1,8 @@ // Placeholder HF for affiliate reward system #ifndef HARDFORK_999_TIME -#define HARDFORK_999_TIME (fc::time_point_sec( 1550491200 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_999_TIME (fc::time_point_sec::from_iso_string("2018-10-20T01:46:40")) +#else +#define HARDFORK_999_TIME (fc::time_point_sec::from_iso_string("2019-02-18T12:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/CORE-429.hf b/libraries/chain/hardfork.d/CORE-429.hf index fb12b85a..504e0fd8 100644 --- a/libraries/chain/hardfork.d/CORE-429.hf +++ b/libraries/chain/hardfork.d/CORE-429.hf @@ -1,4 +1,8 @@ // bitshares-core #429 rounding issue when creating assets #ifndef HARDFORK_CORE_429_TIME -#define HARDFORK_CORE_429_TIME (fc::time_point_sec( 1568340000 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_CORE_429_TIME (fc::time_point_sec::from_iso_string("2019-08-26T02:00:00")) +#else +#define HARDFORK_CORE_429_TIME (fc::time_point_sec::from_iso_string("2019-09-13T02:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/CORE_210.hf b/libraries/chain/hardfork.d/CORE_210.hf index 0f285274..cf3bdade 100644 --- a/libraries/chain/hardfork.d/CORE_210.hf +++ b/libraries/chain/hardfork.d/CORE_210.hf @@ -1,6 +1,10 @@ // #210 Check authorities on custom_operation #ifndef HARDFORK_CORE_210_TIME -#define HARDFORK_CORE_210_TIME (fc::time_point_sec(1893456000)) // Jan 1 00:00:00 2030 (Not yet scheduled) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_CORE_210_TIME (fc::time_point_sec::from_iso_string("2030-01-01T00:00:00")) // (Not yet scheduled) +#else +#define HARDFORK_CORE_210_TIME (fc::time_point_sec::from_iso_string("2030-01-01T00:00:00")) // (Not yet scheduled) +#endif // Bugfix: pre-HF 210, custom_operation's required_auths field was ignored. #define MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time) (chain_time <= HARDFORK_CORE_210_TIME) #endif diff --git a/libraries/chain/hardfork.d/GPOS.hf b/libraries/chain/hardfork.d/GPOS.hf index 1cf9c75c..b8461145 100644 --- a/libraries/chain/hardfork.d/GPOS.hf +++ b/libraries/chain/hardfork.d/GPOS.hf @@ -1,4 +1,7 @@ -// GPOS HARDFORK Monday, 17 February 2020 22:00:00 GMT #ifndef HARDFORK_GPOS_TIME -#define HARDFORK_GPOS_TIME (fc::time_point_sec( 1581976800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_GPOS_TIME (fc::time_point_sec::from_iso_string("2020-01-06T01:00:00")) +#else +#define HARDFORK_GPOS_TIME (fc::time_point_sec::from_iso_string("2020-02-17T22:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/NFT.hf b/libraries/chain/hardfork.d/NFT.hf index 0a540a33..76e6ffb7 100644 --- a/libraries/chain/hardfork.d/NFT.hf +++ b/libraries/chain/hardfork.d/NFT.hf @@ -1,4 +1,7 @@ -// GPOS HARDFORK 2020-12-21 00:00:00 GMT #ifndef HARDFORK_NFT_TIME -#define HARDFORK_NFT_TIME (fc::time_point_sec( 1608508800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_NFT_TIME (fc::time_point_sec::from_iso_string("2020-08-15T00:00:00")) +#else +#define HARDFORK_NFT_TIME (fc::time_point_sec::from_iso_string("2020-12-21T00:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/SON.hf b/libraries/chain/hardfork.d/SON.hf index ee75fbe8..12922d1a 100644 --- a/libraries/chain/hardfork.d/SON.hf +++ b/libraries/chain/hardfork.d/SON.hf @@ -1,4 +1,7 @@ -// GPOS HARDFORK 2020-12-21 00:00:00 GMT #ifndef HARDFORK_SON_TIME -#define HARDFORK_SON_TIME (fc::time_point_sec( 1608508800 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_SON_TIME (fc::time_point_sec::from_iso_string("2020-10-28T00:00:00")) +#else +#define HARDFORK_SON_TIME (fc::time_point_sec::from_iso_string("2020-12-21T00:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/SON2.hf b/libraries/chain/hardfork.d/SON2.hf index bc8fde45..a778d14d 100644 --- a/libraries/chain/hardfork.d/SON2.hf +++ b/libraries/chain/hardfork.d/SON2.hf @@ -1,4 +1,7 @@ -// SON2 HARDFORK Saturday, July 31, 2021 00:00:00 GMT #ifndef HARDFORK_SON2_TIME -#define HARDFORK_SON2_TIME (fc::time_point_sec( 1627689600 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_SON2_TIME (fc::time_point_sec::from_iso_string("2021-07-31T00:00:00")) +#else +#define HARDFORK_SON2_TIME (fc::time_point_sec::from_iso_string("2021-07-31T00:00:00")) +#endif #endif diff --git a/libraries/chain/hardfork.d/SON_FOR_HIVE.hf b/libraries/chain/hardfork.d/SON_FOR_HIVE.hf new file mode 100644 index 00000000..217e999e --- /dev/null +++ b/libraries/chain/hardfork.d/SON_FOR_HIVE.hf @@ -0,0 +1,7 @@ +#ifndef HARDFORK_SON_FOR_HIVE_TIME +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_SON_FOR_HIVE_TIME (fc::time_point_sec::from_iso_string("2021-03-31T00:00:00")) +#else +#define HARDFORK_SON_FOR_HIVE_TIME (fc::time_point_sec::from_iso_string("2021-12-21T00:00:00")) +#endif +#endif diff --git a/libraries/chain/hardfork.d/SWEEPS.hf b/libraries/chain/hardfork.d/SWEEPS.hf index 08dca361..f58a93cd 100644 --- a/libraries/chain/hardfork.d/SWEEPS.hf +++ b/libraries/chain/hardfork.d/SWEEPS.hf @@ -1,3 +1,7 @@ #ifndef HARDFORK_SWEEPS_TIME -#define HARDFORK_SWEEPS_TIME (fc::time_point_sec( 1568340000 )) +#ifdef BUILD_PEERPLAYS_TESTNET +#define HARDFORK_SWEEPS_TIME (fc::time_point_sec::from_iso_string("2019-08-26T02:00:00")) +#else +#define HARDFORK_SWEEPS_TIME (fc::time_point_sec::from_iso_string("2019-09-13T02:00:00")) +#endif #endif diff --git a/libraries/chain/include/graphene/chain/account_role_object.hpp b/libraries/chain/include/graphene/chain/account_role_object.hpp index 2b3be409..ccdfc9bc 100644 --- a/libraries/chain/include/graphene/chain/account_role_object.hpp +++ b/libraries/chain/include/graphene/chain/account_role_object.hpp @@ -46,4 +46,4 @@ namespace graphene } // namespace graphene FC_REFLECT_DERIVED(graphene::chain::account_role_object, (graphene::db::object), - (owner)(name)(metadata)(allowed_operations)(whitelisted_accounts)(valid_to)) \ No newline at end of file + (owner)(name)(metadata)(allowed_operations)(whitelisted_accounts)(valid_to)) diff --git a/libraries/chain/include/graphene/chain/block_database.hpp b/libraries/chain/include/graphene/chain/block_database.hpp index c5cf5df9..5a1df1a1 100644 --- a/libraries/chain/include/graphene/chain/block_database.hpp +++ b/libraries/chain/include/graphene/chain/block_database.hpp @@ -47,7 +47,11 @@ namespace graphene { namespace chain { optional fetch_by_number( uint32_t block_num )const; optional last()const; optional last_id()const; + + void set_replay_mode(bool mode); private: + bool replay_mode = false; + optional last_index_entry()const; fc::path _index_filename; mutable std::fstream _blocks; diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index f3048608..ef9a0c80 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -23,8 +23,13 @@ */ #pragma once +#ifdef BUILD_PEERPLAYS_TESTNET +#define GRAPHENE_SYMBOL "TEST" +#define GRAPHENE_ADDRESS_PREFIX "TEST" +#else #define GRAPHENE_SYMBOL "PPY" #define GRAPHENE_ADDRESS_PREFIX "PPY" +#endif #define GRAPHENE_MIN_ACCOUNT_NAME_LENGTH 1 #define GRAPHENE_MAX_ACCOUNT_NAME_LENGTH 63 diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 8c467ac0..50975174 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -286,6 +286,7 @@ namespace graphene { namespace chain { void check_lottery_end_by_participants( asset_id_type asset_id ); void check_ending_lotteries(); + void check_ending_nft_lotteries(); //////////////////// db_getter.cpp //////////////////// @@ -325,6 +326,7 @@ namespace graphene { namespace chain { uint32_t last_non_undoable_block_num() const; vector get_account_custom_authorities(account_id_type account, const operation& op)const; + vector get_random_numbers(uint64_t minimum, uint64_t maximum, uint64_t selections, bool duplicates); //////////////////// db_init.cpp //////////////////// void initialize_evaluators(); diff --git a/libraries/chain/include/graphene/chain/global_betting_statistics_object.hpp b/libraries/chain/include/graphene/chain/global_betting_statistics_object.hpp index 7c557be5..6ded103a 100644 --- a/libraries/chain/include/graphene/chain/global_betting_statistics_object.hpp +++ b/libraries/chain/include/graphene/chain/global_betting_statistics_object.hpp @@ -37,7 +37,7 @@ class global_betting_statistics_object : public graphene::db::abstract_object< g static const uint8_t space_id = implementation_ids; static const uint8_t type_id = impl_global_betting_statistics_object_type; - uint32_t number_of_active_events; + uint32_t number_of_active_events = 0; map total_amount_staked; }; diff --git a/libraries/chain/include/graphene/chain/impacted.hpp b/libraries/chain/include/graphene/chain/impacted.hpp index fae276f7..3e070ce6 100644 --- a/libraries/chain/include/graphene/chain/impacted.hpp +++ b/libraries/chain/include/graphene/chain/impacted.hpp @@ -38,4 +38,4 @@ void transaction_get_impacted_accounts( const graphene::chain::transaction& tx, fc::flat_set& result, bool ignore_custom_operation_required_auths ); -} } // graphene::app \ No newline at end of file +} } // graphene::app diff --git a/libraries/chain/include/graphene/chain/nft_lottery_evaluator.hpp b/libraries/chain/include/graphene/chain/nft_lottery_evaluator.hpp new file mode 100644 index 00000000..0839cbbd --- /dev/null +++ b/libraries/chain/include/graphene/chain/nft_lottery_evaluator.hpp @@ -0,0 +1,39 @@ +#pragma once +#include +#include +#include + +namespace graphene +{ + namespace chain + { + + class nft_lottery_token_purchase_evaluator : public evaluator + { + public: + typedef nft_lottery_token_purchase_operation operation_type; + + void_result do_evaluate(const nft_lottery_token_purchase_operation &o); + object_id_type do_apply(const nft_lottery_token_purchase_operation &o); + }; + + class nft_lottery_reward_evaluator : public evaluator + { + public: + typedef nft_lottery_reward_operation operation_type; + + void_result do_evaluate(const nft_lottery_reward_operation &o); + void_result do_apply(const nft_lottery_reward_operation &o); + }; + + class nft_lottery_end_evaluator : public evaluator + { + public: + typedef nft_lottery_end_operation operation_type; + + void_result do_evaluate(const nft_lottery_end_operation &o); + void_result do_apply(const nft_lottery_end_operation &o); + }; + + } // namespace chain +} // namespace graphene diff --git a/libraries/chain/include/graphene/chain/nft_object.hpp b/libraries/chain/include/graphene/chain/nft_object.hpp index 6a150852..fe026da5 100644 --- a/libraries/chain/include/graphene/chain/nft_object.hpp +++ b/libraries/chain/include/graphene/chain/nft_object.hpp @@ -6,6 +6,29 @@ namespace graphene { namespace chain { using namespace graphene::db; + class nft_lottery_balance_object : public abstract_object + { + public: + static const uint8_t space_id = implementation_ids; + static const uint8_t type_id = impl_nft_lottery_balance_object_type; + + // Total Progressive jackpot carried over from previous lotteries + asset total_progressive_jackpot; + // Current total jackpot in this lottery inclusive of the progressive jackpot + asset jackpot; + // Total tickets sold + share_type sweeps_tickets_sold; + }; + + struct nft_lottery_data + { + nft_lottery_data() {} + nft_lottery_data(const nft_lottery_options &options, nft_lottery_balance_id_type lottery_id) + : lottery_options(options), lottery_balance_id(lottery_id) {} + nft_lottery_options lottery_options; + nft_lottery_balance_id_type lottery_balance_id; + }; + class nft_metadata_object : public abstract_object { public: @@ -21,6 +44,21 @@ namespace graphene { namespace chain { bool is_transferable = false; bool is_sellable = true; optional account_role; + share_type max_supply = GRAPHENE_MAX_SHARE_SUPPLY; + optional lottery_data; + + nft_metadata_id_type get_id() const { return id; } + bool is_lottery() const { return lottery_data.valid(); } + uint32_t get_owner_num() const { return owner.instance.value; } + time_point_sec get_lottery_expiration() const; + asset get_lottery_jackpot(const database &db) const; + share_type get_token_current_supply(const database &db) const; + vector get_holders(const database &db) const; + vector get_ticket_ids(const database &db) const; + void distribute_benefactors_part(database &db); + map> distribute_winners_part(database &db); + void distribute_sweeps_holders_part(database &db); + void end_lottery(database &db); }; class nft_object : public abstract_object @@ -36,8 +74,23 @@ namespace graphene { namespace chain { std::string token_uri; }; + struct nft_lottery_comparer + { + bool operator()(const nft_metadata_object& lhs, const nft_metadata_object& rhs) const + { + if ( !lhs.is_lottery() ) return false; + if ( !lhs.lottery_data->lottery_options.is_active && !rhs.is_lottery()) return true; // not active lotteries first, just assets then + if ( !lhs.lottery_data->lottery_options.is_active ) return false; + if ( lhs.lottery_data->lottery_options.is_active && ( !rhs.is_lottery() || !rhs.lottery_data->lottery_options.is_active ) ) return true; + return lhs.get_lottery_expiration() > rhs.get_lottery_expiration(); + } + }; + struct by_name; struct by_symbol; + struct active_nft_lotteries; + struct by_nft_lottery; + struct by_nft_lottery_owner; using nft_metadata_multi_index_type = multi_index_container< nft_metadata_object, indexed_by< @@ -49,6 +102,34 @@ namespace graphene { namespace chain { >, ordered_unique< tag, member + >, + ordered_non_unique< tag, + identity< nft_metadata_object >, + nft_lottery_comparer + >, + ordered_unique< tag, + composite_key< + nft_metadata_object, + const_mem_fun, + member + >, + composite_key_compare< + std::greater< bool >, + std::greater< object_id_type > + > + >, + ordered_unique< tag, + composite_key< + nft_metadata_object, + const_mem_fun, + const_mem_fun, + member + >, + composite_key_compare< + std::greater< bool >, + std::greater< uint32_t >, + std::greater< object_id_type > + > > > >; @@ -86,8 +167,23 @@ namespace graphene { namespace chain { >; using nft_index = generic_index; + using nft_lottery_balance_index_type = multi_index_container< + nft_lottery_balance_object, + indexed_by< + ordered_unique< tag, member< object, object_id_type, &object::id > > + > + >; + using nft_lottery_balance_index = generic_index; + } } // graphene::chain +FC_REFLECT_DERIVED( graphene::chain::nft_lottery_balance_object, (graphene::db::object), + (total_progressive_jackpot) + (jackpot) + (sweeps_tickets_sold) ) + +FC_REFLECT( graphene::chain::nft_lottery_data, (lottery_options)(lottery_balance_id) ) + FC_REFLECT_DERIVED( graphene::chain::nft_metadata_object, (graphene::db::object), (owner) (name) @@ -97,7 +193,9 @@ FC_REFLECT_DERIVED( graphene::chain::nft_metadata_object, (graphene::db::object) (revenue_split) (is_transferable) (is_sellable) - (account_role) ) + (account_role) + (max_supply) + (lottery_data) ) FC_REFLECT_DERIVED( graphene::chain::nft_object, (graphene::db::object), (nft_metadata_id) diff --git a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp index c24a0576..3a11e99f 100644 --- a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp +++ b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp @@ -68,6 +68,8 @@ namespace graphene { namespace chain { optional < account_id_type > son_account = GRAPHENE_NULL_ACCOUNT; optional < asset_id_type > btc_asset = asset_id_type(); optional < uint16_t > maximum_son_count = GRAPHENE_DEFAULT_MAX_SONS; ///< maximum number of active SONS + optional < asset_id_type > hbd_asset = asset_id_type(); + optional < asset_id_type > hive_asset = asset_id_type(); }; struct chain_parameters @@ -212,6 +214,12 @@ namespace graphene { namespace chain { inline uint16_t maximum_son_count()const { return extensions.value.maximum_son_count.valid() ? *extensions.value.maximum_son_count : GRAPHENE_DEFAULT_MAX_SONS; } + inline asset_id_type hbd_asset() const { + return extensions.value.hbd_asset.valid() ? *extensions.value.hbd_asset : asset_id_type(); + } + inline asset_id_type hive_asset() const { + return extensions.value.hive_asset.valid() ? *extensions.value.hive_asset : asset_id_type(); + } private: static void safe_copy(chain_parameters& to, const chain_parameters& from); }; @@ -247,6 +255,8 @@ FC_REFLECT( graphene::chain::parameter_extension, (son_account) (btc_asset) (maximum_son_count) + (hbd_asset) + (hive_asset) ) FC_REFLECT( graphene::chain::chain_parameters, diff --git a/libraries/chain/include/graphene/chain/protocol/nft_lottery.hpp b/libraries/chain/include/graphene/chain/protocol/nft_lottery.hpp new file mode 100644 index 00000000..0c8ea855 --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/nft_lottery.hpp @@ -0,0 +1,86 @@ +#pragma once +#include +#include + +namespace graphene +{ + namespace chain + { + struct nft_lottery_token_purchase_operation : public base_operation + { + struct fee_parameters_type + { + uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; + }; + asset fee; + // Lottery NFT Metadata + nft_metadata_id_type lottery_id; + // Buyer purchasing lottery tickets + account_id_type buyer; + // count of tickets to buy + uint64_t tickets_to_buy; + // amount that can spent + asset amount; + + extensions_type extensions; + + account_id_type fee_payer() const { return buyer; } + void validate() const; + share_type calculate_fee(const fee_parameters_type &k) const; + }; + + struct nft_lottery_reward_operation : public base_operation + { + struct fee_parameters_type + { + uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; + }; + + asset fee; + // Lottery NFT Metadata + nft_metadata_id_type lottery_id; + // winner account + account_id_type winner; + // amount that won + asset amount; + // percentage of jackpot that user won + uint16_t win_percentage; + // true if recieved from benefators section of lottery; false otherwise + bool is_benefactor_reward; + + uint64_t winner_ticket_id; + + extensions_type extensions; + + account_id_type fee_payer() const { return account_id_type(); } + void validate() const {}; + share_type calculate_fee(const fee_parameters_type &k) const { return k.fee; }; + }; + + struct nft_lottery_end_operation : public base_operation + { + struct fee_parameters_type + { + uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; + }; + + asset fee; + // Lottery NFT Metadata + nft_metadata_id_type lottery_id; + + extensions_type extensions; + + account_id_type fee_payer() const { return account_id_type(); } + void validate() const {} + share_type calculate_fee(const fee_parameters_type &k) const { return k.fee; } + }; + + } // namespace chain +} // namespace graphene + +FC_REFLECT(graphene::chain::nft_lottery_token_purchase_operation::fee_parameters_type, (fee)) +FC_REFLECT(graphene::chain::nft_lottery_reward_operation::fee_parameters_type, (fee)) +FC_REFLECT(graphene::chain::nft_lottery_end_operation::fee_parameters_type, (fee)) +FC_REFLECT(graphene::chain::nft_lottery_token_purchase_operation, (fee)(lottery_id)(buyer)(tickets_to_buy)(amount)(extensions)) +FC_REFLECT(graphene::chain::nft_lottery_reward_operation, (fee)(lottery_id)(winner)(amount)(win_percentage)(is_benefactor_reward)(winner_ticket_id)(extensions)) +FC_REFLECT(graphene::chain::nft_lottery_end_operation, (fee)(lottery_id)(extensions)) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/protocol/nft_ops.hpp b/libraries/chain/include/graphene/chain/protocol/nft_ops.hpp index 4facf51a..1802623f 100644 --- a/libraries/chain/include/graphene/chain/protocol/nft_ops.hpp +++ b/libraries/chain/include/graphene/chain/protocol/nft_ops.hpp @@ -4,6 +4,29 @@ namespace graphene { namespace chain { + struct nft_lottery_benefactor { + account_id_type id; + uint16_t share; // percent * GRAPHENE_1_PERCENT + nft_lottery_benefactor() = default; + nft_lottery_benefactor( const nft_lottery_benefactor & ) = default; + nft_lottery_benefactor( account_id_type _id, uint16_t _share ) : id( _id ), share( _share ) {} + }; + + struct nft_lottery_options + { + std::vector benefactors; + // specifying winning tickets as shares that will be issued + std::vector winning_tickets; + asset ticket_price; + time_point_sec end_date; + bool ending_on_soldout; + bool is_active; + bool delete_tickets_after_draw = false; + std::vector progressive_jackpots; + + void validate() const; + }; + struct nft_metadata_create_operation : public base_operation { struct fee_parameters_type @@ -23,6 +46,10 @@ namespace graphene { namespace chain { bool is_sellable = true; // Accounts Role optional account_role; + // Max number of NFTs that can be minted from the metadata + optional max_supply; + // Lottery configuration + optional lottery_options; extensions_type extensions; account_id_type fee_payer()const { return owner; } @@ -133,6 +160,9 @@ namespace graphene { namespace chain { } } // graphene::chain +FC_REFLECT( graphene::chain::nft_lottery_benefactor, (id)(share) ) +FC_REFLECT( graphene::chain::nft_lottery_options, (benefactors)(winning_tickets)(ticket_price)(end_date)(ending_on_soldout)(is_active)(delete_tickets_after_draw)(progressive_jackpots) ) + FC_REFLECT( graphene::chain::nft_metadata_create_operation::fee_parameters_type, (fee) (price_per_kbyte) ) FC_REFLECT( graphene::chain::nft_metadata_update_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::nft_mint_operation::fee_parameters_type, (fee) (price_per_kbyte) ) @@ -140,7 +170,7 @@ FC_REFLECT( graphene::chain::nft_safe_transfer_from_operation::fee_parameters_ty FC_REFLECT( graphene::chain::nft_approve_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::nft_set_approval_for_all_operation::fee_parameters_type, (fee) ) -FC_REFLECT( graphene::chain::nft_metadata_create_operation, (fee) (owner) (name) (symbol) (base_uri) (revenue_partner) (revenue_split) (is_transferable) (is_sellable) (account_role) (extensions) ) +FC_REFLECT( graphene::chain::nft_metadata_create_operation, (fee) (owner) (name) (symbol) (base_uri) (revenue_partner) (revenue_split) (is_transferable) (is_sellable) (account_role) (max_supply) (lottery_options) (extensions) ) FC_REFLECT( graphene::chain::nft_metadata_update_operation, (fee) (owner) (nft_metadata_id) (name) (symbol) (base_uri) (revenue_partner) (revenue_split) (is_transferable) (is_sellable) (account_role) (extensions) ) FC_REFLECT( graphene::chain::nft_mint_operation, (fee) (payer) (nft_metadata_id) (owner) (approved) (approved_operators) (token_uri) (extensions) ) FC_REFLECT( graphene::chain::nft_safe_transfer_from_operation, (fee) (operator_) (from) (to) (token_id) (data) (extensions) ) diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index 1a1222a5..83d347ab 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -50,12 +50,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include namespace graphene { namespace chain { @@ -184,7 +186,11 @@ namespace graphene { namespace chain { sidechain_transaction_create_operation, sidechain_transaction_sign_operation, sidechain_transaction_send_operation, - sidechain_transaction_settle_operation + sidechain_transaction_settle_operation, + nft_lottery_token_purchase_operation, + nft_lottery_reward_operation, + nft_lottery_end_operation, + random_number_store_operation > operation; /// @} // operations group diff --git a/libraries/chain/include/graphene/chain/protocol/random_number.hpp b/libraries/chain/include/graphene/chain/protocol/random_number.hpp new file mode 100644 index 00000000..3dbe487f --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/random_number.hpp @@ -0,0 +1,25 @@ +#pragma once + +namespace graphene { namespace chain { + + struct random_number_store_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = 5000 * GRAPHENE_BLOCKCHAIN_PRECISION; }; + + asset fee; + + account_id_type account; + vector random_number; + std::string data; + + account_id_type fee_payer()const { return account; } + }; + +} } // graphene::chain + +FC_REFLECT( graphene::chain::random_number_store_operation::fee_parameters_type, (fee) ) +FC_REFLECT( graphene::chain::random_number_store_operation, (fee) + (account) + (random_number) + (data) ) + diff --git a/libraries/chain/include/graphene/chain/protocol/son.hpp b/libraries/chain/include/graphene/chain/protocol/son.hpp index 10a75412..42ead5b6 100644 --- a/libraries/chain/include/graphene/chain/protocol/son.hpp +++ b/libraries/chain/include/graphene/chain/protocol/son.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace graphene { namespace chain { @@ -32,6 +33,7 @@ namespace graphene { namespace chain { optional new_signing_key; optional> new_sidechain_public_keys; optional new_pay_vb; + optional new_status; account_id_type fee_payer()const { return owner_account; } share_type calculate_fee(const fee_parameters_type& k)const { return 0; } @@ -103,7 +105,7 @@ FC_REFLECT(graphene::chain::son_create_operation, (fee)(owner_account)(url)(depo FC_REFLECT(graphene::chain::son_update_operation::fee_parameters_type, (fee) ) FC_REFLECT(graphene::chain::son_update_operation, (fee)(son_id)(owner_account)(new_url)(new_deposit) - (new_signing_key)(new_sidechain_public_keys)(new_pay_vb) ) + (new_signing_key)(new_sidechain_public_keys)(new_pay_vb)(new_status) ) FC_REFLECT(graphene::chain::son_deregister_operation::fee_parameters_type, (fee) ) FC_REFLECT(graphene::chain::son_deregister_operation, (fee)(son_id)(payer) ) diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index 56a4bb1c..321b08d9 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -183,6 +183,7 @@ namespace graphene { namespace chain { son_wallet_withdraw_object_type, sidechain_address_object_type, sidechain_transaction_object_type, + random_number_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; @@ -214,7 +215,8 @@ namespace graphene { namespace chain { impl_sweeps_vesting_balance_object_type, impl_offer_history_object_type, impl_son_statistics_object_type, - impl_son_schedule_object_type + impl_son_schedule_object_type, + impl_nft_lottery_balance_object_type }; //typedef fc::unsigned_int object_id_type; @@ -258,6 +260,7 @@ namespace graphene { namespace chain { class son_wallet_withdraw_object; class sidechain_address_object; class sidechain_transaction_object; + class random_number_object; typedef object_id< protocol_ids, account_object_type, account_object> account_id_type; typedef object_id< protocol_ids, asset_object_type, asset_object> asset_id_type; @@ -297,6 +300,7 @@ namespace graphene { namespace chain { typedef object_id< protocol_ids, son_wallet_withdraw_object_type, son_wallet_withdraw_object> son_wallet_withdraw_id_type; typedef object_id< protocol_ids, sidechain_address_object_type, sidechain_address_object> sidechain_address_id_type; typedef object_id< protocol_ids, sidechain_transaction_object_type,sidechain_transaction_object> sidechain_transaction_id_type; + typedef object_id< protocol_ids, random_number_object_type, random_number_object> random_number_id_type; // implementation types class global_property_object; @@ -321,6 +325,7 @@ namespace graphene { namespace chain { class lottery_balance_object; class sweeps_vesting_balance_object; class offer_history_object; + class nft_lottery_balance_object; class son_statistics_object; class son_schedule_object; @@ -352,6 +357,7 @@ namespace graphene { namespace chain { typedef object_id< implementation_ids, impl_lottery_balance_object_type, lottery_balance_object > lottery_balance_id_type; typedef object_id< implementation_ids, impl_sweeps_vesting_balance_object_type, sweeps_vesting_balance_object> sweeps_vesting_balance_id_type; typedef object_id< implementation_ids, impl_offer_history_object_type, offer_history_object> offer_history_id_type; + typedef object_id< implementation_ids, impl_nft_lottery_balance_object_type, nft_lottery_balance_object> nft_lottery_balance_id_type; typedef object_id< implementation_ids, impl_son_statistics_object_type, son_statistics_object > son_statistics_id_type; typedef object_id< implementation_ids, impl_son_schedule_object_type, son_schedule_object> son_schedule_id_type; @@ -496,6 +502,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type, (son_wallet_withdraw_object_type) (sidechain_address_object_type) (sidechain_transaction_object_type) + (random_number_object_type) (OBJECT_TYPE_COUNT) ) FC_REFLECT_ENUM( graphene::chain::impl_object_type, @@ -526,6 +533,7 @@ FC_REFLECT_ENUM( graphene::chain::impl_object_type, (impl_offer_history_object_type) (impl_son_statistics_object_type) (impl_son_schedule_object_type) + (impl_nft_lottery_balance_object_type) ) FC_REFLECT_TYPENAME( graphene::chain::share_type ) @@ -575,6 +583,7 @@ FC_REFLECT_TYPENAME( graphene::chain::offer_history_id_type ) FC_REFLECT_TYPENAME( graphene::chain::nft_metadata_id_type ) FC_REFLECT_TYPENAME( graphene::chain::nft_id_type ) FC_REFLECT_TYPENAME( graphene::chain::account_role_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::nft_lottery_balance_id_type ) FC_REFLECT_TYPENAME( graphene::chain::son_id_type ) FC_REFLECT_TYPENAME( graphene::chain::son_proposal_id_type ) FC_REFLECT_TYPENAME( graphene::chain::son_wallet_id_type ) @@ -582,7 +591,7 @@ FC_REFLECT_TYPENAME( graphene::chain::son_wallet_deposit_id_type ) FC_REFLECT_TYPENAME( graphene::chain::son_wallet_withdraw_id_type ) FC_REFLECT_TYPENAME( graphene::chain::sidechain_address_id_type ) FC_REFLECT_TYPENAME( graphene::chain::sidechain_transaction_id_type ) - +FC_REFLECT_TYPENAME( graphene::chain::random_number_id_type ) FC_REFLECT( graphene::chain::void_t, ) diff --git a/libraries/chain/include/graphene/chain/random_number_evaluator.hpp b/libraries/chain/include/graphene/chain/random_number_evaluator.hpp new file mode 100644 index 00000000..a26b9f3e --- /dev/null +++ b/libraries/chain/include/graphene/chain/random_number_evaluator.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include +#include +#include + +namespace graphene { namespace chain { + + class random_number_store_evaluator : public evaluator + { + public: + typedef random_number_store_operation operation_type; + + void_result do_evaluate( const random_number_store_operation& o ); + object_id_type do_apply( const random_number_store_operation& o ); + }; + +} } // graphene::chain + diff --git a/libraries/chain/include/graphene/chain/random_number_object.hpp b/libraries/chain/include/graphene/chain/random_number_object.hpp new file mode 100644 index 00000000..3613d7a1 --- /dev/null +++ b/libraries/chain/include/graphene/chain/random_number_object.hpp @@ -0,0 +1,41 @@ +#pragma once + +namespace graphene { namespace chain { + using namespace graphene::db; + + class random_number_object : public abstract_object + { + public: + static const uint8_t space_id = protocol_ids; + static const uint8_t type_id = random_number_object_type; + + account_id_type account; /* account who requested random number */ + time_point_sec timestamp; /* date and time when the number is read */ + vector random_number; /* random number(s) */ + std::string data; /* custom data in json format */ + }; + + struct by_account; + struct by_timestamp; + using random_number_multi_index_type = multi_index_container< + random_number_object, + indexed_by< + ordered_unique< tag, + member + >, + ordered_non_unique< tag, + member + >, + ordered_non_unique< tag, + member + > + > + >; + using random_number_index = generic_index; + +} } // graphene::chain + +FC_REFLECT_DERIVED( graphene::chain::random_number_object, (graphene::db::object), + (account) (timestamp) + (random_number) (data) ) + diff --git a/libraries/chain/include/graphene/chain/rbac_hardfork_visitor.hpp b/libraries/chain/include/graphene/chain/rbac_hardfork_visitor.hpp index 21cf492f..7e2e8c7c 100644 --- a/libraries/chain/include/graphene/chain/rbac_hardfork_visitor.hpp +++ b/libraries/chain/include/graphene/chain/rbac_hardfork_visitor.hpp @@ -57,6 +57,9 @@ namespace graphene case operation::tag::value: case operation::tag::value: case operation::tag::value: + case operation::tag::value: + case operation::tag::value: + case operation::tag::value: FC_ASSERT(block_time >= HARDFORK_NFT_TIME, "Custom permissions and roles not allowed on this operation yet!"); break; default: diff --git a/libraries/chain/include/graphene/chain/sidechain_defs.hpp b/libraries/chain/include/graphene/chain/sidechain_defs.hpp index 6bbc8b5c..7f986f96 100644 --- a/libraries/chain/include/graphene/chain/sidechain_defs.hpp +++ b/libraries/chain/include/graphene/chain/sidechain_defs.hpp @@ -9,7 +9,8 @@ enum class sidechain_type { bitcoin, ethereum, eos, - peerplays + peerplays, + hive }; } } @@ -19,4 +20,5 @@ FC_REFLECT_ENUM(graphene::chain::sidechain_type, (bitcoin) (ethereum) (eos) + (hive) (peerplays) ) diff --git a/libraries/chain/include/graphene/chain/sidechain_transaction_object.hpp b/libraries/chain/include/graphene/chain/sidechain_transaction_object.hpp index e9011ffb..30a0dd5e 100644 --- a/libraries/chain/include/graphene/chain/sidechain_transaction_object.hpp +++ b/libraries/chain/include/graphene/chain/sidechain_transaction_object.hpp @@ -26,7 +26,8 @@ namespace graphene { namespace chain { static const uint8_t space_id = protocol_ids; static const uint8_t type_id = sidechain_transaction_object_type; - sidechain_type sidechain; + time_point_sec timestamp; + sidechain_type sidechain = sidechain_type::unknown; object_id_type object_id; std::string transaction; std::vector signers; @@ -37,7 +38,7 @@ namespace graphene { namespace chain { uint32_t current_weight = 0; uint32_t threshold = 0; - sidechain_transaction_status status; + sidechain_transaction_status status = sidechain_transaction_status::invalid; }; struct by_object_id; @@ -70,6 +71,7 @@ FC_REFLECT_ENUM( graphene::chain::sidechain_transaction_status, (settled) ) FC_REFLECT_DERIVED( graphene::chain::sidechain_transaction_object, (graphene::db::object ), + (timestamp) (sidechain) (object_id) (transaction) diff --git a/libraries/chain/include/graphene/chain/son_object.hpp b/libraries/chain/include/graphene/chain/son_object.hpp index 53072515..d0b74e79 100644 --- a/libraries/chain/include/graphene/chain/son_object.hpp +++ b/libraries/chain/include/graphene/chain/son_object.hpp @@ -31,9 +31,9 @@ namespace graphene { namespace chain { son_id_type owner; // Lifetime total transactions signed - uint64_t total_txs_signed = 0; + flat_map total_txs_signed; // Transactions signed since the last son payouts - uint64_t txs_signed = 0; + flat_map txs_signed; // Total Voted Active time i.e. duration selected as part of voted active SONs uint64_t total_voted_time = 0; // Total Downtime barring the current down time in seconds, used for stats to present to user @@ -47,9 +47,9 @@ namespace graphene { namespace chain { // Deregistered Timestamp fc::time_point_sec deregistered_timestamp; // Total sidechain transactions reported by SON network while SON was active - uint64_t total_sidechain_txs_reported = 0; + flat_map total_sidechain_txs_reported; // Sidechain transactions reported by this SON - uint64_t sidechain_txs_reported = 0; + flat_map sidechain_txs_reported; }; /** @@ -76,6 +76,7 @@ namespace graphene { namespace chain { void pay_son_fee(share_type pay, database& db); bool has_valid_config()const; + bool has_valid_config(time_point_sec head_block_time)const; }; struct by_account; diff --git a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp index 1e87246e..998950bf 100644 --- a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp +++ b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp @@ -200,6 +200,20 @@ namespace graphene { namespace chain { */ struct by_account; struct by_asset_balance; + + struct by_asset_balance_helper_asset_id { + typedef asset_id_type result_type; + result_type operator()(const vesting_balance_object& vbo) const { + return vbo.balance.asset_id; + } + }; + struct by_asset_balance_helper_asset_amount { + typedef share_type result_type; + result_type operator()(const vesting_balance_object& vbo) const { + return vbo.balance.amount; + } + }; + typedef multi_index_container< vesting_balance_object, indexed_by< @@ -210,11 +224,9 @@ namespace graphene { namespace chain { ordered_non_unique< tag, composite_key< vesting_balance_object, - member_offset, + by_asset_balance_helper_asset_id, member, - member_offset - //member - //member_offset + by_asset_balance_helper_asset_amount >, composite_key_compare< std::less< asset_id_type >, diff --git a/libraries/chain/index.cpp b/libraries/chain/index.cpp deleted file mode 100644 index 41a469b2..00000000 --- a/libraries/chain/index.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2015 Cryptonomex, Inc., 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 -#include -#include - -namespace graphene { namespace chain { - void base_primary_index::save_undo( const object& obj ) - { _db.save_undo( obj ); } - - void base_primary_index::on_add( const object& obj ) - { - _db.save_undo_add( obj ); - for( auto ob : _observers ) ob->on_add( obj ); - } - - void base_primary_index::on_remove( const object& obj ) - { _db.save_undo_remove( obj ); for( auto ob : _observers ) ob->on_remove( obj ); } - - void base_primary_index::on_modify( const object& obj ) - {for( auto ob : _observers ) ob->on_modify( obj ); } -} } // graphene::chain diff --git a/libraries/chain/nft_evaluator.cpp b/libraries/chain/nft_evaluator.cpp index f7f007ff..eedbd5cc 100644 --- a/libraries/chain/nft_evaluator.cpp +++ b/libraries/chain/nft_evaluator.cpp @@ -24,6 +24,26 @@ void_result nft_metadata_create_evaluator::do_evaluate( const nft_metadata_creat const auto& ar_obj = (*op.account_role)(db()); FC_ASSERT(ar_obj.owner == op.owner, "Only the Account Role created by the owner can be attached"); } + + // Lottery Related + if (!op.lottery_options) { + return void_result(); + } + FC_ASSERT((*op.lottery_options).end_date > now || (*op.lottery_options).end_date == time_point_sec()); + if (op.max_supply) { + FC_ASSERT(*op.max_supply >= 5); + } + + for(auto lottery_id: (*op.lottery_options).progressive_jackpots) { + const auto& lottery_obj = lottery_id(db()); + FC_ASSERT(lottery_obj.owner == op.owner, "Only the Owner can attach progressive jackpots"); + FC_ASSERT(lottery_obj.is_lottery(), "Only lottery objects can be attached as progressive jackpots"); + FC_ASSERT(lottery_obj.lottery_data->lottery_options.is_active == false, "Lottery should not be active"); + FC_ASSERT(lottery_obj.lottery_data->lottery_options.ticket_price.asset_id == (*op.lottery_options).ticket_price.asset_id, "Lottery asset type should be same"); + const auto& lottery_balance_obj = lottery_obj.lottery_data->lottery_balance_id(db()); + FC_ASSERT(lottery_balance_obj.jackpot.amount > 0, "Non zero progressive jackpot not allowed"); + } + return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -39,6 +59,26 @@ object_id_type nft_metadata_create_evaluator::do_apply( const nft_metadata_creat obj.is_transferable = op.is_transferable; obj.is_sellable = op.is_sellable; obj.account_role = op.account_role; + if (op.max_supply) { + obj.max_supply = *op.max_supply; + } + if (op.lottery_options) { + asset jackpot_sum(0,(*op.lottery_options).ticket_price.asset_id); + for(auto lottery_id: (*op.lottery_options).progressive_jackpots) { + const auto& lottery_obj = lottery_id(db()); + const auto& lottery_balance_obj = lottery_obj.lottery_data->lottery_balance_id(db()); + FC_ASSERT(lottery_balance_obj.jackpot.amount > 0, "Non zero progressive jackpot not allowed"); + db().modify(lottery_balance_obj, [&] ( nft_lottery_balance_object& nlbo ) { + jackpot_sum += nlbo.jackpot; + nlbo.jackpot -= nlbo.jackpot; + }); + } + const auto& new_lottery_balance_obj = db().create([&](nft_lottery_balance_object& nlbo) { + nlbo.total_progressive_jackpot = jackpot_sum; + nlbo.jackpot = jackpot_sum; + }); + obj.lottery_data = nft_lottery_data(*op.lottery_options, new_lottery_balance_obj.id); + } }); return new_nft_metadata_object.id; } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -110,6 +150,7 @@ void_result nft_mint_evaluator::do_evaluate( const nft_mint_operation& op ) FC_ASSERT( itr_nft_md != idx_nft_md.end(), "NFT metadata not found" ); FC_ASSERT( itr_nft_md->owner == op.payer, "Only metadata owner can mint NFT" ); + FC_ASSERT(itr_nft_md->get_token_current_supply(db()) < itr_nft_md->max_supply, "NFTs can't be minted more than max_supply"); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/chain/nft_lottery_evaluator.cpp b/libraries/chain/nft_lottery_evaluator.cpp new file mode 100644 index 00000000..794616cf --- /dev/null +++ b/libraries/chain/nft_lottery_evaluator.cpp @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include + +namespace graphene +{ + namespace chain + { + void_result nft_lottery_token_purchase_evaluator::do_evaluate(const nft_lottery_token_purchase_operation &op) + { + try + { + const database &d = db(); + auto now = d.head_block_time(); + FC_ASSERT(now >= HARDFORK_NFT_TIME, "Not allowed until NFT HF"); + op.buyer(d); + const auto &lottery_md_obj = op.lottery_id(d); + FC_ASSERT(lottery_md_obj.is_lottery(), "Not a lottery type"); + if (lottery_md_obj.account_role) + { + const auto &ar_idx = d.get_index_type().indices().get(); + auto ar_itr = ar_idx.find(*lottery_md_obj.account_role); + if (ar_itr != ar_idx.end()) + { + FC_ASSERT(d.account_role_valid(*ar_itr, op.buyer, get_type()), "Account role not valid"); + } + } + + auto lottery_options = lottery_md_obj.lottery_data->lottery_options; + FC_ASSERT(lottery_options.ticket_price.asset_id == op.amount.asset_id); + FC_ASSERT((double)op.amount.amount.value / lottery_options.ticket_price.amount.value == (double)op.tickets_to_buy); + return void_result(); + } + FC_CAPTURE_AND_RETHROW((op)) + } + + object_id_type nft_lottery_token_purchase_evaluator::do_apply(const nft_lottery_token_purchase_operation &op) + { + try + { + transaction_evaluation_state nft_mint_context(&db()); + nft_mint_context.skip_fee_schedule_check = true; + const auto &lottery_md_obj = op.lottery_id(db()); + nft_id_type nft_id; + for (size_t i = 0; i < op.tickets_to_buy; i++) + { + nft_mint_operation mint_op; + mint_op.payer = lottery_md_obj.owner; + mint_op.nft_metadata_id = lottery_md_obj.id; + mint_op.owner = op.buyer; + nft_id = db().apply_operation(nft_mint_context, mint_op).get(); + } + db().adjust_balance(op.buyer, -op.amount); + db().modify(lottery_md_obj.lottery_data->lottery_balance_id(db()), [&](nft_lottery_balance_object &obj) { + obj.jackpot += op.amount; + }); + return nft_id; + } + FC_CAPTURE_AND_RETHROW((op)) + } + + void_result nft_lottery_reward_evaluator::do_evaluate(const nft_lottery_reward_operation &op) + { + try + { + const database &d = db(); + auto now = d.head_block_time(); + FC_ASSERT(now >= HARDFORK_NFT_TIME, "Not allowed until NFT HF"); + op.winner(d); + + const auto &lottery_md_obj = op.lottery_id(d); + FC_ASSERT(lottery_md_obj.is_lottery()); + + const auto &lottery_options = lottery_md_obj.lottery_data->lottery_options; + FC_ASSERT(lottery_options.is_active); + FC_ASSERT(lottery_md_obj.get_lottery_jackpot(d) >= op.amount); + return void_result(); + } + FC_CAPTURE_AND_RETHROW((op)) + } + + void_result nft_lottery_reward_evaluator::do_apply(const nft_lottery_reward_operation &op) + { + try + { + const auto &lottery_md_obj = op.lottery_id(db()); + db().adjust_balance(op.winner, op.amount); + db().modify(lottery_md_obj.lottery_data->lottery_balance_id(db()), [&](nft_lottery_balance_object &obj) { + obj.jackpot -= op.amount; + }); + return void_result(); + } + FC_CAPTURE_AND_RETHROW((op)) + } + + void_result nft_lottery_end_evaluator::do_evaluate(const nft_lottery_end_operation &op) + { + try + { + const database &d = db(); + auto now = d.head_block_time(); + FC_ASSERT(now >= HARDFORK_NFT_TIME, "Not allowed until NFT HF"); + const auto &lottery_md_obj = op.lottery_id(d); + FC_ASSERT(lottery_md_obj.is_lottery()); + + const auto &lottery_options = lottery_md_obj.lottery_data->lottery_options; + FC_ASSERT(lottery_options.is_active); + FC_ASSERT(lottery_md_obj.get_lottery_jackpot(d).amount == 0); + return void_result(); + } + FC_CAPTURE_AND_RETHROW((op)) + } + + void_result nft_lottery_end_evaluator::do_apply(const nft_lottery_end_operation &op) + { + try + { + const auto &lottery_md_obj = op.lottery_id(db()); + db().modify(lottery_md_obj, [&](nft_metadata_object &obj) { + obj.lottery_data->lottery_options.is_active = false; + }); + db().modify(lottery_md_obj.lottery_data->lottery_balance_id(db()), [&](nft_lottery_balance_object &obj) { + obj.sweeps_tickets_sold = lottery_md_obj.get_token_current_supply(db()); + }); + + if (lottery_md_obj.lottery_data->lottery_options.delete_tickets_after_draw) + { + const auto &nft_index_by_md = db().get_index_type().indices().get(); + auto delete_nft_itr = nft_index_by_md.lower_bound(op.lottery_id); + while (delete_nft_itr != nft_index_by_md.end() && delete_nft_itr->nft_metadata_id == op.lottery_id) + { + const nft_object &nft_obj = *delete_nft_itr; + ++delete_nft_itr; + db().remove(nft_obj); + } + } + + return void_result(); + } + FC_CAPTURE_AND_RETHROW((op)) + } + } // namespace chain +} // namespace graphene \ No newline at end of file diff --git a/libraries/chain/nft_lottery_object.cpp b/libraries/chain/nft_lottery_object.cpp new file mode 100644 index 00000000..f5e9f674 --- /dev/null +++ b/libraries/chain/nft_lottery_object.cpp @@ -0,0 +1,171 @@ +#include +#include + +namespace graphene +{ + namespace chain + { + time_point_sec nft_metadata_object::get_lottery_expiration() const + { + if (lottery_data) + return lottery_data->lottery_options.end_date; + return time_point_sec(); + } + + asset nft_metadata_object::get_lottery_jackpot(const database &db) const + { + if (lottery_data) + return lottery_data->lottery_balance_id(db).jackpot; + return asset(); + } + + share_type nft_metadata_object::get_token_current_supply(const database &db) const + { + share_type current_supply; + const auto &idx_lottery_by_md = db.get_index_type().indices().get(); + auto lottery_range = idx_lottery_by_md.equal_range(id); + current_supply = std::distance(lottery_range.first, lottery_range.second); + return current_supply; + } + + vector nft_metadata_object::get_holders(const database &db) const + { + const auto &idx_lottery_by_md = db.get_index_type().indices().get(); + auto lottery_range = idx_lottery_by_md.equal_range(id); + vector holders; + holders.reserve(std::distance(lottery_range.first, lottery_range.second)); + std::for_each(lottery_range.first, lottery_range.second, + [&](const nft_object &ticket) { + holders.emplace_back(ticket.owner); + }); + return holders; + } + + vector nft_metadata_object::get_ticket_ids(const database &db) const + { + const auto &idx_lottery_by_md = db.get_index_type().indices().get(); + auto lottery_range = idx_lottery_by_md.equal_range(id); + vector tickets; + tickets.reserve(std::distance(lottery_range.first, lottery_range.second)); + std::for_each(lottery_range.first, lottery_range.second, + [&](const nft_object &ticket) { + tickets.emplace_back(ticket.id.instance()); + }); + return tickets; + } + + void nft_metadata_object::distribute_benefactors_part(database &db) + { + transaction_evaluation_state eval(&db); + const auto &lottery_options = lottery_data->lottery_options; + share_type jackpot = lottery_options.ticket_price.amount * get_token_current_supply(db) + lottery_data->lottery_balance_id(db).total_progressive_jackpot.amount; + + for (auto benefactor : lottery_options.benefactors) + { + nft_lottery_reward_operation reward_op; + reward_op.lottery_id = id; + reward_op.winner = benefactor.id; + reward_op.is_benefactor_reward = true; + reward_op.win_percentage = benefactor.share; + reward_op.amount = asset(jackpot.value * benefactor.share / GRAPHENE_100_PERCENT, lottery_options.ticket_price.asset_id); + db.apply_operation(eval, reward_op); + } + } + + map> nft_metadata_object::distribute_winners_part(database &db) + { + transaction_evaluation_state eval(&db); + auto current_supply = get_token_current_supply(db); + auto &lottery_options = lottery_data->lottery_options; + + auto holders = get_holders(db); + vector ticket_ids = get_ticket_ids(db); + FC_ASSERT(current_supply.value == (int64_t)holders.size()); + FC_ASSERT(get_lottery_jackpot(db).amount.value == current_supply.value * lottery_options.ticket_price.amount.value); + map> structurized_participants; + for (account_id_type holder : holders) + { + if (!structurized_participants.count(holder)) + structurized_participants.emplace(holder, vector()); + } + uint64_t jackpot = get_lottery_jackpot(db).amount.value; + auto selections = lottery_options.winning_tickets.size() <= holders.size() ? lottery_options.winning_tickets.size() : holders.size(); + auto winner_numbers = db.get_random_numbers(0, holders.size(), selections, false); + + auto &tickets(lottery_options.winning_tickets); + + if (holders.size() < tickets.size()) + { + uint16_t percents_to_distribute = 0; + for (auto i = tickets.begin() + holders.size(); i != tickets.end();) + { + percents_to_distribute += *i; + i = tickets.erase(i); + } + for (auto t = tickets.begin(); t != tickets.begin() + holders.size(); ++t) + *t += percents_to_distribute / holders.size(); + } + auto sweeps_distribution_percentage = db.get_global_properties().parameters.sweeps_distribution_percentage(); + for (size_t c = 0; c < winner_numbers.size(); ++c) + { + auto winner_num = winner_numbers[c]; + nft_lottery_reward_operation reward_op; + reward_op.lottery_id = id; + reward_op.is_benefactor_reward = false; + reward_op.winner = holders[winner_num]; + if (ticket_ids.size() > winner_num) + { + reward_op.winner_ticket_id = ticket_ids[winner_num]; + } + reward_op.win_percentage = tickets[c]; + reward_op.amount = asset(jackpot * tickets[c] * (1. - sweeps_distribution_percentage / (double)GRAPHENE_100_PERCENT) / GRAPHENE_100_PERCENT, lottery_options.ticket_price.asset_id); + db.apply_operation(eval, reward_op); + + structurized_participants[holders[winner_num]].push_back(tickets[c]); + } + return structurized_participants; + } + + void nft_metadata_object::distribute_sweeps_holders_part(database &db) + { + transaction_evaluation_state eval(&db); + auto &asset_bal_idx = db.get_index_type().indices().get(); + auto sweeps_params = db.get_global_properties().parameters; + uint64_t distribution_asset_supply = sweeps_params.sweeps_distribution_asset()(db).dynamic_data(db).current_supply.value; + const auto range = asset_bal_idx.equal_range(boost::make_tuple(sweeps_params.sweeps_distribution_asset())); + asset remaining_jackpot = get_lottery_jackpot(db); + uint64_t holders_sum = 0; + for (const account_balance_object &holder_balance : boost::make_iterator_range(range.first, range.second)) + { + int64_t holder_part = remaining_jackpot.amount.value / (double)distribution_asset_supply * holder_balance.balance.value * SWEEPS_VESTING_BALANCE_MULTIPLIER; + db.adjust_sweeps_vesting_balance(holder_balance.owner, holder_part); + holders_sum += holder_part; + } + uint64_t balance_rest = remaining_jackpot.amount.value * SWEEPS_VESTING_BALANCE_MULTIPLIER - holders_sum; + db.adjust_sweeps_vesting_balance(sweeps_params.sweeps_vesting_accumulator_account(), balance_rest); + db.modify(lottery_data->lottery_balance_id(db), [&](nft_lottery_balance_object &obj) { + obj.jackpot -= remaining_jackpot; + }); + } + + void nft_metadata_object::end_lottery(database &db) + { + transaction_evaluation_state eval(&db); + const auto &lottery_options = lottery_data->lottery_options; + + FC_ASSERT(is_lottery()); + FC_ASSERT(lottery_options.is_active && (lottery_options.end_date <= db.head_block_time() || lottery_options.ending_on_soldout)); + + auto participants = distribute_winners_part(db); + if (participants.size() > 0) + { + distribute_benefactors_part(db); + distribute_sweeps_holders_part(db); + } + + nft_lottery_end_operation end_op; + end_op.lottery_id = get_id(); + db.apply_operation(eval, end_op); + } + } // namespace chain +} // namespace graphene diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index 38521284..ac8ef601 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -219,6 +219,18 @@ struct proposal_operation_hardfork_visitor FC_ASSERT( block_time >= HARDFORK_NFT_TIME, "account_role_delete_operation not allowed yet!" ); } + void operator()(const nft_lottery_token_purchase_operation &v) const { + FC_ASSERT( block_time >= HARDFORK_NFT_TIME, "nft_lottery_token_purchase_operation not allowed yet!" ); + } + + void operator()(const nft_lottery_reward_operation &v) const { + FC_ASSERT( block_time >= HARDFORK_NFT_TIME, "nft_lottery_reward_operation not allowed yet!" ); + } + + void operator()(const nft_lottery_end_operation &v) const { + FC_ASSERT( block_time >= HARDFORK_NFT_TIME, "nft_lottery_end_operation not allowed yet!" ); + } + void operator()(const son_create_operation &v) const { FC_ASSERT( block_time >= HARDFORK_SON_TIME, "son_create_operation not allowed yet!" ); } diff --git a/libraries/chain/protocol/competitor.cpp b/libraries/chain/protocol/competitor.cpp deleted file mode 100644 index 1f35cf37..00000000 --- a/libraries/chain/protocol/competitor.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018 Peerplays Blockchain Standards Association, 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 - -namespace graphene { namespace chain { - -void competitor_create_operation::validate() const -{ - FC_ASSERT( fee.amount >= 0 ); -} - - -} } // graphene::chain - diff --git a/libraries/chain/protocol/memo.cpp b/libraries/chain/protocol/memo.cpp index afa0b486..4e863a87 100644 --- a/libraries/chain/protocol/memo.cpp +++ b/libraries/chain/protocol/memo.cpp @@ -30,7 +30,10 @@ namespace graphene { namespace chain { void memo_data::set_message(const fc::ecc::private_key& priv, const fc::ecc::public_key& pub, const string& msg, uint64_t custom_nonce) { - if( priv != fc::ecc::private_key() && public_key_type(pub) != public_key_type() ) + bool should_encrypt = (priv != fc::ecc::private_key() && pub.valid()); + should_encrypt = (should_encrypt) && (msg.size()) && (msg.find("#") == 0); + + if( should_encrypt ) { from = priv.get_public_key(); to = pub; @@ -49,6 +52,7 @@ void memo_data::set_message(const fc::ecc::private_key& priv, const fc::ecc::pub } else { + to = public_key_type(); auto text = memo_message(0, msg).serialize(); message = vector(text.begin(), text.end()); } @@ -57,7 +61,7 @@ void memo_data::set_message(const fc::ecc::private_key& priv, const fc::ecc::pub string memo_data::get_message(const fc::ecc::private_key& priv, const fc::ecc::public_key& pub)const { - if( from != public_key_type() ) + if( from != public_key_type() && to != public_key_type() && pub.valid() ) { auto secret = priv.get_shared_secret(pub); auto nonce_plus_secret = fc::sha512::hash(fc::to_string(nonce) + secret.str()); diff --git a/libraries/chain/protocol/nft.cpp b/libraries/chain/protocol/nft.cpp index 4a66f330..ca7fe816 100644 --- a/libraries/chain/protocol/nft.cpp +++ b/libraries/chain/protocol/nft.cpp @@ -45,6 +45,10 @@ void nft_metadata_create_operation::validate() const FC_ASSERT(fee.amount >= 0, "Fee must not be negative"); FC_ASSERT(is_valid_nft_token_name(name), "Invalid NFT name provided"); FC_ASSERT(is_valid_nft_token_name(symbol), "Invalid NFT symbol provided"); + if (lottery_options) + { + (*lottery_options).validate(); + } } void nft_metadata_update_operation::validate() const diff --git a/libraries/chain/protocol/nft_lottery.cpp b/libraries/chain/protocol/nft_lottery.cpp new file mode 100644 index 00000000..16454962 --- /dev/null +++ b/libraries/chain/protocol/nft_lottery.cpp @@ -0,0 +1,38 @@ +#include +#include +#include + +namespace graphene +{ + namespace chain + { + + void nft_lottery_options::validate() const + { + FC_ASSERT(winning_tickets.size() <= 64); + FC_ASSERT(ticket_price.amount >= 1); + uint16_t total = 0; + for (auto benefactor : benefactors) + { + total += benefactor.share; + } + for (auto share : winning_tickets) + { + total += share; + } + FC_ASSERT(total == GRAPHENE_100_PERCENT, "distribution amount not equals GRAPHENE_100_PERCENT"); + FC_ASSERT(ending_on_soldout == true || end_date != time_point_sec(), "lottery may not end"); + } + + share_type nft_lottery_token_purchase_operation::calculate_fee(const fee_parameters_type &k) const + { + return k.fee; + } + + void nft_lottery_token_purchase_operation::validate() const + { + FC_ASSERT(fee.amount >= 0, "Fee must not be negative"); + FC_ASSERT(tickets_to_buy > 0); + } + } // namespace chain +} // namespace graphene \ No newline at end of file diff --git a/libraries/chain/random_number_evaluator.cpp b/libraries/chain/random_number_evaluator.cpp new file mode 100644 index 00000000..acfab042 --- /dev/null +++ b/libraries/chain/random_number_evaluator.cpp @@ -0,0 +1,24 @@ +#include +#include + +namespace graphene { namespace chain { + +void_result random_number_store_evaluator::do_evaluate( const random_number_store_operation& op ) +{ try { + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +object_id_type random_number_store_evaluator::do_apply( const random_number_store_operation& op ) +{ try { + const auto& new_random_number_object = db().create( [&]( random_number_object& obj ) { + obj.account = op.account; + obj.timestamp = db().head_block_time(); + obj.random_number = op.random_number; + obj.data = op.data; + }); + return new_random_number_object.id; +} FC_CAPTURE_AND_RETHROW( (op) ) } + +} } // graphene::chain + diff --git a/libraries/chain/sidechain_address_evaluator.cpp b/libraries/chain/sidechain_address_evaluator.cpp index ae802627..625ef2f0 100644 --- a/libraries/chain/sidechain_address_evaluator.cpp +++ b/libraries/chain/sidechain_address_evaluator.cpp @@ -9,7 +9,9 @@ namespace graphene { namespace chain { void_result add_sidechain_address_evaluator::do_evaluate(const sidechain_address_add_operation& op) { try{ - FC_ASSERT( op.deposit_public_key.length() > 0 && op.deposit_address.length() == 0 && op.deposit_address_data.length() == 0, "User should add a valid deposit public key and a null deposit address"); + if (op.sidechain == sidechain_type::bitcoin) { + FC_ASSERT( op.deposit_public_key.length() > 0 && op.deposit_address.length() == 0 && op.deposit_address_data.length() == 0, "ser should add a valid deposit public key and a null deposit address (Bitcoin only)"); + } const auto& sdpke_idx = db().get_index_type().indices().get(); FC_ASSERT( sdpke_idx.find(boost::make_tuple(op.sidechain, op.deposit_public_key, time_point_sec::maximum())) == sdpke_idx.end(), "An active deposit key already exists" ); return void_result(); @@ -31,8 +33,8 @@ object_id_type add_sidechain_address_evaluator::do_apply(const sidechain_address obj.sidechain_address_account = op.sidechain_address_account; obj.sidechain = op.sidechain; obj.deposit_public_key = op.deposit_public_key; - obj.deposit_address = ""; - obj.deposit_address_data = ""; + obj.deposit_address = op.deposit_address; + obj.deposit_address_data = op.deposit_address_data; obj.withdraw_public_key = op.withdraw_public_key; obj.withdraw_address = op.withdraw_address; obj.valid_from = db().head_block_time(); diff --git a/libraries/chain/sidechain_transaction_evaluator.cpp b/libraries/chain/sidechain_transaction_evaluator.cpp index 12bf2f42..ba256199 100644 --- a/libraries/chain/sidechain_transaction_evaluator.cpp +++ b/libraries/chain/sidechain_transaction_evaluator.cpp @@ -28,6 +28,7 @@ void_result sidechain_transaction_create_evaluator::do_evaluate(const sidechain_ object_id_type sidechain_transaction_create_evaluator::do_apply(const sidechain_transaction_create_operation &op) { try { const auto &new_sidechain_transaction_object = db().create([&](sidechain_transaction_object &sto) { + sto.timestamp = db().head_block_time(); sto.sidechain = op.sidechain; sto.object_id = op.object_id; sto.transaction = op.transaction; @@ -97,7 +98,15 @@ object_id_type sidechain_transaction_sign_evaluator::do_apply(const sidechain_tr }); db().modify(son_obj->statistics(db()), [&](son_statistics_object& sso) { - sso.txs_signed += 1; + if (sso.total_txs_signed.find(sto_obj->sidechain) == sso.total_txs_signed.end()) { + sso.total_txs_signed[sto_obj->sidechain] = 0; + } + sso.total_txs_signed[sto_obj->sidechain] += 1; + + if (sso.txs_signed.find(sto_obj->sidechain) == sso.txs_signed.end()) { + sso.txs_signed[sto_obj->sidechain] = 0; + } + sso.txs_signed[sto_obj->sidechain] += 1; }); return op.sidechain_transaction_id; diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index bf92b709..e732c145 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -79,6 +79,9 @@ void_result update_son_evaluator::do_evaluate(const son_update_operation& op) FC_ASSERT(vbo.policy.which() == vesting_policy::tag::value, "Payment balance must have linear vesting policy"); } + if(op.new_status.valid()) { + FC_ASSERT(db().get(op.son_id).status == son_status::deregistered, "SON must be in deregistered state"); + } return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -94,6 +97,7 @@ object_id_type update_son_evaluator::do_apply(const son_update_operation& op) if(op.new_signing_key.valid()) so.signing_key = *op.new_signing_key; if(op.new_sidechain_public_keys.valid()) so.sidechain_public_keys = *op.new_sidechain_public_keys; if(op.new_pay_vb.valid()) so.pay_vb = *op.new_pay_vb; + if(op.new_status.valid()) so.status = son_status::inactive; }); } return op.son_id; diff --git a/libraries/chain/son_object.cpp b/libraries/chain/son_object.cpp index bf54c833..c94a6250 100644 --- a/libraries/chain/son_object.cpp +++ b/libraries/chain/son_object.cpp @@ -12,4 +12,16 @@ namespace graphene { namespace chain { (sidechain_public_keys.find( sidechain_type::bitcoin ) != sidechain_public_keys.end()) && (sidechain_public_keys.at(sidechain_type::bitcoin).length() > 0)); } + + bool son_object::has_valid_config(time_point_sec head_block_time)const { + bool retval = has_valid_config(); + + if (head_block_time >= HARDFORK_SON_FOR_HIVE_TIME) { + retval = retval && + (sidechain_public_keys.find( sidechain_type::hive ) != sidechain_public_keys.end()) && + (sidechain_public_keys.at(sidechain_type::hive).length() > 0); + } + + return retval; + } }} diff --git a/libraries/chain/son_wallet_deposit_evaluator.cpp b/libraries/chain/son_wallet_deposit_evaluator.cpp index 24a87e47..f9620282 100644 --- a/libraries/chain/son_wallet_deposit_evaluator.cpp +++ b/libraries/chain/son_wallet_deposit_evaluator.cpp @@ -84,9 +84,16 @@ object_id_type create_son_wallet_deposit_evaluator::do_apply(const son_wallet_de auto stats_itr = db().get_index_type().indices().get().find(si.son_id); db().modify(*stats_itr, [&op, &si](son_statistics_object &sso) { - sso.total_sidechain_txs_reported = sso.total_sidechain_txs_reported + 1; + if (sso.total_sidechain_txs_reported.find(op.sidechain) == sso.total_sidechain_txs_reported.end()) { + sso.total_sidechain_txs_reported[op.sidechain] = 0; + } + sso.total_sidechain_txs_reported[op.sidechain] += 1; + if (si.son_id == op.son_id) { - sso.sidechain_txs_reported = sso.sidechain_txs_reported + 1; + if (sso.sidechain_txs_reported.find(op.sidechain) == sso.sidechain_txs_reported.end()) { + sso.sidechain_txs_reported[op.sidechain] = 0; + } + sso.sidechain_txs_reported[op.sidechain] += 1; } }); } @@ -122,7 +129,10 @@ object_id_type create_son_wallet_deposit_evaluator::do_apply(const son_wallet_de }); auto stats_itr = db().get_index_type().indices().get().find(op.son_id); db().modify(*stats_itr, [&op](son_statistics_object &sso) { - sso.sidechain_txs_reported = sso.sidechain_txs_reported + 1; + if (sso.sidechain_txs_reported.find(op.sidechain) == sso.sidechain_txs_reported.end()) { + sso.sidechain_txs_reported[op.sidechain] = 0; + } + sso.sidechain_txs_reported[op.sidechain] += 1; }); return (*itr).id; } diff --git a/libraries/chain/son_wallet_withdraw_evaluator.cpp b/libraries/chain/son_wallet_withdraw_evaluator.cpp index bf6adaf9..2110e49d 100644 --- a/libraries/chain/son_wallet_withdraw_evaluator.cpp +++ b/libraries/chain/son_wallet_withdraw_evaluator.cpp @@ -82,9 +82,16 @@ object_id_type create_son_wallet_withdraw_evaluator::do_apply(const son_wallet_w auto stats_itr = db().get_index_type().indices().get().find(si.son_id); db().modify(*stats_itr, [&op, &si](son_statistics_object &sso) { - sso.total_sidechain_txs_reported = sso.total_sidechain_txs_reported + 1; + if (sso.total_sidechain_txs_reported.find(op.sidechain) == sso.total_sidechain_txs_reported.end()) { + sso.total_sidechain_txs_reported[op.sidechain] = 0; + } + sso.total_sidechain_txs_reported[op.sidechain] += 1; + if (si.son_id == op.son_id) { - sso.sidechain_txs_reported = sso.sidechain_txs_reported + 1; + if (sso.sidechain_txs_reported.find(op.sidechain) == sso.sidechain_txs_reported.end()) { + sso.sidechain_txs_reported[op.sidechain] = 0; + } + sso.sidechain_txs_reported[op.sidechain] += 1; } }); } @@ -120,7 +127,10 @@ object_id_type create_son_wallet_withdraw_evaluator::do_apply(const son_wallet_w }); auto stats_itr = db().get_index_type().indices().get().find(op.son_id); db().modify(*stats_itr, [&op](son_statistics_object &sso) { - sso.sidechain_txs_reported = sso.sidechain_txs_reported + 1; + if (sso.sidechain_txs_reported.find(op.sidechain) == sso.sidechain_txs_reported.end()) { + sso.sidechain_txs_reported[op.sidechain] = 0; + } + sso.sidechain_txs_reported[op.sidechain] += 1; }); return (*itr).id; } diff --git a/libraries/chain/tournament_object.cpp b/libraries/chain/tournament_object.cpp index ad64b34f..056652e5 100644 --- a/libraries/chain/tournament_object.cpp +++ b/libraries/chain/tournament_object.cpp @@ -605,8 +605,9 @@ namespace graphene { namespace chain { return; // We shouldn't be here if the final match is complete - assert(last_complete_round != num_rounds - 1); - if (last_complete_round == num_rounds - 1) + uint32_t last_complete_round_uint32 = last_complete_round; + assert(last_complete_round_uint32 != num_rounds - 1); + if (last_complete_round_uint32 == num_rounds - 1) return; if (first_incomplete_match_was_waiting) diff --git a/libraries/chain/transaction_object.cpp b/libraries/chain/transaction_object.cpp deleted file mode 100644 index fb4f75df..00000000 --- a/libraries/chain/transaction_object.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2015 Cryptonomex, Inc., 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 - -namespace graphene { namespace chain { - -const object* transaction_index::create(const std::function& constructor, object_id_type) -{ - transaction_object obj; - - obj.id = get_next_available_id(); - constructor(&obj); - - auto result = _index.insert(std::move(obj)); - FC_ASSERT(result.second, "Could not create transaction_object! Most likely a uniqueness constraint is violated."); - return &*result.first; -} - -void transaction_index::modify(const object* obj, - const std::function& m) -{ - assert(obj != nullptr); - FC_ASSERT(obj->id < _index.size()); - - const transaction_object* t = dynamic_cast(obj); - assert(t != nullptr); - - auto itr = _index.find(obj->id.instance()); - assert(itr != _index.end()); - _index.modify(itr, [&m](transaction_object& o) { m(&o); }); -} - -void transaction_index::add(unique_ptr o) -{ - assert(o); - object_id_type id = o->id; - assert(id.space() == transaction_object::space_id); - assert(id.type() == transaction_object::type_id); - assert(id.instance() == size()); - - auto trx = dynamic_cast(o.get()); - assert(trx != nullptr); - o.release(); - - auto result = _index.insert(std::move(*trx)); - FC_ASSERT(result.second, "Could not insert transaction_object! Most likely a uniqueness constraint is violated."); -} - -void transaction_index::remove(object_id_type id) -{ - auto& index = _index.get(); - auto itr = index.find(id.instance()); - if( itr == index.end() ) - return; - - assert(id.space() == transaction_object::space_id); - assert(id.type() == transaction_object::type_id); - - index.erase(itr); -} - -const object*transaction_index::get(object_id_type id) const -{ - if( id.type() != transaction_object::type_id || - id.space() != transaction_object::space_id ) - return nullptr; - - auto itr = _index.find(id.instance()); - if( itr == _index.end() ) - return nullptr; - return &*itr; -} - -} } // graphene::chain diff --git a/libraries/db/include/graphene/db/undo_database.hpp b/libraries/db/include/graphene/db/undo_database.hpp index 9f104869..4b727372 100644 --- a/libraries/db/include/graphene/db/undo_database.hpp +++ b/libraries/db/include/graphene/db/undo_database.hpp @@ -59,17 +59,7 @@ namespace graphene { namespace db { { mv._apply_undo = false; } - ~session() { - try { - if( _apply_undo ) _db.undo(); - } - catch ( const fc::exception& e ) - { - elog( "${e}", ("e",e.to_detail_string() ) ); - throw; // maybe crash.. - } - if( _disable_on_exit ) _db.disable(); - } + ~session(); void commit() { _apply_undo = false; _db.commit(); } void undo() { if( _apply_undo ) _db.undo(); _apply_undo = false; } void merge() { if( _apply_undo ) _db.merge(); _apply_undo = false; } diff --git a/libraries/db/undo_database.cpp b/libraries/db/undo_database.cpp index c5f2ef65..bffd761d 100644 --- a/libraries/db/undo_database.cpp +++ b/libraries/db/undo_database.cpp @@ -30,6 +30,18 @@ namespace graphene { namespace db { void undo_database::enable() { _disabled = false; } void undo_database::disable() { _disabled = true; } +undo_database::session::~session() { + try { + if( _apply_undo ) _db.undo(); + } + catch ( const fc::exception& e ) + { + elog( "${e}", ("e",e.to_detail_string() ) ); + std::terminate(); + } + if( _disable_on_exit ) _db.disable(); +} + undo_database::session undo_database::start_undo_session( bool force_enable ) { if( _disabled && !force_enable ) return session(*this); diff --git a/libraries/egenesis/CMakeLists.txt b/libraries/egenesis/CMakeLists.txt index 68de4b00..75589999 100644 --- a/libraries/egenesis/CMakeLists.txt +++ b/libraries/egenesis/CMakeLists.txt @@ -4,7 +4,7 @@ add_library( graphene_egenesis_none include/graphene/egenesis/egenesis.hpp ) -target_link_libraries( graphene_egenesis_none graphene_chain fc ) +target_link_libraries( graphene_egenesis_none graphene_chain ) target_include_directories( graphene_egenesis_none PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) @@ -12,7 +12,7 @@ add_executable( embed_genesis embed_genesis.cpp ) -target_link_libraries( embed_genesis graphene_chain graphene_app graphene_egenesis_none fc ) +target_link_libraries( embed_genesis PRIVATE graphene_app graphene_egenesis_none ) set( embed_genesis_args -t "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl---${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" @@ -42,8 +42,8 @@ add_custom_command( add_library( graphene_egenesis_brief "${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" include/graphene/egenesis/egenesis.hpp ) add_library( graphene_egenesis_full "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" include/graphene/egenesis/egenesis.hpp ) -target_link_libraries( graphene_egenesis_brief graphene_chain fc ) -target_link_libraries( graphene_egenesis_full graphene_chain fc ) +target_link_libraries( graphene_egenesis_brief graphene_chain ) +target_link_libraries( graphene_egenesis_full graphene_chain ) target_include_directories( graphene_egenesis_brief PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/net/CMakeLists.txt b/libraries/net/CMakeLists.txt index 955012e4..1cc71728 100644 --- a/libraries/net/CMakeLists.txt +++ b/libraries/net/CMakeLists.txt @@ -10,12 +10,8 @@ set(SOURCES node.cpp add_library( graphene_net ${SOURCES} ${HEADERS} ) -target_link_libraries( graphene_net - PUBLIC fc graphene_db ) -target_include_directories( graphene_net - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" - PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../chain/include" "${CMAKE_CURRENT_BINARY_DIR}/../chain/include" -) +target_link_libraries( graphene_net graphene_chain ) +target_include_directories( graphene_net PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) if(MSVC) set_source_files_properties( node.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index 14e32306..3222da08 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -2375,6 +2375,7 @@ namespace graphene { namespace net { namespace detail { VERIFY_CORRECT_THREAD(); item_hash_t reference_point = peer->last_block_delegate_has_seen; uint32_t reference_point_block_num = _delegate->get_block_number(peer->last_block_delegate_has_seen); + (void)reference_point_block_num; // when we call _delegate->get_blockchain_synopsis(), we may yield and there's a // chance this peer's state will change before we get control back. Save off @@ -3414,6 +3415,7 @@ namespace graphene { namespace net { namespace detail { for (const item_hash_t& transaction_message_hash : contained_transaction_message_ids) { size_t items_erased = _items_to_fetch.get().erase(item_id(trx_message_type, transaction_message_hash)); + (void)items_erased; // there are two ways we could behave here: we could either act as if we received // the transaction outside the block and offer it to our peers, or we could just // forget about it (we would still advertise this block to our peers so they should diff --git a/libraries/plugins/CMakeLists.txt b/libraries/plugins/CMakeLists.txt index d2a5be16..20497629 100644 --- a/libraries/plugins/CMakeLists.txt +++ b/libraries/plugins/CMakeLists.txt @@ -1,14 +1,14 @@ -add_subdirectory( witness ) add_subdirectory( account_history ) add_subdirectory( accounts_list ) add_subdirectory( affiliate_stats ) -add_subdirectory( elasticsearch ) -add_subdirectory( market_history ) -add_subdirectory( delayed_node ) add_subdirectory( bookie ) +add_subdirectory( debug_witness ) +add_subdirectory( delayed_node ) +add_subdirectory( elasticsearch ) +add_subdirectory( es_objects ) add_subdirectory( generate_genesis ) add_subdirectory( generate_uia_sharedrop_genesis ) -add_subdirectory( debug_witness ) -add_subdirectory( snapshot ) +add_subdirectory( market_history ) add_subdirectory( peerplays_sidechain ) -add_subdirectory( es_objects ) +add_subdirectory( snapshot ) +add_subdirectory( witness ) diff --git a/libraries/plugins/account_history/CMakeLists.txt b/libraries/plugins/account_history/CMakeLists.txt index 4af81abb..4a40fba8 100644 --- a/libraries/plugins/account_history/CMakeLists.txt +++ b/libraries/plugins/account_history/CMakeLists.txt @@ -4,7 +4,7 @@ add_library( graphene_account_history account_history_plugin.cpp ) -target_link_libraries( graphene_account_history graphene_chain graphene_app ) +target_link_libraries( graphene_account_history PRIVATE graphene_plugin ) target_include_directories( graphene_account_history PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/accounts_list/CMakeLists.txt b/libraries/plugins/accounts_list/CMakeLists.txt index 3c2747c2..b337409e 100644 --- a/libraries/plugins/accounts_list/CMakeLists.txt +++ b/libraries/plugins/accounts_list/CMakeLists.txt @@ -4,7 +4,7 @@ add_library( graphene_accounts_list accounts_list_plugin.cpp ) -target_link_libraries( graphene_accounts_list graphene_chain graphene_app ) +target_link_libraries( graphene_accounts_list PRIVATE graphene_plugin ) target_include_directories( graphene_accounts_list PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/affiliate_stats/CMakeLists.txt b/libraries/plugins/affiliate_stats/CMakeLists.txt index fec2544c..60b2d6e2 100644 --- a/libraries/plugins/affiliate_stats/CMakeLists.txt +++ b/libraries/plugins/affiliate_stats/CMakeLists.txt @@ -5,7 +5,7 @@ add_library( graphene_affiliate_stats affiliate_stats_plugin.cpp ) -target_link_libraries( graphene_affiliate_stats graphene_chain graphene_app ) +target_link_libraries( graphene_affiliate_stats PRIVATE graphene_plugin graphene_account_history ) target_include_directories( graphene_affiliate_stats PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/bookie/CMakeLists.txt b/libraries/plugins/bookie/CMakeLists.txt index 12d84e3c..d7c6d4c0 100644 --- a/libraries/plugins/bookie/CMakeLists.txt +++ b/libraries/plugins/bookie/CMakeLists.txt @@ -5,7 +5,7 @@ add_library( graphene_bookie bookie_api.cpp ) -target_link_libraries( graphene_bookie graphene_chain graphene_app ) +target_link_libraries( graphene_bookie PRIVATE graphene_plugin ) target_include_directories( graphene_bookie PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/debug_witness/CMakeLists.txt b/libraries/plugins/debug_witness/CMakeLists.txt index f0fcb7fb..ac7d7fc9 100644 --- a/libraries/plugins/debug_witness/CMakeLists.txt +++ b/libraries/plugins/debug_witness/CMakeLists.txt @@ -5,7 +5,7 @@ add_library( graphene_debug_witness debug_witness.cpp ) -target_link_libraries( graphene_debug_witness graphene_chain graphene_app ) +target_link_libraries( graphene_debug_witness PRIVATE graphene_plugin ) target_include_directories( graphene_debug_witness PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/delayed_node/CMakeLists.txt b/libraries/plugins/delayed_node/CMakeLists.txt index 63dd73e5..d481eb84 100644 --- a/libraries/plugins/delayed_node/CMakeLists.txt +++ b/libraries/plugins/delayed_node/CMakeLists.txt @@ -4,7 +4,7 @@ add_library( graphene_delayed_node delayed_node_plugin.cpp ) -target_link_libraries( graphene_delayed_node graphene_chain graphene_app ) +target_link_libraries( graphene_delayed_node PRIVATE graphene_plugin graphene_accounts_list graphene_affiliate_stats graphene_bookie graphene_debug_witness graphene_elasticsearch graphene_market_history ) target_include_directories( graphene_delayed_node PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/elasticsearch/CMakeLists.txt b/libraries/plugins/elasticsearch/CMakeLists.txt index f4815576..928d2e3c 100644 --- a/libraries/plugins/elasticsearch/CMakeLists.txt +++ b/libraries/plugins/elasticsearch/CMakeLists.txt @@ -4,13 +4,21 @@ add_library( graphene_elasticsearch elasticsearch_plugin.cpp ) -target_link_libraries( graphene_elasticsearch graphene_chain graphene_app curl ) -target_include_directories( graphene_elasticsearch - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) +find_curl() +include_directories(${CURL_INCLUDE_DIRS}) if(MSVC) set_source_files_properties(elasticsearch_plugin.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) endif(MSVC) +if(CURL_STATICLIB) + SET_TARGET_PROPERTIES(graphene_elasticsearch PROPERTIES + COMPILE_DEFINITIONS "CURL_STATICLIB") +endif(CURL_STATICLIB) +target_link_libraries( graphene_elasticsearch PRIVATE graphene_plugin ${CURL_LIBRARIES} ) +target_include_directories( graphene_elasticsearch + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" + PUBLIC "${CURL_INCLUDE_DIR}" ) + install( TARGETS graphene_elasticsearch diff --git a/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp index dc167b05..8777c06d 100644 --- a/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp +++ b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp @@ -57,9 +57,9 @@ class elasticsearch_plugin_impl bool _elasticsearch_visitor = false; std::string _elasticsearch_basic_auth = ""; std::string _elasticsearch_index_prefix = "peerplays-"; - bool _elasticsearch_operation_object = false; + bool _elasticsearch_operation_object = true; uint32_t _elasticsearch_start_es_after_block = 0; - bool _elasticsearch_operation_string = true; + bool _elasticsearch_operation_string = false; mode _elasticsearch_mode = mode::only_save; CURL *curl; // curl handler vector bulk_lines; // vector of op lines @@ -75,20 +75,19 @@ class elasticsearch_plugin_impl std::string bulk_line; std::string index_name; bool is_sync = false; - fc::time_point last_sync; private: bool add_elasticsearch( const account_id_type account_id, const optional& oho, const uint32_t block_number ); const account_transaction_history_object& addNewEntry(const account_statistics_object& stats_obj, - const account_id_type account_id, + const account_id_type& account_id, const optional & oho); - const account_statistics_object& getStatsObject(const account_id_type account_id); + const account_statistics_object& getStatsObject(const account_id_type& account_id); void growStats(const account_statistics_object& stats_obj, const account_transaction_history_object& ath); void getOperationType(const optional & oho); void doOperationHistory(const optional & oho); - void doBlock(const optional & oho, const signed_block& b); + void doBlock(uint32_t trx_in_block, const signed_block& b); void doVisitor(const optional & oho); void checkState(const fc::time_point_sec& block_time); - void cleanObjects(const account_transaction_history_object& ath, account_id_type account_id); + void cleanObjects(const account_transaction_history_id_type& ath, const account_id_type& account_id); void createBulkLine(const account_transaction_history_object& ath); void prepareBulk(const account_transaction_history_id_type& ath_id); void populateESstruct(); @@ -148,7 +147,7 @@ bool elasticsearch_plugin_impl::update_account_histories( const signed_block& b // populate what we can before impacted loop getOperationType(oho); doOperationHistory(oho); - doBlock(oho, b); + doBlock(oho->trx_in_block, b); if(_elasticsearch_visitor) doVisitor(oho); @@ -174,7 +173,11 @@ bool elasticsearch_plugin_impl::update_account_histories( const signed_block& b for( auto& account_id : impacted ) { if(!add_elasticsearch( account_id, oho, b.block_num() )) + { + elog( "Error adding data to Elastic Search: block num ${b}, account ${a}, data ${d}", + ("b",b.block_num()) ("a",account_id) ("d", oho) ); return false; + } } } // we send bulk at end of block when we are in sync for better real time client experience @@ -185,23 +188,33 @@ bool elasticsearch_plugin_impl::update_account_histories( const signed_block& b { prepare.clear(); if(!graphene::utilities::SendBulk(es)) + { + // Note: although called with `std::move()`, `es` is not updated in `SendBulk()` + elog( "Error sending ${n} lines of bulk data to Elastic Search, the first lines are:", + ("n",es.bulk_lines.size()) ); + for( size_t i = 0; i < es.bulk_lines.size() && i < 10; ++i ) + { + edump( (es.bulk_lines[i]) ); + } return false; + } else bulk_lines.clear(); } } + if(bulk_lines.size() != limit_documents) + bulk_lines.reserve(limit_documents); + return true; } void elasticsearch_plugin_impl::checkState(const fc::time_point_sec& block_time) { - fc::time_point current_time(fc::time_point::now()); - if(((current_time - block_time) < fc::seconds(30)) || (current_time - last_sync > fc::seconds(60))) + if((fc::time_point::now() - block_time) < fc::seconds(30)) { limit_documents = _elasticsearch_bulk_sync; is_sync = true; - last_sync = current_time; } else { @@ -232,11 +245,11 @@ void elasticsearch_plugin_impl::doOperationHistory(const optional op); } -void elasticsearch_plugin_impl::doBlock(const optional & oho, const signed_block& b) +void elasticsearch_plugin_impl::doBlock(uint32_t trx_in_block, const signed_block& b) { std::string trx_id = ""; - if(oho->trx_in_block < b.transactions.size()) - trx_id = b.transactions[oho->trx_in_block].id().str(); + if(trx_in_block < b.transactions.size()) + trx_id = b.transactions[trx_in_block].id().str(); bs.block_num = b.block_num(); bs.block_time = b.timestamp; bs.trx_id = trx_id; @@ -244,23 +257,41 @@ void elasticsearch_plugin_impl::doBlock(const optional & oho) { + graphene::chain::database& db = database(); + operation_visitor o_v; oho->op.visit(o_v); + auto fee_asset = o_v.fee_asset(db); vs.fee_data.asset = o_v.fee_asset; + vs.fee_data.asset_name = fee_asset.symbol; vs.fee_data.amount = o_v.fee_amount; + vs.fee_data.amount_units = (o_v.fee_amount.value)/(double)asset::scaled_precision(fee_asset.precision).value; + auto transfer_asset = o_v.transfer_asset_id(db); vs.transfer_data.asset = o_v.transfer_asset_id; + vs.transfer_data.asset_name = transfer_asset.symbol; vs.transfer_data.amount = o_v.transfer_amount; + vs.transfer_data.amount_units = (o_v.transfer_amount.value)/(double)asset::scaled_precision(transfer_asset.precision).value; vs.transfer_data.from = o_v.transfer_from; vs.transfer_data.to = o_v.transfer_to; + auto fill_pays_asset = o_v.fill_pays_asset_id(db); + auto fill_receives_asset = o_v.fill_receives_asset_id(db); vs.fill_data.order_id = o_v.fill_order_id; vs.fill_data.account_id = o_v.fill_account_id; vs.fill_data.pays_asset_id = o_v.fill_pays_asset_id; + vs.fill_data.pays_asset_name = fill_pays_asset.symbol; vs.fill_data.pays_amount = o_v.fill_pays_amount; + vs.fill_data.pays_amount_units = (o_v.fill_pays_amount.value)/(double)asset::scaled_precision(fill_pays_asset.precision).value; vs.fill_data.receives_asset_id = o_v.fill_receives_asset_id; + vs.fill_data.receives_asset_name = fill_receives_asset.symbol; vs.fill_data.receives_amount = o_v.fill_receives_amount; + vs.fill_data.receives_amount_units = (o_v.fill_receives_amount.value)/(double)asset::scaled_precision(fill_receives_asset.precision).value; + + auto fill_price = (o_v.fill_receives_amount.value/(double)asset::scaled_precision(fill_receives_asset.precision).value) / + (o_v.fill_pays_amount.value/(double)asset::scaled_precision(fill_pays_asset.precision).value); + vs.fill_data.fill_price_units = fill_price; //vs.fill_data.fill_price = o_v.fill_fill_price; //vs.fill_data.is_maker = o_v.fill_is_maker; } @@ -276,13 +307,22 @@ bool elasticsearch_plugin_impl::add_elasticsearch( const account_id_type account createBulkLine(ath); prepareBulk(ath.id); } - cleanObjects(ath, account_id); + cleanObjects(ath.id, account_id); if (curl && bulk_lines.size() >= limit_documents) { // we are in bulk time, ready to add data to elasticsearech prepare.clear(); populateESstruct(); if(!graphene::utilities::SendBulk(es)) + { + // Note: although called with `std::move()`, `es` is not updated in `SendBulk()` + elog( "Error sending ${n} lines of bulk data to Elastic Search, the first lines are:", + ("n",es.bulk_lines.size()) ); + for( size_t i = 0; i < es.bulk_lines.size() && i < 10; ++i ) + { + edump( (es.bulk_lines[i]) ); + } return false; + } else bulk_lines.clear(); } @@ -290,15 +330,16 @@ bool elasticsearch_plugin_impl::add_elasticsearch( const account_id_type account return true; } -const account_statistics_object& elasticsearch_plugin_impl::getStatsObject(const account_id_type account_id) +const account_statistics_object& elasticsearch_plugin_impl::getStatsObject(const account_id_type& account_id) { graphene::chain::database& db = database(); - const auto &acct = db.get(account_id); - return acct.statistics(db); + const auto &stats_obj = db.get_account_stats_by_owner(account_id); + + return stats_obj; } const account_transaction_history_object& elasticsearch_plugin_impl::addNewEntry(const account_statistics_object& stats_obj, - const account_id_type account_id, + const account_id_type& account_id, const optional & oho) { graphene::chain::database& db = database(); @@ -340,19 +381,21 @@ void elasticsearch_plugin_impl::prepareBulk(const account_transaction_history_id fc::mutable_variant_object bulk_header; bulk_header["_index"] = index_name; bulk_header["_type"] = "data"; - bulk_header["_id"] = fc::to_string(ath_id.space_id) + "." + fc::to_string(ath_id.type_id) + "." + ath_id.instance; - prepare = graphene::utilities::createBulk(bulk_header, bulk_line); - bulk_lines.insert(bulk_lines.end(), prepare.begin(), prepare.end()); + bulk_header["_id"] = fc::to_string(ath_id.space_id) + "." + fc::to_string(ath_id.type_id) + "." + + fc::to_string(ath_id.instance.value); + prepare = graphene::utilities::createBulk(bulk_header, std::move(bulk_line)); + std::move(prepare.begin(), prepare.end(), std::back_inserter(bulk_lines)); + prepare.clear(); } -void elasticsearch_plugin_impl::cleanObjects(const account_transaction_history_object& ath, account_id_type account_id) +void elasticsearch_plugin_impl::cleanObjects(const account_transaction_history_id_type& ath_id, const account_id_type& account_id) { graphene::chain::database& db = database(); // remove everything except current object from ath const auto &his_idx = db.get_index_type(); const auto &by_seq_idx = his_idx.indices().get(); auto itr = by_seq_idx.lower_bound(boost::make_tuple(account_id, 0)); - if (itr != by_seq_idx.end() && itr->account == account_id && itr->id != ath.id) { + if (itr != by_seq_idx.end() && itr->account == account_id && itr->id != ath_id) { // if found, remove the entry const auto remove_op_id = itr->operation_id; const auto itr_remove = itr; @@ -377,9 +420,12 @@ void elasticsearch_plugin_impl::cleanObjects(const account_transaction_history_o void elasticsearch_plugin_impl::populateESstruct() { es.curl = curl; - es.bulk_lines = bulk_lines; + es.bulk_lines = std::move(bulk_lines); es.elasticsearch_url = _elasticsearch_node_url; es.auth = _elasticsearch_basic_auth; + es.index_prefix = _elasticsearch_index_prefix; + es.endpoint = ""; + es.query = ""; } } // end namespace detail @@ -421,11 +467,11 @@ void elasticsearch_plugin::plugin_set_program_options( ("elasticsearch-index-prefix", boost::program_options::value(), "Add a prefix to the index(peerplays-)") ("elasticsearch-operation-object", boost::program_options::value(), - "Save operation as object(false)") + "Save operation as object(true)") ("elasticsearch-start-es-after-block", boost::program_options::value(), "Start doing ES job after block(0)") ("elasticsearch-operation-string", boost::program_options::value(), - "Save operation as string. Needed to serve history api calls(true)") + "Save operation as string. Needed to serve history api calls(false)") ("elasticsearch-mode", boost::program_options::value(), "Mode of operation: only_save(0), only_query(1), all(2) - Default: 0") ; @@ -467,18 +513,18 @@ void elasticsearch_plugin::plugin_initialize(const boost::program_options::varia if (options.count("elasticsearch-mode")) { const auto option_number = options["elasticsearch-mode"].as(); if(option_number > mode::all) - FC_THROW_EXCEPTION(fc::exception, "Elasticsearch mode not valid"); + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Elasticsearch mode not valid"); my->_elasticsearch_mode = static_cast(options["elasticsearch-mode"].as()); } if(my->_elasticsearch_mode != mode::only_query) { if (my->_elasticsearch_mode == mode::all && !my->_elasticsearch_operation_string) - FC_THROW_EXCEPTION(fc::exception, + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "If elasticsearch-mode is set to all then elasticsearch-operation-string need to be true"); database().applied_block.connect([this](const signed_block &b) { if (!my->update_account_histories(b)) - FC_THROW_EXCEPTION(fc::exception, + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error populating ES database, we are going to keep trying."); }); } @@ -563,13 +609,12 @@ vector elasticsearch_plugin::get_account_history( const auto response = graphene::utilities::simpleQuery(es); variant variant_response = fc::json::from_string(response); - const auto hits = variant_response["hits"]["total"]["value"]; + const auto hits = variant_response["hits"]["total"]; uint32_t size; if( hits.is_object() ) // ES-7 ? size = static_cast(hits["value"].as_uint64()); else // probably ES-6 size = static_cast(hits.as_uint64()); - size = std::min( size, limit ); for(unsigned i=0; i #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include namespace graphene { namespace es_objects { @@ -61,6 +77,16 @@ class es_objects_plugin_impl bool _es_objects_balances = true; bool _es_objects_limit_orders = true; bool _es_objects_asset_bitasset = true; + + bool _es_objects_account_role = true; + bool _es_objects_committee_member = true; + bool _es_objects_nft = true; + bool _es_objects_son = true; + bool _es_objects_transaction = true; + bool _es_objects_vesting_balance = true; + bool _es_objects_witness = true; + bool _es_objects_worker = true; + std::string _es_objects_index_prefix = "ppobjects-"; uint32_t _es_objects_start_es_after_block = 0; CURL *curl; // curl handler @@ -79,7 +105,6 @@ class es_objects_plugin_impl bool es_objects_plugin_impl::genesis() { - ilog("elasticsearch OBJECTS: inserting data from genesis"); graphene::chain::database &db = _self.database(); @@ -112,13 +137,142 @@ bool es_objects_plugin_impl::genesis() }); } + if (_es_objects_account_role) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "account_role"); + }); + } + if (_es_objects_committee_member) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "committee_member"); + }); + } + if (_es_objects_nft) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "nft"); + }); + } + if (_es_objects_nft) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "nft_metadata"); + }); + } + if (_es_objects_nft) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "offer"); + }); + } + if (_es_objects_son) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "sidechain_address"); + }); + } + if (_es_objects_son) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "sidechain_transaction"); + }); + } + if (_es_objects_son) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "son"); + }); + } + if (_es_objects_son) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "son_proposal"); + }); + } + if (_es_objects_son) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "son_wallet"); + }); + } + if (_es_objects_son) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "son_wallet_deposit"); + }); + } + if (_es_objects_son) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "son_wallet_withdraw"); + }); + } + if (_es_objects_transaction) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "transaction"); + }); + } + if (_es_objects_vesting_balance) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "vesting_balance"); + }); + } + if (_es_objects_witness) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "witness"); + }); + } + if (_es_objects_worker) { + auto &idx = db.get_index_type(); + idx.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "worker"); + }); + } + graphene::utilities::ES es; es.curl = curl; es.bulk_lines = bulk; es.elasticsearch_url = _es_objects_elasticsearch_url; es.auth = _es_objects_auth; if (!graphene::utilities::SendBulk(es)) - FC_THROW_EXCEPTION(fc::exception, "Error inserting genesis data."); + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error inserting genesis data."); else bulk.clear(); @@ -197,6 +351,150 @@ bool es_objects_plugin_impl::index_database(const vector& ids, s else prepareTemplate(*ba, "bitasset"); } + } else if (value.is() && _es_objects_account_role) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "account_role"); + else + prepareTemplate(*ba, "account_role"); + } + } else if (value.is() && _es_objects_committee_member) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "committee_member"); + else + prepareTemplate(*ba, "committee_member"); + } + } else if (value.is() && _es_objects_nft) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "nft"); + else + prepareTemplate(*ba, "nft"); + } + } else if (value.is() && _es_objects_nft) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "nft_metadata"); + else + prepareTemplate(*ba, "nft_metadata"); + } + } else if (value.is() && _es_objects_nft) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "offer"); + else + prepareTemplate(*ba, "offer"); + } + } else if (value.is() && _es_objects_son) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "sidechain_address"); + else + prepareTemplate(*ba, "sidechain_address"); + } + } else if (value.is() && _es_objects_son) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "sidechain_transaction"); + else + prepareTemplate(*ba, "sidechain_transaction"); + } + } else if (value.is() && _es_objects_son) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "son"); + else + prepareTemplate(*ba, "son"); + } + } else if (value.is() && _es_objects_son) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "son_proposal"); + else + prepareTemplate(*ba, "son_proposal"); + } + } else if (value.is() && _es_objects_son) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "son_wallet"); + else + prepareTemplate(*ba, "son_wallet"); + } + } else if (value.is() && _es_objects_son) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "son_wallet_deposit"); + else + prepareTemplate(*ba, "son_wallet_deposit"); + } + } else if (value.is() && _es_objects_son) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "son_wallet_withdraw"); + else + prepareTemplate(*ba, "son_wallet_withdraw"); + } + } else if (value.is() && _es_objects_transaction) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "transaction"); + else + prepareTemplate(*ba, "transaction"); + } + } else if (value.is() && _es_objects_vesting_balance) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "vesting_balance"); + else + prepareTemplate(*ba, "vesting_balance"); + } + } else if (value.is() && _es_objects_witness) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "witness"); + else + prepareTemplate(*ba, "witness"); + } + } else if (value.is() && _es_objects_worker) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "worker"); + else + prepareTemplate(*ba, "worker"); + } } } @@ -296,52 +594,39 @@ void es_objects_plugin::plugin_set_program_options( ) { cli.add_options() - ("es-objects-elasticsearch-url", boost::program_options::value(), "Elasticsearch node url(http://localhost:9200/)") + ("es-objects-elasticsearch-url", boost::program_options::value(), + "Elasticsearch node url(http://localhost:9200/)") ("es-objects-auth", boost::program_options::value(), "Basic auth username:password('')") - ("es-objects-bulk-replay", boost::program_options::value(), "Number of bulk documents to index on replay(10000)") - ("es-objects-bulk-sync", boost::program_options::value(), "Number of bulk documents to index on a synchronized chain(100)") + ("es-objects-bulk-replay", boost::program_options::value(), + "Number of bulk documents to index on replay(10000)") + ("es-objects-bulk-sync", boost::program_options::value(), + "Number of bulk documents to index on a synchronized chain(100)") ("es-objects-proposals", boost::program_options::value(), "Store proposal objects(true)") ("es-objects-accounts", boost::program_options::value(), "Store account objects(true)") ("es-objects-assets", boost::program_options::value(), "Store asset objects(true)") ("es-objects-balances", boost::program_options::value(), "Store balances objects(true)") - ("es-objects-limit-orders", boost::program_options::value(), "Store limit order objects(true)") - ("es-objects-asset-bitasset", boost::program_options::value(), "Store feed data(true)") - ("es-objects-index-prefix", boost::program_options::value(), "Add a prefix to the index(ppobjects-)") - ("es-objects-keep-only-current", boost::program_options::value(), "Keep only current state of the objects(true)") - ("es-objects-start-es-after-block", boost::program_options::value(), "Start doing ES job after block(0)") + ("es-objects-limit-orders", boost::program_options::value(), "Store limit order objects(false)") + ("es-objects-bitasset", boost::program_options::value(), "Store feed data(true)") + ("es-objects-account-role", boost::program_options::value(), "Store account role objects (true)") + ("es-objects-committee-member", boost::program_options::value(), "Store committee member objects(true)") + ("es-objects-nft", boost::program_options::value(), "Store nft objects (true)") + ("es-objects-son", boost::program_options::value(), "Store son objects (true)") + ("es-objects-transaction", boost::program_options::value(), "Store transaction objects (true)") + ("es-objects-vesting-balance", boost::program_options::value(), "Store vesting balance objects (true)") + ("es-objects-witness", boost::program_options::value(), "Store witness objects (true)") + ("es-objects-worker", boost::program_options::value(), "Store worker objects (true)") + ("es-objects-index-prefix", boost::program_options::value(), + "Add a prefix to the index(ppobjects-)") + ("es-objects-keep-only-current", boost::program_options::value(), + "Keep only current state of the objects(true)") + ("es-objects-start-es-after-block", boost::program_options::value(), + "Start doing ES job after block(0)") ; cfg.add(cli); } void es_objects_plugin::plugin_initialize(const boost::program_options::variables_map& options) { - database().applied_block.connect([this](const signed_block &b) { - if(b.block_num() == 1) { - if (!my->genesis()) - FC_THROW_EXCEPTION(fc::exception, "Error populating genesis data."); - } - }); - - database().new_objects.connect([this]( const vector& ids, const flat_set& impacted_accounts ) { - if(!my->index_database(ids, "create")) - { - FC_THROW_EXCEPTION(fc::exception, "Error creating object from ES database, we are going to keep trying."); - } - }); - database().changed_objects.connect([this]( const vector& ids, const flat_set& impacted_accounts ) { - if(!my->index_database(ids, "update")) - { - FC_THROW_EXCEPTION(fc::exception, "Error updating object from ES database, we are going to keep trying."); - } - }); - database().removed_objects.connect([this](const vector& ids, const vector& objs, const flat_set& impacted_accounts) { - if(!my->index_database(ids, "delete")) - { - FC_THROW_EXCEPTION(fc::exception, "Error deleting object from ES database, we are going to keep trying."); - } - }); - - if (options.count("es-objects-elasticsearch-url")) { my->_es_objects_elasticsearch_url = options["es-objects-elasticsearch-url"].as(); } @@ -372,6 +657,30 @@ void es_objects_plugin::plugin_initialize(const boost::program_options::variable if (options.count("es-objects-asset-bitasset")) { my->_es_objects_asset_bitasset = options["es-objects-asset-bitasset"].as(); } + if (options.count("es-objects-account-role")) { + my->_es_objects_balances = options["es-objects-account-role"].as(); + } + if (options.count("es-objects-committee-member")) { + my->_es_objects_balances = options["es-objects-committee-member"].as(); + } + if (options.count("es-objects-nft")) { + my->_es_objects_balances = options["es-objects-nft"].as(); + } + if (options.count("es-objects-son")) { + my->_es_objects_balances = options["es-objects-son"].as(); + } + if (options.count("es-objects-transaction")) { + my->_es_objects_balances = options["es-objects-transaction"].as(); + } + if (options.count("es-objects-vesting-balance")) { + my->_es_objects_balances = options["es-objects-vesting-balance"].as(); + } + if (options.count("es-objects-witness")) { + my->_es_objects_balances = options["es-objects-witness"].as(); + } + if (options.count("es-objects-worker")) { + my->_es_objects_balances = options["es-objects-worker"].as(); + } if (options.count("es-objects-index-prefix")) { my->_es_objects_index_prefix = options["es-objects-index-prefix"].as(); } @@ -381,6 +690,37 @@ void es_objects_plugin::plugin_initialize(const boost::program_options::variable if (options.count("es-objects-start-es-after-block")) { my->_es_objects_start_es_after_block = options["es-objects-start-es-after-block"].as(); } + + database().applied_block.connect([this](const signed_block &b) { + if(b.block_num() == 1 && my->_es_objects_start_es_after_block == 0) { + if (!my->genesis()) + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error populating genesis data."); + } + }); + database().new_objects.connect([this]( const vector& ids, + const flat_set& impacted_accounts ) { + if(!my->index_database(ids, "create")) + { + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, + "Error creating object from ES database, we are going to keep trying."); + } + }); + database().changed_objects.connect([this]( const vector& ids, + const flat_set& impacted_accounts ) { + if(!my->index_database(ids, "update")) + { + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, + "Error updating object from ES database, we are going to keep trying."); + } + }); + database().removed_objects.connect([this](const vector& ids, + const vector& objs, const flat_set& impacted_accounts) { + if(!my->index_database(ids, "delete")) + { + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, + "Error deleting object from ES database, we are going to keep trying."); + } + }); } void es_objects_plugin::plugin_startup() @@ -396,4 +736,4 @@ void es_objects_plugin::plugin_startup() ilog("elasticsearch OBJECTS: plugin_startup() begin"); } -} } +} } \ No newline at end of file diff --git a/libraries/plugins/generate_genesis/CMakeLists.txt b/libraries/plugins/generate_genesis/CMakeLists.txt index 45ad5719..acc24202 100644 --- a/libraries/plugins/generate_genesis/CMakeLists.txt +++ b/libraries/plugins/generate_genesis/CMakeLists.txt @@ -4,7 +4,7 @@ add_library( graphene_generate_genesis generate_genesis.cpp ) -target_link_libraries( graphene_generate_genesis graphene_chain graphene_app graphene_time ) +target_link_libraries( graphene_generate_genesis PRIVATE graphene_plugin ) target_include_directories( graphene_generate_genesis PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/generate_uia_sharedrop_genesis/CMakeLists.txt b/libraries/plugins/generate_uia_sharedrop_genesis/CMakeLists.txt index d2a50ab6..737e7614 100644 --- a/libraries/plugins/generate_uia_sharedrop_genesis/CMakeLists.txt +++ b/libraries/plugins/generate_uia_sharedrop_genesis/CMakeLists.txt @@ -4,7 +4,7 @@ add_library( graphene_generate_uia_sharedrop_genesis generate_uia_sharedrop_genesis.cpp ) -target_link_libraries( graphene_generate_uia_sharedrop_genesis graphene_chain graphene_app graphene_time ) +target_link_libraries( graphene_generate_uia_sharedrop_genesis PRIVATE graphene_plugin ) target_include_directories( graphene_generate_uia_sharedrop_genesis PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/grouped_orders/grouped_orders_plugin.cpp b/libraries/plugins/grouped_orders/grouped_orders_plugin.cpp deleted file mode 100644 index ef1ae04c..00000000 --- a/libraries/plugins/grouped_orders/grouped_orders_plugin.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2018 Abit More, 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 - -#include - -namespace graphene { namespace grouped_orders { - -namespace detail -{ - -class grouped_orders_plugin_impl -{ - public: - grouped_orders_plugin_impl(grouped_orders_plugin& _plugin) - :_self( _plugin ) {} - virtual ~grouped_orders_plugin_impl(); - - graphene::chain::database& database() - { - return _self.database(); - } - - grouped_orders_plugin& _self; - flat_set _tracked_groups; -}; - -/** - * @brief This secondary index is used to track changes on limit order objects. - */ -class limit_order_group_index : public secondary_index -{ - public: - limit_order_group_index( const flat_set& groups ) : _tracked_groups( groups ) {}; - - 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 flat_set& get_tracked_groups() const - { return _tracked_groups; } - - const map< limit_order_group_key, limit_order_group_data >& get_order_groups() const - { return _og_data; } - - private: - void remove_order( const limit_order_object& obj, bool remove_empty = true ); - - /** tracked groups */ - flat_set _tracked_groups; - - /** maps the group key to group data */ - map< limit_order_group_key, limit_order_group_data > _og_data; -}; - -void limit_order_group_index::object_inserted( const object& objct ) -{ try { - const limit_order_object& o = static_cast( objct ); - - auto& idx = _og_data; - - for( uint16_t group : get_tracked_groups() ) - { - auto create_ogo = [&]() { - idx[ limit_order_group_key( group, o.sell_price ) ] = limit_order_group_data( o.sell_price, o.for_sale ); - }; - // if idx is empty, insert this order - // Note: not capped - if( idx.empty() ) - { - create_ogo(); - continue; - } - - // cap the price - price capped_price = o.sell_price; - price max = o.sell_price.max(); - price min = o.sell_price.min(); - bool capped_max = false; - bool capped_min = false; - if( o.sell_price > max ) - { - capped_price = max; - capped_max = true; - } - else if( o.sell_price < min ) - { - capped_price = min; - capped_min = true; - } - // if idx is not empty, find the group that is next to this order - auto itr = idx.lower_bound( limit_order_group_key( group, capped_price ) ); - bool check_previous = false; - if( itr == idx.end() || itr->first.group != group - || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id - || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id ) - // not same market or group type - check_previous = true; - else // same market and group type - { - bool update_max = false; - if( capped_price > itr->second.max_price ) // implies itr->min_price <= itr->max_price < max - { - update_max = true; - price max_price = itr->first.min_price * ratio_type( GRAPHENE_100_PERCENT + group, GRAPHENE_100_PERCENT ); - // max_price should have been capped here - if( capped_price > max_price ) // new order is out of range - check_previous = true; - } - if( !check_previous ) // new order is within the range - { - if( capped_min && o.sell_price < itr->first.min_price ) - { // need to update itr->min_price here, if itr is below min, and new order is even lower - // TODO improve performance - limit_order_group_data data( itr->second.max_price, o.for_sale + itr->second.total_for_sale ); - idx.erase( itr ); - idx[ limit_order_group_key( group, o.sell_price ) ] = data; - } - else - { - if( update_max || ( capped_max && o.sell_price > itr->second.max_price ) ) - itr->second.max_price = o.sell_price; // store real price here, not capped - itr->second.total_for_sale += o.for_sale; - } - } - } - - if( check_previous ) - { - if( itr == idx.begin() ) // no previous - create_ogo(); - else - { - --itr; // should be valid - if( itr->first.group != group || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id - || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id ) - // not same market or group type - create_ogo(); - else // same market and group type - { - // due to lower_bound, always true: capped_price < itr->first.min_price, so no need to check again, - // if new order is in range of itr group, always need to update itr->first.min_price, unless - // o.sell_price is higher than max - price min_price = itr->second.max_price / ratio_type( GRAPHENE_100_PERCENT + group, GRAPHENE_100_PERCENT ); - // min_price should have been capped here - if( capped_price < min_price ) // new order is out of range - create_ogo(); - else if( capped_max && o.sell_price >= itr->first.min_price ) - { // itr is above max, and price of new order is even higher - if( o.sell_price > itr->second.max_price ) - itr->second.max_price = o.sell_price; - itr->second.total_for_sale += o.for_sale; - } - else - { // new order is within the range - // TODO improve performance - limit_order_group_data data( itr->second.max_price, o.for_sale + itr->second.total_for_sale ); - idx.erase( itr ); - idx[ limit_order_group_key( group, o.sell_price ) ] = data; - } - } - } - } - } -} FC_CAPTURE_AND_RETHROW( (objct) ); } - -void limit_order_group_index::object_removed( const object& objct ) -{ try { - const limit_order_object& o = static_cast( objct ); - remove_order( o ); -} FC_CAPTURE_AND_RETHROW( (objct) ); } - -void limit_order_group_index::about_to_modify( const object& objct ) -{ try { - const limit_order_object& o = static_cast( objct ); - remove_order( o, false ); -} FC_CAPTURE_AND_RETHROW( (objct) ); } - -void limit_order_group_index::object_modified( const object& objct ) -{ try { - object_inserted( objct ); -} FC_CAPTURE_AND_RETHROW( (objct) ); } - -void limit_order_group_index::remove_order( const limit_order_object& o, bool remove_empty ) -{ - auto& idx = _og_data; - - for( uint16_t group : get_tracked_groups() ) - { - // find the group that should contain this order - auto itr = idx.lower_bound( limit_order_group_key( group, o.sell_price ) ); - if( itr == idx.end() || itr->first.group != group - || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id - || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id - || itr->second.max_price < o.sell_price ) - { - // can not find corresponding group, should not happen - wlog( "can not find the order group containing order for removing (price dismatch): ${o}", ("o",o) ); - continue; - } - else // found - { - if( itr->second.total_for_sale < o.for_sale ) - // should not happen - wlog( "can not find the order group containing order for removing (amount dismatch): ${o}", ("o",o) ); - else if( !remove_empty || itr->second.total_for_sale > o.for_sale ) - itr->second.total_for_sale -= o.for_sale; - else - // it's the only order in the group and need to be removed - idx.erase( itr ); - } - } -} - -grouped_orders_plugin_impl::~grouped_orders_plugin_impl() -{} - -} // end namespace detail - - -grouped_orders_plugin::grouped_orders_plugin() : - my( new detail::grouped_orders_plugin_impl(*this) ) -{ -} - -grouped_orders_plugin::~grouped_orders_plugin() -{ -} - -std::string grouped_orders_plugin::plugin_name()const -{ - return "grouped_orders"; -} - -void grouped_orders_plugin::plugin_set_program_options( - boost::program_options::options_description& cli, - boost::program_options::options_description& cfg - ) -{ - cli.add_options() - ("tracked-groups", boost::program_options::value()->default_value("[10,100]"), // 0.1% and 1% - "Group orders by percentage increase on price. Specify a JSON array of numbers here, each number is a group, number 1 means 0.01%. ") - ; - cfg.add(cli); -} - -void grouped_orders_plugin::plugin_initialize(const boost::program_options::variables_map& options) -{ try { - - if( options.count( "tracked-groups" ) ) - { - const std::string& groups = options["tracked-groups"].as(); - my->_tracked_groups = fc::json::from_string(groups).as>( 2 ); - my->_tracked_groups.erase( 0 ); - } - else - my->_tracked_groups = fc::json::from_string("[10,100]").as>(2); - - database().add_secondary_index< primary_index, detail::limit_order_group_index >( my->_tracked_groups ); - -} FC_CAPTURE_AND_RETHROW() } - -void grouped_orders_plugin::plugin_startup() -{ -} - -const flat_set& grouped_orders_plugin::tracked_groups() const -{ - return my->_tracked_groups; -} - -const map< limit_order_group_key, limit_order_group_data >& grouped_orders_plugin::limit_order_groups() -{ - const auto& idx = database().get_index_type< limit_order_index >(); - const auto& pidx = dynamic_cast&>(idx); - const auto& logidx = pidx.get_secondary_index< detail::limit_order_group_index >(); - return logidx.get_order_groups(); -} - -} } diff --git a/libraries/plugins/market_history/CMakeLists.txt b/libraries/plugins/market_history/CMakeLists.txt index 47410d74..8100de28 100644 --- a/libraries/plugins/market_history/CMakeLists.txt +++ b/libraries/plugins/market_history/CMakeLists.txt @@ -4,7 +4,7 @@ add_library( graphene_market_history market_history_plugin.cpp ) -target_link_libraries( graphene_market_history graphene_chain graphene_app ) +target_link_libraries( graphene_market_history PRIVATE graphene_plugin ) target_include_directories( graphene_market_history PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/peerplays_sidechain/CMakeLists.txt b/libraries/plugins/peerplays_sidechain/CMakeLists.txt index 3e37b6fe..bb74df29 100755 --- a/libraries/plugins/peerplays_sidechain/CMakeLists.txt +++ b/libraries/plugins/peerplays_sidechain/CMakeLists.txt @@ -5,6 +5,7 @@ add_library( peerplays_sidechain sidechain_net_manager.cpp sidechain_net_handler.cpp sidechain_net_handler_bitcoin.cpp + sidechain_net_handler_hive.cpp sidechain_net_handler_peerplays.cpp bitcoin/bech32.cpp bitcoin/bitcoin_address.cpp @@ -13,6 +14,12 @@ add_library( peerplays_sidechain bitcoin/segwit_addr.cpp bitcoin/utils.cpp bitcoin/sign_bitcoin_transaction.cpp + common/rpc_client.cpp + common/utils.cpp + hive/asset.cpp + hive/operations.cpp + hive/transaction.cpp + hive/types.cpp ) if (ENABLE_DEV_FEATURES) @@ -36,7 +43,7 @@ endif() unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS) unset(ENABLE_PEERPLAYS_ASSET_DEPOSITS CACHE) -target_link_libraries( peerplays_sidechain graphene_chain graphene_app fc zmq ) +target_link_libraries( peerplays_sidechain PRIVATE curl graphene_plugin zmq ) target_include_directories( peerplays_sidechain PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_script.cpp b/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_script.cpp index 07078147..50c02964 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_script.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_script.cpp @@ -1,3 +1,4 @@ +#include #include #include diff --git a/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_transaction.cpp b/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_transaction.cpp index b4fde6dc..fac29f5a 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin/bitcoin_transaction.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp b/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp index edb45c5b..afad2093 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin/sign_bitcoin_transaction.cpp @@ -1,4 +1,7 @@ #include + +#include + #include namespace graphene { namespace peerplays_sidechain { namespace bitcoin { diff --git a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp new file mode 100644 index 00000000..d08d337b --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp @@ -0,0 +1,1017 @@ +#include + +#include +#include + +//#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace graphene { namespace peerplays_sidechain { + +constexpr auto http_port = 80; +constexpr auto https_port = 443; + +template +void make_trimmed(string *str) { + boost::algorithm::trim(*str); +} + +template +void make_lower(string *str) { + boost::algorithm::to_lower(*str); +} + +bool convert_hex_to_num_helper1(const std::string &str, uint32_t *value) { + try { + size_t idx; + auto v = stol(str, &idx, 16); + if (idx != str.size()) + return false; + if (value) + *value = v; + return true; + } catch (...) { + return false; + } +} + +bool convert_dec_to_num_helper1(const std::string &str, uint32_t *value) { + try { + size_t idx; + auto v = stol(str, &idx, 10); + if (idx != str.size()) + return false; + if (value) + *value = v; + return true; + } catch (...) { + return false; + } +} + +bool convert_dec_to_num_helper1(const std::string &str, uint16_t *value) { + try { + size_t idx; + auto v = stol(str, &idx, 10); + if (idx != str.size()) + return false; + if (v > std::numeric_limits::max()) + return false; + if (value) + *value = v; + return true; + } catch (...) { + return false; + } +} + +template +constexpr V ceilDiv(V value, D divider) { + return (value + divider - 1) / divider; +} + +template +constexpr V aligned(V value, A align) { + return ceilDiv(value, align) * align; +} + +template +void reserve( + Container *container, + typename Container::size_type freeSpaceRequired, + typename Container::size_type firstAlloc, + typename Container::size_type nextAlloc) { + //TSL_ASSERT(container); + auto &c = *container; + auto required = c.size() + freeSpaceRequired; + if (c.capacity() >= required) + return; + c.reserve((firstAlloc >= required) ? firstAlloc + : firstAlloc + aligned(required - firstAlloc, nextAlloc)); +} + +template +void reserve( + Container *container, + typename Container::size_type freeSpaceRequired, + typename Container::size_type alloc) { + //TSL_ASSERT(container); + auto &c = *container; + auto required = c.size() + freeSpaceRequired; + if (c.capacity() >= required) + return; + c.reserve(aligned(required, alloc)); +} + +bool is_valid(const boost::asio::ip::tcp::endpoint &ep) { + + if (ep.port() == 0) + return false; + + if (ep.address().is_unspecified()) + return false; + + return true; +} + +// utl + +url_schema_type identify_url_schema_type(const std::string &schema_name) { + // rework + auto temp = schema_name; + make_lower(&temp); + if (temp == "http") + return url_schema_type::http; + if (temp == "https") + return url_schema_type::https; + return url_schema_type::unknown; +} + +// url_data + +url_data::url_data(const std::string &url) { + if (!parse(url)) + FC_THROW("URL parse failed"); +} + +void url_data::clear() { + schema_type = url_schema_type::unknown; + schema = decltype(schema)(); + host = decltype(host)(); + port = 0; + path = decltype(path)(); +} + +bool url_data::parse(const std::string &url) { + + typedef std::string::size_type size_t; + constexpr auto npos = std::string::npos; + + size_t schema_end = url.find("://"); + size_t host_begin; + std::string temp_schema; + + if (schema_end == npos) + host_begin = 0; // no schema + else { + if (schema_end < 3) { // schema too short: less than 3 chars + return false; + } + if (schema_end > 5) { // schema too long: more than 5 chars + return false; + } + host_begin = schema_end + 3; + temp_schema = url.substr(0, schema_end); + } + + // ASSERT(url.size() >= host_begin); + + if (url.size() == host_begin) // host is empty + return false; + + size_t port_sep = url.find(':', host_begin); + + if (port_sep == host_begin) + return false; + + size_t path_sep = url.find('/', host_begin); + + if (path_sep == host_begin) + return false; + + if ((port_sep != npos) && (path_sep != npos) && (port_sep > path_sep)) + port_sep = npos; + + std::string temp_port; + + if (port_sep != npos) { + auto port_index = port_sep + 1; + if (path_sep == npos) + temp_port = url.substr(port_index); + else + temp_port = url.substr(port_index, path_sep - port_index); + } + + if (temp_port.empty()) + port = 0; + else { + if (!convert_dec_to_num_helper1(temp_port, &port)) + return false; + } + + std::string temp_path; + + if (path_sep != npos) + temp_path = url.substr(path_sep); + + std::string temp_host; + + if (port_sep != npos) { + temp_host = url.substr(host_begin, port_sep - host_begin); + } else { + if (path_sep != npos) + temp_host = url.substr(host_begin, path_sep - host_begin); + else + temp_host = url.substr(host_begin); + } + + schema = temp_schema; + host = temp_host; + path = temp_path; + schema_type = identify_url_schema_type(schema); + + return true; +} + +}} // namespace graphene::peerplays_sidechain + +namespace graphene { namespace peerplays_sidechain { + +using namespace boost::asio; +using error_code = boost::system::error_code; +using endpoint = ip::tcp::endpoint; + +namespace detail { + +// http_call_impl + +struct tcp_socket { + + typedef ip::tcp::socket underlying_type; + + underlying_type underlying; + + tcp_socket(http_call &call) : + underlying(call.m_service) { + } + + underlying_type &operator()() { + return underlying; + } + + void connect(const http_call &call, const endpoint &ep, error_code *ec) { + // TCP connect + underlying.connect(ep, *ec); + } + + void shutdown() { + error_code ec; + underlying.close(ec); + } +}; + +struct ssl_socket { + + typedef ssl::stream underlying_type; + + underlying_type underlying; + + ssl_socket(http_call &call) : + underlying(call.m_service, *call.m_context) { + } + + underlying_type &operator()() { + return underlying; + } + + void connect(const http_call &call, const endpoint &ep, error_code *ec) { + + auto &u = underlying; + + // TCP connect + u.lowest_layer().connect(ep, *ec); + + // SSL connect + if (!SSL_set_tlsext_host_name(u.native_handle(), call.m_host.c_str())) + FC_THROW("SSL_set_tlsext_host_name failed"); + + u.set_verify_mode(ssl::verify_peer, *ec); + u.handshake(ssl::stream_base::client, *ec); + } + + void shutdown() { + auto &u = underlying; + error_code ec; + u.shutdown(ec); + u.lowest_layer().close(ec); + } +}; + +template +class http_call_impl { +public: + http_call_impl(http_call &call, const void *body_data, size_t body_size, const std::string &content_type_, http_response &response); + void exec(); + +private: + http_call &call; + const void *body_data; + size_t body_size; + std::string content_type; + http_response &response; + + socket_type socket; + streambuf response_buf; + + int32_t content_length; + bool transfer_encoding_chunked; + +private: + void connect(); + void shutdown(); + void send_request(); + void on_header(std::string &name, std::string &value); + void on_header(); + void process_headers(); + void append_entity_body(std::istream *stream, size_t size); + void append_entity_body_2(std::istream *strm); + bool read_next_chunk(std::istream *strm); + void skip_footer(); + void read_body_chunked(); + void read_body_until_eof(); + void read_body_exact(); + void process_response(); +}; + +static const char cr = 0x0D; +static const char lf = 0x0A; +static const char *crlf = "\x0D\x0A"; +static const char *crlfcrlf = "\x0D\x0A\x0D\x0A"; +static const auto crlf_uint = (((uint16_t)lf) << 8) + cr; + +template +http_call_impl::http_call_impl(http_call &call_, const void *body_data_, size_t body_size_, const std::string &content_type_, http_response &response_) : + call(call_), + body_data(body_data_), + body_size(body_size_), + content_type(content_type_), + response(response_), + socket(call), + response_buf(http_call::response_size_limit_bytes) { +} + +template +void http_call_impl::exec() { + try { + connect(); + send_request(); + process_response(); + shutdown(); + } catch (...) { + shutdown(); + throw; + } +} + +template +void http_call_impl::connect() { + + { + error_code ec; + auto &ep = call.m_endpoint; + if (is_valid(ep)) { + socket.connect(call, ep, &ec); + if (!ec) + return; + } + } + + ip::tcp::resolver resolver(call.m_service); + + auto rng = resolver.resolve(call.m_host, std::string()); + + //ASSERT(rng.begin() != rng.end()); + + error_code ec; + + for (endpoint ep : rng) { + ep.port(call.m_port); + socket.connect(call, ep, &ec); + if (!ec) { + call.m_endpoint = ep; + return; // comment to test1 + } + } + // if (!ec) return; // uncomment to test1 + + //ASSERT(ec); + throw boost::system::system_error(ec); +} + +template +void http_call_impl::shutdown() { + socket.shutdown(); +} + +template +void http_call_impl::send_request() { + + streambuf request; + std::ostream stream(&request); + + // start string: HTTP/1.0 + + //ASSERT(!call.m_path.empty()); + + stream << call.m_method << " " << call.m_path << " HTTP/1.1" << crlf; + + // host + + stream << "Host: " << call.m_host << ":" << call.m_endpoint.port() << crlf; + + // content + + if (body_size) { + stream << "Content-Type: " << content_type << crlf; + stream << "Content-Length: " << body_size << crlf; + } + + // additional headers + + const auto &h = call.m_headers; + + if (!h.empty()) { + if (h.size() < 2) + FC_THROW("invalid headers data"); + stream << h; + // ensure headers finished correctly + if ((h.substr(h.size() - 2) != crlf)) + stream << crlf; + } + + // other + + // stream << "Accept: *\x2F*" << crlf; + stream << "Accept: text/html, application/json" << crlf; + stream << "Connection: close" << crlf; + + // end + + stream << crlf; + + // send headers + + write(socket(), request); + + // send body + + if (body_size) + write(socket(), buffer(body_data, body_size)); +} + +template +void http_call_impl::on_header(std::string &name, std::string &value) { + + if (name == "content-length") { + uint32_t u; + if (!convert_dec_to_num_helper1(value, &u)) + FC_THROW("invalid content-length header data"); + content_length = u; + return; + } + + if (name == "transfer-encoding") { + boost::algorithm::to_lower(value); + if (value == "chunked") + transfer_encoding_chunked = true; + return; + } +} + +template +void http_call_impl::process_headers() { + + std::istream stream(&response_buf); + + std::string http_version; + stream >> http_version; + stream >> response.status_code; + + make_trimmed(&http_version); + make_lower(&http_version); + + if (!stream || http_version.substr(0, 6) != "http/1") + FC_THROW("invalid response data"); + + // read/skip headers + + content_length = -1; + transfer_encoding_chunked = false; + + for (;;) { + std::string header; + if (!std::getline(stream, header, lf) || (header.size() == 1 && header[0] == cr)) + break; + auto pos = header.find(':'); + if (pos == std::string::npos) + continue; + auto name = header.substr(0, pos); + make_trimmed(&name); + boost::algorithm::to_lower(name); + auto value = header.substr(pos + 1); + make_trimmed(&value); + on_header(name, value); + } +} + +template +void http_call_impl::append_entity_body(std::istream *strm, size_t size) { + if (size == 0) + return; + auto &body = response.body; + reserve(&body, size, http_call::response_first_alloc_bytes, http_call::response_next_alloc_bytes); + auto cur = body.size(); + body.resize(cur + size); + auto p = &body[cur]; + if (!strm->read(p, size)) + FC_THROW("stream read failed"); +} + +template +void http_call_impl::append_entity_body_2(std::istream *strm) { + auto avail = response_buf.size(); + if (response.body.size() + avail > http_call::response_size_limit_bytes) + FC_THROW("response body size limit exceeded"); + append_entity_body(strm, avail); +} + +template +bool http_call_impl::read_next_chunk(std::istream *strm) { + + // content length info is used as pre-alloc hint only + // it is not used inside the reading logic + + auto &buf = response_buf; + auto &stream = *strm; + auto &body = response.body; + + read_until(socket(), buf, crlf); + + std::string chunk_header; + + if (!std::getline(stream, chunk_header, lf)) + FC_THROW("failed to read chunk size"); + + auto ext_index = chunk_header.find(':'); + + if (ext_index != std::string::npos) + chunk_header.resize(ext_index); + + make_trimmed(&chunk_header); + + uint32_t chink_size; + + if (!convert_hex_to_num_helper1(chunk_header, &chink_size)) + FC_THROW("invalid chunk size string"); + + if (body.size() + chink_size > http_call::response_size_limit_bytes) + FC_THROW("response body size limit exceeded"); + + auto avail = buf.size(); + if (avail < chink_size + 2) { + auto rest = chink_size + 2 - avail; + read(socket(), buf, transfer_at_least(rest)); + } + + append_entity_body(&stream, chink_size); + + uint16_t temp; + if (!stream.read((char *)(&temp), 2)) + FC_THROW("stream read failed"); + if (temp != crlf_uint) + FC_THROW("invalid chink end"); + + return chink_size != 0; +} + +template +void http_call_impl::skip_footer() { + // to be implemeted +} + +template +void http_call_impl::read_body_chunked() { + + std::istream stream(&response_buf); + + for (;;) { + if (!read_next_chunk(&stream)) + break; + } + + skip_footer(); +} + +template +void http_call_impl::read_body_until_eof() { + + auto &buf = response_buf; + std::istream stream(&buf); + + append_entity_body_2(&stream); + + error_code ec; + + for (;;) { + auto readed = read(socket(), buf, transfer_at_least(1), ec); + append_entity_body_2(&stream); + if (ec) + break; + if (!readed) { + //ASSERT(buf.size() == 0); + FC_THROW("logic error: read failed but no error conditon"); + } + } + if ((ec != error::eof) && + (ec != ssl::error::stream_truncated)) + throw boost::system::system_error(ec); +} + +template +void http_call_impl::read_body_exact() { + + auto &buf = response_buf; + auto &body = response.body; + + auto avail = buf.size(); + + if (avail > ((size_t)content_length)) + FC_THROW("invalid response body (content length mismatch)"); + + body.resize(content_length); + + if (avail) { + if (avail != ((size_t)buf.sgetn(&body[0], avail))) + FC_THROW("stream read failed"); + } + + auto rest = content_length - avail; + + if (rest > 0) { + auto readed = read(socket(), buffer(&body[avail], rest), transfer_exactly(rest)); + //ASSERT(readed <= rest); + if (readed < rest) + FC_THROW("logic error: read failed but no error conditon"); + } +} + +template +void http_call_impl::process_response() { + + auto &buf = response_buf; + auto &body = response.body; + + read_until(socket(), buf, crlfcrlf); + + process_headers(); + + // check content length + + if (content_length >= 0) { + if (content_length < 2) { // minimum content is "{}" + FC_THROW("invalid response body (too short)"); + } + if (content_length > http_call::response_size_limit_bytes) + FC_THROW("response body size limit exceeded"); + body.reserve(content_length); + } + + if (transfer_encoding_chunked) { + read_body_chunked(); + } else { + if (content_length < 0) + read_body_until_eof(); + else { + if (content_length > 0) + read_body_exact(); + } + } +} + +} // namespace detail + +// https_call + +http_call::http_call(const url_data &url, const std::string &method, const std::string &headers) : + m_host(url.host), + m_method(method), + m_headers(headers) { + + if (url.schema_type == url_schema_type::https) { + m_context = new boost::asio::ssl::context(ssl::context::tlsv12_client); + } else { + m_context = 0; + } + + if (url.port) + m_port_default = url.port; + else { + if (url.schema_type == url_schema_type::https) + m_port_default = https_port; + else + m_port_default = http_port; + } + + m_port = m_port_default; + + set_path(url.path); + + try { + ctor_priv(); + } catch (...) { + if (m_context) + delete m_context; + throw; + } +} + +http_call::~http_call() { + if (m_context) + delete m_context; +} + +bool http_call::is_ssl() const { + return m_context != 0; +} + +const std::string &http_call::path() const { + return m_path; +} + +void http_call::set_path(const std::string &path) { + if (path.empty()) + m_path = "/"; + else + m_path = path; +} + +void http_call::set_method(const std::string &method) { + m_method = method; +} + +void http_call::set_headers(const std::string &headers) { + m_headers = headers; +} + +const std::string &http_call::host() const { + return m_host; +} + +void http_call::set_host(const std::string &host) { + m_host = host; +} + +uint16_t http_call::port() const { + return m_port; +} + +void http_call::set_port(uint16_t port) { + if (port) + m_port = port; + else + m_port = m_port_default; +} + +bool http_call::exec(const http_request &request, http_response *response) { + + //ASSERT(response); + auto &resp = *response; + m_error_what = decltype(m_error_what)(); + resp.clear(); + + try { + try { + using namespace detail; + if (!m_context) + http_call_impl(*this, request.body.data(), request.body.size(), request.content_type, resp).exec(); + else + http_call_impl(*this, request.body.data(), request.body.size(), request.content_type, resp).exec(); + return true; + } catch (const std::exception &e) { + m_error_what = e.what(); + } + } catch (...) { + m_error_what = "unknown exception"; + } + + resp.clear(); + return false; +} + +const std::string &http_call::error_what() const { + return m_error_what; +} + +void http_call::ctor_priv() { + if (m_context) { + m_context->set_default_verify_paths(); + m_context->set_options(ssl::context::default_workarounds); + } +} + +}} // namespace graphene::peerplays_sidechain + +namespace graphene { namespace peerplays_sidechain { + +rpc_client::rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug) : + debug_rpc_calls(debug), + request_id(0), + client(url) + +{ + + client.set_method("POST"); + client.set_headers("Authorization : Basic" + fc::base64_encode(user_name + ":" + password)); +} + +std::string rpc_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) { + if (reply_str.empty()) + return std::string(); + std::stringstream ss(reply_str); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + if (json.find("result") == json.not_found()) { + return std::string(); + } + auto json_result = json.get_child("result"); + if (json_result.find(array_path) == json_result.not_found()) { + return std::string(); + } + + boost::property_tree::ptree array_ptree = json_result; + if (!array_path.empty()) { + array_ptree = json_result.get_child(array_path); + } + uint32_t array_el_idx = -1; + for (const auto &array_el : array_ptree) { + array_el_idx = array_el_idx + 1; + if (array_el_idx == idx) { + std::stringstream ss_res; + boost::property_tree::json_parser::write_json(ss_res, array_el.second); + return ss_res.str(); + } + } + + return std::string(); +} + +std::string rpc_client::retrieve_value_from_reply(std::string reply_str, std::string value_path) { + if (reply_str.empty()) + return std::string(); + std::stringstream ss(reply_str); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + if (json.find("result") == json.not_found()) { + return std::string(); + } + auto json_result = json.get_child("result"); + if (json_result.find(value_path) == json_result.not_found()) { + return std::string(); + } + return json_result.get(value_path); +} + +std::string rpc_client::send_post_request(std::string method, std::string params, bool show_log) { + std::stringstream body; + + request_id = request_id + 1; + + body << "{ \"jsonrpc\": \"2.0\", \"id\": " << request_id << ", \"method\": \"" << method << "\""; + + if (!params.empty()) { + body << ", \"params\": " << params; + } + + body << " }"; + + const auto reply = send_post_request(body.str(), show_log); + + if (reply.body.empty()) { + wlog("RPC call ${function} failed", ("function", __FUNCTION__)); + return ""; + } + + std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + + if (reply.status_code == 200) { + return ss.str(); + } + + if (json.count("error") && !json.get_child("error").empty()) { + wlog("RPC call ${function} with body ${body} failed with reply '${msg}'", ("function", __FUNCTION__)("body", body.str())("msg", ss.str())); + } + return ""; +} + +//fc::http::reply rpc_client::send_post_request(std::string body, bool show_log) { +// fc::http::connection conn; +// conn.connect_to(fc::ip::endpoint(fc::ip::address(ip), port)); +// +// std::string url = "http://" + ip + ":" + std::to_string(port); +// +// //if (wallet.length() > 0) { +// // url = url + "/wallet/" + wallet; +// //} +// +// fc::http::reply reply = conn.request("POST", url, body, fc::http::headers{authorization}); +// +// if (show_log) { +// ilog("### Request URL: ${url}", ("url", url)); +// ilog("### Request: ${body}", ("body", body)); +// std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); +// ilog("### Response: ${ss}", ("ss", ss.str())); +// } +// +// return reply; +//} + +//static size_t write_callback(char *ptr, size_t size, size_t nmemb, rpc_reply *reply) { +// size_t retval = 0; +// if (reply != nullptr) { +// reply->body.append(ptr, size * nmemb); +// retval = size * nmemb; +// } +// return retval; +//} + +//rpc_reply rpc_client::send_post_request(std::string body, bool show_log) { +// +// struct curl_slist *headers = nullptr; +// headers = curl_slist_append(headers, "Accept: application/json"); +// headers = curl_slist_append(headers, "Content-Type: application/json"); +// headers = curl_slist_append(headers, "charset: utf-8"); +// +// CURL *curl = curl_easy_init(); +// if (ip.find("https://", 0) != 0) { +// curl_easy_setopt(curl, CURLOPT_URL, ip.c_str()); +// curl_easy_setopt(curl, CURLOPT_PORT, port); +// } else { +// std::string full_address = ip + ":" + std::to_string(port); +// curl_easy_setopt(curl, CURLOPT_URL, full_address.c_str()); +// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); +// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); +// } +// if (!user.empty()) { +// curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str()); +// curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); +// } +// +// curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); +// curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); +// +// //curl_easy_setopt(curl, CURLOPT_VERBOSE, true); +// +// rpc_reply reply; +// +// curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); +// curl_easy_setopt(curl, CURLOPT_WRITEDATA, &reply); +// +// curl_easy_perform(curl); +// +// curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &reply.status); +// +// curl_easy_cleanup(curl); +// curl_slist_free_all(headers); +// +// if (show_log) { +// std::string url = ip + ":" + std::to_string(port); +// ilog("### Request URL: ${url}", ("url", url)); +// ilog("### Request: ${body}", ("body", body)); +// std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); +// ilog("### Response: ${ss}", ("ss", ss.str())); +// } +// +// return reply; +//} + +http_response rpc_client::send_post_request(const std::string &body, bool show_log) { + + http_request request(body, "application/json"); + http_response response; + + client.exec(request, &response); + + if (show_log) { + std::string url = client.is_ssl() ? "https" : "http"; + url = url + "://" + client.host() + ":" + std::to_string(client.port()) + client.path(); + ilog("### Request URL: ${url}", ("url", url)); + ilog("### Request: ${body}", ("body", body)); + std::stringstream ss(std::string(response.body.begin(), response.body.end())); + ilog("### Response: ${ss}", ("ss", ss.str())); + } + + return response; +} + +}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/common/utils.cpp b/libraries/plugins/peerplays_sidechain/common/utils.cpp new file mode 100644 index 00000000..4491487f --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/common/utils.cpp @@ -0,0 +1,8 @@ +#include + +std::string object_id_to_string(graphene::chain::object_id_type id) { + std::string object_id = fc::to_string(id.space()) + "." + + fc::to_string(id.type()) + "." + + fc::to_string(id.instance()); + return object_id; +} diff --git a/libraries/plugins/peerplays_sidechain/hive/asset.cpp b/libraries/plugins/peerplays_sidechain/hive/asset.cpp new file mode 100644 index 00000000..7417107f --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/hive/asset.cpp @@ -0,0 +1,69 @@ +#include + +#include + +#include +#include + +#define ASSET_AMOUNT_KEY "amount" +#define ASSET_PRECISION_KEY "precision" +#define ASSET_NAI_KEY "nai" + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +uint64_t asset::hbd_symbol_ser = HBD_SYMBOL_SER; +uint64_t asset::hive_symbol_ser = HIVE_SYMBOL_SER; + +}}} // namespace graphene::peerplays_sidechain::hive + +namespace fc { + +void to_variant(const graphene::peerplays_sidechain::hive::asset &var, fc::variant &vo, uint32_t max_depth) { + try { + if (var.symbol == HBD_SYMBOL_SER) { + variant v = mutable_variant_object(ASSET_AMOUNT_KEY, boost::lexical_cast(var.amount.value))(ASSET_PRECISION_KEY, uint64_t(HBD_PRECISION))(ASSET_NAI_KEY, HBD_NAI); + vo = v; + } + if (var.symbol == HIVE_SYMBOL_SER) { + variant v = mutable_variant_object(ASSET_AMOUNT_KEY, boost::lexical_cast(var.amount.value))(ASSET_PRECISION_KEY, uint64_t(HIVE_PRECISION))(ASSET_NAI_KEY, HIVE_NAI); + vo = v; + } + if (var.symbol == TBD_SYMBOL_SER) { + variant v = mutable_variant_object(ASSET_AMOUNT_KEY, boost::lexical_cast(var.amount.value))(ASSET_PRECISION_KEY, uint64_t(TBD_PRECISION))(ASSET_NAI_KEY, TBD_NAI); + vo = v; + } + if (var.symbol == TESTS_SYMBOL_SER) { + variant v = mutable_variant_object(ASSET_AMOUNT_KEY, boost::lexical_cast(var.amount.value))(ASSET_PRECISION_KEY, uint64_t(TESTS_PRECISION))(ASSET_NAI_KEY, TESTS_NAI); + vo = v; + } + } + FC_CAPTURE_AND_RETHROW() +} + +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::asset &vo, uint32_t max_depth) { + try { + FC_ASSERT(var.is_object(), "Asset has to be treated as object."); + + const auto &v_object = var.get_object(); + + FC_ASSERT(v_object.contains(ASSET_AMOUNT_KEY), "Amount field doesn't exist."); + FC_ASSERT(v_object[ASSET_AMOUNT_KEY].is_string(), "Expected a string type for value '${key}'.", ("key", ASSET_AMOUNT_KEY)); + vo.amount = boost::lexical_cast(v_object[ASSET_AMOUNT_KEY].as(max_depth)); + FC_ASSERT(vo.amount >= 0, "Asset amount cannot be negative"); + + FC_ASSERT(v_object.contains(ASSET_PRECISION_KEY), "Precision field doesn't exist."); + FC_ASSERT(v_object[ASSET_PRECISION_KEY].is_uint64(), "Expected an unsigned integer type for value '${key}'.", ("key", ASSET_PRECISION_KEY)); + + FC_ASSERT(v_object.contains(ASSET_NAI_KEY), "NAI field doesn't exist."); + FC_ASSERT(v_object[ASSET_NAI_KEY].is_string(), "Expected a string type for value '${key}'.", ("key", ASSET_NAI_KEY)); + + if (v_object[ASSET_NAI_KEY].as(max_depth) == HBD_NAI) { + vo.symbol = graphene::peerplays_sidechain::hive::asset::hbd_symbol_ser; + } + if (v_object[ASSET_NAI_KEY].as(max_depth) == HIVE_NAI) { + vo.symbol = graphene::peerplays_sidechain::hive::asset::hive_symbol_ser; + } + } + FC_CAPTURE_AND_RETHROW() +} +} // namespace fc diff --git a/libraries/plugins/peerplays_sidechain/hive/operations.cpp b/libraries/plugins/peerplays_sidechain/hive/operations.cpp new file mode 100644 index 00000000..b21b564e --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/hive/operations.cpp @@ -0,0 +1,101 @@ +#include + +#include + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +}}} // namespace graphene::peerplays_sidechain::hive + +namespace fc { + +static std::string trim_typename_namespace(const std::string &name) { + auto start = name.find_last_of(':'); + start = (start == std::string::npos) ? 0 : start + 1; + return name.substr(start); +} + +struct from_static_variant_for_hive { + fc::variant &var; + from_static_variant_for_hive(fc::variant &dv) : + var(dv) { + } + + typedef void result_type; + template + void operator()(const T &v) const { + auto name = trim_typename_namespace(fc::get_typename::name()); + fc::variant value; + to_variant(v, value, 5); + var = mutable_variant_object("type", name).set("value", value); + } +}; + +struct to_static_variant_for_hive { + const fc::variant &var; + to_static_variant_for_hive(const fc::variant &dv) : + var(dv) { + } + + typedef void result_type; + template + void operator()(T &v) const { + from_variant(var, v, 5); + } +}; + +struct get_static_variant_name { + string &name; + get_static_variant_name(string &n) : + name(n) { + } + + typedef void result_type; + template + void operator()(T &v) const { + name = trim_typename_namespace(fc::get_typename::name()); + } +}; + +void to_variant(const graphene::peerplays_sidechain::hive::hive_operation &var, fc::variant &vo, uint32_t max_depth) { + var.visit(from_static_variant_for_hive(vo)); +} + +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::hive_operation &vo, uint32_t max_depth) { + static std::map to_tag = []() { + std::map name_map; + for (int i = 0; i < graphene::peerplays_sidechain::hive::hive_operation::count(); ++i) { + graphene::peerplays_sidechain::hive::hive_operation tmp; + tmp.set_which(i); + string n; + tmp.visit(get_static_variant_name(n)); + name_map[n] = i; + } + return name_map; + }(); + + auto ar = var.get_array(); + if (ar.size() < 2) + return; + auto var_second = ar[1]; + + FC_ASSERT(var_second.is_object(), "Input data have to treated as object."); + auto v_object = var_second.get_object(); + + FC_ASSERT(v_object.contains("type"), "Type field doesn't exist."); + FC_ASSERT(v_object.contains("value"), "Value field doesn't exist."); + + int64_t which = -1; + + if (v_object["type"].is_integer()) { + which = v_object["type"].as_int64(); + } else { + auto itr = to_tag.find(v_object["type"].as_string()); + FC_ASSERT(itr != to_tag.end(), "Invalid object name: ${n}", ("n", v_object["type"])); + which = itr->second; + } + + vo.set_which(which); + vo.visit(fc::to_static_variant_for_hive(v_object["value"])); +} + +} // namespace fc diff --git a/libraries/plugins/peerplays_sidechain/hive/transaction.cpp b/libraries/plugins/peerplays_sidechain/hive/transaction.cpp new file mode 100644 index 00000000..3e4a59f5 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/hive/transaction.cpp @@ -0,0 +1,57 @@ +#include + +#include + +#include +#include + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +digest_type transaction::digest() const { + digest_type::encoder enc; + fc::raw::pack(enc, *this); + return enc.result(); +} + +transaction_id_type transaction::id() const { + auto h = digest(); + transaction_id_type result; + memcpy(result._hash, h._hash, std::min(sizeof(result), sizeof(h))); + return result; +} + +digest_type transaction::sig_digest(const chain_id_type &chain_id) const { + digest_type::encoder enc; + fc::raw::pack(enc, chain_id); + fc::raw::pack(enc, *this); + return enc.result(); +} + +void transaction::set_expiration(fc::time_point_sec expiration_time) { + expiration = expiration_time; +} + +void transaction::set_reference_block(const block_id_type &reference_block) { + ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]); + ref_block_prefix = reference_block._hash[1]; +} + +void signed_transaction::clear() { + operations.clear(); + signatures.clear(); +} + +const signature_type &signed_transaction::sign(const hive::private_key_type &key, const hive::chain_id_type &chain_id) { + digest_type h = sig_digest(chain_id); + signatures.push_back(key.sign_compact(h, true)); + return signatures.back(); +} + +signature_type signed_transaction::sign(const hive::private_key_type &key, const hive::chain_id_type &chain_id) const { + digest_type::encoder enc; + fc::raw::pack(enc, chain_id); + fc::raw::pack(enc, *this); + return key.sign_compact(enc.result(), true); +} + +}}} // namespace graphene::peerplays_sidechain::hive diff --git a/libraries/plugins/peerplays_sidechain/hive/types.cpp b/libraries/plugins/peerplays_sidechain/hive/types.cpp new file mode 100644 index 00000000..7a5506e7 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/hive/types.cpp @@ -0,0 +1,73 @@ +#include + +#include +#include +#include +#include + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +std::string public_key_type::prefix = KEY_PREFIX_STM; + +public_key_type::public_key_type() : + key_data(){}; + +public_key_type::public_key_type(const fc::ecc::public_key_data &data) : + key_data(data){}; + +public_key_type::public_key_type(const fc::ecc::public_key &pubkey) : + key_data(pubkey){}; + +public_key_type::public_key_type(const std::string &base58str) { + const size_t prefix_len = prefix.size(); + FC_ASSERT(base58str.size() > prefix_len); + FC_ASSERT(base58str.substr(0, prefix_len) == prefix, "", ("base58str", base58str)); + auto bin = fc::from_base58(base58str.substr(prefix_len)); + auto bin_key = fc::raw::unpack(bin); + key_data = bin_key.data; + FC_ASSERT(fc::ripemd160::hash(key_data.data, key_data.size())._hash[0] == bin_key.check); +}; + +public_key_type::operator fc::ecc::public_key_data() const { + return key_data; +}; + +public_key_type::operator fc::ecc::public_key() const { + return fc::ecc::public_key(key_data); +}; + +public_key_type::operator std::string() const { + binary_key k; + k.data = key_data; + k.check = fc::ripemd160::hash(k.data.data, k.data.size())._hash[0]; + auto data = fc::raw::pack(k); + return prefix + fc::to_base58(data.data(), data.size()); +} + +bool operator==(const public_key_type &p1, const fc::ecc::public_key &p2) { + return p1.key_data == p2.serialize(); +} + +bool operator==(const public_key_type &p1, const public_key_type &p2) { + return p1.key_data == p2.key_data; +} + +bool operator!=(const public_key_type &p1, const public_key_type &p2) { + return p1.key_data != p2.key_data; +} + +}}} // namespace graphene::peerplays_sidechain::hive + +namespace fc { + +using namespace std; + +void to_variant(const graphene::peerplays_sidechain::hive::public_key_type &var, fc::variant &vo, uint32_t max_depth) { + vo = std::string(var); +} + +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::public_key_type &vo, uint32_t max_depth) { + vo = graphene::peerplays_sidechain::hive::public_key_type(var.as_string()); +} + +} // namespace fc diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp new file mode 100644 index 00000000..63d218ee --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp @@ -0,0 +1,136 @@ +#pragma once + +#include +#include + +#include +#include + +//#include + +namespace graphene { namespace peerplays_sidechain { + +enum class url_schema_type { unknown, + http, + https, +}; + +// utl + +url_schema_type identify_url_schema_type(const std::string &schema_name); + +struct url_data { + + url_schema_type schema_type; + std::string schema; + std::string host; + uint16_t port; + std::string path; + + url_data() : + schema_type(url_schema_type::unknown), + port(0) { + } + + url_data(const std::string &url); + + void clear(); + + bool parse(const std::string &url); +}; + +struct http_request { + + std::string body; + std::string content_type; + + http_request(const std::string &body_, const std::string &content_type_) : + body(body_), + content_type(content_type_) { + } +}; + +struct http_response { + + uint16_t status_code; + std::string body; + + void clear() { + status_code = 0; + body = decltype(body)(); + } +}; + +namespace detail { +template +class http_call_impl; +class tcp_socket; +class ssl_socket; +} // namespace detail + +class http_call { +public: + http_call(const url_data &url, const std::string &method = std::string(), const std::string &headers = std::string()); + ~http_call(); + + bool is_ssl() const; + + const std::string &path() const; + void set_path(const std::string &path); + void set_method(const std::string &method); + void set_headers(const std::string &headers); + const std::string &host() const; + void set_host(const std::string &host); + + uint16_t port() const; + void set_port(uint16_t port); + + bool exec(const http_request &request, http_response *response); + + const std::string &error_what() const; + +private: + template + friend class detail::http_call_impl; + friend detail::tcp_socket; + friend detail::ssl_socket; + static constexpr auto response_size_limit_bytes = 16 * 1024 * 1024; + static constexpr auto response_first_alloc_bytes = 32 * 1024; + static constexpr auto response_next_alloc_bytes = 256 * 1024; + std::string m_host; + uint16_t m_port_default; + uint16_t m_port; + std::string m_path; + std::string m_method; + std::string m_headers; + std::string m_error_what; + + boost::asio::io_service m_service; + boost::asio::ssl::context *m_context; + boost::asio::ip::tcp::endpoint m_endpoint; + + void ctor_priv(); +}; + +}} // namespace graphene::peerplays_sidechain + +namespace graphene { namespace peerplays_sidechain { + +class rpc_client { +public: + rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug); + +protected: + std::string retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx); + std::string retrieve_value_from_reply(std::string reply_str, std::string value_path); + std::string send_post_request(std::string method, std::string params, bool show_log); + + bool debug_rpc_calls; + uint32_t request_id; + +private: + http_call client; + http_response send_post_request(const std::string &body, bool show_log); +}; + +}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/utils.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/utils.hpp new file mode 100644 index 00000000..99c59019 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/utils.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +std::string object_id_to_string(graphene::chain::object_id_type id); diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset.hpp new file mode 100644 index 00000000..f0743741 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/asset.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +#define HBD_NAI "@@000000013" +#define HBD_PRECISION 3 +#define HBD_SYMBOL_U64 (uint64_t('S') | (uint64_t('B') << 8) | (uint64_t('D') << 16)) +#define HBD_SYMBOL_SER (uint64_t(3) | (HBD_SYMBOL_U64 << 8)) + +#define HIVE_NAI "@@000000021" +#define HIVE_PRECISION 3 +#define HIVE_SYMBOL_U64 (uint64_t('S') | (uint64_t('T') << 8) | (uint64_t('E') << 16) | (uint64_t('E') << 24) | (uint64_t('M') << 32)) +#define HIVE_SYMBOL_SER (uint64_t(3) | (HIVE_SYMBOL_U64 << 8)) + +#define TBD_NAI "@@000000013" +#define TBD_PRECISION 3 +#define TBD_SYMBOL_U64 (uint64_t('T') | (uint64_t('B') << 8) | (uint64_t('D') << 16)) +#define TBD_SYMBOL_SER (uint64_t(3) | (TBD_SYMBOL_U64 << 8)) + +#define TESTS_NAI "@@000000021" +#define TESTS_PRECISION 3 +#define TESTS_SYMBOL_U64 (uint64_t('T') | (uint64_t('E') << 8) | (uint64_t('S') << 16) | (uint64_t('T') << 24) | (uint64_t('S') << 32)) +#define TESTS_SYMBOL_SER (uint64_t(3) | (TESTS_SYMBOL_U64 << 8)) + +struct asset { + static uint64_t hbd_symbol_ser; + static uint64_t hive_symbol_ser; + share_type amount; + uint64_t symbol; +}; + +}}} // namespace graphene::peerplays_sidechain::hive + +namespace fc { +void to_variant(const graphene::peerplays_sidechain::hive::asset &var, fc::variant &vo, uint32_t max_depth); +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::asset &vo, uint32_t max_depth); +} // namespace fc + +FC_REFLECT(graphene::peerplays_sidechain::hive::asset, (amount)(symbol)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/authority.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/authority.hpp new file mode 100644 index 00000000..bd67ae23 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/authority.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include + +#include + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +struct authority { + authority() { + } + + enum classification { + owner = 0, + active = 1, + key = 2, + posting = 3 + }; + + uint32_t weight_threshold = 0; + fc::flat_map account_auths; + fc::flat_map key_auths; +}; + +}}} // namespace graphene::peerplays_sidechain::hive + +FC_REFLECT_ENUM(graphene::peerplays_sidechain::hive::authority::classification, + (owner)(active)(key)(posting)) + +FC_REFLECT(graphene::peerplays_sidechain::hive::authority, + (weight_threshold)(account_auths)(key_auths)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/hive_operations.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/hive_operations.hpp new file mode 100644 index 00000000..1348ce35 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/hive_operations.hpp @@ -0,0 +1,123 @@ +#pragma once + +#include +#include + +#include + +#include +#include +#include +#include + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +struct vote_operation {}; +struct comment_operation {}; + +struct transfer_operation { + hive::account_name_type from; + hive::account_name_type to; + hive::asset amount; + std::string memo; +}; + +struct transfer_to_vesting_operation {}; +struct withdraw_vesting_operation {}; +struct limit_order_create_operation {}; +struct limit_order_cancel_operation {}; +struct feed_publish_operation {}; +struct convert_operation {}; +struct account_create_operation {}; + +struct account_update_operation { + hive::account_name_type account; + fc::optional owner; + fc::optional active; + fc::optional posting; + hive::public_key_type memo_key; + std::string json_metadata; +}; + +struct witness_update_operation {}; +struct account_witness_vote_operation {}; +struct account_witness_proxy_operation {}; +struct pow_operation {}; +struct custom_operation {}; +struct report_over_production_operation {}; +struct delete_comment_operation {}; +struct custom_json_operation {}; +struct comment_options_operation {}; +struct set_withdraw_vesting_route_operation {}; +struct limit_order_create2_operation {}; +struct claim_account_operation {}; +struct create_claimed_account_operation {}; +struct request_account_recovery_operation {}; +struct recover_account_operation {}; +struct change_recovery_account_operation {}; +struct escrow_transfer_operation {}; +struct escrow_dispute_operation {}; +struct escrow_release_operation {}; +struct pow2_operation {}; +struct escrow_approve_operation {}; +struct transfer_to_savings_operation {}; +struct transfer_from_savings_operation {}; +struct cancel_transfer_from_savings_operation {}; +struct custom_binary_operation {}; +struct decline_voting_rights_operation {}; +struct reset_account_operation {}; +struct set_reset_account_operation {}; +struct claim_reward_balance_operation {}; + +struct delegate_vesting_shares_operation { + hive::account_name_type delegator; + hive::account_name_type delegatee; + hive::asset vesting_shares; +}; + +}}} // namespace graphene::peerplays_sidechain::hive + +FC_REFLECT(graphene::peerplays_sidechain::hive::vote_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::comment_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::transfer_operation, + (from)(to)(amount)(memo)) +FC_REFLECT(graphene::peerplays_sidechain::hive::transfer_to_vesting_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::withdraw_vesting_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::limit_order_create_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::limit_order_cancel_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::feed_publish_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::convert_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::account_create_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::account_update_operation, + (account)(owner)(active)(posting)(memo_key)(json_metadata)) +FC_REFLECT(graphene::peerplays_sidechain::hive::witness_update_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::account_witness_vote_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::account_witness_proxy_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::pow_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::custom_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::report_over_production_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::delete_comment_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::custom_json_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::comment_options_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::set_withdraw_vesting_route_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::limit_order_create2_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::claim_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::create_claimed_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::request_account_recovery_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::recover_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::change_recovery_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::escrow_transfer_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::escrow_dispute_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::escrow_release_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::pow2_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::escrow_approve_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::transfer_to_savings_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::transfer_from_savings_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::cancel_transfer_from_savings_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::custom_binary_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::decline_voting_rights_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::reset_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::set_reset_account_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::claim_reward_balance_operation, ) +FC_REFLECT(graphene::peerplays_sidechain::hive::delegate_vesting_shares_operation, + (delegator)(delegatee)(vesting_shares)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/operations.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/operations.hpp new file mode 100644 index 00000000..e64eb1ae --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/operations.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +typedef fc::static_variant< + vote_operation, + comment_operation, + + transfer_operation, + transfer_to_vesting_operation, + withdraw_vesting_operation, + + limit_order_create_operation, + limit_order_cancel_operation, + + feed_publish_operation, + convert_operation, + + account_create_operation, + account_update_operation, + + witness_update_operation, + account_witness_vote_operation, + account_witness_proxy_operation, + + pow_operation, + + custom_operation, + + report_over_production_operation, + + delete_comment_operation, + custom_json_operation, + comment_options_operation, + set_withdraw_vesting_route_operation, + limit_order_create2_operation, + claim_account_operation, + create_claimed_account_operation, + request_account_recovery_operation, + recover_account_operation, + change_recovery_account_operation, + escrow_transfer_operation, + escrow_dispute_operation, + escrow_release_operation, + pow2_operation, + escrow_approve_operation, + transfer_to_savings_operation, + transfer_from_savings_operation, + cancel_transfer_from_savings_operation, + custom_binary_operation, + decline_voting_rights_operation, + reset_account_operation, + set_reset_account_operation, + claim_reward_balance_operation, + delegate_vesting_shares_operation> + hive_operation; + +}}} // namespace graphene::peerplays_sidechain::hive + +namespace fc { + +void to_variant(const graphene::peerplays_sidechain::hive::hive_operation &var, fc::variant &vo, uint32_t max_depth = 5); +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::hive_operation &vo, uint32_t max_depth = 5); + +} // namespace fc + +FC_REFLECT_TYPENAME(graphene::peerplays_sidechain::hive::hive_operation) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/transaction.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/transaction.hpp new file mode 100644 index 00000000..8b35b7b3 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/transaction.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +#include +#include + +#include + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +struct transaction { + uint16_t ref_block_num = 0; + uint32_t ref_block_prefix = 0; + fc::time_point_sec expiration; + std::vector operations; + extensions_type extensions; + + digest_type digest() const; + transaction_id_type id() const; + digest_type sig_digest(const chain_id_type &chain_id) const; + + void set_expiration(fc::time_point_sec expiration_time); + void set_reference_block(const block_id_type &reference_block); +}; + +struct signed_transaction : public transaction { + + std::vector signatures; + + const signature_type &sign(const hive::private_key_type &key, const hive::chain_id_type &chain_id); + signature_type sign(const hive::private_key_type &key, const hive::chain_id_type &chain_id) const; + void clear(); +}; + +}}} // namespace graphene::peerplays_sidechain::hive + +FC_REFLECT(graphene::peerplays_sidechain::hive::transaction, + (ref_block_num)(ref_block_prefix)(expiration)(operations)(extensions)) + +FC_REFLECT_DERIVED(graphene::peerplays_sidechain::hive::signed_transaction, + (graphene::peerplays_sidechain::hive::transaction), + (signatures)) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types.hpp new file mode 100644 index 00000000..f5b986e4 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/hive/types.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include + +namespace graphene { namespace peerplays_sidechain { namespace hive { + +#define KEY_PREFIX_STM "STM" +#define KEY_PREFIX_TST "TST" + +enum network { + mainnet, + testnet +}; + +struct void_t {}; + +typedef fc::static_variant future_extensions; +typedef fc::flat_set extensions_type; + +typedef fc::ecc::private_key private_key_type; +typedef fc::sha256 chain_id_type; +typedef std::string account_name_type; +typedef fc::ripemd160 block_id_type; +//typedef fc::ripemd160 checksum_type; +typedef fc::ripemd160 transaction_id_type; +typedef fc::sha256 digest_type; +typedef fc::ecc::compact_signature signature_type; +typedef fc::safe share_type; +//typedef safe ushare_type; +//typedef uint16_t weight_type; +//typedef uint32_t contribution_id_type; +//typedef fixed_string<32> custom_id_type; + +struct public_key_type { + + static std::string prefix; + + struct binary_key { + binary_key() { + } + uint32_t check = 0; + fc::ecc::public_key_data data; + }; + fc::ecc::public_key_data key_data; + public_key_type(); + public_key_type(const fc::ecc::public_key_data &data); + public_key_type(const fc::ecc::public_key &pubkey); + explicit public_key_type(const std::string &base58str); + operator fc::ecc::public_key_data() const; + operator fc::ecc::public_key() const; + explicit operator std::string() const; + friend bool operator==(const public_key_type &p1, const fc::ecc::public_key &p2); + friend bool operator==(const public_key_type &p1, const public_key_type &p2); + friend bool operator<(const public_key_type &p1, const public_key_type &p2) { + return p1.key_data < p2.key_data; + } + friend bool operator!=(const public_key_type &p1, const public_key_type &p2); +}; + +}}} // namespace graphene::peerplays_sidechain::hive + +namespace fc { +void to_variant(const graphene::peerplays_sidechain::hive::public_key_type &var, fc::variant &vo, uint32_t max_depth = 2); +void from_variant(const fc::variant &var, graphene::peerplays_sidechain::hive::public_key_type &vo, uint32_t max_depth = 2); +} // namespace fc + +FC_REFLECT(graphene::peerplays_sidechain::hive::public_key_type, (key_data)) +FC_REFLECT(graphene::peerplays_sidechain::hive::public_key_type::binary_key, (data)(check)) + +FC_REFLECT(graphene::peerplays_sidechain::hive::void_t, ) +FC_REFLECT_TYPENAME(graphene::peerplays_sidechain::hive::future_extensions) diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp index 5b7ea6e9..6adfe944 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/peerplays_sidechain_plugin.hpp @@ -37,6 +37,7 @@ public: boost::program_options::options_description &cfg) override; virtual void plugin_initialize(const boost::program_options::variables_map &options) override; virtual void plugin_startup() override; + virtual void plugin_shutdown() override; std::unique_ptr my; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp index 50dfd505..21526d05 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler.hpp @@ -4,7 +4,6 @@ #include -#include #include #include #include @@ -46,15 +45,19 @@ public: virtual bool process_withdrawal(const son_wallet_withdraw_object &swwo) = 0; virtual std::string process_sidechain_transaction(const sidechain_transaction_object &sto) = 0; virtual std::string send_sidechain_transaction(const sidechain_transaction_object &sto) = 0; - virtual int64_t settle_sidechain_transaction(const sidechain_transaction_object &sto) = 0; + virtual bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) = 0; protected: peerplays_sidechain_plugin &plugin; graphene::chain::database &database; sidechain_type sidechain; + bool debug_rpc_calls; + std::map private_keys; + void on_applied_block(const signed_block &b); + private: }; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp index eb218a4c..9b08bc15 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp @@ -1,13 +1,16 @@ #pragma once -#include #include #include #include +#include + +#include + #include -#include +#include namespace graphene { namespace peerplays_sidechain { @@ -20,7 +23,7 @@ public: class bitcoin_rpc_client { public: - bitcoin_rpc_client(std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet, std::string _wallet_password); + bitcoin_rpc_client(std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet, std::string _wallet_password, bool _debug_rpc_calls); std::string addmultisigaddress(const uint32_t nrequired, const std::vector public_keys); std::string combinepsbt(const vector &psbts); @@ -50,7 +53,7 @@ public: //bool walletpassphrase(const std::string &passphrase, uint32_t timeout = 60); private: - fc::http::reply send_post_request(std::string body, bool show_log = false); + fc::http::reply send_post_request(std::string body, bool show_log); std::string ip; uint32_t rpc_port; @@ -58,6 +61,7 @@ private: std::string password; std::string wallet; std::string wallet_password; + bool debug_rpc_calls; fc::http::header authorization; }; @@ -68,7 +72,7 @@ class zmq_listener { public: zmq_listener(std::string _ip, uint32_t _zmq); - fc::signal event_received; + boost::signals2::signal event_received; private: void handle_zmq(); @@ -95,7 +99,7 @@ public: bool process_withdrawal(const son_wallet_withdraw_object &swwo); std::string process_sidechain_transaction(const sidechain_transaction_object &sto); std::string send_sidechain_transaction(const sidechain_transaction_object &sto); - int64_t settle_sidechain_transaction(const sidechain_transaction_object &sto); + bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); private: std::string ip; @@ -112,6 +116,9 @@ private: fc::future on_changed_objects_task; bitcoin::bitcoin_address::network network_type; + std::mutex event_handler_mutex; + typedef std::lock_guard scoped_lock; + std::string create_primary_wallet_address(const std::vector &son_pubkeys); std::string create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address); diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp new file mode 100644 index 00000000..47e6bf90 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_hive.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include + +#include + +#include + +#include +#include +#include + +namespace graphene { namespace peerplays_sidechain { + +class hive_node_rpc_client : public rpc_client { +public: + hive_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls); + + std::string account_history_api_get_transaction(std::string transaction_id); + std::string block_api_get_block(uint32_t block_number); + std::string condenser_api_get_accounts(std::vector accounts); + std::string condenser_api_get_config(); + std::string database_api_get_dynamic_global_properties(); + std::string database_api_get_version(); + std::string network_broadcast_api_broadcast_transaction(std::string htrx); + + std::string get_account(std::string account); + std::string get_account_memo_key(std::string account); + std::string get_chain_id(); + std::string get_head_block_id(); + std::string get_head_block_time(); + std::string get_is_test_net(); + std::string get_last_irreversible_block_num(); +}; + +class sidechain_net_handler_hive : public sidechain_net_handler { +public: + sidechain_net_handler_hive(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options); + virtual ~sidechain_net_handler_hive(); + + bool process_proposal(const proposal_object &po); + void process_primary_wallet(); + void process_sidechain_addresses(); + bool process_deposit(const son_wallet_deposit_object &swdo); + bool process_withdrawal(const son_wallet_withdraw_object &swwo); + std::string process_sidechain_transaction(const sidechain_transaction_object &sto); + std::string send_sidechain_transaction(const sidechain_transaction_object &sto); + bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); + +private: + std::string node_rpc_url; + std::string node_rpc_user; + std::string node_rpc_password; + hive_node_rpc_client *node_rpc_client; + + hive::chain_id_type chain_id; + hive::network network_type; + + uint64_t last_block_received; + fc::future _listener_task; + boost::signals2::signal event_received; + void schedule_hive_listener(); + void hive_listener_loop(); + void handle_event(const std::string &event_data); +}; + +}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp index aa094d95..69eea1a9 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_peerplays.hpp @@ -4,8 +4,6 @@ #include -#include - namespace graphene { namespace peerplays_sidechain { class sidechain_net_handler_peerplays : public sidechain_net_handler { @@ -20,10 +18,9 @@ public: bool process_withdrawal(const son_wallet_withdraw_object &swwo); std::string process_sidechain_transaction(const sidechain_transaction_object &sto); std::string send_sidechain_transaction(const sidechain_transaction_object &sto); - int64_t settle_sidechain_transaction(const sidechain_transaction_object &sto); + bool settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount); private: - void on_applied_block(const signed_block &b); }; }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp index c2d40e14..a35c1933 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_manager.hpp @@ -29,6 +29,8 @@ private: peerplays_sidechain_plugin &plugin; graphene::chain::database &database; std::vector> net_handlers; + + void on_applied_block(const signed_block &b); }; }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 7a57effb..67a1783f 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -29,6 +29,7 @@ public: boost::program_options::options_description &cfg); void plugin_initialize(const boost::program_options::variables_map &opt); void plugin_startup(); + void plugin_shutdown(); std::set &get_sons(); const son_id_type get_current_son_id(); @@ -68,8 +69,15 @@ private: bool config_ready_son; bool config_ready_bitcoin; + bool config_ready_ethereum; + bool config_ready_hive; bool config_ready_peerplays; + bool sidechain_enabled_bitcoin; + bool sidechain_enabled_ethereum; + bool sidechain_enabled_hive; + bool sidechain_enabled_peerplays; + son_id_type current_son_id; std::unique_ptr net_manager; @@ -88,7 +96,13 @@ peerplays_sidechain_plugin_impl::peerplays_sidechain_plugin_impl(peerplays_sidec plugin(_plugin), config_ready_son(false), config_ready_bitcoin(false), + config_ready_ethereum(false), + config_ready_hive(false), config_ready_peerplays(false), + sidechain_enabled_bitcoin(false), + sidechain_enabled_ethereum(false), + sidechain_enabled_hive(false), + sidechain_enabled_peerplays(false), current_son_id(son_id_type(std::numeric_limits().max())), net_manager(nullptr), first_block_skipped(false) { @@ -125,6 +139,12 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("son-ids", bpo::value(), ("IDs of multiple SONs controlled by this node (e.g. [" + son_id_example + ", " + son_id_example2 + "], quotes are required)").c_str()); cli.add_options()("peerplays-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))), "Tuple of [PublicKey, WIF private key] (may specify multiple times)"); + + cli.add_options()("sidechain-retry-threshold", bpo::value()->default_value(150), "Sidechain retry throttling threshold"); + + cli.add_options()("debug-rpc-calls", bpo::value()->default_value(false), "Outputs RPC calls to console"); + + cli.add_options()("bitcoin-sidechain-enabled", bpo::value()->default_value(false), "Bitcoin sidechain handler enabled"); cli.add_options()("bitcoin-node-ip", bpo::value()->default_value("127.0.0.1"), "IP address of Bitcoin node"); cli.add_options()("bitcoin-node-zmq-port", bpo::value()->default_value(11111), "ZMQ port of Bitcoin node"); cli.add_options()("bitcoin-node-rpc-port", bpo::value()->default_value(8332), "RPC port of Bitcoin node"); @@ -134,7 +154,14 @@ void peerplays_sidechain_plugin_impl::plugin_set_program_options( cli.add_options()("bitcoin-wallet-password", bpo::value(), "Bitcoin wallet password"); cli.add_options()("bitcoin-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("02d0f137e717fb3aab7aff99904001d49a0a636c5e1342f8927a4ba2eaee8e9772", "cVN31uC9sTEr392DLVUEjrtMgLA8Yb3fpYmTRj7bomTm6nn2ANPr")), "Tuple of [Bitcoin public key, Bitcoin private key] (may specify multiple times)"); - cli.add_options()("sidechain-retry-threshold", bpo::value()->default_value(150), "Sidechain retry throttling threshold"); + + cli.add_options()("hive-sidechain-enabled", bpo::value()->default_value(false), "Hive sidechain handler enabled"); + cli.add_options()("hive-node-rpc-url", bpo::value()->default_value("127.0.0.1:28090"), "Hive node RPC URL [http[s]://]host[:port]"); + cli.add_options()("hive-node-rpc-user", bpo::value(), "Hive node RPC user"); + cli.add_options()("hive-node-rpc-password", bpo::value(), "Hive node RPC password"); + cli.add_options()("hive-private-key", bpo::value>()->composing()->multitoken()->DEFAULT_VALUE_VECTOR(std::make_pair("TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4", "5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n")), + "Tuple of [Hive public key, Hive private key] (may specify multiple times)"); + cfg.add(cli); } @@ -143,8 +170,10 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt config_ready_son = (options.count("son-id") || options.count("son-ids")) && options.count("peerplays-private-key"); if (config_ready_son) { LOAD_VALUE_SET(options, "son-id", sons, chain::son_id_type) - if (options.count("son-ids")) - boost::insert(sons, fc::json::from_string(options.at("son-ids").as()).as>(5)); + if (options.count("son-ids")) { + vector v = fc::json::from_string(options.at("son-ids").as()).as>(5); + sons.insert(v.begin(), v.end()); + } config_ready_son = config_ready_son && !sons.empty(); #ifndef ENABLE_MULTIPLE_SONS @@ -172,7 +201,9 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt } config_ready_son = config_ready_son && !private_keys.empty(); } - retries_threshold = options.at("sidechain-retry-threshold").as(); + if (options.count("sidechain-retry-threshold")) { + retries_threshold = options.at("sidechain-retry-threshold").as(); + } ilog("sidechain-retry-threshold: ${sidechain-retry-threshold}", ("sidechain-retry-threshold", retries_threshold)); } if (!config_ready_son) { @@ -180,27 +211,46 @@ void peerplays_sidechain_plugin_impl::plugin_initialize(const boost::program_opt throw; } + sidechain_enabled_bitcoin = options.at("bitcoin-sidechain-enabled").as(); config_ready_bitcoin = options.count("bitcoin-node-ip") && options.count("bitcoin-node-zmq-port") && options.count("bitcoin-node-rpc-port") && options.count("bitcoin-node-rpc-user") && options.count("bitcoin-node-rpc-password") && - /*options.count( "bitcoin-wallet" ) && options.count( "bitcoin-wallet-password" ) &&*/ + /*options.count("bitcoin-wallet") && options.count("bitcoin-wallet-password") &&*/ options.count("bitcoin-private-key"); if (!config_ready_bitcoin) { wlog("Haven't set up Bitcoin sidechain parameters"); } - //config_ready_ethereum = options.count( "ethereum-node-ip" ) && - // options.count( "ethereum-address" ) && options.count( "ethereum-public-key" ) && options.count( "ethereum-private-key" ); + //sidechain_enabled_ethereum = options.at("ethereum-sidechain-enabled").as(); + //config_ready_ethereum = options.count("ethereum-node-ip") && + // options.count("ethereum-address") && + // options.count("ethereum-public-key") && options.count("ethereum-private-key"); //if (!config_ready_ethereum) { // wlog("Haven't set up Ethereum sidechain parameters"); //} + sidechain_enabled_hive = options.at("hive-sidechain-enabled").as(); + config_ready_hive = options.count("hive-node-rpc-url") && + /*options.count("hive-node-rpc-user") && options.count("hive-node-rpc-password") &&*/ + options.count("hive-private-key"); + if (!config_ready_hive) { + wlog("Haven't set up Hive sidechain parameters"); + } + +#ifdef ENABLE_PEERPLAYS_ASSET_DEPOSITS + sidechain_enabled_peerplays = true; //options.at("peerplays-sidechain-enabled").as(); +#else + sidechain_enabled_peerplays = false; +#endif config_ready_peerplays = true; if (!config_ready_peerplays) { wlog("Haven't set up Peerplays sidechain parameters"); } - if (!(config_ready_bitcoin /*&& config_ready_ethereum*/ && config_ready_peerplays)) { + if (!(config_ready_bitcoin && + /*config_ready_ethereum &&*/ + config_ready_hive && + config_ready_peerplays)) { wlog("Haven't set up any sidechain parameters"); throw; } @@ -218,17 +268,22 @@ void peerplays_sidechain_plugin_impl::plugin_startup() { net_manager = std::unique_ptr(new sidechain_net_manager(plugin)); - if (config_ready_bitcoin) { + if (sidechain_enabled_bitcoin && config_ready_bitcoin) { net_manager->create_handler(sidechain_type::bitcoin, options); ilog("Bitcoin sidechain handler running"); } - //if (config_ready_ethereum) { + //if (sidechain_enabled_ethereum && config_ready_ethereum) { // net_manager->create_handler(sidechain_type::ethereum, options); // ilog("Ethereum sidechain handler running"); //} - if (config_ready_peerplays) { + if (sidechain_enabled_hive && config_ready_hive) { + net_manager->create_handler(sidechain_type::hive, options); + ilog("Hive sidechain handler running"); + } + + if (sidechain_enabled_peerplays && config_ready_peerplays) { net_manager->create_handler(sidechain_type::peerplays, options); ilog("Peerplays sidechain handler running"); } @@ -238,6 +293,9 @@ void peerplays_sidechain_plugin_impl::plugin_startup() { }); } +void peerplays_sidechain_plugin_impl::plugin_shutdown() { +} + std::set &peerplays_sidechain_plugin_impl::get_sons() { return sons; } @@ -388,9 +446,15 @@ void peerplays_sidechain_plugin_impl::son_processing() { return; } + //fc::time_point now_fine = fc::time_point::now(); + //fc::time_point_sec now = now_fine + fc::microseconds(500000); + //if (plugin.database().get_slot_time(1) < now) { + // return; // Not synced + //} + fc::time_point now_fine = fc::time_point::now(); - fc::time_point_sec now = now_fine + fc::microseconds(500000); - if (plugin.database().get_slot_time(1) < now) { + fc::time_point_sec now = now_fine - fc::milliseconds(3000); + if (plugin.database().head_block_time() < now) { return; // Not synced } @@ -684,6 +748,12 @@ void peerplays_sidechain_plugin::plugin_startup() { ilog("peerplays sidechain plugin: plugin_startup() end"); } +void peerplays_sidechain_plugin::plugin_shutdown() { + ilog("peerplays sidechain plugin: plugin_shutdown() begin"); + my->plugin_shutdown(); + ilog("peerplays sidechain plugin: plugin_shutdown() end"); +} + std::set &peerplays_sidechain_plugin::get_sons() { return my->get_sons(); } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp index d025c178..06a76502 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler.cpp @@ -1,14 +1,21 @@ #include +#include + #include #include #include +#include namespace graphene { namespace peerplays_sidechain { sidechain_net_handler::sidechain_net_handler(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : plugin(_plugin), database(_plugin.database()) { + + database.applied_block.connect([&](const signed_block &b) { + on_applied_block(b); + }); } sidechain_net_handler::~sidechain_net_handler() { @@ -161,21 +168,25 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ const chain::global_property_object &gpo = database.get_global_properties(); - asset_id_type btc_asset_id = database.get_global_properties().parameters.btc_asset(); - std::string btc_asset_id_str = fc::to_string(btc_asset_id.space_id) + "." + - fc::to_string(btc_asset_id.type_id) + "." + - fc::to_string((uint64_t)btc_asset_id.instance); - + bool enable_peerplays_asset_deposits = false; #ifdef ENABLE_PEERPLAYS_ASSET_DEPOSITS - // Accepts BTC and peerplays asset deposits - bool deposit_condition = ((sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain_currency.compare(btc_asset_id_str) != 0)); - bool withdraw_condition = ((sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain_currency.compare(btc_asset_id_str) == 0)); -#else - // Accepts BTC deposits only - bool deposit_condition = ((sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain_currency.compare("BTC") == 0)); - bool withdraw_condition = ((sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain_currency.compare(btc_asset_id_str) == 0)); + //enable_peerplays_asset_deposits = (sed.sidechain == sidechain_type::peerplays) && + // (sed.sidechain_currency.compare("BTC") != 0) && + // (sed.sidechain_currency.compare("HBD") != 0) && + // (sed.sidechain_currency.compare("HIVE") != 0); #endif + bool deposit_condition = (sed.peerplays_to == gpo.parameters.son_account()) && + (((sed.sidechain == sidechain_type::bitcoin) && (sed.sidechain_currency.compare("BTC") == 0)) || + ((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HBD") == 0)) || + ((sed.sidechain == sidechain_type::hive) && (sed.sidechain_currency.compare("HIVE") == 0)) || + enable_peerplays_asset_deposits); + + bool withdraw_condition = (sed.peerplays_to == gpo.parameters.son_account()) && (sed.sidechain == sidechain_type::peerplays) && + ((sed.sidechain_currency == object_id_to_string(gpo.parameters.btc_asset())) || + (sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) || + (sed.sidechain_currency == object_id_to_string(gpo.parameters.hive_asset()))); + // Deposit request if (deposit_condition) { @@ -214,11 +225,32 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ // Withdrawal request if (withdraw_condition) { - // BTC Payout only (for now) + std::string withdraw_address = ""; const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); - const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sed.peerplays_from, sidechain_type::bitcoin, time_point_sec::maximum())); - if (addr_itr == sidechain_addresses_idx.end()) + const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sed.peerplays_from, sidechain, time_point_sec::maximum())); + if (addr_itr != sidechain_addresses_idx.end()) { + withdraw_address = addr_itr->withdraw_address; + } else { + withdraw_address = sed.sidechain_from; + } + + std::string withdraw_currency = ""; + price withdraw_currency_price = {}; + if (sed.sidechain_currency == object_id_to_string(gpo.parameters.btc_asset())) { + withdraw_currency = "BTC"; + withdraw_currency_price = database.get(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate; + } + if (sed.sidechain_currency == object_id_to_string(gpo.parameters.hbd_asset())) { + withdraw_currency = "HBD"; + withdraw_currency_price = database.get(database.get_global_properties().parameters.hbd_asset()).options.core_exchange_rate; + } + if (sed.sidechain_currency == object_id_to_string(gpo.parameters.hive_asset())) { + withdraw_currency = "HIVE"; + withdraw_currency_price = database.get(database.get_global_properties().parameters.hive_asset()).options.core_exchange_rate; + } + if (withdraw_currency.empty()) { return; + } for (son_id_type son_id : plugin.get_sons()) { if (plugin.is_active_son(son_id)) { @@ -233,12 +265,10 @@ void sidechain_net_handler::sidechain_event_data_received(const sidechain_event_ op.peerplays_transaction_id = sed.sidechain_transaction_id; op.peerplays_from = sed.peerplays_from; op.peerplays_asset = sed.peerplays_asset; - // BTC payout only (for now) - op.withdraw_sidechain = sidechain_type::bitcoin; - op.withdraw_address = addr_itr->withdraw_address; - op.withdraw_currency = "BTC"; - price btc_price = database.get(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate; - op.withdraw_amount = sed.peerplays_asset.amount * btc_price.quote.amount / btc_price.base.amount; + op.withdraw_sidechain = sidechain; + op.withdraw_address = withdraw_address; + op.withdraw_currency = withdraw_currency; + op.withdraw_amount = sed.peerplays_asset.amount * withdraw_currency_price.quote.amount / withdraw_currency_price.base.amount; signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(son_id), op); try { @@ -389,9 +419,13 @@ void sidechain_net_handler::process_deposits() { } //Ignore the deposits which are not valid anymore, considered refunds. const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); - const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, swdo.sidechain_to, time_point_sec::maximum())); + const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, swdo.sidechain_from, time_point_sec::maximum())); if (addr_itr == sidechain_addresses_idx.end()) { - return; + const auto &account_idx = database.get_index_type().indices().get(); + const auto &account_itr = account_idx.find(swdo.sidechain_from); + if (account_itr == account_idx.end()) { + return; + } } ilog("Deposit to process: ${swdo}", ("swdo", swdo)); @@ -532,9 +566,10 @@ void sidechain_net_handler::settle_sidechain_transactions() { ilog("Sidechain transaction to settle: ${sto}", ("sto", sto.id)); - int64_t settle_amount = settle_sidechain_transaction(sto); + asset settle_amount; + bool settle_sidechain_result = settle_sidechain_transaction(sto, settle_amount); - if (settle_amount < 0) { + if (settle_sidechain_result == false) { wlog("Sidechain transaction not settled: ${sto}", ("sto", sto.id)); return; } @@ -551,12 +586,12 @@ void sidechain_net_handler::settle_sidechain_transactions() { sts_op.sidechain_transaction_id = sto.id; proposal_op.proposed_ops.emplace_back(sts_op); - if (settle_amount != 0) { + if (settle_amount.amount != 0) { if (sto.object_id.is()) { asset_issue_operation ai_op; ai_op.fee = asset(2001000); ai_op.issuer = gpo.parameters.son_account(); - ai_op.asset_to_issue = asset(settle_amount, database.get_global_properties().parameters.btc_asset()); + ai_op.asset_to_issue = settle_amount; ai_op.issue_to_account = database.get(sto.object_id).peerplays_from; proposal_op.proposed_ops.emplace_back(ai_op); } @@ -565,7 +600,7 @@ void sidechain_net_handler::settle_sidechain_transactions() { asset_reserve_operation ar_op; ar_op.fee = asset(2001000); ar_op.payer = gpo.parameters.son_account(); - ar_op.amount_to_reserve = asset(settle_amount, database.get_global_properties().parameters.btc_asset()); + ar_op.amount_to_reserve = settle_amount; proposal_op.proposed_ops.emplace_back(ar_op); } } @@ -583,4 +618,63 @@ void sidechain_net_handler::settle_sidechain_transactions() { }); } +void sidechain_net_handler::on_applied_block(const signed_block &b) { + + const chain::global_property_object &gpo = plugin.database().get_global_properties(); + + for (const auto &trx : b.transactions) { + size_t operation_index = -1; + for (auto op : trx.operations) { + operation_index = operation_index + 1; + if (op.which() == operation::tag::value) { + transfer_operation transfer_op = op.get(); + + if (transfer_op.to != gpo.parameters.son_account()) { + continue; + } + + bool is_tracked_asset = + ((sidechain == sidechain_type::bitcoin) && (transfer_op.amount.asset_id == gpo.parameters.btc_asset())) || + ((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hbd_asset())) || + ((sidechain == sidechain_type::hive) && (transfer_op.amount.asset_id == gpo.parameters.hive_asset())); + + if (!is_tracked_asset) { + continue; + } + + std::string sidechain_from = object_id_to_string(transfer_op.from); + std::string memo = ""; + if (transfer_op.memo) { + memo = transfer_op.memo->get_message(fc::ecc::private_key(), public_key_type()); + boost::trim(memo); + if (!memo.empty()) { + sidechain_from = memo; + } + } + + std::stringstream ss; + ss << "peerplays" + << "-" << trx.id().str() << "-" << operation_index; + std::string sidechain_uid = ss.str(); + + sidechain_event_data sed; + sed.timestamp = database.head_block_time(); + sed.block_num = database.head_block_num(); + sed.sidechain = sidechain_type::peerplays; + sed.sidechain_uid = sidechain_uid; + sed.sidechain_transaction_id = trx.id().str(); + sed.sidechain_from = sidechain_from; + sed.sidechain_to = object_id_to_string(transfer_op.to); + sed.sidechain_currency = object_id_to_string(transfer_op.amount.asset_id); + sed.sidechain_amount = transfer_op.amount.amount; + sed.peerplays_from = transfer_op.from; + sed.peerplays_to = transfer_op.to; + price asset_price = database.get(transfer_op.amount.asset_id).options.core_exchange_rate; + sed.peerplays_asset = asset(transfer_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); + sidechain_event_data_received(sed); + } + } + } +} + }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index 7c0b0074..1ad0d9c8 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -26,13 +26,14 @@ namespace graphene { namespace peerplays_sidechain { // ============================================================================= -bitcoin_rpc_client::bitcoin_rpc_client(std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet, std::string _wallet_password) : +bitcoin_rpc_client::bitcoin_rpc_client(std::string _ip, uint32_t _rpc, std::string _user, std::string _password, std::string _wallet, std::string _wallet_password, bool _debug_rpc_calls) : ip(_ip), rpc_port(_rpc), user(_user), password(_password), wallet(_wallet), - wallet_password(_wallet_password) { + wallet_password(_wallet_password), + debug_rpc_calls(_debug_rpc_calls) { authorization.key = "Authorization"; authorization.val = "Basic " + fc::base64_encode(user + ":" + password); } @@ -51,7 +52,7 @@ std::string bitcoin_rpc_client::addmultisigaddress(const uint32_t nrequired, con params = params + pubkeys + std::string("]"); body = body + params + std::string(", null, \"bech32\"] }"); - const auto reply = send_post_request(body); + const auto reply = send_post_request(body, debug_rpc_calls); if (reply.body.empty()) { wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); @@ -83,7 +84,7 @@ std::string bitcoin_rpc_client::combinepsbt(const vector &psbts) { params = params + std::string("\"") + psbt + std::string("\""); } body = body + params + std::string("]] }"); - const auto reply = send_post_request(body); + const auto reply = send_post_request(body, debug_rpc_calls); if (reply.body.empty()) { wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); @@ -120,7 +121,7 @@ std::string bitcoin_rpc_client::createmultisig(const uint32_t nrequired, const s params = params + pubkeys + std::string("]"); body = body + params + std::string(", \"p2sh-segwit\" ] }"); - const auto reply = send_post_request(body); + const auto reply = send_post_request(body, debug_rpc_calls); if (reply.body.empty()) { wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); @@ -162,7 +163,7 @@ std::string bitcoin_rpc_client::createpsbt(const std::vector &ins, co } body += std::string("]] }"); - const auto reply = send_post_request(body); + const auto reply = send_post_request(body, debug_rpc_calls); if (reply.body.empty()) { wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); @@ -206,7 +207,7 @@ std::string bitcoin_rpc_client::createrawtransaction(const std::vector bitcoin_rpc_client::listunspent(const uint32_t minconf, c "\"listunspent\", \"params\": [" + std::to_string(minconf) + "," + std::to_string(maxconf) + "] }"); - const auto reply = send_post_request(body); + const auto reply = send_post_request(body, debug_rpc_calls); std::vector result; @@ -617,7 +618,7 @@ std::vector bitcoin_rpc_client::listunspent_by_address_and_amount(con body += std::to_string(minimum_amount); body += std::string("} ] }"); - const auto reply = send_post_request(body); + const auto reply = send_post_request(body, debug_rpc_calls); std::vector result; if (reply.body.empty()) { @@ -652,7 +653,7 @@ std::string bitcoin_rpc_client::loadwallet(const std::string &filename) { "\"loadwallet\", \"params\": [\"" + filename + "\"] }"); - const auto reply = send_post_request(body); + const auto reply = send_post_request(body, debug_rpc_calls); if (reply.body.empty()) { wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); @@ -680,7 +681,7 @@ std::string bitcoin_rpc_client::sendrawtransaction(const std::string &tx_hex) { "\"method\": \"sendrawtransaction\", \"params\": [") + std::string("\"") + tx_hex + std::string("\"") + std::string("] }"); - const auto reply = send_post_request(body); + const auto reply = send_post_request(body, debug_rpc_calls); if (reply.body.empty()) { wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); @@ -707,7 +708,7 @@ std::string bitcoin_rpc_client::signrawtransactionwithwallet(const std::string & std::string params = "\"" + tx_hash + "\""; body = body + params + std::string("]}"); - const auto reply = send_post_request(body); + const auto reply = send_post_request(body, debug_rpc_calls); if (reply.body.empty()) { wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); @@ -733,7 +734,7 @@ std::string bitcoin_rpc_client::unloadwallet(const std::string &filename) { "\"unloadwallet\", \"params\": [\"" + filename + "\"] }"); - const auto reply = send_post_request(body); + const auto reply = send_post_request(body, debug_rpc_calls); if (reply.body.empty()) { wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); @@ -760,7 +761,7 @@ std::string bitcoin_rpc_client::unloadwallet(const std::string &filename) { // std::string body = std::string("{\"jsonrpc\": \"1.0\", \"id\":\"walletlock\", \"method\": " // "\"walletlock\", \"params\": [] }"); // -// const auto reply = send_post_request(body); +// const auto reply = send_post_request(body, debug_rpc_calls); // // if (reply.body.empty()) { // wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); @@ -788,7 +789,7 @@ std::string bitcoin_rpc_client::walletprocesspsbt(std::string const &tx_psbt) { "\"walletprocesspsbt\", \"params\": [\"" + tx_psbt + "\"] }"); - const auto reply = send_post_request(body); + const auto reply = send_post_request(body, debug_rpc_calls); if (reply.body.empty()) { wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); @@ -814,7 +815,7 @@ std::string bitcoin_rpc_client::walletprocesspsbt(std::string const &tx_psbt) { // "\"walletpassphrase\", \"params\": [\"" + // passphrase + "\", " + std::to_string(timeout) + "] }"); // -// const auto reply = send_post_request(body); +// const auto reply = send_post_request(body, debug_rpc_calls); // // if (reply.body.empty()) { // wlog("Bitcoin RPC call ${function} failed", ("function", __FUNCTION__)); @@ -911,6 +912,10 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain sidechain_net_handler(_plugin, options) { sidechain = sidechain_type::bitcoin; + if (options.count("debug-rpc-calls")) { + debug_rpc_calls = options.at("debug-rpc-calls").as(); + } + ip = options.at("bitcoin-node-ip").as(); zmq_port = options.at("bitcoin-node-zmq-port").as(); rpc_port = options.at("bitcoin-node-rpc-port").as(); @@ -945,7 +950,7 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain FC_ASSERT(false); } - bitcoin_client = std::unique_ptr(new bitcoin_rpc_client(ip, rpc_port, rpc_user, rpc_password, wallet, wallet_password)); + bitcoin_client = std::unique_ptr(new bitcoin_rpc_client(ip, rpc_port, rpc_user, rpc_password, wallet, wallet_password, debug_rpc_calls)); if (!wallet.empty()) { bitcoin_client->loadwallet(wallet); } @@ -989,7 +994,7 @@ sidechain_net_handler_bitcoin::~sidechain_net_handler_bitcoin() { bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) { - ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); + //ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); bool should_approve = false; @@ -1094,7 +1099,7 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) if (swdo != idx.end()) { std::string swdo_txid = swdo->sidechain_transaction_id; - std::string swdo_address = swdo->sidechain_to; + std::string swdo_address = swdo->sidechain_from; uint64_t swdo_amount = swdo->sidechain_amount.value; uint64_t swdo_vout = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-") + 1)); @@ -1108,8 +1113,8 @@ bool sidechain_net_handler_bitcoin::process_proposal(const proposal_object &po) std::string tx_txid = tx_json.get("result.txid"); uint32_t tx_confirmations = tx_json.get("result.confirmations"); std::string tx_address = ""; - int64_t tx_amount = -1; - int64_t tx_vout = -1; + uint64_t tx_amount = -1; + uint64_t tx_vout = -1; for (auto &input : tx_json.get_child("result.vout")) { std::string tx_vout_s = input.second.get("n"); @@ -1354,38 +1359,44 @@ void sidechain_net_handler_bitcoin::process_sidechain_addresses() { const auto &sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain); std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second, [&](const sidechain_address_object &sao) { - if (sao.expires == time_point_sec::maximum()) { - auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key))); + bool retval = true; + try { + if (sao.expires == time_point_sec::maximum()) { + auto usr_pubkey = fc::ecc::public_key(create_public_key_data(parse_hex(sao.deposit_public_key))); - btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type); - std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) + - "\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }"; + btc_one_or_weighted_multisig_address addr(usr_pubkey, pubkeys, network_type); + std::string address_data = "{ \"redeemScript\": \"" + fc::to_hex(addr.get_redeem_script()) + + "\", \"witnessScript\": \"" + fc::to_hex(addr.get_witness_script()) + "\" }"; - if (addr.get_address() != sao.deposit_address) { - sidechain_address_update_operation op; - op.payer = plugin.get_current_son_object().son_account; - op.sidechain_address_id = sao.id; - op.sidechain_address_account = sao.sidechain_address_account; - op.sidechain = sao.sidechain; - op.deposit_public_key = sao.deposit_public_key; - op.deposit_address = addr.get_address(); - op.deposit_address_data = address_data; - op.withdraw_public_key = sao.withdraw_public_key; - op.withdraw_address = sao.withdraw_address; + if (addr.get_address() != sao.deposit_address) { + sidechain_address_update_operation op; + op.payer = plugin.get_current_son_object().son_account; + op.sidechain_address_id = sao.id; + op.sidechain_address_account = sao.sidechain_address_account; + op.sidechain = sao.sidechain; + op.deposit_public_key = sao.deposit_public_key; + op.deposit_address = addr.get_address(); + op.deposit_address_data = address_data; + op.withdraw_public_key = sao.withdraw_public_key; + op.withdraw_address = sao.withdraw_address; - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - return true; - } catch (fc::exception &e) { - elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); - return false; + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + retval = true; + } catch (fc::exception &e) { + elog("Sending transaction for sidechain address update operation failed with exception ${e}", ("e", e.what())); + retval = false; + } } } + } catch (fc::exception &e) { + retval = false; } + return retval; }); } @@ -1485,16 +1496,15 @@ std::string sidechain_net_handler_bitcoin::send_sidechain_transaction(const side return send_transaction(sto); } -int64_t sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain_transaction_object &sto) { +bool sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) { if (sto.object_id.is()) { - return 0; + settle_amount = asset(0, database.get_global_properties().parameters.btc_asset()); + return true; } - int64_t settle_amount = -1; - if (sto.sidechain_transaction.empty()) { - return settle_amount; + return false; } std::string tx_str = bitcoin_client->getrawtransaction(sto.sidechain_transaction, true); @@ -1503,7 +1513,7 @@ int64_t sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidech boost::property_tree::read_json(tx_ss, tx_json); if ((tx_json.count("error")) && (!tx_json.get_child("error").empty())) { - return settle_amount; + return false; } const chain::global_property_object &gpo = database.get_global_properties(); @@ -1534,15 +1544,17 @@ int64_t sidechain_net_handler_bitcoin::settle_sidechain_transaction(const sidech } } } - settle_amount = tx_amount; + settle_amount = asset(tx_amount, database.get_global_properties().parameters.btc_asset()); + return true; } if (sto.object_id.is()) { auto swwo = database.get(sto.object_id); - settle_amount = swwo.withdraw_amount.value; + settle_amount = asset(swwo.withdraw_amount, database.get_global_properties().parameters.btc_asset()); + return true; } } - return settle_amount; + return false; } std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const std::vector &son_pubkeys) { @@ -1568,7 +1580,17 @@ std::string sidechain_net_handler_bitcoin::create_primary_wallet_address(const s std::string sidechain_net_handler_bitcoin::create_primary_wallet_transaction(const son_wallet_object &prev_swo, std::string new_sw_address) { - std::stringstream prev_sw_ss(prev_swo.addresses.find(sidechain_type::bitcoin)->second); + const auto &address_data = prev_swo.addresses.find(sidechain_type::bitcoin); + if (address_data == prev_swo.addresses.end()) { + return ""; + } + + std::string s = address_data->second; + if (s.empty()) { + return ""; + } + + std::stringstream prev_sw_ss(s); boost::property_tree::ptree prev_sw_pt; boost::property_tree::read_json(prev_sw_ss, prev_sw_pt); std::string prev_pw_address = prev_sw_pt.get("address"); @@ -1613,7 +1635,7 @@ std::string sidechain_net_handler_bitcoin::create_deposit_transaction(const son_ return ""; } //Get redeem script for deposit address - std::string redeem_script = get_redeemscript_for_userdeposit(swdo.sidechain_to); + std::string redeem_script = get_redeemscript_for_userdeposit(swdo.sidechain_from); std::string pw_address_json = obj->addresses.find(sidechain_type::bitcoin)->second; std::stringstream ss(pw_address_json); @@ -1663,11 +1685,11 @@ std::string sidechain_net_handler_bitcoin::create_withdrawal_transaction(const s std::string pw_address = json.get("address"); std::string redeem_script = json.get("redeemScript"); - uint64_t fee_rate = bitcoin_client->estimatesmartfee(); - uint64_t min_fee_rate = 1000; + int64_t fee_rate = bitcoin_client->estimatesmartfee(); + int64_t min_fee_rate = 1000; fee_rate = std::max(fee_rate, min_fee_rate); - uint64_t total_amount = 0; + int64_t total_amount = 0; std::vector inputs = bitcoin_client->listunspent_by_address_and_amount(pw_address, 0); if (inputs.size() == 0) { @@ -1783,38 +1805,39 @@ std::string sidechain_net_handler_bitcoin::send_transaction(const sidechain_tran void sidechain_net_handler_bitcoin::handle_event(const std::string &event_data) { std::string block = bitcoin_client->getblock(event_data); - if (block != "") { - const auto &vins = extract_info_from_block(block); + if (block.empty()) + return; - const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); + auto vins = extract_info_from_block(block); + scoped_lock interlock(event_handler_mutex); + const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); - for (const auto &v : vins) { - // !!! EXTRACT DEPOSIT ADDRESS FROM SIDECHAIN ADDRESS OBJECT - const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, v.address, time_point_sec::maximum())); - if (addr_itr == sidechain_addresses_idx.end()) - continue; + for (const auto &v : vins) { + // !!! EXTRACT DEPOSIT ADDRESS FROM SIDECHAIN ADDRESS OBJECT + const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, v.address, time_point_sec::maximum())); + if (addr_itr == sidechain_addresses_idx.end()) + continue; - std::stringstream ss; - ss << "bitcoin" - << "-" << v.out.hash_tx << "-" << v.out.n_vout; - std::string sidechain_uid = ss.str(); + std::stringstream ss; + ss << "bitcoin" + << "-" << v.out.hash_tx << "-" << v.out.n_vout; + std::string sidechain_uid = ss.str(); - sidechain_event_data sed; - sed.timestamp = database.head_block_time(); - sed.block_num = database.head_block_num(); - sed.sidechain = addr_itr->sidechain; - sed.sidechain_uid = sidechain_uid; - sed.sidechain_transaction_id = v.out.hash_tx; - sed.sidechain_from = ""; - sed.sidechain_to = v.address; - sed.sidechain_currency = "BTC"; - sed.sidechain_amount = v.out.amount; - sed.peerplays_from = addr_itr->sidechain_address_account; - sed.peerplays_to = database.get_global_properties().parameters.son_account(); - price btc_price = database.get(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate; - sed.peerplays_asset = asset(sed.sidechain_amount * btc_price.base.amount / btc_price.quote.amount); - sidechain_event_data_received(sed); - } + sidechain_event_data sed; + sed.timestamp = database.head_block_time(); + sed.block_num = database.head_block_num(); + sed.sidechain = addr_itr->sidechain; + sed.sidechain_uid = sidechain_uid; + sed.sidechain_transaction_id = v.out.hash_tx; + sed.sidechain_from = v.address; + sed.sidechain_to = ""; + sed.sidechain_currency = "BTC"; + sed.sidechain_amount = v.out.amount; + sed.peerplays_from = addr_itr->sidechain_address_account; + sed.peerplays_to = database.get_global_properties().parameters.son_account(); + price btc_price = database.get(database.get_global_properties().parameters.btc_asset()).options.core_exchange_rate; + sed.peerplays_asset = asset(sed.sidechain_amount * btc_price.base.amount / btc_price.quote.amount); + sidechain_event_data_received(sed); } } diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp new file mode 100644 index 00000000..499f1e65 --- /dev/null +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_hive.cpp @@ -0,0 +1,943 @@ +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace graphene { namespace peerplays_sidechain { + +hive_node_rpc_client::hive_node_rpc_client(const std::string &url, const std::string &user_name, const std::string &password, bool debug_rpc_calls) : + rpc_client(url, user_name, password, debug_rpc_calls) { +} + +std::string hive_node_rpc_client::account_history_api_get_transaction(std::string transaction_id) { + std::string params = "{ \"id\": \"" + transaction_id + "\" }"; + return send_post_request("account_history_api.get_transaction", params, debug_rpc_calls); +} + +std::string hive_node_rpc_client::block_api_get_block(uint32_t block_number) { + std::string params = "{ \"block_num\": " + std::to_string(block_number) + " }"; + return send_post_request("block_api.get_block", params, debug_rpc_calls); +} + +std::string hive_node_rpc_client::condenser_api_get_accounts(std::vector accounts) { + std::string params = ""; + for (auto account : accounts) { + if (!params.empty()) { + params = params + ","; + } + params = "\"" + account + "\""; + } + params = "[[" + params + "]]"; + return send_post_request("condenser_api.get_accounts", params, debug_rpc_calls); +} + +std::string hive_node_rpc_client::condenser_api_get_config() { + std::string params = "[]"; + return send_post_request("condenser_api.get_config", params, debug_rpc_calls); +} + +std::string hive_node_rpc_client::database_api_get_dynamic_global_properties() { + return send_post_request("database_api.get_dynamic_global_properties", "", debug_rpc_calls); +} + +std::string hive_node_rpc_client::database_api_get_version() { + return send_post_request("database_api.get_version", "", debug_rpc_calls); +} + +std::string hive_node_rpc_client::network_broadcast_api_broadcast_transaction(std::string htrx) { + std::string params = "{ \"trx\": " + htrx + ", \"max_block_age\": -1 }"; + return send_post_request("network_broadcast_api.broadcast_transaction", params, debug_rpc_calls); +} + +std::string hive_node_rpc_client::get_account(std::string account) { + std::vector accounts; + accounts.push_back(account); + std::string reply_str = condenser_api_get_accounts(accounts); + return retrieve_array_value_from_reply(reply_str, "", 0); +} + +std::string hive_node_rpc_client::get_account_memo_key(std::string account) { + std::string reply_str = get_account(account); + reply_str = "{\"result\":" + reply_str + "}"; + return retrieve_value_from_reply(reply_str, "memo_key"); +} + +std::string hive_node_rpc_client::get_chain_id() { + std::string reply_str = database_api_get_version(); + return retrieve_value_from_reply(reply_str, "chain_id"); +} + +std::string hive_node_rpc_client::get_head_block_id() { + std::string reply_str = database_api_get_dynamic_global_properties(); + return retrieve_value_from_reply(reply_str, "head_block_id"); +} + +std::string hive_node_rpc_client::get_head_block_time() { + std::string reply_str = database_api_get_dynamic_global_properties(); + return retrieve_value_from_reply(reply_str, "time"); +} + +std::string hive_node_rpc_client::get_is_test_net() { + std::string reply_str = condenser_api_get_config(); + return retrieve_value_from_reply(reply_str, "IS_TEST_NET"); +} + +std::string hive_node_rpc_client::get_last_irreversible_block_num() { + std::string reply_str = database_api_get_dynamic_global_properties(); + return retrieve_value_from_reply(reply_str, "last_irreversible_block_num"); +} + +sidechain_net_handler_hive::sidechain_net_handler_hive(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : + sidechain_net_handler(_plugin, options) { + sidechain = sidechain_type::hive; + + if (options.count("debug-rpc-calls")) { + debug_rpc_calls = options.at("debug-rpc-calls").as(); + } + + node_rpc_url = options.at("hive-node-rpc-url").as(); + if (options.count("hive-node-rpc-user")) { + node_rpc_user = options.at("hive-node-rpc-user").as(); + } else { + node_rpc_user = ""; + } + if (options.count("hive-node-rpc-password")) { + node_rpc_password = options.at("hive-node-rpc-password").as(); + } else { + node_rpc_password = ""; + } + + if (options.count("hive-private-key")) { + const std::vector pub_priv_keys = options["hive-private-key"].as>(); + for (const std::string &itr_key_pair : pub_priv_keys) { + auto key_pair = graphene::app::dejsonify>(itr_key_pair, 5); + ilog("Hive Public Key: ${public}", ("public", key_pair.first)); + if (!key_pair.first.length() || !key_pair.second.length()) { + FC_THROW("Invalid public private key pair."); + } + private_keys[key_pair.first] = key_pair.second; + } + } + + node_rpc_client = new hive_node_rpc_client(node_rpc_url, node_rpc_user, node_rpc_password, debug_rpc_calls); + + std::string chain_id_str = node_rpc_client->get_chain_id(); + if (chain_id_str.empty()) { + elog("No Hive node running at ${url}", ("url", node_rpc_url)); + FC_ASSERT(false); + } + chain_id = chain_id_type(chain_id_str); + + std::string is_test_net = node_rpc_client->get_is_test_net(); + network_type = is_test_net.compare("true") == 0 ? hive::network::testnet : hive::network::mainnet; + if (network_type == hive::network::mainnet) { + ilog("Running on Hive mainnet, chain id ${chain_id_str}", ("chain_id_str", chain_id_str)); + hive::asset::hbd_symbol_ser = HBD_SYMBOL_SER; + hive::asset::hive_symbol_ser = HIVE_SYMBOL_SER; + hive::public_key_type::prefix = KEY_PREFIX_STM; + } else { + ilog("Running on Hive testnet, chain id ${chain_id_str}", ("chain_id_str", chain_id_str)); + hive::asset::hbd_symbol_ser = TBD_SYMBOL_SER; + hive::asset::hive_symbol_ser = TESTS_SYMBOL_SER; + hive::public_key_type::prefix = KEY_PREFIX_TST; + } + + last_block_received = 0; + schedule_hive_listener(); + event_received.connect([this](const std::string &event_data) { + std::thread(&sidechain_net_handler_hive::handle_event, this, event_data).detach(); + }); +} + +sidechain_net_handler_hive::~sidechain_net_handler_hive() { +} + +bool sidechain_net_handler_hive::process_proposal(const proposal_object &po) { + //ilog("Proposal to process: ${po}, SON id ${son_id}", ("po", po.id)("son_id", plugin.get_current_son_id())); + + bool should_approve = false; + + const chain::global_property_object &gpo = database.get_global_properties(); + + int32_t op_idx_0 = -1; + chain::operation op_obj_idx_0; + + if (po.proposed_transaction.operations.size() >= 1) { + op_idx_0 = po.proposed_transaction.operations[0].which(); + op_obj_idx_0 = po.proposed_transaction.operations[0]; + } + + int32_t op_idx_1 = -1; + chain::operation op_obj_idx_1; + (void)op_idx_1; + + if (po.proposed_transaction.operations.size() >= 2) { + op_idx_1 = po.proposed_transaction.operations[1].which(); + op_obj_idx_1 = po.proposed_transaction.operations[1]; + } + + switch (op_idx_0) { + + case chain::operation::tag::value: { + bool address_ok = false; + bool transaction_ok = false; + son_wallet_id_type swo_id = op_obj_idx_0.get().son_wallet_id; + const auto &idx = database.get_index_type().indices().get(); + const auto swo = idx.find(swo_id); + if (swo != idx.end()) { + + auto active_sons = gpo.active_sons; + vector wallet_sons = swo->sons; + + bool son_sets_equal = (active_sons.size() == wallet_sons.size()); + + if (son_sets_equal) { + for (size_t i = 0; i < active_sons.size(); i++) { + son_sets_equal = son_sets_equal && active_sons.at(i) == wallet_sons.at(i); + } + } + + if (son_sets_equal) { + address_ok = (op_obj_idx_0.get().address == "son-account"); + } + + if (po.proposed_transaction.operations.size() >= 2) { + object_id_type object_id = op_obj_idx_1.get().object_id; + std::string op_tx_str = op_obj_idx_1.get().transaction; + + const auto &st_idx = database.get_index_type().indices().get(); + const auto st = st_idx.find(object_id); + if (st == st_idx.end()) { + + std::string tx_str = ""; + + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swo = idx.find(object_id); + if (swo != idx.end()) { + + std::stringstream ss_trx(boost::algorithm::unhex(op_tx_str)); + hive::signed_transaction op_trx; + fc::raw::unpack(ss_trx, op_trx, 1000); + + fc::flat_map account_auths; + uint32_t total_weight = 0; + for (const auto &wallet_son : wallet_sons) { + total_weight = total_weight + wallet_son.weight; + account_auths[wallet_son.sidechain_public_keys.at(sidechain)] = wallet_son.weight; + } + + std::string memo_key = node_rpc_client->get_account_memo_key("son-account"); + + hive::authority active; + active.weight_threshold = total_weight * 2 / 3 + 1; + active.account_auths = account_auths; + + hive::account_update_operation auo; + auo.account = "son-account"; + auo.active = active; + auo.memo_key = op_trx.operations[0].get().memo_key; + + hive::signed_transaction htrx; + htrx.ref_block_num = op_trx.ref_block_num; + htrx.ref_block_prefix = op_trx.ref_block_prefix; + htrx.set_expiration(op_trx.expiration); + + htrx.operations.push_back(auo); + + std::stringstream ss; + fc::raw::pack(ss, htrx, 1000); + tx_str = boost::algorithm::hex(ss.str()); + } + } + + transaction_ok = (op_tx_str == tx_str); + } + } else { + transaction_ok = true; + } + } + + should_approve = address_ok && + transaction_ok; + break; + } + + case chain::operation::tag::value: { + bool process_ok = false; + son_wallet_deposit_id_type swdo_id = op_obj_idx_0.get().son_wallet_deposit_id; + const auto &idx = database.get_index_type().indices().get(); + const auto swdo = idx.find(swdo_id); + if (swdo != idx.end()) { + + std::string swdo_txid = swdo->sidechain_transaction_id; + std::string swdo_sidechain_from = swdo->sidechain_from; + std::string swdo_sidechain_currency = swdo->sidechain_currency; + uint64_t swdo_sidechain_amount = swdo->sidechain_amount.value; + uint64_t swdo_op_idx = std::stoll(swdo->sidechain_uid.substr(swdo->sidechain_uid.find_last_of("-"))); + + std::string tx_str = node_rpc_client->account_history_api_get_transaction(swdo_txid); + if (tx_str != "") { + + std::stringstream ss_tx(tx_str); + boost::property_tree::ptree tx; + boost::property_tree::read_json(ss_tx, tx); + + uint64_t op_idx = -1; + for (const auto &ops : tx.get_child("result.operations")) { + const auto &op = ops.second; + op_idx = op_idx + 1; + if (op_idx == swdo_op_idx) { + std::string operation_type = op.get("type"); + + if (operation_type == "transfer_operation") { + const auto &op_value = op.get_child("value"); + + std::string sidechain_from = op_value.get("from"); + + const auto &amount_child = op_value.get_child("amount"); + + uint64_t amount = amount_child.get("amount"); + std::string nai = amount_child.get("nai"); + std::string sidechain_currency = ""; + if ((nai == "@@000000013" /*?? HBD*/) || (nai == "@@000000013" /*TBD*/)) { + sidechain_currency = "HBD"; + } + if ((nai == "@@000000021") /*?? HIVE*/ || (nai == "@@000000021" /*TESTS*/)) { + sidechain_currency = "HIVE"; + } + + std::string memo = op_value.get("memo"); + boost::trim(memo); + if (!memo.empty()) { + sidechain_from = memo; + } + + process_ok = (swdo_sidechain_from == sidechain_from) && + (swdo_sidechain_currency == sidechain_currency) && + (swdo_sidechain_amount == amount); + } + } + } + } + } + should_approve = process_ok; + break; + } + + case chain::operation::tag::value: { + bool process_ok = false; + bool transaction_ok = false; + son_wallet_withdraw_id_type swwo_id = op_obj_idx_0.get().son_wallet_withdraw_id; + const auto &idx = database.get_index_type().indices().get(); + const auto swwo = idx.find(swwo_id); + if (swwo != idx.end()) { + + uint32_t swwo_block_num = swwo->block_num; + std::string swwo_peerplays_transaction_id = swwo->peerplays_transaction_id; + uint32_t swwo_op_idx = std::stoll(swwo->peerplays_uid.substr(swwo->peerplays_uid.find_last_of("-") + 1)); + + const auto &block = database.fetch_block_by_number(swwo_block_num); + + for (const auto &tx : block->transactions) { + if (tx.id().str() == swwo_peerplays_transaction_id) { + operation op = tx.operations[swwo_op_idx]; + transfer_operation t_op = op.get(); + + price asset_price = database.get(t_op.amount.asset_id).options.core_exchange_rate; + asset peerplays_asset = asset(t_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); + + process_ok = (t_op.to == gpo.parameters.son_account()) && + (swwo->peerplays_from == t_op.from) && + (swwo->peerplays_asset == peerplays_asset); + break; + } + } + + object_id_type object_id = op_obj_idx_1.get().object_id; + std::string op_tx_str = op_obj_idx_1.get().transaction; + + const auto &st_idx = database.get_index_type().indices().get(); + const auto st = st_idx.find(object_id); + if (st == st_idx.end()) { + + std::string tx_str = ""; + + if (object_id.is()) { + const auto &idx = database.get_index_type().indices().get(); + const auto swwo = idx.find(object_id); + if (swwo != idx.end()) { + + std::stringstream ss_trx(boost::algorithm::unhex(op_tx_str)); + hive::signed_transaction op_trx; + fc::raw::unpack(ss_trx, op_trx, 1000); + + uint64_t symbol = 0; + if (swwo->withdraw_currency == "HBD") { + symbol = hive::asset::hbd_symbol_ser; + } + if (swwo->withdraw_currency == "HIVE") { + symbol = hive::asset::hive_symbol_ser; + } + + hive::transfer_operation t_op; + t_op.from = "son-account"; + t_op.to = swwo->withdraw_address; + t_op.amount.amount = swwo->withdraw_amount; + t_op.amount.symbol = symbol; + t_op.memo = ""; + + hive::signed_transaction htrx; + htrx.ref_block_num = op_trx.ref_block_num; + htrx.ref_block_prefix = op_trx.ref_block_prefix; + htrx.set_expiration(op_trx.expiration); + + htrx.operations.push_back(t_op); + + std::stringstream ss; + fc::raw::pack(ss, htrx, 1000); + tx_str = boost::algorithm::hex(ss.str()); + } + } + + transaction_ok = (op_tx_str == tx_str); + } + } + + should_approve = process_ok && + transaction_ok; + break; + } + + case chain::operation::tag::value: { + should_approve = true; + son_id_type signer = op_obj_idx_0.get().signer; + std::string signature = op_obj_idx_0.get().signature; + sidechain_transaction_id_type sidechain_transaction_id = op_obj_idx_0.get().sidechain_transaction_id; + const auto &st_idx = database.get_index_type().indices().get(); + const auto sto = st_idx.find(sidechain_transaction_id); + if (sto == st_idx.end()) { + should_approve = false; + break; + } + + const auto &s_idx = database.get_index_type().indices().get(); + const auto son = s_idx.find(signer); + if (son == s_idx.end()) { + should_approve = false; + break; + } + + break; + } + + case chain::operation::tag::value: { + should_approve = true; + break; + } + + default: + should_approve = false; + elog("=================================================="); + elog("Proposal not considered for approval ${po}", ("po", po)); + elog("=================================================="); + } + + return should_approve; +} + +void sidechain_net_handler_hive::process_primary_wallet() { + const auto &swi = database.get_index_type().indices().get(); + const auto &active_sw = swi.rbegin(); + if (active_sw != swi.rend()) { + + if ((active_sw->addresses.find(sidechain) == active_sw->addresses.end()) || + (active_sw->addresses.at(sidechain).empty())) { + + if (proposal_exists(chain::operation::tag::value, active_sw->id)) { + return; + } + + const chain::global_property_object &gpo = database.get_global_properties(); + + auto active_sons = gpo.active_sons; + fc::flat_map account_auths; + uint32_t total_weight = 0; + for (const auto &active_son : active_sons) { + total_weight = total_weight + active_son.weight; + account_auths[active_son.sidechain_public_keys.at(sidechain)] = active_son.weight; + } + + std::string memo_key = node_rpc_client->get_account_memo_key("son-account"); + + if (memo_key.empty()) { + return; + } + + hive::authority active; + active.weight_threshold = total_weight * 2 / 3 + 1; + active.account_auths = account_auths; + + hive::account_update_operation auo; + auo.account = "son-account"; + auo.active = active; + auo.memo_key = hive::public_key_type(memo_key); + + std::string block_id_str = node_rpc_client->get_head_block_id(); + hive::block_id_type head_block_id(block_id_str); + + std::string head_block_time_str = node_rpc_client->get_head_block_time(); + time_point head_block_time = fc::time_point_sec::from_iso_string(head_block_time_str); + + hive::signed_transaction htrx; + htrx.set_reference_block(head_block_id); + htrx.set_expiration(head_block_time + fc::seconds(180)); + + htrx.operations.push_back(auo); + + std::stringstream ss; + fc::raw::pack(ss, htrx, 1000); + std::string tx_str = boost::algorithm::hex(ss.str()); + if (tx_str.empty()) { + return; + } + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + son_wallet_update_operation swu_op; + swu_op.payer = gpo.parameters.son_account(); + swu_op.son_wallet_id = active_sw->id; + swu_op.sidechain = sidechain; + swu_op.address = "son-account"; + + proposal_op.proposed_ops.emplace_back(swu_op); + + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = active_sw->id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = gpo.active_sons; + + proposal_op.proposed_ops.emplace_back(stc_op); + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + } catch (fc::exception &e) { + elog("Sending proposal for son wallet update operation failed with exception ${e}", ("e", e.what())); + return; + } + } + } +} + +void sidechain_net_handler_hive::process_sidechain_addresses() { + const auto &sidechain_addresses_idx = database.get_index_type(); + const auto &sidechain_addresses_by_sidechain_idx = sidechain_addresses_idx.indices().get(); + const auto &sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain); + std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second, + [&](const sidechain_address_object &sao) { + bool retval = true; + if (sao.expires == time_point_sec::maximum()) { + if (sao.deposit_address == "") { + sidechain_address_update_operation op; + op.payer = plugin.get_current_son_object().son_account; + op.sidechain_address_id = sao.id; + op.sidechain_address_account = sao.sidechain_address_account; + op.sidechain = sao.sidechain; + op.deposit_public_key = sao.deposit_public_key; + op.deposit_address = sao.withdraw_address; + op.deposit_address_data = sao.withdraw_address; + op.withdraw_public_key = sao.withdraw_public_key; + op.withdraw_address = sao.withdraw_address; + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + retval = true; + } catch (fc::exception &e) { + elog("Sending transaction for sidechain address update operation failed with exception ${e}", ("e", e.what())); + retval = false; + } + } + } + return retval; + }); +} + +bool sidechain_net_handler_hive::process_deposit(const son_wallet_deposit_object &swdo) { + const chain::global_property_object &gpo = database.get_global_properties(); + + price asset_price; + asset asset_to_issue; + if (swdo.sidechain_currency == "HBD") { + asset_price = database.get(database.get_global_properties().parameters.hbd_asset()).options.core_exchange_rate; + asset_to_issue = asset(swdo.peerplays_asset.amount * asset_price.quote.amount / asset_price.base.amount, database.get_global_properties().parameters.hbd_asset()); + } + if (swdo.sidechain_currency == "HIVE") { + asset_price = database.get(database.get_global_properties().parameters.hive_asset()).options.core_exchange_rate; + asset_to_issue = asset(swdo.peerplays_asset.amount * asset_price.quote.amount / asset_price.base.amount, database.get_global_properties().parameters.hive_asset()); + } + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + son_wallet_deposit_process_operation swdp_op; + swdp_op.payer = gpo.parameters.son_account(); + swdp_op.son_wallet_deposit_id = swdo.id; + proposal_op.proposed_ops.emplace_back(swdp_op); + + asset_issue_operation ai_op; + ai_op.fee = asset(2001000); + ai_op.issuer = gpo.parameters.son_account(); + ai_op.asset_to_issue = asset_to_issue; + ai_op.issue_to_account = swdo.peerplays_from; + proposal_op.proposed_ops.emplace_back(ai_op); + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception &e) { + elog("Sending proposal for deposit sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + + return false; +} + +bool sidechain_net_handler_hive::process_withdrawal(const son_wallet_withdraw_object &swwo) { + const chain::global_property_object &gpo = database.get_global_properties(); + + //===== + + uint64_t symbol = 0; + if (swwo.withdraw_currency == "HBD") { + symbol = hive::asset::hbd_symbol_ser; + } + if (swwo.withdraw_currency == "HIVE") { + symbol = hive::asset::hive_symbol_ser; + } + + hive::transfer_operation t_op; + t_op.from = "son-account"; + t_op.to = swwo.withdraw_address; + t_op.amount.amount = swwo.withdraw_amount; + t_op.amount.symbol = symbol; + t_op.memo = ""; + + std::string block_id_str = node_rpc_client->get_head_block_id(); + hive::block_id_type head_block_id(block_id_str); + + std::string head_block_time_str = node_rpc_client->get_head_block_time(); + time_point head_block_time = fc::time_point_sec::from_iso_string(head_block_time_str); + + hive::signed_transaction htrx; + htrx.set_reference_block(head_block_id); + htrx.set_expiration(head_block_time + fc::seconds(180)); + + htrx.operations.push_back(t_op); + + std::stringstream ss; + fc::raw::pack(ss, htrx, 1000); + std::string tx_str = boost::algorithm::hex(ss.str()); + if (tx_str.empty()) { + return false; + } + + //===== + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = plugin.get_current_son_object().son_account; + uint32_t lifetime = (gpo.parameters.block_interval * gpo.active_witnesses.size()) * 3; + proposal_op.expiration_time = time_point_sec(database.head_block_time().sec_since_epoch() + lifetime); + + son_wallet_withdraw_process_operation swwp_op; + swwp_op.payer = gpo.parameters.son_account(); + swwp_op.son_wallet_withdraw_id = swwo.id; + proposal_op.proposed_ops.emplace_back(swwp_op); + + sidechain_transaction_create_operation stc_op; + stc_op.payer = gpo.parameters.son_account(); + stc_op.object_id = swwo.id; + stc_op.sidechain = sidechain; + stc_op.transaction = tx_str; + stc_op.signers = gpo.active_sons; + proposal_op.proposed_ops.emplace_back(stc_op); + + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), proposal_op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + return true; + } catch (fc::exception &e) { + elog("Sending proposal for withdraw sidechain transaction create operation failed with exception ${e}", ("e", e.what())); + return false; + } + + return false; +} + +std::string sidechain_net_handler_hive::process_sidechain_transaction(const sidechain_transaction_object &sto) { + std::stringstream ss_trx(boost::algorithm::unhex(sto.transaction)); + hive::signed_transaction htrx; + fc::raw::unpack(ss_trx, htrx, 1000); + + std::string chain_id_str = node_rpc_client->get_chain_id(); + const hive::chain_id_type chain_id(chain_id_str); + + fc::optional privkey = graphene::utilities::wif_to_key(get_private_key(plugin.get_current_son_object().sidechain_public_keys.at(sidechain))); + signature_type st = htrx.sign(*privkey, chain_id); + + std::stringstream ss_st; + fc::raw::pack(ss_st, st, 1000); + std::string st_str = boost::algorithm::hex(ss_st.str()); + + return st_str; +} + +std::string sidechain_net_handler_hive::send_sidechain_transaction(const sidechain_transaction_object &sto) { + std::stringstream ss_trx(boost::algorithm::unhex(sto.transaction)); + hive::signed_transaction htrx; + fc::raw::unpack(ss_trx, htrx, 1000); + + for (auto signature : sto.signatures) { + if (!signature.second.empty()) { + std::stringstream ss_st(boost::algorithm::unhex(signature.second)); + signature_type st; + fc::raw::unpack(ss_st, st, 1000); + htrx.signatures.push_back(st); + } + } + + std::string params = fc::json::to_string(htrx); + node_rpc_client->network_broadcast_api_broadcast_transaction(params); + + return htrx.id().str(); +} + +bool sidechain_net_handler_hive::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) { + if (sto.object_id.is()) { + settle_amount.amount = 0; + return true; + } + + if (sto.sidechain_transaction.empty()) { + return false; + } + + std::string tx_str = node_rpc_client->account_history_api_get_transaction(sto.sidechain_transaction); + if (tx_str != "") { + + std::stringstream ss_tx(tx_str); + boost::property_tree::ptree tx_json; + boost::property_tree::read_json(ss_tx, tx_json); + + //const chain::global_property_object &gpo = database.get_global_properties(); + + std::string tx_txid = tx_json.get("result.transaction_id"); + uint32_t tx_block_num = tx_json.get("result.block_num"); + uint32_t last_irreversible_block = std::stoul(node_rpc_client->get_last_irreversible_block_num()); + + //std::string tx_address = addr.get_address(); + //int64_t tx_amount = -1; + + if (tx_block_num <= last_irreversible_block) { + if (sto.object_id.is()) { + auto swwo = database.get(sto.object_id); + if (swwo.withdraw_currency == "HBD") { + settle_amount = asset(swwo.withdraw_amount, database.get_global_properties().parameters.hbd_asset()); + } + if (swwo.withdraw_currency == "HIVE") { + settle_amount = asset(swwo.withdraw_amount, database.get_global_properties().parameters.hive_asset()); + } + return true; + } + } + } + return false; +} + +void sidechain_net_handler_hive::schedule_hive_listener() { + fc::time_point now = fc::time_point::now(); + int64_t time_to_next = 1000; + + fc::time_point next_wakeup(now + fc::milliseconds(time_to_next)); + + _listener_task = fc::schedule([this] { + hive_listener_loop(); + }, + next_wakeup, "SON Hive listener task"); +} + +void sidechain_net_handler_hive::hive_listener_loop() { + schedule_hive_listener(); + + std::string reply = node_rpc_client->database_api_get_dynamic_global_properties(); + if (!reply.empty()) { + std::stringstream ss(reply); + boost::property_tree::ptree json; + boost::property_tree::read_json(ss, json); + if (json.count("result")) { + uint64_t head_block_number = json.get("result.head_block_number"); + if (head_block_number != last_block_received) { + std::string event_data = std::to_string(head_block_number); + handle_event(event_data); + last_block_received = head_block_number; + } + } + } + + //std::string reply = node_rpc_client->get_last_irreversible_block_num(); + //if (!reply.empty()) { + // uint64_t last_irreversible_block = std::stoul(reply); + // if (last_irreversible_block != last_block_received) { + // std::string event_data = std::to_string(last_irreversible_block); + // handle_event(event_data); + // last_block_received = last_irreversible_block; + // } + //} +} + +void sidechain_net_handler_hive::handle_event(const std::string &event_data) { + std::string block = node_rpc_client->block_api_get_block(std::atoll(event_data.c_str())); + if (block != "") { + std::stringstream ss(block); + boost::property_tree::ptree block_json; + boost::property_tree::read_json(ss, block_json); + + size_t tx_idx = -1; + for (const auto &tx_ids_child : block_json.get_child("result.block.transactions")) { + boost::property_tree::ptree tx = tx_ids_child.second; + tx_idx = tx_idx + 1; + + size_t op_idx = -1; + for (const auto &ops : tx.get_child("operations")) { + const auto &op = ops.second; + op_idx = op_idx + 1; + + std::string operation_type = op.get("type"); + + if (operation_type == "transfer_operation") { + const auto &op_value = op.get_child("value"); + + std::string from = op_value.get("from"); + std::string to = op_value.get("to"); + + if (to == "son-account") { + + const auto &amount_child = op_value.get_child("amount"); + + uint64_t amount = amount_child.get("amount"); + //uint64_t precision = amount_child.get("precision"); + std::string nai = amount_child.get("nai"); + std::string sidechain_currency = ""; + price sidechain_currency_price = {}; + if ((nai == "@@000000013" /*?? HBD*/) || (nai == "@@000000013" /*TBD*/)) { + sidechain_currency = "HBD"; + sidechain_currency_price = database.get(database.get_global_properties().parameters.hbd_asset()).options.core_exchange_rate; + } + if ((nai == "@@000000021") /*?? HIVE*/ || (nai == "@@000000021" /*TESTS*/)) { + sidechain_currency = "HIVE"; + sidechain_currency_price = database.get(database.get_global_properties().parameters.hive_asset()).options.core_exchange_rate; + } + + std::string memo = op_value.get("memo"); + boost::trim(memo); + if (!memo.empty()) { + from = memo; + } + + const auto &sidechain_addresses_idx = database.get_index_type().indices().get(); + const auto &addr_itr = sidechain_addresses_idx.find(std::make_tuple(sidechain, from, time_point_sec::maximum())); + account_id_type accn = account_id_type(); + if (addr_itr == sidechain_addresses_idx.end()) { + const auto &account_idx = database.get_index_type().indices().get(); + const auto &account_itr = account_idx.find(from); + if (account_itr == account_idx.end()) { + continue; + } else { + accn = account_itr->id; + } + } else { + accn = addr_itr->sidechain_address_account; + } + + std::vector transaction_ids; + for (const auto &tx_ids_child : block_json.get_child("result.block.transaction_ids")) { + const auto &transaction_id = tx_ids_child.second.get_value(); + transaction_ids.push_back(transaction_id); + } + std::string transaction_id = transaction_ids.at(tx_idx); + + std::stringstream ss; + ss << "hive" + << "-" << transaction_id << "-" << op_idx; + std::string sidechain_uid = ss.str(); + + sidechain_event_data sed; + sed.timestamp = database.head_block_time(); + sed.block_num = database.head_block_num(); + sed.sidechain = sidechain; + sed.sidechain_uid = sidechain_uid; + sed.sidechain_transaction_id = transaction_id; + sed.sidechain_from = from; + sed.sidechain_to = to; + sed.sidechain_currency = sidechain_currency; + sed.sidechain_amount = amount; + sed.peerplays_from = accn; + sed.peerplays_to = database.get_global_properties().parameters.son_account(); + sed.peerplays_asset = asset(sed.sidechain_amount * sidechain_currency_price.base.amount / sidechain_currency_price.quote.amount); + sidechain_event_data_received(sed); + } + } + } + } + } +} + +}} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp index ecf3cc00..d5a9ec32 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_peerplays.cpp @@ -25,6 +25,15 @@ namespace graphene { namespace peerplays_sidechain { sidechain_net_handler_peerplays::sidechain_net_handler_peerplays(peerplays_sidechain_plugin &_plugin, const boost::program_options::variables_map &options) : sidechain_net_handler(_plugin, options) { sidechain = sidechain_type::peerplays; + //const auto &assets_by_symbol = database.get_index_type().indices().get(); + //const auto get_asset_id = [&assets_by_symbol](const string &symbol) { + // auto asset_itr = assets_by_symbol.find(symbol); + // FC_ASSERT(asset_itr != assets_by_symbol.end(), "Unable to find asset '${sym}'", ("sym", symbol)); + // return asset_itr->get_id(); + //}; + //tracked_assets.push_back(get_asset_id("PBTC")); + //tracked_assets.push_back(get_asset_id("PETH")); + //tracked_assets.push_back(get_asset_id("PEOS")); if (options.count("peerplays-private-key")) { const std::vector pub_priv_keys = options["peerplays-private-key"].as>(); @@ -37,10 +46,6 @@ sidechain_net_handler_peerplays::sidechain_net_handler_peerplays(peerplays_sidec private_keys[key_pair.first] = key_pair.second; } } - - database.applied_block.connect([&](const signed_block &b) { - on_applied_block(b); - }); } sidechain_net_handler_peerplays::~sidechain_net_handler_peerplays() { @@ -131,32 +136,34 @@ void sidechain_net_handler_peerplays::process_sidechain_addresses() { const auto &sidechain_addresses_by_sidechain_range = sidechain_addresses_by_sidechain_idx.equal_range(sidechain); std::for_each(sidechain_addresses_by_sidechain_range.first, sidechain_addresses_by_sidechain_range.second, [&](const sidechain_address_object &sao) { + bool retval = true; if (sao.expires == time_point_sec::maximum()) { if (sao.deposit_address == "") { sidechain_address_update_operation op; - op.payer = plugin.get_current_son_object().son_account; - op.sidechain_address_id = sao.id; - op.sidechain_address_account = sao.sidechain_address_account; - op.sidechain = sao.sidechain; - op.deposit_public_key = sao.deposit_public_key; - op.deposit_address = sao.withdraw_address; - op.deposit_address_data = sao.withdraw_address; - op.withdraw_public_key = sao.withdraw_public_key; - op.withdraw_address = sao.withdraw_address; + op.payer = plugin.get_current_son_object().son_account; + op.sidechain_address_id = sao.id; + op.sidechain_address_account = sao.sidechain_address_account; + op.sidechain = sao.sidechain; + op.deposit_public_key = sao.deposit_public_key; + op.deposit_address = sao.withdraw_address; + op.deposit_address_data = sao.withdraw_address; + op.withdraw_public_key = sao.withdraw_public_key; + op.withdraw_address = sao.withdraw_address; - signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); - try { - trx.validate(); - database.push_transaction(trx, database::validation_steps::skip_block_size_check); - if (plugin.app().p2p_node()) - plugin.app().p2p_node()->broadcast(net::trx_message(trx)); - return true; - } catch (fc::exception &e) { - elog("Sending transaction for update deposit address operation failed with exception ${e}", ("e", e.what())); - return false; - } + signed_transaction trx = database.create_signed_transaction(plugin.get_private_key(plugin.get_current_son_id()), op); + try { + trx.validate(); + database.push_transaction(trx, database::validation_steps::skip_block_size_check); + if (plugin.app().p2p_node()) + plugin.app().p2p_node()->broadcast(net::trx_message(trx)); + retval = true; + } catch (fc::exception &e) { + elog("Sending transaction for update deposit address operation failed with exception ${e}", ("e", e.what())); + retval = false; + } } } + return retval; }); return; } @@ -264,45 +271,23 @@ std::string sidechain_net_handler_peerplays::send_sidechain_transaction(const si return ""; } -int64_t sidechain_net_handler_peerplays::settle_sidechain_transaction(const sidechain_transaction_object &sto) { - int64_t settle_amount = 0; - return settle_amount; -} +bool sidechain_net_handler_peerplays::settle_sidechain_transaction(const sidechain_transaction_object &sto, asset &settle_amount) { -void sidechain_net_handler_peerplays::on_applied_block(const signed_block &b) { - for (const auto &trx : b.transactions) { - size_t operation_index = -1; - for (auto op : trx.operations) { - operation_index = operation_index + 1; - if (op.which() == operation::tag::value) { - transfer_operation transfer_op = op.get(); - if (transfer_op.to != plugin.database().get_global_properties().parameters.son_account()) { - continue; - } - - std::stringstream ss; - ss << "peerplays" - << "-" << trx.id().str() << "-" << operation_index; - std::string sidechain_uid = ss.str(); - - sidechain_event_data sed; - sed.timestamp = database.head_block_time(); - sed.block_num = database.head_block_num(); - sed.sidechain = sidechain_type::peerplays; - sed.sidechain_uid = sidechain_uid; - sed.sidechain_transaction_id = trx.id().str(); - sed.sidechain_from = fc::to_string(transfer_op.from.space_id) + "." + fc::to_string(transfer_op.from.type_id) + "." + fc::to_string((uint64_t)transfer_op.from.instance); - sed.sidechain_to = fc::to_string(transfer_op.to.space_id) + "." + fc::to_string(transfer_op.to.type_id) + "." + fc::to_string((uint64_t)transfer_op.to.instance); - sed.sidechain_currency = fc::to_string(transfer_op.amount.asset_id.space_id) + "." + fc::to_string(transfer_op.amount.asset_id.type_id) + "." + fc::to_string((uint64_t)transfer_op.amount.asset_id.instance); - sed.sidechain_amount = transfer_op.amount.amount; - sed.peerplays_from = transfer_op.from; - sed.peerplays_to = transfer_op.to; - price asset_price = database.get(transfer_op.amount.asset_id).options.core_exchange_rate; - sed.peerplays_asset = asset(transfer_op.amount.amount * asset_price.base.amount / asset_price.quote.amount); - sidechain_event_data_received(sed); - } - } + if (sto.object_id.is()) { + settle_amount = asset(0); } + + if (sto.object_id.is()) { + //auto swdo = database.get(sto.object_id); + //settle_amount = asset(swdo.sidechain_amount, swdo.sidechain_currency); + } + + if (sto.object_id.is()) { + auto swwo = database.get(sto.object_id); + settle_amount = swwo.peerplays_asset; + } + + return true; } }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp index 962488a6..ff876b0c 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_manager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include namespace graphene { namespace peerplays_sidechain { @@ -10,6 +11,10 @@ namespace graphene { namespace peerplays_sidechain { sidechain_net_manager::sidechain_net_manager(peerplays_sidechain_plugin &_plugin) : plugin(_plugin), database(_plugin.database()) { + + //database.applied_block.connect([&](const signed_block &b) { + // on_applied_block(b); + //}); } sidechain_net_manager::~sidechain_net_manager() { @@ -26,6 +31,12 @@ bool sidechain_net_manager::create_handler(sidechain_type sidechain, const boost ret_val = true; break; } + case sidechain_type::hive: { + std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_hive(plugin, options)); + net_handlers.push_back(std::move(h)); + ret_val = true; + break; + } case sidechain_type::peerplays: { std::unique_ptr h = std::unique_ptr(new sidechain_net_handler_peerplays(plugin, options)); net_handlers.push_back(std::move(h)); @@ -87,4 +98,7 @@ void sidechain_net_manager::settle_sidechain_transactions() { } } +void sidechain_net_manager::on_applied_block(const signed_block &b) { +} + }} // namespace graphene::peerplays_sidechain diff --git a/libraries/plugins/snapshot/CMakeLists.txt b/libraries/plugins/snapshot/CMakeLists.txt index 728740de..57fb1689 100644 --- a/libraries/plugins/snapshot/CMakeLists.txt +++ b/libraries/plugins/snapshot/CMakeLists.txt @@ -4,7 +4,7 @@ add_library( graphene_snapshot snapshot.cpp ) -target_link_libraries( graphene_snapshot graphene_chain graphene_app ) +target_link_libraries( graphene_snapshot PRIVATE graphene_plugin ) target_include_directories( graphene_snapshot PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/witness/CMakeLists.txt b/libraries/plugins/witness/CMakeLists.txt index 95759bbf..a4272b2d 100644 --- a/libraries/plugins/witness/CMakeLists.txt +++ b/libraries/plugins/witness/CMakeLists.txt @@ -4,7 +4,7 @@ add_library( graphene_witness witness.cpp ) -target_link_libraries( graphene_witness graphene_chain graphene_app ) +target_link_libraries( graphene_witness PRIVATE graphene_plugin ) target_include_directories( graphene_witness PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index 1e7a9d6e..d535ca3b 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -91,8 +91,10 @@ void witness_plugin::plugin_initialize(const boost::program_options::variables_m ilog("witness plugin: plugin_initialize() begin"); _options = &options; LOAD_VALUE_SET(options, "witness-id", _witnesses, chain::witness_id_type) - if (options.count("witness-ids")) - boost::insert(_witnesses, fc::json::from_string(options.at("witness-ids").as()).as>( 5 )); + if (options.count("witness-ids")) { + vector v = fc::json::from_string(options.at("witness-ids").as()).as>( 5 ); + _witnesses.insert(v.begin(), v.end()); + } if( options.count("private-key") ) { diff --git a/libraries/wallet/CMakeLists.txt b/libraries/wallet/CMakeLists.txt index 8c9f8790..d3825810 100644 --- a/libraries/wallet/CMakeLists.txt +++ b/libraries/wallet/CMakeLists.txt @@ -23,7 +23,7 @@ else() endif() add_library( graphene_wallet wallet.cpp ${CMAKE_CURRENT_BINARY_DIR}/api_documentation.cpp ${HEADERS} ) -target_link_libraries( graphene_wallet PRIVATE graphene_app graphene_net graphene_chain graphene_utilities fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( graphene_wallet PRIVATE graphene_app ) target_include_directories( graphene_db PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) if(MSVC) diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index ac7d8996..ff32ac10 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -62,13 +62,18 @@ struct brain_key_info public_key_type pub_key; }; +enum authority_type +{ + owner, + active +}; /** * Contains the confirmation receipt the sender must give the receiver and * the meta data about the receipt that helps the sender identify which receipt is * for the receiver and which is for the change address. */ -struct blind_confirmation +struct blind_confirmation { struct output { @@ -313,7 +318,7 @@ class wallet_api */ uint64_t get_account_count()const; /** Lists all accounts controlled by this wallet. - * This returns a list of the full account objects for all accounts whose private keys + * This returns a list of the full account objects for all accounts whose private keys * we possess. * @returns a list of account objects */ @@ -325,14 +330,14 @@ class wallet_api * start by setting \c lowerbound to the empty string \c "", and then each iteration, pass * the last account name returned as the \c lowerbound for the next \c list_accounts() call. * - * @param lowerbound the name of the first account to return. If the named account does not exist, + * @param lowerbound the name of the first account to return. If the named account does not exist, * the list will start at the account that comes after \c lowerbound * @param limit the maximum number of accounts to return (max: 1000) * @returns a list of accounts mapping account names to account ids */ map list_accounts(const string& lowerbound, uint32_t limit); /** List the balances of an account. - * Each account can have multiple balances, one for each type of asset owned by that + * Each account can have multiple balances, one for each type of asset owned by that * account. The returned list will only contain assets for which the account has a * nonzero balance * @param id the name or id of the account whose balances you want @@ -340,7 +345,7 @@ class wallet_api */ vector list_account_balances(const string& id); /** Lists all assets registered on the blockchain. - * + * * To list all assets, pass the empty string \c "" for the lowerbound to start * at the beginning of the list, and iterate as necessary. * @@ -351,12 +356,12 @@ class wallet_api vector list_assets(const string& lowerbound, uint32_t limit)const; /** Returns assets count registered on the blockchain. - * + * * @returns assets count */ uint64_t get_asset_count()const; - - + + vector get_lotteries( asset_id_type stop = asset_id_type(), unsigned limit = 100, asset_id_type start = asset_id_type() )const; @@ -392,7 +397,7 @@ class wallet_api vector get_limit_orders(string a, string b, uint32_t limit)const; vector get_call_orders(string a, uint32_t limit)const; vector get_settle_orders(string a, uint32_t limit)const; - + /** Returns the block chain's slowly-changing settings. * This object contains all of the properties of the blockchain that are fixed * or that change only once per maintenance interval (daily) such as the @@ -448,8 +453,8 @@ class wallet_api * Returns the blockchain object corresponding to the given id. * * This generic function can be used to retrieve any object from the blockchain - * that is assigned an ID. Certain types of objects have specialized convenience - * functions to return their objects -- e.g., assets have \c get_asset(), accounts + * that is assigned an ID. Certain types of objects have specialized convenience + * functions to return their objects -- e.g., assets have \c get_asset(), accounts * have \c get_account(), but this function will work for any object. * * @param id the id of the object to return @@ -457,7 +462,7 @@ class wallet_api */ variant get_object(object_id_type id) const; - /** Returns the current wallet filename. + /** Returns the current wallet filename. * * This is the filename that will be used when automatically saving the wallet. * @@ -533,21 +538,21 @@ class wallet_api * @ingroup Wallet Management */ bool is_new()const; - - /** Checks whether the wallet is locked (is unable to use its private keys). + + /** Checks whether the wallet is locked (is unable to use its private keys). * * This state can be changed by calling \c lock() or \c unlock(). * @return true if the wallet is locked * @ingroup Wallet Management */ bool is_locked()const; - + /** Locks the wallet immediately. * @ingroup Wallet Management */ void lock(); - - /** Unlocks the wallet. + + /** Unlocks the wallet. * * The wallet remain unlocked until the \c lock is called * or the program exits. @@ -555,7 +560,7 @@ class wallet_api * @ingroup Wallet Management */ void unlock(string password); - + /** Sets a new password on the wallet. * * The wallet must be either 'new' or 'unlocked' to @@ -568,7 +573,7 @@ class wallet_api * * The keys are printed in WIF format. You can import these keys into another wallet * using \c import_key() - * @returns a map containing the private keys, indexed by their public key + * @returns a map containing the private keys, indexed by their public key */ map dump_private_keys(); @@ -603,13 +608,13 @@ class wallet_api bool load_wallet_file(string wallet_filename = ""); /** Quitting from Peerplays wallet. - * + * * The current wallet will be closed. */ void quit(); /** Saves the current wallet to the given filename. - * + * * @warning This does not change the wallet filename that will be used for future * writes, so think of this function as 'Save a Copy As...' instead of * 'Save As...'. Use \c set_wallet_filename() to make the filename @@ -647,7 +652,7 @@ class wallet_api * @see suggest_brain_key() * * @param brain_key Brain key - * @param numberOfDesiredKeys Number of desired keys + * @param number_of_desired_keys Number of desired keys * @return A list of keys that are deterministically derived from the brainkey */ vector derive_owner_keys_from_brain_key(string brain_key, int number_of_desired_keys = 1) const; @@ -662,7 +667,12 @@ class wallet_api bool is_public_key_registered(string public_key) const; /** - * @param role - active | owner | memo + * Gets private key from password + * + * @param account Account name + * @param role Account role - active | owner | memo + * @param password Account password + * @return public/private key pair */ pair get_private_key_from_password( string account, string role, string password )const; @@ -678,7 +688,7 @@ class wallet_api /** Imports the private key for an existing account. * * The private key must match either an owner key or an active key for the - * named account. + * named account. * * @see dump_private_keys() * @@ -741,6 +751,41 @@ class wallet_api uint32_t referrer_percent, bool broadcast = false); + /** Updates account public keys + * + * @param name the name of the existing account + * @param old_owner the owner key for the named account to be replaced + * @param new_owner the owner key for the named account to be set as new + * @param old_active the active key for the named account to be replaced + * @param new_active the active key for the named account to be set as new + * @param broadcast true to broadcast the transaction on the network + * @returns the signed transaction updating account public keys + */ + signed_transaction update_account_keys(string name, + public_key_type old_owner, + public_key_type new_owner, + public_key_type old_active, + public_key_type new_active, + bool broadcast = false); + + /** + * This method updates the key of an authority for an exisiting account. + * Warning: You can create impossible authorities using this method. The method + * will fail if you create an impossible owner authority, but will allow impossible + * active and posting authorities. + * + * @param account_name The name of the account whose authority you wish to update + * @param type The authority type. e.g. owner or active + * @param key The public key to add to the authority + * @param weight The weight the key should have in the authority. A weight of 0 indicates the removal of the key. + * @param broadcast true if you wish to broadcast the transaction. + */ + signed_transaction update_account_auth_key(string account_name, + authority_type type, + public_key_type key, + weight_type weight, + bool broadcast); + /** * Upgrades an account to prime status. * This makes the account holder a 'lifetime member'. @@ -781,7 +826,7 @@ class wallet_api * @param to the name or id of the account receiving the funds * @param amount the amount to send (in nominal units -- to send half of a BTS, specify 0.5) * @param asset_symbol the symbol or id of the asset to send - * @param memo a memo to attach to the transaction. The memo will be encrypted in the + * @param memo a memo to attach to the transaction. The memo will be encrypted in the * transaction and readable for the receiver. There is no length limit * other than the limit imposed by maximum transaction size, but transaction * increase with transaction size @@ -855,27 +900,33 @@ class wallet_api * that it exists in the blockchain. If it exists then it will report the amount received and * who sent it. * - * @param opt_from - if not empty and the sender is a unknown public key, then the unknown public key will be given the label opt_from - * @param confirmation_receipt - a base58 encoded stealth confirmation + * @param confirmation_receipt - a base58 encoded stealth confirmation + * @param opt_from - if not empty and the sender is a unknown public key, then the unknown public key will be given the label opt_from + * @param opt_memo - optional memo */ blind_receipt receive_blind_transfer( string confirmation_receipt, string opt_from, string opt_memo ); /** - * Transfers a public balance from @from to one or more blinded balances using a + * Transfers a public balance from from_account_id_or_name to one or more blinded balances using a * stealth transfer. + * + * @param from_account_id_or_name account id or name + * @param asset_symbol asset symbol + * @param to_amounts map from key or label to amount + * @param broadcast true to broadcast the transaction on the network + * @returns blind confirmation structure */ - blind_confirmation transfer_to_blind( string from_account_id_or_name, + blind_confirmation transfer_to_blind( string from_account_id_or_name, string asset_symbol, - /** map from key or label to amount */ - vector> to_amounts, + vector> to_amounts, bool broadcast = false ); /** * Transfers funds from a set of blinded balances to a public account balance. */ - blind_confirmation transfer_from_blind( + blind_confirmation transfer_from_blind( string from_blind_account_key_or_label, - string to_account_id_or_name, + string to_account_id_or_name, string amount, string asset_symbol, bool broadcast = false ); @@ -891,14 +942,14 @@ class wallet_api /** Place a limit order attempting to sell one asset for another. * - * Buying and selling are the same operation on Graphene; if you want to buy BTS + * Buying and selling are the same operation on Graphene; if you want to buy BTS * with USD, you should sell USD for BTS. * * The blockchain will attempt to sell the \c symbol_to_sell for as - * much \c symbol_to_receive as possible, as long as the price is at - * least \c min_to_receive / \c amount_to_sell. + * much \c symbol_to_receive as possible, as long as the price is at + * least \c min_to_receive / \c amount_to_sell. * - * In addition to the transaction fees, market fees will apply as specified + * In addition to the transaction fees, market fees will apply as specified * by the issuer of both the selling asset and the receiving asset as * a percentage of the amount exchanged. * @@ -911,16 +962,16 @@ class wallet_api * * @todo Allow order expiration to be set here. Document default/max expiration time * - * @param seller_account the account providing the asset being sold, and which will + * @param seller_account the account providing the asset being sold, and which will * receive the proceeds of the sale. * @param amount_to_sell the amount of the asset being sold to sell (in nominal units) * @param symbol_to_sell the name or id of the asset to sell * @param min_to_receive the minimum amount you are willing to receive in return for * selling the entire amount_to_sell * @param symbol_to_receive the name or id of the asset you wish to receive - * @param timeout_sec if the order does not fill immediately, this is the length of - * time the order will remain on the order books before it is - * cancelled and the un-spent funds are returned to the seller's + * @param timeout_sec if the order does not fill immediately, this is the length of + * time the order will remain on the order books before it is + * cancelled and the un-spent funds are returned to the seller's * account * @param fill_or_kill if true, the order will only be included in the blockchain * if it is filled immediately; if false, an open order will be @@ -937,12 +988,12 @@ class wallet_api uint32_t timeout_sec = 0, bool fill_or_kill = false, bool broadcast = false); - + /** Place a limit order attempting to sell one asset for another. - * + * * This API call abstracts away some of the details of the sell_asset call to be more * user friendly. All orders placed with sell never timeout and will not be killed if they - * cannot be filled immediately. If you wish for one of these parameters to be different, + * cannot be filled immediately. If you wish for one of these parameters to be different, * then sell_asset should be used instead. * * @param seller_account the account providing the asset being sold, and which will @@ -952,7 +1003,7 @@ class wallet_api * @param rate The rate in base:quote at which you want to sell. * @param amount The amount of base you want to sell. * @param broadcast true to broadcast the transaction on the network. - * @returns The signed transaction selling the funds. + * @returns The signed transaction selling the funds. */ signed_transaction sell( string seller_account, string base, @@ -960,7 +1011,7 @@ class wallet_api double rate, double amount, bool broadcast ); - + /** Place a limit order attempting to buy one asset with another. * * This API call abstracts away some of the details of the sell_asset call to be more @@ -970,11 +1021,11 @@ class wallet_api * * @param buyer_account The account buying the asset for another asset. * @param base The name or id of the asset to buy. - * @param quote The name or id of the assest being offered as payment. + * @param quote The name or id of the asset being offered as payment. * @param rate The rate in base:quote at which you want to buy. * @param amount the amount of base you want to buy. * @param broadcast true to broadcast the transaction on the network. - * @param The signed transaction selling the funds. + * @returns The signed transaction buying the funds. */ signed_transaction buy( string buyer_account, string base, @@ -1015,14 +1066,14 @@ class wallet_api * Right now this function is difficult to use because you must provide raw JSON data * structures for the options objects, and those include prices and asset ids. * - * @param issuer the name or id of the account who will pay the fee and become the + * @param issuer the name or id of the account who will pay the fee and become the * issuer of the new asset. This can be updated later * @param symbol the ticker symbol of the new asset * @param precision the number of digits of precision to the right of the decimal point, * must be less than or equal to 12 * @param common asset options required for all new assets. - * Note that core_exchange_rate technically needs to store the asset ID of - * this new asset. Since this ID is not known at the time this operation is + * Note that core_exchange_rate technically needs to store the asset ID of + * this new asset. Since this ID is not known at the time this operation is * created, create this price as though the new asset has instance ID 1, and * the chain will overwrite it with the new asset's ID. * @param bitasset_opts options specific to BitAssets. This may be null unless the @@ -1042,7 +1093,7 @@ class wallet_api asset_options common, lottery_asset_options lottery_opts, bool broadcast = false); - + signed_transaction buy_ticket( asset_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy ); /** Issue new shares of an asset. @@ -1060,8 +1111,8 @@ class wallet_api bool broadcast = false); /** Update the core options on an asset. - * There are a number of options which all assets in the network use. These options are - * enumerated in the asset_object::asset_options struct. This command is used to update + * There are a number of options which all assets in the network use. These options are + * enumerated in the asset_object::asset_options struct. This command is used to update * these options for an existing asset. * * @note This operation cannot be used to update BitAsset-specific options. For these options, @@ -1125,7 +1176,7 @@ class wallet_api signed_transaction update_asset_feed_producers(string symbol, flat_set new_feed_producers, bool broadcast = false); - + /** Publishes a price feed for the named asset. * * Price feed providers use this command to publish their price feeds for market-issued assets. A price feed is @@ -1153,7 +1204,7 @@ class wallet_api /** Pay into the fee pool for the given asset. * - * User-issued assets can optionally have a pool of the core asset which is + * User-issued assets can optionally have a pool of the core asset which is * automatically used to pay transaction fees for any transaction using that * asset (using the asset's core exchange rate). * @@ -1194,7 +1245,7 @@ class wallet_api * used as backing for other bitassets, those bitassets will be force settled at their current * feed price. * - * @note this operation is used only by the asset issuer, \c settle_asset() may be used by + * @note this operation is used only by the asset issuer, \c settle_asset() may be used by * any user owning the asset * * @param symbol the name or id of the asset to force settlement on @@ -1262,7 +1313,7 @@ class wallet_api * @returns the signed transaction registering a committee_member */ signed_transaction create_committee_member(string owner_account, - string url, + string url, bool broadcast = false); /** Lists all witnesses registered in the blockchain. @@ -1273,7 +1324,7 @@ class wallet_api * start by setting \c lowerbound to the empty string \c "", and then each iteration, pass * the last witness name returned as the \c lowerbound for the next \c list_witnesss() call. * - * @param lowerbound the name of the first witness to return. If the named witness does not exist, + * @param lowerbound the name of the first witness to return. If the named witness does not exist, * the list will start at the witness that comes after \c lowerbound * @param limit the maximum number of witnesss to return (max: 1000) * @returns a list of witnesss mapping witness names to witness ids @@ -1288,7 +1339,7 @@ class wallet_api * start by setting \c lowerbound to the empty string \c "", and then each iteration, pass * the last committee_member name returned as the \c lowerbound for the next \c list_committee_members() call. * - * @param lowerbound the name of the first committee_member to return. If the named committee_member does not exist, + * @param lowerbound the name of the first committee_member to return. If the named committee_member does not exist, * the list will start at the committee_member that comes after \c lowerbound * @param limit the maximum number of committee_members to return (max: 1000) * @returns a list of committee_members mapping committee_member names to committee_member ids @@ -1374,6 +1425,16 @@ class wallet_api flat_map sidechain_public_keys, bool broadcast = false); + /** + * Activate deregistered SON object owned by the given account. + * + * @param owner_account The name of the SON's owner account. Also accepts the ID of the owner account or the ID of the SON. + * @param broadcast true if you wish to broadcast the transaction. + */ + signed_transaction activate_deregistered_son(const string & owner_account, + bool broadcast /* = false */); + + /** * Updates vesting balances of the SON object owned by the given account. * @@ -1427,6 +1488,12 @@ class wallet_api */ map list_active_sons(); + /** + * @brief Get SON network status + * @return SON network status description + */ + map get_son_network_status(); + /** * @brief Get active SON wallet * @return Active SON wallet object @@ -1454,6 +1521,7 @@ class wallet_api * @param account the name or id of the account who owns the address * @param sidechain a sidechain to whom address belongs * @param deposit_public_key sidechain public key used for deposit address + * @param deposit_address sidechain address for deposits * @param withdraw_public_key sidechain public key used for withdraw address * @param withdraw_address sidechain address for withdrawals * @param broadcast true to broadcast the transaction on the network @@ -1462,6 +1530,7 @@ class wallet_api signed_transaction add_sidechain_address(string account, sidechain_type sidechain, string deposit_public_key, + string deposit_address, string withdraw_public_key, string withdraw_address, bool broadcast = false); @@ -1522,7 +1591,7 @@ class wallet_api /** * Update a witness object owned by the given account. * - * @param witness The name of the witness's owner account. Also accepts the ID of the owner account or the ID of the witness. + * @param witness_name The name of the witness's owner account. Also accepts the ID of the owner account or the ID of the witness. * @param url Same as for create_witness. The empty string makes it remain the same. * @param block_signing_key The new block signing public key. The empty string makes it remain the same. * @param broadcast true if you wish to broadcast the transaction. @@ -1560,7 +1629,7 @@ class wallet_api * Update your votes for a worker * * @param account The account which will pay the fee and update votes. - * @param worker_vote_delta {"vote_for" : [...], "vote_against" : [...], "vote_abstain" : [...]} + * @param delta {"vote_for" : [...], "vote_against" : [...], "vote_abstain" : [...]} * @param broadcast true if you wish to broadcast the transaction. */ signed_transaction update_worker_votes( @@ -1621,7 +1690,7 @@ class wallet_api /** Vote for a given committee_member. * - * An account can publish a list of all committee_memberes they approve of. This + * An account can publish a list of all committee_memberes they approve of. This * command allows you to add or remove committee_memberes from this list. * Each account's vote is weighted according to the number of shares of the * core asset owned by that account at the time the votes are tallied. @@ -1631,7 +1700,7 @@ class wallet_api * * @param voting_account the name or id of the account who is voting with their shares * @param committee_member the name or id of the committee_member' owner account - * @param approve true if you wish to vote in favor of that committee_member, false to + * @param approve true if you wish to vote in favor of that committee_member, false to * remove your vote in favor of that committee_member * @param broadcast true if you wish to broadcast the transaction * @return the signed transaction changing your vote for the given committee_member @@ -1693,12 +1762,12 @@ class wallet_api signed_transaction update_son_votes(string voting_account, std::vector sons_to_approve, std::vector sons_to_reject, - uint16_t desired_number_of_son, + uint16_t desired_number_of_sons, bool broadcast = false); /** Vote for a given witness. * - * An account can publish a list of all witnesses they approve of. This + * An account can publish a list of all witnesses they approve of. This * command allows you to add or remove witnesses from this list. * Each account's vote is weighted according to the number of shares of the * core asset owned by that account at the time the votes are tallied. @@ -1708,7 +1777,7 @@ class wallet_api * * @param voting_account the name or id of the account who is voting with their shares * @param witness the name or id of the witness' owner account - * @param approve true if you wish to vote in favor of that witness, false to + * @param approve true if you wish to vote in favor of that witness, false to * remove your vote in favor of that witness * @param broadcast true if you wish to broadcast the transaction * @return the signed transaction changing your vote for the given witness @@ -1720,12 +1789,12 @@ class wallet_api /** Change your witness votes. * - * An account can publish a list of all witnesses they approve of. + * An account can publish a list of all witnesses they approve of. * Each account's vote is weighted according to the number of shares of the * core asset owned by that account at the time the votes are tallied. - * This command allows you to add or remove one or more witnesses from this list + * This command allows you to add or remove one or more witnesses from this list * in one call. When you are changing your vote on several witnesses, this - * may be easier than multiple `vote_for_witness` and + * may be easier than multiple `vote_for_witness` and * `set_desired_witness_and_committee_member_count` calls. * * @note you cannot vote against a witness, you can only vote for the witness @@ -1740,7 +1809,7 @@ class wallet_api * you currently approve). This list can be empty. * @param desired_number_of_witnesses the number of witnesses you believe the network * should have. You must vote for at least this many - * witnesses. You can set this to 0 to abstain from + * witnesses. You can set this to 0 to abstain from * voting on the number of witnesses. * @param broadcast true if you wish to broadcast the transaction * @return the signed transaction changing your vote for the given witnesses @@ -1771,24 +1840,24 @@ class wallet_api signed_transaction set_voting_proxy(string account_to_modify, optional voting_account, bool broadcast = false); - + /** Set your vote for the number of witnesses and committee_members in the system. * - * Each account can voice their opinion on how many committee_members and how many + * Each account can voice their opinion on how many committee_members and how many * witnesses there should be in the active committee_member/active witness list. These * are independent of each other. You must vote your approval of at least as many * committee_members or witnesses as you claim there should be (you can't say that there should - * be 20 committee_members but only vote for 10). + * be 20 committee_members but only vote for 10). * - * There are maximum values for each set in the blockchain parameters (currently + * There are maximum values for each set in the blockchain parameters (currently * defaulting to 1001). * * This setting can be changed at any time. If your account has a voting proxy * set, your preferences will be ignored. * * @param account_to_modify the name or id of the account to update - * @param number_of_committee_members the number - * + * @param desired_number_of_witnesses desired number of witnesses + * @param desired_number_of_committee_members desired number of committee members * @param broadcast true if you wish to broadcast the transaction * @return the signed transaction changing your vote proxy settings */ @@ -1840,16 +1909,16 @@ class wallet_api /** Returns an uninitialized object representing a given blockchain operation. * - * This returns a default-initialized object of the given type; it can be used + * This returns a default-initialized object of the given type; it can be used * during early development of the wallet when we don't yet have custom commands for - * creating all of the operations the blockchain supports. + * creating all of the operations the blockchain supports. * * Any operation the blockchain supports can be created using the transaction builder's - * \c add_operation_to_builder_transaction() , but to do that from the CLI you need to + * \c add_operation_to_builder_transaction() , but to do that from the CLI you need to * know what the JSON form of the operation looks like. This will give you a template * you can fill in. It's better than nothing. - * - * @param operation_type the type of operation to return, must be one of the + * + * @param operation_type the type of operation to return, must be one of the * operations defined in `graphene/chain/operations.hpp` * (e.g., "global_parameters_update_operation") * @return a default-constructed operation of the given type @@ -1874,7 +1943,7 @@ class wallet_api bool broadcast = false); /** Propose a fee change. - * + * * @param proposing_account The account paying the fee to propose the tx * @param expiration_time Timestamp specifying when the proposal will either take effect or expire. * @param changed_values Map of operation type to new fee. Operations may be specified by name or ID. @@ -1955,7 +2024,7 @@ class wallet_api sport_id_type sport_id, fc::optional name, bool broadcast = false); - + signed_transaction propose_delete_sport( const string& proposing_account, fc::time_point_sec expiration_time, @@ -1982,7 +2051,7 @@ class wallet_api fc::time_point_sec expiration_time, event_group_id_type event_group, bool broadcast = false); - + signed_transaction propose_create_event( const string& proposing_account, fc::time_point_sec expiration_time, @@ -2053,7 +2122,7 @@ class wallet_api fc::optional payout_condition, bool broadcast = false); - /** Place a bet + /** Place a bet * @param bettor the account placing the bet * @param betting_market_id the market on which to bet * @param back_or_lay back or lay @@ -2090,6 +2159,7 @@ class wallet_api /** Creates a new tournament * @param creator the accout that is paying the fee to create the tournament * @param options the options detailing the specifics of the tournament + * @param broadcast true if you wish to broadcast the transaction * @return the signed version of the transaction */ signed_transaction tournament_create( string creator, tournament_options options, bool broadcast = false ); @@ -2129,7 +2199,7 @@ class wallet_api tournament_state state); /** Get specific information about a tournament - * @param tournament_id the ID of the tournament + * @param id the ID of the tournament */ tournament_object get_tournament(tournament_id_type id); @@ -2137,6 +2207,7 @@ class wallet_api * @param game_id the id of the game * @param player_account the name of the player * @param gesture rock, paper, or scissors + * @param broadcast true if you wish to broadcast the transaction * @return the signed version of the transaction */ signed_transaction rps_throw(game_id_type game_id, @@ -2175,6 +2246,7 @@ class wallet_api vector get_custom_account_authorities_by_permission_id(custom_permission_id_type permission_id) const; vector get_custom_account_authorities_by_permission_name(string owner, string permission_name) const; vector get_active_custom_account_authorities_by_operation(string owner, int operation_type) const; + ///////// // NFT // ///////// @@ -2188,6 +2260,9 @@ class wallet_api * @param revenue_split revenue split for the sale * @param is_transferable can transfer the NFT or not * @param is_sellable can sell NFT or not + * @param role_id account role id + * @param max_supply max supply of NTFs + * @param lottery_options lottery options * @param broadcast true to broadcast transaction to the network * @return Signed transaction transfering the funds */ @@ -2200,6 +2275,8 @@ class wallet_api bool is_transferable, bool is_sellable, optional role_id, + optional max_supply, + optional lottery_options, bool broadcast); /** @@ -2213,6 +2290,7 @@ class wallet_api * @param revenue_split revenue split for the sale * @param is_transferable can transfer the NFT or not * @param is_sellable can sell NFT or not + * @param role_id account role id * @param broadcast true to broadcast transaction to the network * @return Signed transaction transfering the funds */ @@ -2326,8 +2404,8 @@ class wallet_api /** * @brief Returns operator approved state for all NFT owned by owner - * @param owner NFT owner account ID - * @param token_id NFT ID + * @param owner_account_id_or_name NFT owner account ID or name + * @param operator_account_id_or_name NFT operator account ID or name * @return True if operator is approved for all NFT owned by owner, else False */ bool nft_is_approved_for_all(string owner_account_id_or_name, string operator_account_id_or_name) const; @@ -2337,6 +2415,7 @@ class wallet_api * @return Returns vector of NFT objects, empty vector if none */ vector nft_get_all_tokens() const; + signed_transaction nft_lottery_buy_ticket( nft_metadata_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy, bool broadcast ); signed_transaction create_offer(set item_ids, string issuer_accound_id_or_name, @@ -2447,6 +2526,8 @@ FC_REFLECT( graphene::wallet::brain_key_info, (pub_key) ) +FC_REFLECT_ENUM( graphene::wallet::authority_type, (owner)(active) ) + FC_REFLECT( graphene::wallet::exported_account_keys, (account_name)(encrypted_private_keys)(public_keys) ) FC_REFLECT( graphene::wallet::exported_keys, (password_checksum)(account_keys) ) @@ -2475,7 +2556,7 @@ FC_REFLECT_DERIVED( graphene::wallet::signed_block_with_info, (graphene::chain:: FC_REFLECT_DERIVED( graphene::wallet::vesting_balance_object_with_info, (graphene::chain::vesting_balance_object), (allowed_withdraw)(allowed_withdraw_time) ) -FC_REFLECT( graphene::wallet::operation_detail, +FC_REFLECT( graphene::wallet::operation_detail, (memo)(description)(op) ) FC_API( graphene::wallet::wallet_api, @@ -2510,6 +2591,8 @@ FC_API( graphene::wallet::wallet_api, (derive_owner_keys_from_brain_key) (get_private_key_from_password) (register_account) + (update_account_keys) + (update_account_auth_key) (upgrade_account) (create_account_with_brain_key) (sell_asset) @@ -2549,8 +2632,10 @@ FC_API( graphene::wallet::wallet_api, (try_create_son) (update_son) (update_son_vesting_balances) + (activate_deregistered_son) (list_sons) (list_active_sons) + (get_son_network_status) (request_son_maintenance) (cancel_request_son_maintenance) (get_active_son_wallet) @@ -2669,6 +2754,7 @@ FC_API( graphene::wallet::wallet_api, (nft_get_approved) (nft_is_approved_for_all) (nft_get_all_tokens) + (nft_lottery_buy_ticket) (create_offer) (create_bid) (cancel_offer) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 7d4eb9f8..cc013736 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -615,7 +615,7 @@ public: throw fc::canceled_exception(); } - + bool copy_wallet_file( string destination_filename ) { fc::path src_path = get_wallet_filename(); @@ -734,12 +734,16 @@ public: { return _remote_db->get_dynamic_global_properties(); } + std::string object_id_to_string(object_id_type id) const + { + std::string object_id = fc::to_string(id.space()) + + "." + fc::to_string(id.type()) + + "." + fc::to_string(id.instance()); + return object_id; + } std::string account_id_to_string(account_id_type id) const { - std::string account_id = fc::to_string(id.space_id) - + "." + fc::to_string(id.type_id) - + "." + fc::to_string(id.instance.value); - return account_id; + return object_id_to_string(id); } account_object get_account(account_id_type id) const { @@ -909,7 +913,7 @@ public: const rock_paper_scissors_game_details& rps_details = game_obj.game_details.get(); for (unsigned i = 0; i < 2; ++i) { - if (rps_details.commit_moves.at(i) && + if (rps_details.commit_moves.at(i) && !rps_details.reveal_moves.at(i)) // if this player has committed but not revealed { const account_id_type& account_id = game_obj.players[i]; @@ -929,7 +933,7 @@ public: if (iter != _wallet.committed_game_moves.end()) { const rock_paper_scissors_throw_reveal& reveal = iter->second; - + game_move_operation move_operation; move_operation.game_id = game_obj.id; move_operation.player_account_id = account_id; @@ -972,7 +976,7 @@ public: } } FC_RETHROW_EXCEPTIONS(warn, "") } - // Cache all matches in the tournament, which will also register us for + // Cache all matches in the tournament, which will also register us for // updates on those matches void monitor_matches_in_tournament(const tournament_object& tournament_obj) { try { @@ -1129,8 +1133,8 @@ public: dlog( "validated successfully tmp wallet file ${fn}", ("fn", tmp_wallet_filename) ); fc::rename( tmp_wallet_filename, wallet_filename ); dlog( "renamed successfully tmp wallet file ${fn}", ("fn", tmp_wallet_filename) ); - } - else + } + else { FC_THROW("tmp wallet file cannot be validated ${fn}", ("fn", tmp_wallet_filename) ); } @@ -1335,6 +1339,102 @@ public: } FC_CAPTURE_AND_RETHROW( (name)(owner)(active)(registrar_account)(referrer_account)(referrer_percent)(broadcast) ) } + signed_transaction update_account_keys(string name, + public_key_type old_owner, + public_key_type new_owner, + public_key_type old_active, + public_key_type new_active, + bool broadcast) + { try { + FC_ASSERT( !self.is_locked() ); + account_object account_obj = get_account(name); + + authority owner = account_obj.owner; + owner.key_auths[new_owner] = owner.key_auths[old_owner]; + owner.key_auths.erase(old_owner); + + authority active = account_obj.active; + active.key_auths[new_active] = active.key_auths[old_active]; + active.key_auths.erase(old_active); + + signed_transaction tx; + account_update_operation op; + + op.account = account_obj.get_id(); + op.owner = owner; + op.active = active; + + ilog("account_update_operation: ${op}", ("op", op)); + + tx.operations = {op}; + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees ); + tx.validate(); + + return sign_transaction( tx, broadcast ); + } FC_CAPTURE_AND_RETHROW( (name) ) } + + + signed_transaction update_account_auth_key(string account_name, + authority_type type, + public_key_type key, + weight_type weight, + bool broadcast) + { + FC_ASSERT( !is_locked() ); + account_object account_obj = get_account(account_name); + + account_update_operation op; + op.account = account_obj.get_id(); + + authority new_auth; + + switch( type ) + { + case( owner ): + new_auth = account_obj.owner; + break; + case( active ): + new_auth = account_obj.active; + break; + } + + if( weight == 0 ) // Remove the key + { + new_auth.key_auths.erase( key ); + } + else + { + new_auth.add_authority( key, weight ); + } + + if( new_auth.is_impossible() ) + { + if ( type == owner ) + { + FC_ASSERT( false, "Owner authority change would render account irrecoverable." ); + } + + wlog( "Authority is now impossible." ); + } + + switch( type ) + { + case( owner ): + op.owner = new_auth; + break; + case( active ): + op.active = new_auth; + break; + } + + signed_transaction tx; + tx.operations.push_back(op); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees ); + tx.validate(); + + return sign_transaction( tx, broadcast ); + } + signed_transaction upgrade_account(string name, bool broadcast) { try { FC_ASSERT( !self.is_locked() ); @@ -1529,7 +1629,7 @@ public: return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (issuer)(symbol)(common)(broadcast) ) } - + signed_transaction buy_ticket( asset_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy ) { try { auto asset_obj = get_asset( lottery ); @@ -1540,7 +1640,7 @@ public: top.buyer = buyer; top.tickets_to_buy = tickets_to_buy; top.amount = asset( asset_obj.lottery_options->ticket_price.amount * tickets_to_buy, asset_obj.lottery_options->ticket_price.asset_id ); - + signed_transaction tx; tx.operations.push_back( top ); set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees); @@ -1548,8 +1648,8 @@ public: return sign_transaction( tx, true ); } FC_CAPTURE_AND_RETHROW( (lottery)(tickets_to_buy) ) } - - + + signed_transaction update_asset(string symbol, optional new_issuer, asset_options new_options, @@ -2014,6 +2114,23 @@ public: return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (owner_account)(url)(block_signing_key)(broadcast) ) } + signed_transaction activate_deregistered_son(const string & owner_account, + bool broadcast /* = false */) + { try { + son_object son = get_son(owner_account); + + son_update_operation son_update_op; + son_update_op.son_id = son.id; + son_update_op.owner_account = son.son_account; + son_update_op.new_status = son_status::inactive; + signed_transaction tx; + tx.operations.push_back( son_update_op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees ); + tx.validate(); + + return sign_transaction( tx, broadcast ); + } FC_CAPTURE_AND_RETHROW( (owner_account)(broadcast) ) } + signed_transaction update_son_vesting_balances(string owner_account, optional new_deposit, optional new_pay_vb, @@ -2107,6 +2224,40 @@ public: return result; } FC_CAPTURE_AND_RETHROW() } + map get_son_network_status() + { try { + global_property_object gpo = get_global_properties(); + vector son_ids; + son_ids.reserve(gpo.active_sons.size()); + std::transform(gpo.active_sons.begin(), gpo.active_sons.end(), + std::inserter(son_ids, son_ids.end()), + [](const son_info& swi) { + return swi.son_id; + }); + + map result; + std::vector> son_objects = _remote_db->get_sons(son_ids); + for(auto son_obj: son_objects) { + string status; + if (son_obj) { + son_statistics_object sso = get_object(son_obj->statistics); + if (sso.last_active_timestamp + fc::seconds(gpo.parameters.son_heartbeat_frequency()) > time_point::now()) { + status = "OK, regular SON heartbeat"; + } else { + if (sso.last_active_timestamp + fc::seconds(gpo.parameters.son_down_time()) > time_point::now()) { + status = "OK, irregular SON heartbeat, but not triggering SON down proposal"; + } else { + status = "NOT OK, irregular SON heartbeat, triggering SON down proposal"; + } + } + } else { + status = "NOT OK, invalid SON id"; + } + result[son_obj->id] = status; + } + return result; + } FC_CAPTURE_AND_RETHROW() } + optional get_active_son_wallet() { try { return _remote_db->get_active_son_wallet(); @@ -2125,6 +2276,7 @@ public: signed_transaction add_sidechain_address(string account, sidechain_type sidechain, string deposit_public_key, + string deposit_address, string withdraw_public_key, string withdraw_address, bool broadcast /* = false */) @@ -2136,6 +2288,7 @@ public: op.sidechain_address_account = sidechain_address_account_id; op.sidechain = sidechain; op.deposit_public_key = deposit_public_key; + op.deposit_address = deposit_address; op.withdraw_public_key = withdraw_public_key; op.withdraw_address = withdraw_address; @@ -2407,13 +2560,13 @@ public: fc::optional vbid = maybe_id(witness_name); if( !vbid ) { - if (is_witness(witness_name)) + if (is_witness(witness_name)) { witness_object wit = get_witness( witness_name ); FC_ASSERT( wit.pay_vb, "Account ${account} has no core Token ${TOKEN} vested and thus its not allowed to withdraw.", ("account", witness_name)("TOKEN", GRAPHENE_SYMBOL)); vbid = wit.pay_vb; } - else + else FC_THROW("Account ${account} has no core Token ${TOKEN} vested and thus its not allowed to withdraw.", ("account", witness_name)("TOKEN", GRAPHENE_SYMBOL)); } @@ -2456,14 +2609,14 @@ public: if( !vbid ) { vbos = _remote_db->get_vesting_balances( account_name ); - if( vbos.size() == 0 ) + if( vbos.size() == 0 ) FC_THROW("Account ${account} has no core TOKEN vested and thus its not allowed to withdraw.", ("account", account_name)); } - //whether it is a witness or user, keep it in a container and iterate over to process all vesting balances and types + //whether it is a witness or user, keep it in a container and iterate over to process all vesting balances and types if(!vbos.size()) vbos.emplace_back( get_object(*vbid) ); - + for (const vesting_balance_object& vesting_balance_obj: vbos) { if(vesting_balance_obj.balance_type == vesting_balance_type::gpos) { @@ -2493,7 +2646,7 @@ public: bool broadcast /* = false */) { try { std::vector vbo_info = get_vesting_balances(voting_account); - + time_point_sec now = time_point::now(); if(now >= HARDFORK_GPOS_TIME) //can be removed after GPOS HARDFORK time pass { @@ -2520,7 +2673,7 @@ public: const auto vesting_subperiod = _remote_db->get_global_properties().parameters.gpos_subperiod(); const auto gpos_start_time = fc::time_point_sec(_remote_db->get_global_properties().parameters.gpos_period_start()); const auto subperiod_start_time = gpos_start_time.sec_since_epoch() + (gpos_info.current_subperiod - 1) * vesting_subperiod; - + if (!insert_result.second && (gpos_info.last_voted_time.sec_since_epoch() >= subperiod_start_time)) FC_THROW("Account ${account} was already voting for committee_member ${committee_member} in the current GPOS sub-period", ("account", voting_account)("committee_member", committee_member)); else @@ -2646,7 +2799,7 @@ public: bool broadcast /* = false */) { try { std::vector vbo_info = get_vesting_balances(voting_account); - + time_point_sec now = time_point::now(); if(now >= HARDFORK_GPOS_TIME) //can be removed after GPOS HARDFORK time pass { @@ -2657,7 +2810,7 @@ public: } account_object voting_account_object = get_account(voting_account); - + fc::optional witness_obj = _remote_db->get_witness_by_account(witness); if (!witness_obj) FC_THROW("Account ${witness} is not registered as a witness", ("witness", witness)); @@ -2673,7 +2826,7 @@ public: const auto vesting_subperiod = _remote_db->get_global_properties().parameters.gpos_subperiod(); const auto gpos_start_time = fc::time_point_sec(_remote_db->get_global_properties().parameters.gpos_period_start()); const auto subperiod_start_time = gpos_start_time.sec_since_epoch() + (gpos_info.current_subperiod - 1) * vesting_subperiod; - + if (!insert_result.second && (gpos_info.last_voted_time.sec_since_epoch() >= subperiod_start_time)) FC_THROW("Account ${account} was already voting for witness ${witness} in the current GPOS sub-period", ("account", voting_account)("witness", witness)); else @@ -2691,7 +2844,7 @@ public: if (!votes_removed) FC_THROW("Account ${account} has not voted for witness ${witness}", ("account", voting_account)("witness", witness)); } - + account_update_operation account_update_op; account_update_op.account = voting_account_object.id; account_update_op.new_options = voting_account_object.options; @@ -3300,7 +3453,7 @@ public: { unsigned row_offset = (1 << round) - 1; unsigned row_vertical_spacing = 1 << (round + 1); - if (row >= row_offset && + if (row >= row_offset && (row - row_offset) % row_vertical_spacing == 0) { unsigned player_number_in_round = (row - row_offset) / row_vertical_spacing; @@ -3314,7 +3467,7 @@ public: if (round == num_rounds) { match_object match = get_object(tournament_details.matches[num_matches - 1]); - if (match.get_state() == match_state::match_complete && + if (match.get_state() == match_state::match_complete && !match.match_winners.empty()) { assert(match.match_winners.size() == 1); @@ -4127,7 +4280,7 @@ std::string operation_printer::operator()(const bet_place_operation& op)const auto asset = wallet.get_asset(op.amount_to_bet.asset_id); auto bettor = wallet.get_account(op.bettor_id); - out << bettor.name << " placed a " << fc::json::to_string(op.back_or_lay) << " bet for " + out << bettor.name << " placed a " << fc::json::to_string(op.back_or_lay) << " bet for " << asset.amount_to_pretty_string(op.amount_to_bet) << " at odds " << ((double)op.backer_multiplier / GRAPHENE_BETTING_ODDS_PRECISION) << " on market " << fc::json::to_string(op.betting_market_id) << " fee: " << fee_asset.amount_to_pretty_string(op.fee); @@ -4275,7 +4428,7 @@ vector wallet_api::get_account_lotteries( account_id_type issuer, return my->_remote_db->get_account_lotteries( issuer, stop, limit, start ); } -asset wallet_api::get_lottery_balance( asset_id_type lottery_id )const +asset wallet_api::get_lottery_balance( asset_id_type lottery_id )const { return my->_remote_db->get_lottery_balance( lottery_id ); } @@ -4283,7 +4436,7 @@ asset wallet_api::get_lottery_balance( asset_id_type lottery_id )const vector wallet_api::get_account_history(string name, int limit) const { vector result; - + while (limit > 0) { bool skip_first_row = false; @@ -4334,9 +4487,9 @@ vector wallet_api::get_account_history(string name, int limit) vector wallet_api::get_relative_account_history(string name, uint32_t stop, int limit, uint32_t start)const { - + FC_ASSERT( start > 0 || limit <= 100 ); - + vector result; while( limit > 0 ) @@ -4917,6 +5070,11 @@ signed_transaction wallet_api::update_son(string owner_account, return my->update_son(owner_account, url, block_signing_key, sidechain_public_keys, broadcast); } +signed_transaction wallet_api::activate_deregistered_son(const string & owner_account, bool broadcast) { + return my->activate_deregistered_son(owner_account, broadcast); +} + + signed_transaction wallet_api::update_son_vesting_balances(string owner_account, optional new_deposit, optional new_pay_vb, @@ -4945,6 +5103,11 @@ map wallet_api::list_active_sons() return my->list_active_sons(); } +map wallet_api::get_son_network_status() +{ + return my->get_son_network_status(); +} + optional wallet_api::get_active_son_wallet() { return my->get_active_son_wallet(); @@ -4963,11 +5126,12 @@ vector> wallet_api::get_son_wallets(uint32_t limit) signed_transaction wallet_api::add_sidechain_address(string account, sidechain_type sidechain, string deposit_public_key, + string deposit_address, string withdraw_public_key, string withdraw_address, bool broadcast /* = false */) { - return my->add_sidechain_address(account, sidechain, deposit_public_key, withdraw_public_key, withdraw_address, broadcast); + return my->add_sidechain_address(account, sidechain, deposit_public_key, deposit_address, withdraw_public_key, withdraw_address, broadcast); } signed_transaction wallet_api::delete_sidechain_address(string account, @@ -5596,6 +5760,25 @@ map wallet_api::dump_private_keys() return my->_keys; } +signed_transaction wallet_api::update_account_keys(string name, + public_key_type old_owner, + public_key_type new_owner, + public_key_type old_active, + public_key_type new_active, + bool broadcast ) +{ + return my->update_account_keys(name, old_owner, new_owner, old_active, new_active, broadcast); +} + +signed_transaction wallet_api::update_account_auth_key(string account_name, + authority_type type, + public_key_type key, + weight_type weight, + bool broadcast) +{ + return my->update_account_auth_key(account_name, type, key, weight, broadcast); +} + signed_transaction wallet_api::upgrade_account( string name, bool broadcast ) { return my->upgrade_account(name,broadcast); @@ -5621,8 +5804,15 @@ signed_transaction wallet_api::sell( string seller_account, double amount, bool broadcast ) { - return my->sell_asset( seller_account, std::to_string( amount ), base, - std::to_string( rate * amount ), quote, 0, false, broadcast ); + std::stringstream ss; + ss.str(std::string()); + ss << std::noshowpoint << amount; + std::string amount_to_sell = ss.str(); + ss.str(std::string()); + ss << std::noshowpoint << rate * amount; + std::string min_to_receive = ss.str(); + return my->sell_asset( seller_account, amount_to_sell, base, + min_to_receive, quote, 0, false, broadcast ); } signed_transaction wallet_api::buy( string buyer_account, @@ -5632,8 +5822,15 @@ signed_transaction wallet_api::buy( string buyer_account, double amount, bool broadcast ) { - return my->sell_asset( buyer_account, std::to_string( rate * amount ), quote, - std::to_string( amount ), base, 0, false, broadcast ); + std::stringstream ss; + ss.str(std::string()); + ss << std::noshowpoint << rate * amount; + std::string amount_to_sell = ss.str(); + ss.str(std::string()); + ss << std::noshowpoint << amount; + std::string min_to_receive = ss.str(); + return my->sell_asset( buyer_account, amount_to_sell, quote, + min_to_receive, base, 0, false, broadcast ); } signed_transaction wallet_api::borrow_asset(string seller_name, string amount_to_sell, @@ -6284,22 +6481,22 @@ signed_transaction wallet_api::propose_delete_sport( { FC_ASSERT( !is_locked() ); const chain_parameters& current_params = get_global_properties().parameters; - + sport_delete_operation sport_delete_op; sport_delete_op.sport_id = sport_id; - + proposal_create_operation prop_op; prop_op.expiration_time = expiration_time; prop_op.review_period_seconds = current_params.committee_proposal_review_period; prop_op.fee_paying_account = get_account(proposing_account).id; prop_op.proposed_ops.emplace_back( sport_delete_op ); current_params.current_fees->set_fee( prop_op.proposed_ops.back().op ); - + signed_transaction tx; tx.operations.push_back(prop_op); my->set_operation_fees(tx, current_params.current_fees); tx.validate(); - + return my->sign_transaction(tx, broadcast); } @@ -6362,7 +6559,7 @@ signed_transaction wallet_api::propose_update_event_group( return my->sign_transaction(tx, broadcast); } - + signed_transaction wallet_api::propose_delete_event_group( const string& proposing_account, fc::time_point_sec expiration_time, @@ -6371,22 +6568,22 @@ signed_transaction wallet_api::propose_delete_event_group( { FC_ASSERT( !is_locked() ); const chain_parameters& current_params = get_global_properties().parameters; - + event_group_delete_operation event_group_delete_op; event_group_delete_op.event_group_id = event_group; - + proposal_create_operation prop_op; prop_op.expiration_time = expiration_time; prop_op.review_period_seconds = current_params.committee_proposal_review_period; prop_op.fee_paying_account = get_account(proposing_account).id; prop_op.proposed_ops.emplace_back( event_group_delete_op ); current_params.current_fees->set_fee( prop_op.proposed_ops.back().op ); - + signed_transaction tx; tx.operations.push_back(prop_op); my->set_operation_fees(tx, current_params.current_fees); tx.validate(); - + return my->sign_transaction(tx, broadcast); } @@ -6771,10 +6968,10 @@ signed_transaction wallet_api::tournament_create( string creator, tournament_opt return my->sign_transaction( tx, broadcast ); } -signed_transaction wallet_api::tournament_join( string payer_account, - string player_account, - tournament_id_type tournament_id, - string buy_in_amount, +signed_transaction wallet_api::tournament_join( string payer_account, + string player_account, + tournament_id_type tournament_id, + string buy_in_amount, string buy_in_asset_symbol, bool broadcast ) { @@ -6856,7 +7053,7 @@ signed_transaction wallet_api::rps_throw(game_id_type game_id, graphene::chain::game_object game_obj = my->get_object(game_id); graphene::chain::match_object match_obj = my->get_object(game_obj.match_id); graphene::chain::tournament_object tournament_obj = my->get_object(match_obj.tournament_id); - graphene::chain::rock_paper_scissors_game_options game_options = + graphene::chain::rock_paper_scissors_game_options game_options = tournament_obj.options.game_options.get(); if ((int)gesture >= game_options.number_of_gestures) FC_THROW("Gesture ${gesture} not supported in this game", ("gesture", gesture)); @@ -6903,6 +7100,8 @@ signed_transaction wallet_api::nft_metadata_create(string owner_account_id_or_na bool is_transferable, bool is_sellable, optional role_id, + optional max_supply, + optional lottery_options, bool broadcast) { account_object owner_account = my->get_account(owner_account_id_or_name); @@ -6926,6 +7125,8 @@ signed_transaction wallet_api::nft_metadata_create(string owner_account_id_or_na op.is_transferable = is_transferable; op.is_sellable = is_sellable; op.account_role = role_id; + op.max_supply = max_supply; + op.lottery_options = lottery_options; signed_transaction trx; trx.operations.push_back(op); @@ -7109,6 +7310,21 @@ vector wallet_api::nft_get_all_tokens() const return my->_remote_db->nft_get_all_tokens(); } +signed_transaction wallet_api::nft_lottery_buy_ticket( nft_metadata_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy, bool broadcast ) +{ + nft_lottery_token_purchase_operation op; + op.lottery_id = lottery; + op.buyer = buyer; + op.tickets_to_buy = tickets_to_buy; + + signed_transaction trx; + trx.operations.push_back(op); + my->set_operation_fees( trx, my->_remote_db->get_global_properties().parameters.current_fees ); + trx.validate(); + + return my->sign_transaction( trx, broadcast ); +} + signed_transaction wallet_api::create_offer(set item_ids, string issuer_accound_id_or_name, asset minimum_price, diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index ba73cdca..d9c82346 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -1,5 +1,5 @@ add_subdirectory( build_helpers ) -if( BUILD_BITSHARES_PROGRAMS ) +if( BUILD_PEERPLAYS_PROGRAMS ) add_subdirectory( cli_wallet ) add_subdirectory( genesis_util ) add_subdirectory( witness_node ) @@ -7,4 +7,4 @@ if( BUILD_BITSHARES_PROGRAMS ) add_subdirectory( delayed_node ) add_subdirectory( js_operation_serializer ) add_subdirectory( size_checker ) -endif( BUILD_BITSHARES_PROGRAMS ) +endif( BUILD_PEERPLAYS_PROGRAMS ) diff --git a/programs/build_helpers/CMakeLists.txt b/programs/build_helpers/CMakeLists.txt index 7a625b25..e6e92455 100644 --- a/programs/build_helpers/CMakeLists.txt +++ b/programs/build_helpers/CMakeLists.txt @@ -5,7 +5,7 @@ if( UNIX AND NOT APPLE ) endif() # we only actually need Boost, but link against FC for now so we don't duplicate it. -target_link_libraries( cat-parts PRIVATE fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( cat-parts PRIVATE fc ${PLATFORM_SPECIFIC_LIBS} ) add_executable( member_enumerator member_enumerator.cpp ) if( UNIX AND NOT APPLE ) @@ -13,5 +13,5 @@ if( UNIX AND NOT APPLE ) endif() # we only actually need Boost, but link against FC for now so we don't duplicate it. -target_link_libraries( member_enumerator PRIVATE fc graphene_app graphene_net graphene_chain graphene_egenesis_brief graphene_utilities graphene_wallet ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( member_enumerator PRIVATE graphene_chain ${PLATFORM_SPECIFIC_LIBS} ) diff --git a/programs/cli_wallet/CMakeLists.txt b/programs/cli_wallet/CMakeLists.txt index 140bdce3..31f697eb 100644 --- a/programs/cli_wallet/CMakeLists.txt +++ b/programs/cli_wallet/CMakeLists.txt @@ -10,7 +10,7 @@ if( GPERFTOOLS_FOUND ) endif() target_link_libraries( cli_wallet - PRIVATE graphene_app graphene_net graphene_chain graphene_egenesis_brief graphene_utilities graphene_wallet fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) + PRIVATE graphene_app graphene_egenesis_brief graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) if(MSVC) set_source_files_properties( main.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) diff --git a/programs/debug_node/CMakeLists.txt b/programs/debug_node/CMakeLists.txt index 232d265e..e39ea929 100644 --- a/programs/debug_node/CMakeLists.txt +++ b/programs/debug_node/CMakeLists.txt @@ -10,7 +10,7 @@ if( GPERFTOOLS_FOUND ) endif() target_link_libraries( debug_node - PRIVATE graphene_app graphene_account_history graphene_market_history graphene_witness graphene_debug_witness graphene_bookie graphene_chain graphene_egenesis_full fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) + PRIVATE graphene_app graphene_egenesis_full ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS debug_node diff --git a/programs/delayed_node/CMakeLists.txt b/programs/delayed_node/CMakeLists.txt index 4dbe2bbf..7e610ace 100644 --- a/programs/delayed_node/CMakeLists.txt +++ b/programs/delayed_node/CMakeLists.txt @@ -10,7 +10,7 @@ if( GPERFTOOLS_FOUND ) endif() target_link_libraries( delayed_node - PRIVATE graphene_app graphene_account_history graphene_market_history graphene_delayed_node graphene_chain graphene_egenesis_full fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) + PRIVATE graphene_app graphene_egenesis_full graphene_delayed_node ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS delayed_node diff --git a/programs/genesis_util/CMakeLists.txt b/programs/genesis_util/CMakeLists.txt index 9c3b278d..80a3c7b8 100644 --- a/programs/genesis_util/CMakeLists.txt +++ b/programs/genesis_util/CMakeLists.txt @@ -5,7 +5,7 @@ if( UNIX AND NOT APPLE ) endif() target_link_libraries( genesis_update - PRIVATE graphene_app graphene_chain graphene_egenesis_none fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) + PRIVATE graphene_app graphene_egenesis_none ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS genesis_update @@ -18,7 +18,7 @@ install( TARGETS add_executable( get_dev_key get_dev_key.cpp ) target_link_libraries( get_dev_key - PRIVATE graphene_app graphene_chain graphene_egenesis_none graphene_utilities fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) + PRIVATE graphene_app ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS get_dev_key @@ -31,4 +31,4 @@ install( TARGETS add_executable( convert_address convert_address.cpp ) target_link_libraries( convert_address - PRIVATE graphene_chain fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) + PRIVATE graphene_chain ${PLATFORM_SPECIFIC_LIBS} ) diff --git a/programs/js_operation_serializer/CMakeLists.txt b/programs/js_operation_serializer/CMakeLists.txt index dad8ded2..a49d164e 100644 --- a/programs/js_operation_serializer/CMakeLists.txt +++ b/programs/js_operation_serializer/CMakeLists.txt @@ -4,7 +4,7 @@ if( UNIX AND NOT APPLE ) endif() target_link_libraries( js_operation_serializer - PRIVATE graphene_app graphene_net graphene_chain graphene_egenesis_none graphene_utilities graphene_wallet fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) + PRIVATE graphene_app ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS js_operation_serializer diff --git a/programs/size_checker/CMakeLists.txt b/programs/size_checker/CMakeLists.txt index 5e0a167c..a1a504a3 100644 --- a/programs/size_checker/CMakeLists.txt +++ b/programs/size_checker/CMakeLists.txt @@ -4,7 +4,7 @@ if( UNIX AND NOT APPLE ) endif() target_link_libraries( size_checker - PRIVATE graphene_chain graphene_egenesis_none fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) + PRIVATE graphene_chain ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS size_checker diff --git a/programs/witness_node/CMakeLists.txt b/programs/witness_node/CMakeLists.txt index d5578379..806330d6 100644 --- a/programs/witness_node/CMakeLists.txt +++ b/programs/witness_node/CMakeLists.txt @@ -11,7 +11,7 @@ endif() # We have to link against graphene_debug_witness because deficiency in our API infrastructure doesn't allow plugins to be fully abstracted #246 target_link_libraries( witness_node - PRIVATE graphene_app graphene_account_history graphene_affiliate_stats graphene_elasticsearch graphene_market_history graphene_witness graphene_chain graphene_debug_witness graphene_bookie graphene_egenesis_full graphene_snapshot graphene_es_objects fc peerplays_sidechain ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) + PRIVATE graphene_app graphene_egenesis_full graphene_snapshot graphene_witness peerplays_sidechain ${PLATFORM_SPECIFIC_LIBS} ) # also add dependencies to graphene_generate_genesis graphene_generate_uia_sharedrop_genesis if you want those plugins install( TARGETS diff --git a/programs/witness_node/genesis.json b/programs/witness_node/genesis.json index d38f3e4e..1e0610f4 100644 --- a/programs/witness_node/genesis.json +++ b/programs/witness_node/genesis.json @@ -392,7 +392,7 @@ "son_deregister_time": 43200, "son_heartbeat_frequency": 180, "son_down_time": 360, - "maximum_son_count": 7 + "maximum_son_count": 15 } }, "initial_bts_accounts": [], diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index 7823fed3..af5086b2 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -71,10 +71,7 @@ int main(int argc, char** argv) { ("help,h", "Print this help message and exit.") ("data-dir,d", bpo::value()->default_value("witness_node_data_dir"), "Directory containing databases, configuration file, etc.") - ("version,v", "Display version information") - ("plugins", bpo::value() - ->default_value("witness account_history market_history accounts_list affiliate_stats bookie"), - "Space-separated list of plugins to activate"); + ("version,v", "Display version information"); bpo::variables_map options; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 01474582..6ff915a9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,62 +1,65 @@ -file(GLOB COMMON_SOURCES "common/*.cpp") - find_package( Gperftools QUIET ) if( GPERFTOOLS_FOUND ) message( STATUS "Found gperftools; compiling tests with TCMalloc") list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc ) endif() +file(GLOB COMMON_SOURCES "common/*.cpp") +add_library(graphene_tests_common "${COMMON_SOURCES}" ) +target_link_libraries( graphene_tests_common + PUBLIC graphene_app graphene_egenesis_none ) + file(GLOB UNIT_TESTS "tests/*.cpp") -add_executable( chain_test ${UNIT_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( chain_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_bookie graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) +add_executable( chain_test ${UNIT_TESTS} ) +target_link_libraries( chain_test PRIVATE graphene_wallet graphene_tests_common ${PLATFORM_SPECIFIC_LIBS} ) if(MSVC) set_source_files_properties( tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) endif(MSVC) file(GLOB PERFORMANCE_TESTS "performance/*.cpp") -add_executable( performance_test ${PERFORMANCE_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( performance_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +add_executable( performance_test ${PERFORMANCE_TESTS} ) +target_link_libraries( performance_test PRIVATE graphene_tests_common ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB BENCH_MARKS "benchmarks/*.cpp") -add_executable( chain_bench ${BENCH_MARKS} ${COMMON_SOURCES} ) -target_link_libraries( chain_bench graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +add_executable( chain_bench ${BENCH_MARKS} ) +target_link_libraries( chain_bench PRIVATE graphene_tests_common ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB APP_SOURCES "app/*.cpp") add_executable( app_test ${APP_SOURCES} ) -target_link_libraries( app_test graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_witness graphene_bookie graphene_net graphene_chain graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( app_test PRIVATE graphene_tests_common graphene_witness ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB INTENSE_SOURCES "intense/*.cpp") -add_executable( intense_test ${INTENSE_SOURCES} ${COMMON_SOURCES} ) -target_link_libraries( intense_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +add_executable( intense_test ${INTENSE_SOURCES} ) +target_link_libraries( intense_test PRIVATE graphene_tests_common ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB BETTING_TESTS "betting/*.cpp") -add_executable( betting_test ${BETTING_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( betting_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_bookie graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) +add_executable( betting_test ${BETTING_TESTS} ) +target_link_libraries( betting_test PRIVATE graphene_tests_common ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB PEERPLAYS_SIDECHAIN_TESTS "peerplays_sidechain/*.cpp") -add_executable( peerplays_sidechain_test ${PEERPLAYS_SIDECHAIN_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( peerplays_sidechain_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_elasticsearch graphene_es_objects graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) +add_executable( peerplays_sidechain_test ${PEERPLAYS_SIDECHAIN_TESTS} ) +target_link_libraries( peerplays_sidechain_test PRIVATE graphene_tests_common peerplays_sidechain ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB TOURNAMENT_TESTS "tournament/*.cpp") -add_executable( tournament_test ${TOURNAMENT_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( tournament_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +add_executable( tournament_test ${TOURNAMENT_TESTS} ) +target_link_libraries( tournament_test PRIVATE graphene_tests_common ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB RANDOM_SOURCES "random/*.cpp") -add_executable( random_test ${RANDOM_SOURCES} ${COMMON_SOURCES} ) -target_link_libraries( random_test graphene_chain graphene_app graphene_elasticsearch graphene_es_objects graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +add_executable( random_test ${RANDOM_SOURCES} ) +target_link_libraries( random_test PRIVATE graphene_tests_common ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB CLI_SOURCES "cli/*.cpp") add_executable( cli_test ${CLI_SOURCES} ) if(WIN32) list(APPEND PLATFORM_SPECIFIC_LIBS ws2_32) endif() -target_link_libraries( cli_test graphene_chain graphene_app graphene_witness graphene_wallet graphene_egenesis_none fc graphene_elasticsearch graphene_es_objects ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( cli_test PRIVATE graphene_wallet graphene_tests_common graphene_witness ${PLATFORM_SPECIFIC_LIBS} ) if(MSVC) set_source_files_properties( cli/main.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) endif(MSVC) file(GLOB ES_SOURCES "elasticsearch/*.cpp") -add_executable( es_test ${ES_SOURCES} ${COMMON_SOURCES} ) -target_link_libraries( es_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +add_executable( es_test ${ES_SOURCES} ) +target_link_libraries( es_test PRIVATE graphene_tests_common ) add_subdirectory( generate_empty_blocks ) diff --git a/tests/betting/betting_tests.cpp b/tests/betting/betting_tests.cpp index cb6118a6..3898bb6c 100644 --- a/tests/betting/betting_tests.cpp +++ b/tests/betting/betting_tests.cpp @@ -132,114 +132,6 @@ using namespace graphene::chain::keywords; // 1.58 50:29 | 2.34 50:67 | 4.6 5:18 | 25 1:24 | 430 1:429 | // 1.59 100:59 | 2.36 25:34 | 4.7 10:37 -#define CREATE_ICE_HOCKEY_BETTING_MARKET(never_in_play, delay_before_settling) \ - create_sport({{"en", "Ice Hockey"}, {"zh_Hans", "冰球"}, {"ja", "アイスホッケー"}}); \ - generate_blocks(1); \ - const sport_object& ice_hockey = *db.get_index_type().indices().get().rbegin(); \ - create_event_group({{"en", "NHL"}, {"zh_Hans", "國家冰球聯盟"}, {"ja", "ナショナルホッケーリーグ"}}, ice_hockey.id); \ - generate_blocks(1); \ - const event_group_object& nhl = *db.get_index_type().indices().get().rbegin(); \ - create_event({{"en", "Washington Capitals/Chicago Blackhawks"}, {"zh_Hans", "華盛頓首都隊/芝加哥黑鷹"}, {"ja", "ワシントン・キャピタルズ/シカゴ・ブラックホークス"}}, {{"en", "2016-17"}}, nhl.id); \ - generate_blocks(1); \ - const event_object& capitals_vs_blackhawks = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market_rules({{"en", "NHL Rules v1.0"}}, {{"en", "The winner will be the team with the most points at the end of the game. The team with fewer points will not be the winner."}}); \ - generate_blocks(1); \ - const betting_market_rules_object& betting_market_rules = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market_group({{"en", "Moneyline"}}, capitals_vs_blackhawks.id, betting_market_rules.id, asset_id_type(), never_in_play, delay_before_settling); \ - generate_blocks(1); \ - const betting_market_group_object& moneyline_betting_markets = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_betting_markets.id, {{"en", "Washington Capitals win"}}); \ - generate_blocks(1); \ - const betting_market_object& capitals_win_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_betting_markets.id, {{"en", "Chicago Blackhawks win"}}); \ - generate_blocks(1); \ - const betting_market_object& blackhawks_win_market = *db.get_index_type().indices().get().rbegin(); \ - (void)capitals_win_market; (void)blackhawks_win_market; - -// create the basic betting market, plus groups for the first, second, and third period results -#define CREATE_EXTENDED_ICE_HOCKEY_BETTING_MARKET(never_in_play, delay_before_settling) \ - CREATE_ICE_HOCKEY_BETTING_MARKET(never_in_play, delay_before_settling) \ - create_betting_market_group({{"en", "First Period Result"}}, capitals_vs_blackhawks.id, betting_market_rules.id, asset_id_type(), never_in_play, delay_before_settling); \ - generate_blocks(1); \ - const betting_market_group_object& first_period_result_betting_markets = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(first_period_result_betting_markets.id, {{"en", "Washington Capitals win"}}); \ - generate_blocks(1); \ - const betting_market_object& first_period_capitals_win_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(first_period_result_betting_markets.id, {{"en", "Chicago Blackhawks win"}}); \ - generate_blocks(1); \ - const betting_market_object& first_period_blackhawks_win_market = *db.get_index_type().indices().get().rbegin(); \ - (void)first_period_capitals_win_market; (void)first_period_blackhawks_win_market; \ - \ - create_betting_market_group({{"en", "Second Period Result"}}, capitals_vs_blackhawks.id, betting_market_rules.id, asset_id_type(), never_in_play, delay_before_settling); \ - generate_blocks(1); \ - const betting_market_group_object& second_period_result_betting_markets = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(second_period_result_betting_markets.id, {{"en", "Washington Capitals win"}}); \ - generate_blocks(1); \ - const betting_market_object& second_period_capitals_win_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(second_period_result_betting_markets.id, {{"en", "Chicago Blackhawks win"}}); \ - generate_blocks(1); \ - const betting_market_object& second_period_blackhawks_win_market = *db.get_index_type().indices().get().rbegin(); \ - (void)second_period_capitals_win_market; (void)second_period_blackhawks_win_market; \ - \ - create_betting_market_group({{"en", "Third Period Result"}}, capitals_vs_blackhawks.id, betting_market_rules.id, asset_id_type(), never_in_play, delay_before_settling); \ - generate_blocks(1); \ - const betting_market_group_object& third_period_result_betting_markets = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(third_period_result_betting_markets.id, {{"en", "Washington Capitals win"}}); \ - generate_blocks(1); \ - const betting_market_object& third_period_capitals_win_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(third_period_result_betting_markets.id, {{"en", "Chicago Blackhawks win"}}); \ - generate_blocks(1); \ - const betting_market_object& third_period_blackhawks_win_market = *db.get_index_type().indices().get().rbegin(); \ - (void)third_period_capitals_win_market; (void)third_period_blackhawks_win_market; - -#define CREATE_TENNIS_BETTING_MARKET() \ - create_betting_market_rules({{"en", "Tennis Rules v1.0"}}, {{"en", "The winner is the player who wins the last ball in the match."}}); \ - generate_blocks(1); \ - const betting_market_rules_object& tennis_rules = *db.get_index_type().indices().get().rbegin(); \ - create_sport({{"en", "Tennis"}}); \ - generate_blocks(1); \ - const sport_object& tennis = *db.get_index_type().indices().get().rbegin(); \ - create_event_group({{"en", "Wimbledon"}}, tennis.id); \ - generate_blocks(1); \ - const event_group_object& wimbledon = *db.get_index_type().indices().get().rbegin(); \ - create_event({{"en", "R. Federer/T. Berdych"}}, {{"en", "2017"}}, wimbledon.id); \ - generate_blocks(1); \ - const event_object& berdych_vs_federer = *db.get_index_type().indices().get().rbegin(); \ - create_event({{"en", "M. Cilic/S. Querrye"}}, {{"en", "2017"}}, wimbledon.id); \ - generate_blocks(1); \ - const event_object& cilic_vs_querrey = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market_group({{"en", "Moneyline 1st sf"}}, berdych_vs_federer.id, tennis_rules.id, asset_id_type(), false, 0); \ - generate_blocks(1); \ - const betting_market_group_object& moneyline_berdych_vs_federer = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market_group({{"en", "Moneyline 2nd sf"}}, cilic_vs_querrey.id, tennis_rules.id, asset_id_type(), false, 0); \ - generate_blocks(1); \ - const betting_market_group_object& moneyline_cilic_vs_querrey = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_berdych_vs_federer.id, {{"en", "T. Berdych defeats R. Federer"}}); \ - generate_blocks(1); \ - const betting_market_object& berdych_wins_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_berdych_vs_federer.id, {{"en", "R. Federer defeats T. Berdych"}}); \ - generate_blocks(1); \ - const betting_market_object& federer_wins_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_cilic_vs_querrey.id, {{"en", "M. Cilic defeats S. Querrey"}}); \ - generate_blocks(1); \ - const betting_market_object& cilic_wins_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_cilic_vs_querrey.id, {{"en", "S. Querrey defeats M. Cilic"}});\ - generate_blocks(1); \ - const betting_market_object& querrey_wins_market = *db.get_index_type().indices().get().rbegin(); \ - create_event({{"en", "R. Federer/M. Cilic"}}, {{"en", "2017"}}, wimbledon.id); \ - generate_blocks(1); \ - const event_object& cilic_vs_federer = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market_group({{"en", "Moneyline final"}}, cilic_vs_federer.id, tennis_rules.id, asset_id_type(), false, 0); \ - generate_blocks(1); \ - const betting_market_group_object& moneyline_cilic_vs_federer = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_cilic_vs_federer.id, {{"en", "R. Federer defeats M. Cilic"}}); \ - generate_blocks(1); \ - const betting_market_object& federer_wins_final_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_cilic_vs_federer.id, {{"en", "M. Cilic defeats R. Federer"}}); \ - generate_blocks(1); \ - const betting_market_object& cilic_wins_final_market = *db.get_index_type().indices().get().rbegin(); \ - (void)federer_wins_market;(void)cilic_wins_market;(void)federer_wins_final_market; (void)cilic_wins_final_market; (void)berdych_wins_market; (void)querrey_wins_market; - BOOST_FIXTURE_TEST_SUITE( betting_tests, database_fixture ) BOOST_AUTO_TEST_CASE(try_create_sport) @@ -309,12 +201,12 @@ BOOST_AUTO_TEST_CASE(simple_bet_win) transfer(account_id_type(), bob_id, asset(10000)); // place bets at 10:1 - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(100, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); // reverse positions at 1:1 - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); } FC_LOG_AND_RETHROW() } @@ -332,23 +224,23 @@ BOOST_AUTO_TEST_CASE(binned_order_books) transfer(account_id_type(), bob_id, asset(10000)); // place back bets at decimal odds of 1.55, 1.6, 1.65, 1.66, and 1.67 - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100); - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 16 * GRAPHENE_BETTING_ODDS_PRECISION / 10); - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 166 * GRAPHENE_BETTING_ODDS_PRECISION / 100); - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 167 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(100, asset_id_type()), 16 * GRAPHENE_BETTING_ODDS_PRECISION / 10); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(100, asset_id_type()), 166 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(100, asset_id_type()), 167 * GRAPHENE_BETTING_ODDS_PRECISION / 100); const auto& bet_odds_idx = db.get_index_type().indices().get(); - auto bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); + auto bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)); while (bet_iter != bet_odds_idx.end() && - bet_iter->betting_market_id == capitals_win_market.id) + bet_iter->betting_market_id == capitals_win_market_id) { idump((*bet_iter)); ++bet_iter; } - graphene::bookie::binned_order_book binned_orders_point_one = bookie_api.get_binned_order_book(capitals_win_market.id, 1); + graphene::bookie::binned_order_book binned_orders_point_one = bookie_api.get_binned_order_book(capitals_win_market_id, 1); idump((binned_orders_point_one)); // the binned orders returned should be chosen so that we if we assume those orders are real and we place @@ -362,28 +254,28 @@ BOOST_AUTO_TEST_CASE(binned_order_books) // compute the matching lay order share_type lay_amount = bet_object::get_approximate_matching_amount(binned_order.amount_to_bet, binned_order.backer_multiplier, bet_type::back, true /* round up */); ilog("Alice is laying with ${lay_amount} at odds ${odds} to match the binned back amount ${back_amount}", ("lay_amount", lay_amount)("odds", binned_order.backer_multiplier)("back_amount", binned_order.amount_to_bet)); - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(lay_amount, asset_id_type()), binned_order.backer_multiplier); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(lay_amount, asset_id_type()), binned_order.backer_multiplier); } - bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); + bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)); while (bet_iter != bet_odds_idx.end() && - bet_iter->betting_market_id == capitals_win_market.id) + bet_iter->betting_market_id == capitals_win_market_id) { idump((*bet_iter)); ++bet_iter; } - BOOST_CHECK(bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)) == bet_odds_idx.end()); + BOOST_CHECK(bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)) == bet_odds_idx.end()); // place lay bets at decimal odds of 1.55, 1.6, 1.65, 1.66, and 1.67 // these bets will get rounded down, actual amounts are 99, 99, 91, 99, and 67 -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100); -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100); -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); +// place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100); +// place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100); +// place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); +// place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); +// place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); // -// binned_orders_point_one = bookie_api.get_binned_order_book(capitals_win_market.id, 1); +// binned_orders_point_one = bookie_api.get_binned_order_book(capitals_win_market_id, 1); // idump((binned_orders_point_one)); // // // the binned orders returned should be chosen so that we if we assume those orders are real and we place @@ -397,20 +289,20 @@ BOOST_AUTO_TEST_CASE(binned_order_books) // // compute the matching lay order // share_type back_amount = bet_object::get_approximate_matching_amount(binned_order.amount_to_bet, binned_order.backer_multiplier, bet_type::lay, true /* round up */); // ilog("Alice is backing with ${back_amount} at odds ${odds} to match the binned lay amount ${lay_amount}", ("back_amount", back_amount)("odds", binned_order.backer_multiplier)("lay_amount", binned_order.amount_to_bet)); -// place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(back_amount, asset_id_type()), binned_order.backer_multiplier); +// place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(back_amount, asset_id_type()), binned_order.backer_multiplier); // // } // // -// bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); +// bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)); // while (bet_iter != bet_odds_idx.end() && -// bet_iter->betting_market_id == capitals_win_market.id) +// bet_iter->betting_market_id == capitals_win_market_id) // { // idump((*bet_iter)); // ++bet_iter; // } // -// BOOST_CHECK(bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)) == bet_odds_idx.end()); +// BOOST_CHECK(bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)) == bet_odds_idx.end()); // } FC_LOG_AND_RETHROW() } @@ -427,19 +319,19 @@ BOOST_AUTO_TEST_CASE( peerplays_sport_create_test ) transfer(account_id_type(), bob_id, asset(10000000)); // have bob lay a bet for 1M (+20k fees) at 1:1 odds - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); // have alice back a matching bet at 1:1 odds (also costing 1.02M) - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000); BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000); - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::closed); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::closed); // caps win - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); @@ -464,18 +356,18 @@ BOOST_AUTO_TEST_CASE( cancel_unmatched_in_betting_group_test ) transfer(account_id_type(), bob_id, asset(10000000)); // have bob lay a bet for 1M (+20k fees) at 1:1 odds - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); // have alice back a matching bet at 1:1 odds (also costing 1.02M) - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); // place unmatched - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(bob_id, blackhawks_win_market.id, bet_type::lay, asset(600, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, blackhawks_win_market_id, bet_type::lay, asset(600, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 500); BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 600); // cancel unmatched - cancel_unmatched_bets(moneyline_betting_markets.id); + cancel_unmatched_bets(moneyline_betting_markets_id); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000); BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000); @@ -498,19 +390,19 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts) // lay 46 at 1.94 odds (50:47) -- this is too small to be placed on the books and there's // nothing for it to match, so it should be canceled BOOST_TEST_MESSAGE("lay 46 at 1.94 odds (50:47) -- this is too small to be placed on the books and there's nothing for it to match, so it should be canceled"); - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(46, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(46, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); BOOST_TEST_MESSAGE("alice's balance should be " << alice_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); ilog("message"); // lay 47 at 1.94 odds (50:47) -- this is an exact amount, nothing surprising should happen here BOOST_TEST_MESSAGE("alice lays 470 at 1.94 odds (50:47) -- this is an exact amount, nothing surprising should happen here"); - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(47, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(47, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 47; BOOST_TEST_MESSAGE("alice's balance should be " << alice_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); // lay 100 at 1.91 odds (100:91) -- this is an inexact match, we should get refunded 9 and leave a bet for 91 on the books - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 191 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(100, asset_id_type()), 191 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 91; BOOST_TEST_MESSAGE("alice's balance should be " << alice_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); @@ -528,7 +420,7 @@ ilog("message"); // bob's balance goes down by 300 (150 is matched, 150 is still on the books) // leaves a back bet of 150 @ 1.5 on the books BOOST_TEST_MESSAGE("now have bob match it with a back of 300 at 1.5"); - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(300, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(300, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); bob_expected_balance -= 300; BOOST_TEST_MESSAGE("bob's balance should be " << bob_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); @@ -550,7 +442,7 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts2) // lay 470 at 1.94 odds (50:47) -- this is an exact amount, nothing surprising should happen here BOOST_TEST_MESSAGE("alice lays 470 at 1.94 odds (50:47) -- this is an exact amount, nothing surprising should happen here"); - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(470, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(470, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 470; BOOST_TEST_MESSAGE("alice's balance should be " << alice_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); @@ -565,7 +457,7 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts2) // bob's balance goes down by the 900 he paid (500 matched, 400 unmatched) // alice's bet is completely removed from the books. BOOST_TEST_MESSAGE("now have bob match it with a back of 900 at 1.5"); - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(900, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(900, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); bob_expected_balance -= 900; BOOST_TEST_MESSAGE("bob's balance should be " << bob_expected_balance.value); @@ -587,7 +479,7 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts3) BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); // lay 470 at 1.94 odds (50:47) -- this is an exact amount, nothing surprising should happen here - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(470, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(470, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 470; BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); @@ -600,7 +492,7 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts3) // match all of the 470 @ 1.94 with 500, and leave 500 left on the books // bob's balance goes down by the 1000 he paid, 500 matching, 500 unmatching // alice's bet is removed from the books - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(1000, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); bob_expected_balance -= 1000; BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); } @@ -620,12 +512,12 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts4) BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); // back 1000 at 1.89 odds (100:89) -- this is an exact amount, nothing surprising should happen here - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 189 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000, asset_id_type()), 189 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 1000; BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); // back 1000 at 1.97 odds (100:97) -- again, this is an exact amount, nothing surprising should happen here - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 197 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000, asset_id_type()), 197 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 1000; BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); @@ -655,7 +547,7 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts4) // * alice's top bet on the books is reduced 200 @ 1.97 // * Bob now has as much of a position as he was willing to buy. We refund // the remainder of his bet, which is 552 - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(3000, asset_id_type()), 266 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(3000, asset_id_type()), 266 * GRAPHENE_BETTING_ODDS_PRECISION / 100); bob_expected_balance -= 3000 - 12 - 770 - 552; BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); } @@ -675,7 +567,7 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts5) BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); // back 1100 at 1.86 odds (50:43) -- this is an exact amount, nothing surprising should happen here - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1100, asset_id_type()), 186 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1100, asset_id_type()), 186 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 1100; BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); @@ -699,7 +591,7 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts5) // * bob's bet is fully matched, he is refunded the remaining 132 and his // bet is complete // * bob's balance is reduced by the 946 he paid - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1100, asset_id_type()), 198 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(1100, asset_id_type()), 198 * GRAPHENE_BETTING_ODDS_PRECISION / 100); bob_expected_balance -= 1100 - 22 - 132; BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); } @@ -720,40 +612,40 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts6) share_type alice_expected_balance = 1000000000; BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(10000000, asset_id_type()), 13 * GRAPHENE_BETTING_ODDS_PRECISION / 10); - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(10000000, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(10000000, asset_id_type()), 16 * GRAPHENE_BETTING_ODDS_PRECISION / 10); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(10000000, asset_id_type()), 13 * GRAPHENE_BETTING_ODDS_PRECISION / 10); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(10000000, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(10000000, asset_id_type()), 16 * GRAPHENE_BETTING_ODDS_PRECISION / 10); alice_expected_balance -= 30000000; BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); // check order books to see they match the bets we placed const auto& bet_odds_idx = db.get_index_type().indices().get(); - auto bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); + auto bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)); BOOST_REQUIRE(bet_iter != bet_odds_idx.end()); - BOOST_REQUIRE(bet_iter->betting_market_id == capitals_win_market.id); + BOOST_REQUIRE(bet_iter->betting_market_id == capitals_win_market_id); BOOST_REQUIRE(bet_iter->bettor_id == alice_id); BOOST_REQUIRE(bet_iter->amount_to_bet == asset(10000000, asset_id_type())); BOOST_REQUIRE(bet_iter->backer_multiplier == 13 * GRAPHENE_BETTING_ODDS_PRECISION / 10); BOOST_REQUIRE(bet_iter->back_or_lay == bet_type::back); ++bet_iter; BOOST_REQUIRE(bet_iter != bet_odds_idx.end()); - BOOST_REQUIRE(bet_iter->betting_market_id == capitals_win_market.id); + BOOST_REQUIRE(bet_iter->betting_market_id == capitals_win_market_id); BOOST_REQUIRE(bet_iter->bettor_id == alice_id); BOOST_REQUIRE(bet_iter->amount_to_bet == asset(10000000, asset_id_type())); BOOST_REQUIRE(bet_iter->backer_multiplier == 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); BOOST_REQUIRE(bet_iter->back_or_lay == bet_type::back); ++bet_iter; BOOST_REQUIRE(bet_iter != bet_odds_idx.end()); - BOOST_REQUIRE(bet_iter->betting_market_id == capitals_win_market.id); + BOOST_REQUIRE(bet_iter->betting_market_id == capitals_win_market_id); BOOST_REQUIRE(bet_iter->bettor_id == alice_id); BOOST_REQUIRE(bet_iter->amount_to_bet == asset(10000000, asset_id_type())); BOOST_REQUIRE(bet_iter->backer_multiplier == 16 * GRAPHENE_BETTING_ODDS_PRECISION / 10); BOOST_REQUIRE(bet_iter->back_or_lay == bet_type::back); ++bet_iter; - BOOST_REQUIRE(bet_iter == bet_odds_idx.end() || bet_iter->betting_market_id != capitals_win_market.id); + BOOST_REQUIRE(bet_iter == bet_odds_idx.end() || bet_iter->betting_market_id != capitals_win_market_id); // check the binned order books from the bookie plugin to make sure they match - graphene::bookie::binned_order_book binned_orders_point_one = bookie_api.get_binned_order_book(capitals_win_market.id, 1); + graphene::bookie::binned_order_book binned_orders_point_one = bookie_api.get_binned_order_book(capitals_win_market_id, 1); auto aggregated_back_bets_iter = binned_orders_point_one.aggregated_back_bets.begin(); BOOST_REQUIRE(aggregated_back_bets_iter != binned_orders_point_one.aggregated_back_bets.end()); BOOST_REQUIRE(aggregated_back_bets_iter->amount_to_bet.value == 10000000); @@ -774,11 +666,11 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts6) share_type bob_expected_balance = 1000000000; BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(5000000, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(5000000, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); ilog("Order books after bob's matching lay bet:"); - bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); + bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)); while (bet_iter != bet_odds_idx.end() && - bet_iter->betting_market_id == capitals_win_market.id) + bet_iter->betting_market_id == capitals_win_market_id) { idump((*bet_iter)); ++bet_iter; @@ -788,25 +680,25 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts6) BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); // check order books to see they match after bob's bet matched - bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); + bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)); BOOST_REQUIRE(bet_iter != bet_odds_idx.end()); - BOOST_REQUIRE(bet_iter->betting_market_id == capitals_win_market.id); + BOOST_REQUIRE(bet_iter->betting_market_id == capitals_win_market_id); BOOST_REQUIRE(bet_iter->bettor_id == alice_id); BOOST_REQUIRE(bet_iter->amount_to_bet == asset(10000000, asset_id_type())); BOOST_REQUIRE(bet_iter->backer_multiplier == 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); BOOST_REQUIRE(bet_iter->back_or_lay == bet_type::back); ++bet_iter; BOOST_REQUIRE(bet_iter != bet_odds_idx.end()); - BOOST_REQUIRE(bet_iter->betting_market_id == capitals_win_market.id); + BOOST_REQUIRE(bet_iter->betting_market_id == capitals_win_market_id); BOOST_REQUIRE(bet_iter->bettor_id == alice_id); BOOST_REQUIRE(bet_iter->amount_to_bet == asset(10000000, asset_id_type())); BOOST_REQUIRE(bet_iter->backer_multiplier == 16 * GRAPHENE_BETTING_ODDS_PRECISION / 10); BOOST_REQUIRE(bet_iter->back_or_lay == bet_type::back); ++bet_iter; - BOOST_REQUIRE(bet_iter == bet_odds_idx.end() || bet_iter->betting_market_id != capitals_win_market.id); + BOOST_REQUIRE(bet_iter == bet_odds_idx.end() || bet_iter->betting_market_id != capitals_win_market_id); // check the binned order books from the bookie plugin to make sure they match - binned_orders_point_one = bookie_api.get_binned_order_book(capitals_win_market.id, 1); + binned_orders_point_one = bookie_api.get_binned_order_book(capitals_win_market_id, 1); aggregated_back_bets_iter = binned_orders_point_one.aggregated_back_bets.begin(); BOOST_REQUIRE(aggregated_back_bets_iter != binned_orders_point_one.aggregated_back_bets.end()); BOOST_REQUIRE(aggregated_back_bets_iter->amount_to_bet.value == 10000000); @@ -838,16 +730,16 @@ BOOST_AUTO_TEST_CASE(inexact_odds) // lay 46 at 1.94 odds (50:47) -- this is too small to be placed on the books and there's // nothing for it to match, so it should be canceled - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(46, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(46, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); // lay 47 at 1.94 odds (50:47) -- this is an exact amount, nothing surprising should happen here - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(47, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(47, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 47; BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); // lay 100 at 1.91 odds (100:91) -- this is an inexact match, we should get refunded 9 and leave a bet for 91 on the books - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 191 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(100, asset_id_type()), 191 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 91; BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); @@ -863,7 +755,7 @@ BOOST_AUTO_TEST_CASE(inexact_odds) // leaving 150 // back bets at 100:91 must be a multiple of 100, so refund 50 // leaves a back bet of 100 @ 1.91 on the books - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(300, asset_id_type()), 191 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(300, asset_id_type()), 191 * GRAPHENE_BETTING_ODDS_PRECISION / 100); bob_expected_balance -= 250; BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); } @@ -884,15 +776,15 @@ BOOST_AUTO_TEST_CASE(bet_reversal_test) BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); // back with our entire balance - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(10000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(10000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), 0); // reverse the bet - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(20000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(20000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), 0); // try to re-reverse it, but go too far - BOOST_CHECK_THROW( place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(30000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION), fc::exception); + BOOST_CHECK_THROW( place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(30000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION), fc::exception); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), 0); } FC_LOG_AND_RETHROW() @@ -916,21 +808,21 @@ BOOST_AUTO_TEST_CASE(bet_reversal_test) // BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance); // // // back with alice's entire balance -// place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(10000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); +// place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(10000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); // alice_expected_balance -= 10000000; // BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance); // // // lay with bob's entire balance, which fully matches bob's bet -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(10000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); +// place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(10000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); // bob_expected_balance -= 10000000; // BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance); // // // reverse the bet -// place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(20000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); +// place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(20000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); // BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance); // // // try to re-reverse it, but go too far -// BOOST_CHECK_THROW( place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(30000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION), fc::exception); +// BOOST_CHECK_THROW( place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(30000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION), fc::exception); // BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance); // } // FC_LOG_AND_RETHROW() @@ -952,11 +844,11 @@ BOOST_AUTO_TEST_CASE(persistent_objects_test) BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); - idump((capitals_win_market.get_status())); + idump((capitals_win_market_id(db).get_status())); // lay 46 at 1.94 odds (50:47) -- this is too small to be placed on the books and there's // nothing for it to match, so it should be canceled - bet_id_type automatically_canceled_bet_id = place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(46, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + bet_id_type automatically_canceled_bet_id = place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(46, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); generate_blocks(1); BOOST_CHECK_MESSAGE(!db.find(automatically_canceled_bet_id), "Bet should have been canceled, but the blockchain still knows about it"); fc::variants objects_from_bookie = bookie_api.get_objects({automatically_canceled_bet_id}); @@ -965,7 +857,7 @@ BOOST_AUTO_TEST_CASE(persistent_objects_test) BOOST_CHECK_MESSAGE(objects_from_bookie[0]["id"].as(1) == automatically_canceled_bet_id, "Bookie Plugin didn't return a deleted bet it"); // lay 47 at 1.94 odds (50:47) -- this bet should go on the order books normally - bet_id_type first_bet_on_books = place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(47, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + bet_id_type first_bet_on_books = place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(47, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); generate_blocks(1); BOOST_CHECK_MESSAGE(db.find(first_bet_on_books), "Bet should exist on the blockchain"); objects_from_bookie = bookie_api.get_objects({first_bet_on_books}); @@ -974,7 +866,7 @@ BOOST_AUTO_TEST_CASE(persistent_objects_test) BOOST_CHECK_MESSAGE(objects_from_bookie[0]["id"].as(1) == first_bet_on_books, "Bookie Plugin didn't return a bet that is currently on the books"); // place a bet that exactly matches 'first_bet_on_books', should result in empty books (thus, no bet_objects from the blockchain) - bet_id_type matching_bet = place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(50, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + bet_id_type matching_bet = place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(50, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); BOOST_CHECK_MESSAGE(!db.find(first_bet_on_books), "Bet should have been filled, but the blockchain still knows about it"); BOOST_CHECK_MESSAGE(!db.find(matching_bet), "Bet should have been filled, but the blockchain still knows about it"); generate_blocks(1); // the bookie plugin doesn't detect matches until a block is generated @@ -985,17 +877,11 @@ BOOST_AUTO_TEST_CASE(persistent_objects_test) BOOST_CHECK_MESSAGE(objects_from_bookie[0]["id"].as(1) == first_bet_on_books, "Bookie Plugin didn't return a bet that has been filled"); BOOST_CHECK_MESSAGE(objects_from_bookie[1]["id"].as(1) == matching_bet, "Bookie Plugin didn't return a bet that has been filled"); - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::closed); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::closed); - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::cancel}, - {blackhawks_win_market.id, betting_market_resolution_type::cancel}}); - - // as soon as the market is resolved during the generate_block(), these markets - // should be deleted and our references will go out of scope. Save the - // market ids here so we can verify that they were really deleted - betting_market_id_type capitals_win_market_id = capitals_win_market.id; - betting_market_id_type blackhawks_win_market_id = blackhawks_win_market.id; + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::cancel}, + {blackhawks_win_market_id, betting_market_resolution_type::cancel}}); generate_blocks(1); @@ -1049,25 +935,19 @@ BOOST_AUTO_TEST_CASE(test_settled_market_states) BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); - idump((capitals_win_market.get_status())); + idump((capitals_win_market_id(db).get_status())); BOOST_TEST_MESSAGE("setting the event to in_progress"); - update_event(capitals_vs_blackhawks.id, _status = event_status::in_progress); + update_event(capitals_vs_blackhawks_id, _status = event_status::in_progress); generate_blocks(1); BOOST_TEST_MESSAGE("setting the event to finished"); - update_event(capitals_vs_blackhawks.id, _status = event_status::finished); + update_event(capitals_vs_blackhawks_id, _status = event_status::finished); generate_blocks(1); - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); - - // as soon as the market is resolved during the generate_block(), these markets - // should be deleted and our references will go out of scope. Save the - // market ids here so we can verify that they were really deleted - betting_market_id_type capitals_win_market_id = capitals_win_market.id; - betting_market_id_type blackhawks_win_market_id = blackhawks_win_market.id; + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); @@ -1098,7 +978,7 @@ BOOST_AUTO_TEST_CASE(delayed_bets_test) // test live betting generate_blocks(1); - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::in_play); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::in_play); generate_blocks(1); transfer(account_id_type(), alice_id, asset(10000000)); @@ -1113,17 +993,17 @@ BOOST_AUTO_TEST_CASE(delayed_bets_test) // test live betting BOOST_TEST_MESSAGE("Testing basic delayed bet mechanics"); // alice backs 100 at odds 2 BOOST_TEST_MESSAGE("Alice places a back bet of 100 at odds 2.0"); - bet_id_type delayed_back_bet = place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + bet_id_type delayed_back_bet = place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); generate_blocks(1); // verify the bet hasn't been placed in the active book - auto first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); + auto first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)); BOOST_CHECK(first_bet_in_market == bet_odds_idx.end()); // after 3 blocks, the delay should have expired and it will be promoted to the active book generate_blocks(2); - first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); - auto last_bet_in_market = bet_odds_idx.upper_bound(std::make_tuple(capitals_win_market.id)); + first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)); + auto last_bet_in_market = bet_odds_idx.upper_bound(std::make_tuple(capitals_win_market_id)); BOOST_CHECK(first_bet_in_market != bet_odds_idx.end()); BOOST_CHECK(std::distance(first_bet_in_market, last_bet_in_market) == 1); @@ -1131,19 +1011,19 @@ BOOST_AUTO_TEST_CASE(delayed_bets_test) // test live betting edump((bet)); // bob lays 100 at odds 2 to match alice's bet currently on the books BOOST_TEST_MESSAGE("Bob places a lay bet of 100 at odds 2.0"); - /* bet_id_type delayed_lay_bet = */ place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + /* bet_id_type delayed_lay_bet = */ place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); edump((db.get_global_properties().parameters.block_interval)(db.head_block_time())); // the bet should not enter the order books before a block has been generated - first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); - last_bet_in_market = bet_odds_idx.upper_bound(std::make_tuple(capitals_win_market.id)); + first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)); + last_bet_in_market = bet_odds_idx.upper_bound(std::make_tuple(capitals_win_market_id)); for (const auto& bet : bet_odds_idx) edump((bet)); generate_blocks(1); // bob's bet will still be delayed, so the active order book will only contain alice's bet - first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); - last_bet_in_market = bet_odds_idx.upper_bound(std::make_tuple(capitals_win_market.id)); + first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)); + last_bet_in_market = bet_odds_idx.upper_bound(std::make_tuple(capitals_win_market_id)); // edump((std::distance(first_bet_in_market, last_bet_in_market))); BOOST_CHECK(std::distance(first_bet_in_market, last_bet_in_market) == 1); for (const auto& bet : boost::make_iterator_range(first_bet_in_market, last_bet_in_market)) @@ -1156,13 +1036,13 @@ BOOST_AUTO_TEST_CASE(delayed_bets_test) // test live betting // now test that when we cancel all bets on a market, delayed bets get canceled too BOOST_TEST_MESSAGE("Alice places a back bet of 100 at odds 2.0"); - delayed_back_bet = place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + delayed_back_bet = place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); generate_blocks(1); - first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); + first_bet_in_market = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market_id)); BOOST_CHECK(!bet_odds_idx.empty()); BOOST_CHECK(first_bet_in_market == bet_odds_idx.end()); BOOST_TEST_MESSAGE("Cancel all bets"); - cancel_unmatched_bets(moneyline_betting_markets.id); + cancel_unmatched_bets(moneyline_betting_markets_id); BOOST_CHECK(bet_odds_idx.empty()); } FC_LOG_AND_RETHROW() @@ -1283,28 +1163,28 @@ BOOST_AUTO_TEST_CASE( testnet_witness_block_production_error ) try { CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); - create_betting_market_group({{"en", "Unused"}}, capitals_vs_blackhawks.id, betting_market_rules.id, asset_id_type(), false, 0); + create_betting_market_group({{"en", "Unused"}}, capitals_vs_blackhawks_id, betting_market_rules_id, asset_id_type(), false, 0); generate_blocks(1); const betting_market_group_object& unused_betting_markets = *db.get_index_type().indices().get().rbegin(); BOOST_TEST_MESSAGE("setting the event in progress"); - update_event(capitals_vs_blackhawks.id, _status = event_status::in_progress); + update_event(capitals_vs_blackhawks_id, _status = event_status::in_progress); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::in_progress); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::in_play); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::in_progress); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::in_play); BOOST_CHECK(unused_betting_markets.get_status() == betting_market_group_status::in_play); BOOST_TEST_MESSAGE("setting the event to finished"); - update_event(capitals_vs_blackhawks.id, _status = event_status::finished); + update_event(capitals_vs_blackhawks_id, _status = event_status::finished); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_CHECK(unused_betting_markets.get_status() == betting_market_group_status::closed); BOOST_TEST_MESSAGE("setting the event to canceled"); - update_event(capitals_vs_blackhawks.id, _status = event_status::canceled); + update_event(capitals_vs_blackhawks_id, _status = event_status::canceled); generate_blocks(1); } FC_LOG_AND_RETHROW() } @@ -1318,10 +1198,10 @@ BOOST_AUTO_TEST_CASE( cancel_one_event_in_group ) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); // create a second event in the same betting market group - create_event({{"en", "Boston Bruins/Pittsburgh Penguins"}}, {{"en", "2016-17"}}, nhl.id); + create_event({{"en", "Boston Bruins/Pittsburgh Penguins"}}, {{"en", "2016-17"}}, nhl_id); generate_blocks(1); const event_object& bruins_vs_penguins = *db.get_index_type().indices().get().rbegin(); - create_betting_market_group({{"en", "Moneyline"}}, bruins_vs_penguins.id, betting_market_rules.id, asset_id_type(), false, 0); + create_betting_market_group({{"en", "Moneyline"}}, bruins_vs_penguins.id, betting_market_rules_id, asset_id_type(), false, 0); generate_blocks(1); const betting_market_group_object& bruins_penguins_moneyline_betting_markets = *db.get_index_type().indices().get().rbegin(); create_betting_market(bruins_penguins_moneyline_betting_markets.id, {{"en", "Boston Bruins win"}}); @@ -1333,14 +1213,14 @@ BOOST_AUTO_TEST_CASE( cancel_one_event_in_group ) (void)bruins_win_market; (void)penguins_win_market; // check the initial state - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); BOOST_CHECK(bruins_vs_penguins.get_status() == event_status::upcoming); BOOST_TEST_MESSAGE("setting the capitals_vs_blackhawks event to in-progress, leaving bruins_vs_penguins in upcoming"); - update_event(capitals_vs_blackhawks.id, _status = event_status::in_progress); + update_event(capitals_vs_blackhawks_id, _status = event_status::in_progress); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::in_progress); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::in_play); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::in_progress); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::in_play); BOOST_CHECK(bruins_vs_penguins.get_status() == event_status::upcoming); BOOST_CHECK(bruins_penguins_moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); @@ -1348,19 +1228,19 @@ BOOST_AUTO_TEST_CASE( cancel_one_event_in_group ) BOOST_CHECK(penguins_win_market.get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the capitals_vs_blackhawks event to finished"); - update_event(capitals_vs_blackhawks.id, _status = event_status::finished); + update_event(capitals_vs_blackhawks_id, _status = event_status::finished); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_CHECK(bruins_vs_penguins.get_status() == event_status::upcoming); BOOST_CHECK(bruins_penguins_moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); BOOST_CHECK(bruins_win_market.get_status() == betting_market_status::unresolved); BOOST_CHECK(penguins_win_market.get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the capitals_vs_blackhawks event to canceled"); - update_event(capitals_vs_blackhawks.id, _status = event_status::canceled); + update_event(capitals_vs_blackhawks_id, _status = event_status::canceled); generate_blocks(1); BOOST_CHECK(bruins_vs_penguins.get_status() == event_status::upcoming); BOOST_CHECK(bruins_penguins_moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); @@ -1456,23 +1336,23 @@ struct simple_bet_test_fixture_2 : database_fixture { transfer(account_id_type(), bob_id, asset(10000)); // alice backs 1000 at 1:1, matches - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(1000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); // now alice lays at 2500 at 1:1. This should require a deposit of 500, with the remaining 200 being funded from exposure - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(2500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(2500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); // match the bet bit by bit. bob matches 500 of alice's 2500 bet. This effectively cancels half of bob's lay position // so he immediately gets 500 back. It reduces alice's back position, but doesn't return any money to her (all 2000 of her exposure // was already "promised" to her lay bet, so the 500 she would have received is placed in her refundable_unmatched_bets) - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); // match another 500, which will fully cancel bob's lay position and return the other 500 he had locked up in his position. // alice's back position is now canceled, 1500 remains of her unmatched lay bet, and the 500 from canceling her position has // been moved to her refundable_unmatched_bets - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - capitals_win_betting_market_id = capitals_win_market.id; + capitals_win_betting_market_id = capitals_win_market_id; } }; @@ -1484,10 +1364,10 @@ BOOST_AUTO_TEST_CASE(sport_update_test) { ACTORS( (alice) ); CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); - update_sport(ice_hockey.id, {{"en", "Hockey on Ice"}, {"zh_Hans", "冰"}, {"ja", "アイスホッケ"}}); + update_sport(ice_hockey_id, {{"en", "Hockey on Ice"}, {"zh_Hans", "冰"}, {"ja", "アイスホッケ"}}); transfer(account_id_type(), alice_id, asset(10000000)); - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000); @@ -1500,13 +1380,13 @@ BOOST_AUTO_TEST_CASE(sport_delete_test) { CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); - const auto& event_group_1 = create_event_group({{"en", "group1"}}, ice_hockey.id); - const auto& event_group_2 = create_event_group({{"en", "group2"}}, ice_hockey.id); + const auto& event_group_1 = create_event_group({{"en", "group1"}}, ice_hockey_id); + const auto& event_group_2 = create_event_group({{"en", "group2"}}, ice_hockey_id); - delete_sport(ice_hockey.id); + delete_sport(ice_hockey_id); const auto& sport_by_id = db.get_index_type().indices().get(); - BOOST_CHECK(sport_by_id.end() == sport_by_id.find(ice_hockey.id)); + BOOST_CHECK(sport_by_id.end() == sport_by_id.find(ice_hockey_id)); const auto& event_group_by_id = db.get_index_type().indices().get(); BOOST_CHECK(event_group_by_id.end() == event_group_by_id.find(event_group_1.id)); @@ -1521,7 +1401,7 @@ BOOST_AUTO_TEST_CASE(sport_delete_test_not_proposal) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); sport_delete_operation sport_delete_op; - sport_delete_op.sport_id = ice_hockey.id; + sport_delete_op.sport_id = ice_hockey_id; BOOST_CHECK_THROW(force_operation_by_witnesses(sport_delete_op), fc::exception); } FC_LOG_AND_RETHROW() @@ -1534,9 +1414,9 @@ BOOST_AUTO_TEST_CASE(sport_delete_test_not_proposal) // { // CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); // -// delete_sport(ice_hockey.id); +// delete_sport(ice_hockey_id); // -// BOOST_CHECK_THROW(delete_sport(ice_hockey.id), fc::exception); +// BOOST_CHECK_THROW(delete_sport(ice_hockey_id), fc::exception); // } FC_LOG_AND_RETHROW() // } @@ -1550,28 +1430,28 @@ BOOST_AUTO_TEST_CASE(event_group_update_test) transfer(account_id_type(), alice_id, asset(10000000)); transfer(account_id_type(), bob_id, asset(10000000)); - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); const sport_object& ice_on_hockey = create_sport({{"en", "Hockey on Ice"}, {"zh_Hans", "冰球"}, {"ja", "アイスホッケー"}}); \ fc::optional sport_id = ice_on_hockey.id; fc::optional name = internationalized_string_type({{"en", "IBM"}, {"zh_Hans", "國家冰球聯"}, {"ja", "ナショナルホッケーリー"}}); - update_event_group(nhl.id, fc::optional(), name); - update_event_group(nhl.id, sport_id, fc::optional()); - update_event_group(nhl.id, sport_id, name); + update_event_group(nhl_id, fc::optional(), name); + update_event_group(nhl_id, sport_id, fc::optional()); + update_event_group(nhl_id, sport_id, name); - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000); BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000); - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::closed); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::closed); // caps win - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); @@ -1760,9 +1640,9 @@ BOOST_AUTO_TEST_CASE(event_group_delete_test) transfer(account_id_type(), alice_id, asset(initialAccountAsset)); transfer(account_id_type(), bob_id, asset(initialAccountAsset)); - const auto& event = create_event({{"en", "event"}}, {{"en", "2016-17"}}, nhl.id); + const auto& event = create_event({{"en", "event"}}, {{"en", "2016-17"}}, nhl_id); - const auto& market_group = create_betting_market_group({{"en", "market group"}}, event.id, betting_market_rules.id, asset_id_type(), false, 0); + const auto& market_group = create_betting_market_group({{"en", "market group"}}, event.id, betting_market_rules_id, asset_id_type(), false, 0); //to make bets be not removed immediately update_betting_market_group_impl(market_group.id, fc::optional(), @@ -1772,17 +1652,17 @@ BOOST_AUTO_TEST_CASE(event_group_delete_test) const auto& market = create_betting_market(market_group.id, {{"en", "market"}}); - test_events events(*this, nhl.id); - test_markets_groups markets_groups(*this, event.id, betting_market_rules.id); + test_events events(*this, nhl_id); + test_markets_groups markets_groups(*this, event.id, betting_market_rules_id); test_markets markets(*this, market_group.id); const auto& bet_1_id = place_bet(alice_id, market.id, bet_type::back, asset(betAsset, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); const auto& bet_2_id = place_bet(bob_id, market.id, bet_type::lay, asset(betAsset, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - delete_event_group(nhl.id); + delete_event_group(nhl_id); const auto& event_group_by_id = db.get_index_type().indices().get(); - BOOST_CHECK(event_group_by_id.end() == event_group_by_id.find(nhl.id)); + BOOST_CHECK(event_group_by_id.end() == event_group_by_id.find(nhl_id)); BOOST_CHECK(event_status::canceled == event.get_status()); @@ -1838,11 +1718,11 @@ BOOST_AUTO_TEST_CASE(event_group_delete_test_with_matched_bets) transfer(account_id_type(), bob_id, asset(initialAccountAsset)); generate_blocks(1); - create_event({{"en", "event"}}, {{"en", "2016-17"}}, nhl.id); + create_event({{"en", "event"}}, {{"en", "2016-17"}}, nhl_id); generate_blocks(1); const event_object& event = *db.get_index_type().indices().get().rbegin(); - create_betting_market_group({{"en", "market group"}}, event.id, betting_market_rules.id, asset_id_type(), false, 0); + create_betting_market_group({{"en", "market group"}}, event.id, betting_market_rules_id, asset_id_type(), false, 0); generate_blocks(1); const betting_market_group_object& market_group = *db.get_index_type().indices().get().rbegin(); @@ -1854,7 +1734,7 @@ BOOST_AUTO_TEST_CASE(event_group_delete_test_with_matched_bets) place_bet(bob_id, market.id, bet_type::lay, asset(betAsset, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); generate_blocks(1); - delete_event_group(nhl.id); + delete_event_group(nhl_id); generate_blocks(1); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), initialAccountAsset); @@ -1869,7 +1749,7 @@ BOOST_AUTO_TEST_CASE(event_group_delete_test_not_proposal) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); event_group_delete_operation event_group_delete_op; - event_group_delete_op.event_group_id = nhl.id; + event_group_delete_op.event_group_id = nhl_id; BOOST_CHECK_THROW(force_operation_by_witnesses(event_group_delete_op), fc::exception); } FC_LOG_AND_RETHROW() @@ -1880,7 +1760,6 @@ BOOST_AUTO_TEST_CASE(event_group_delete_test_not_existed_event_group) try { CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); - event_group_id_type nhl_id = nhl.id; delete_event_group(nhl_id); BOOST_CHECK_THROW(delete_event_group(nhl_id), fc::exception); @@ -1897,31 +1776,31 @@ BOOST_AUTO_TEST_CASE(event_update_test) transfer(account_id_type(), alice_id, asset(10000000)); transfer(account_id_type(), bob_id, asset(10000000)); - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); fc::optional name = internationalized_string_type({{"en", "Washington Capitals vs. Chicago Blackhawks"}, {"zh_Hans", "華盛頓首都隊/芝加哥黑"}, {"ja", "ワシントン・キャピタルズ/シカゴ・ブラックホーク"}}); fc::optional season = internationalized_string_type({{"en", "2017-18"}}); - update_event(capitals_vs_blackhawks.id, _name = name); - update_event(capitals_vs_blackhawks.id, _season = season); - update_event(capitals_vs_blackhawks.id, _name = name, _season = season); + update_event(capitals_vs_blackhawks_id, _name = name); + update_event(capitals_vs_blackhawks_id, _season = season); + update_event(capitals_vs_blackhawks_id, _name = name, _season = season); const sport_object& ice_on_hockey = create_sport({{"en", "Hockey on Ice"}, {"zh_Hans", "冰球"}, {"ja", "アイスホッケー"}}); const event_group_object& nhl2 = create_event_group({{"en", "NHL2"}, {"zh_Hans", "國家冰球聯盟"}, {"ja", "ナショナルホッケーリーグ"}}, ice_on_hockey.id); - update_event(capitals_vs_blackhawks.id, _event_group_id = nhl2.id); + update_event(capitals_vs_blackhawks_id, _event_group_id = nhl2.id); - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000); BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000); - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::closed); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::closed); // caps win - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); @@ -1946,12 +1825,12 @@ BOOST_AUTO_TEST_CASE(betting_market_rules_update_test) fc::optional name = internationalized_string_type({{"en", "NHL Rules v1.1"}}); fc::optional desc = internationalized_string_type({{"en", "The winner will be the team with the most points at the end of the game. The team with fewer points will not be the winner."}}); - update_betting_market_rules(betting_market_rules.id, name, empty); - update_betting_market_rules(betting_market_rules.id, empty, desc); - update_betting_market_rules(betting_market_rules.id, name, desc); + update_betting_market_rules(betting_market_rules_id, name, empty); + update_betting_market_rules(betting_market_rules_id, empty, desc); + update_betting_market_rules(betting_market_rules_id, name, desc); transfer(account_id_type(), alice_id, asset(10000000)); - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000); @@ -1966,28 +1845,28 @@ BOOST_AUTO_TEST_CASE(betting_market_group_update_test) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); transfer(account_id_type(), alice_id, asset(10000000)); - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); internationalized_string_type new_description = internationalized_string_type({{"en", "Money line"}}); const betting_market_rules_object& new_betting_market_rules = create_betting_market_rules({{"en", "NHL Rules v2.0"}}, {{"en", "The winner will be the team with the most points at the end of the game. The team with fewer points will not be the winner."}}); fc::optional new_rule = new_betting_market_rules.id; - update_betting_market_group(moneyline_betting_markets.id, _description = new_description); - update_betting_market_group(moneyline_betting_markets.id, _rules_id = new_betting_market_rules.id); - update_betting_market_group(moneyline_betting_markets.id, _description = new_description, _rules_id = new_betting_market_rules.id); + update_betting_market_group(moneyline_betting_markets_id, _description = new_description); + update_betting_market_group(moneyline_betting_markets_id, _rules_id = new_betting_market_rules.id); + update_betting_market_group(moneyline_betting_markets_id, _description = new_description, _rules_id = new_betting_market_rules.id); transfer(account_id_type(), bob_id, asset(10000000)); - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000); BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000); - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::closed); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::closed); // caps win - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); @@ -2008,24 +1887,24 @@ BOOST_AUTO_TEST_CASE(betting_market_update_test) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); transfer(account_id_type(), alice_id, asset(10000000)); - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); fc::optional payout_condition = internationalized_string_type({{"en", "Washington Capitals lose"}}); // update the payout condition - update_betting_market(capitals_win_market.id, fc::optional(), payout_condition); + update_betting_market(capitals_win_market_id, fc::optional(), payout_condition); transfer(account_id_type(), bob_id, asset(10000000)); - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000); BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000); - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::closed); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::closed); // caps win - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); uint16_t rake_fee_percentage = db.get_global_properties().parameters.betting_rake_fee_percentage(); @@ -2052,27 +1931,25 @@ BOOST_AUTO_TEST_CASE(event_driven_standard_progression_1) { CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); graphene::bookie::bookie_api bookie_api(app); - // save the event id for checking after it is deleted - event_id_type capitals_vs_blackhawks_id = capitals_vs_blackhawks.id; BOOST_TEST_MESSAGE("verify everything is in the correct initial state"); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event to finished"); - update_event(capitals_vs_blackhawks.id, _status = event_status::finished); + update_event(capitals_vs_blackhawks_id, _status = event_status::finished); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("grading betting market"); - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); // as soon as a block is generated, the betting market group will settle, and the market @@ -2096,40 +1973,33 @@ BOOST_AUTO_TEST_CASE(event_driven_standard_progression_1_with_delay) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 60 /* seconds */); graphene::bookie::bookie_api bookie_api(app); - // save the ids for checking after it is deleted - event_id_type capitals_vs_blackhawks_id = capitals_vs_blackhawks.id; - betting_market_group_id_type moneyline_betting_markets_id = moneyline_betting_markets.id; - betting_market_id_type capitals_win_market_id = capitals_win_market.id; - betting_market_id_type blackhawks_win_market_id = blackhawks_win_market.id; - - BOOST_TEST_MESSAGE("verify everything is in the correct initial state"); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event to finished"); - update_event(capitals_vs_blackhawks.id, _status = event_status::finished); + update_event(capitals_vs_blackhawks_id, _status = event_status::finished); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("grading betting market"); - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); // it should be waiting 60 seconds before it settles - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::graded); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::graded); - BOOST_CHECK(capitals_win_market.resolution == betting_market_resolution_type::win); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::graded); - BOOST_CHECK(blackhawks_win_market.resolution == betting_market_resolution_type::not_win); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::graded); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::graded); + BOOST_CHECK(capitals_win_market_id(db).resolution == betting_market_resolution_type::win); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::graded); + BOOST_CHECK(blackhawks_win_market_id(db).resolution == betting_market_resolution_type::not_win); generate_blocks(60); // as soon as a block is generated, the betting market group will settle, and the market @@ -2167,65 +2037,63 @@ BOOST_AUTO_TEST_CASE(event_driven_standard_progression_2) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); graphene::bookie::bookie_api bookie_api(app); - // save the event id for checking after it is deleted - event_id_type capitals_vs_blackhawks_id = capitals_vs_blackhawks.id; BOOST_TEST_MESSAGE("verify everything is in the correct initial state"); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event frozen"); - update_event(capitals_vs_blackhawks.id, _status = event_status::frozen); + update_event(capitals_vs_blackhawks_id, _status = event_status::frozen); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::frozen); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::frozen); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::frozen); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::frozen); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::frozen); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::frozen); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::frozen); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::frozen); BOOST_TEST_MESSAGE("setting the event back to upcoming"); - update_event(capitals_vs_blackhawks.id, _status = event_status::upcoming); + update_event(capitals_vs_blackhawks_id, _status = event_status::upcoming); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event in-progress"); - update_event(capitals_vs_blackhawks.id, _status = event_status::in_progress); + update_event(capitals_vs_blackhawks_id, _status = event_status::in_progress); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::in_progress); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::in_play); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::in_progress); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::in_play); BOOST_TEST_MESSAGE("setting the event frozen"); - update_event(capitals_vs_blackhawks.id, _status = event_status::frozen); + update_event(capitals_vs_blackhawks_id, _status = event_status::frozen); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::frozen); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::frozen); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::frozen); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::frozen); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::frozen); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::frozen); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::frozen); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::frozen); BOOST_TEST_MESSAGE("setting the event back in-progress"); - update_event(capitals_vs_blackhawks.id, _status = event_status::in_progress); + update_event(capitals_vs_blackhawks_id, _status = event_status::in_progress); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::in_progress); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::in_play); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::in_progress); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::in_play); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event to finished"); - update_event(capitals_vs_blackhawks.id, _status = event_status::finished); + update_event(capitals_vs_blackhawks_id, _status = event_status::finished); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("grading betting market"); - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); // as soon as a block is generated, the betting market group will settle, and the market @@ -2255,65 +2123,63 @@ BOOST_AUTO_TEST_CASE(event_driven_standard_progression_2_never_in_play) CREATE_ICE_HOCKEY_BETTING_MARKET(true, 0); graphene::bookie::bookie_api bookie_api(app); - // save the event id for checking after it is deleted - event_id_type capitals_vs_blackhawks_id = capitals_vs_blackhawks.id; BOOST_TEST_MESSAGE("verify everything is in the correct initial state"); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event frozen"); - update_event(capitals_vs_blackhawks.id, _status = event_status::frozen); + update_event(capitals_vs_blackhawks_id, _status = event_status::frozen); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::frozen); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::frozen); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::frozen); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::frozen); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::frozen); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::frozen); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::frozen); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::frozen); BOOST_TEST_MESSAGE("setting the event back to upcoming"); - update_event(capitals_vs_blackhawks.id, _status = event_status::upcoming); + update_event(capitals_vs_blackhawks_id, _status = event_status::upcoming); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event in-progress"); - update_event(capitals_vs_blackhawks.id, _status = event_status::in_progress); + update_event(capitals_vs_blackhawks_id, _status = event_status::in_progress); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::in_progress); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::in_progress); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); BOOST_TEST_MESSAGE("setting the event frozen"); - update_event(capitals_vs_blackhawks.id, _status = event_status::frozen); + update_event(capitals_vs_blackhawks_id, _status = event_status::frozen); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::frozen); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::frozen); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::frozen); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::frozen); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::frozen); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::frozen); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::frozen); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::frozen); BOOST_TEST_MESSAGE("setting the event back in-progress"); - update_event(capitals_vs_blackhawks.id, _status = event_status::in_progress); + update_event(capitals_vs_blackhawks_id, _status = event_status::in_progress); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::in_progress); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::in_progress); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event to finished"); - update_event(capitals_vs_blackhawks.id, _status = event_status::finished); + update_event(capitals_vs_blackhawks_id, _status = event_status::finished); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("grading betting market"); - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); // as soon as a block is generated, the betting market group will settle, and the market @@ -2341,55 +2207,53 @@ BOOST_AUTO_TEST_CASE(event_driven_standard_progression_3) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); graphene::bookie::bookie_api bookie_api(app); - // save the event id for checking after it is deleted - event_id_type capitals_vs_blackhawks_id = capitals_vs_blackhawks.id; BOOST_TEST_MESSAGE("verify everything is in the correct initial state"); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event frozen"); - update_event(capitals_vs_blackhawks.id, _status = event_status::frozen); + update_event(capitals_vs_blackhawks_id, _status = event_status::frozen); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::frozen); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::frozen); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::frozen); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::frozen); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::frozen); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::frozen); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::frozen); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::frozen); BOOST_TEST_MESSAGE("setting the event in progress"); - update_event(capitals_vs_blackhawks.id, _status = event_status::in_progress); + update_event(capitals_vs_blackhawks_id, _status = event_status::in_progress); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::in_progress); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::in_play); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::in_progress); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::in_play); BOOST_TEST_MESSAGE("setting the event frozen"); - update_event(capitals_vs_blackhawks.id, _status = event_status::frozen); + update_event(capitals_vs_blackhawks_id, _status = event_status::frozen); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::frozen); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::frozen); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::frozen); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::frozen); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::frozen); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::frozen); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::frozen); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::frozen); BOOST_TEST_MESSAGE("setting the event back in-progress"); - update_event(capitals_vs_blackhawks.id, _status = event_status::in_progress); + update_event(capitals_vs_blackhawks_id, _status = event_status::in_progress); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::in_progress); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::in_play); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::in_progress); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::in_play); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event to finished"); - update_event(capitals_vs_blackhawks.id, _status = event_status::finished); + update_event(capitals_vs_blackhawks_id, _status = event_status::finished); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event to canceled"); - update_event(capitals_vs_blackhawks.id, _status = event_status::canceled); + update_event(capitals_vs_blackhawks_id, _status = event_status::canceled); generate_blocks(1); // as soon as a block is generated, the betting market group will cancel, and the market @@ -2414,80 +2278,78 @@ BOOST_AUTO_TEST_CASE(event_driven_progression_errors_1) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); graphene::bookie::bookie_api bookie_api(app); - // save the event id for checking after it is deleted - event_id_type capitals_vs_blackhawks_id = capitals_vs_blackhawks.id; BOOST_TEST_MESSAGE("verify everything is in the correct initial state"); - BOOST_REQUIRE(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_REQUIRE(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_REQUIRE(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_REQUIRE(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_REQUIRE(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_REQUIRE(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_REQUIRE(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_REQUIRE(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); // settled is the only illegal transition from upcoming BOOST_TEST_MESSAGE("verifying we can't jump to settled"); - BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks.id, _status = event_status::settled, _force = true), fc::exception); + BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks_id, _status = event_status::settled, _force = true), fc::exception); BOOST_TEST_MESSAGE("setting the event frozen"); - update_event(capitals_vs_blackhawks.id, _status = event_status::frozen); + update_event(capitals_vs_blackhawks_id, _status = event_status::frozen); generate_blocks(1); - BOOST_REQUIRE(capitals_vs_blackhawks.get_status() == event_status::frozen); - BOOST_REQUIRE(moneyline_betting_markets.get_status() == betting_market_group_status::frozen); - BOOST_REQUIRE(capitals_win_market.get_status() == betting_market_status::frozen); - BOOST_REQUIRE(blackhawks_win_market.get_status() == betting_market_status::frozen); + BOOST_REQUIRE(capitals_vs_blackhawks_id(db).get_status() == event_status::frozen); + BOOST_REQUIRE(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::frozen); + BOOST_REQUIRE(capitals_win_market_id(db).get_status() == betting_market_status::frozen); + BOOST_REQUIRE(blackhawks_win_market_id(db).get_status() == betting_market_status::frozen); // settled is the only illegal transition from this frozen event BOOST_TEST_MESSAGE("verifying we can't jump to settled"); - BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks.id, _status = event_status::settled, _force = true), fc::exception); + BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks_id, _status = event_status::settled, _force = true), fc::exception); BOOST_TEST_MESSAGE("setting the event in progress"); - update_event(capitals_vs_blackhawks.id, _status = event_status::in_progress); + update_event(capitals_vs_blackhawks_id, _status = event_status::in_progress); generate_blocks(1); - BOOST_REQUIRE(capitals_vs_blackhawks.get_status() == event_status::in_progress); - BOOST_REQUIRE(moneyline_betting_markets.get_status() == betting_market_group_status::in_play); + BOOST_REQUIRE(capitals_vs_blackhawks_id(db).get_status() == event_status::in_progress); + BOOST_REQUIRE(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::in_play); // we can't go back to upcoming from in_progress. // settled is disallowed everywhere BOOST_TEST_MESSAGE("verifying we can't jump to upcoming"); - BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks.id, _status = event_status::upcoming, _force = true), fc::exception); + BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks_id, _status = event_status::upcoming, _force = true), fc::exception); BOOST_TEST_MESSAGE("verifying we can't jump to settled"); - BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks.id, _status = event_status::settled, _force = true), fc::exception); + BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks_id, _status = event_status::settled, _force = true), fc::exception); BOOST_TEST_MESSAGE("setting the event frozen"); - update_event(capitals_vs_blackhawks.id, _status = event_status::frozen); + update_event(capitals_vs_blackhawks_id, _status = event_status::frozen); generate_blocks(1); - BOOST_REQUIRE(capitals_vs_blackhawks.get_status() == event_status::frozen); - BOOST_REQUIRE(moneyline_betting_markets.get_status() == betting_market_group_status::frozen); - BOOST_REQUIRE(capitals_win_market.get_status() == betting_market_status::frozen); - BOOST_REQUIRE(blackhawks_win_market.get_status() == betting_market_status::frozen); + BOOST_REQUIRE(capitals_vs_blackhawks_id(db).get_status() == event_status::frozen); + BOOST_REQUIRE(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::frozen); + BOOST_REQUIRE(capitals_win_market_id(db).get_status() == betting_market_status::frozen); + BOOST_REQUIRE(blackhawks_win_market_id(db).get_status() == betting_market_status::frozen); // we can't go back to upcoming from frozen once we've gone in_progress. // settled is disallowed everywhere BOOST_TEST_MESSAGE("verifying we can't jump to upcoming"); - BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks.id, _status = event_status::upcoming, _force = true), fc::exception); + BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks_id, _status = event_status::upcoming, _force = true), fc::exception); BOOST_TEST_MESSAGE("verifying we can't jump to settled"); - BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks.id, _status = event_status::settled, _force = true), fc::exception); + BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks_id, _status = event_status::settled, _force = true), fc::exception); BOOST_TEST_MESSAGE("setting the event to finished"); - update_event(capitals_vs_blackhawks.id, _status = event_status::finished); + update_event(capitals_vs_blackhawks_id, _status = event_status::finished); generate_blocks(1); - BOOST_REQUIRE(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_REQUIRE(moneyline_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_REQUIRE(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_REQUIRE(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_REQUIRE(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_REQUIRE(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_REQUIRE(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_REQUIRE(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); // we can't go back to upcoming, in_progress, or frozen once we're finished. // settled is disallowed everywhere BOOST_TEST_MESSAGE("verifying we can't jump to upcoming"); - BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks.id, _status = event_status::upcoming, _force = true), fc::exception); + BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks_id, _status = event_status::upcoming, _force = true), fc::exception); BOOST_TEST_MESSAGE("verifying we can't jump to in_progress"); - BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks.id, _status = event_status::in_progress, _force = true), fc::exception); + BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks_id, _status = event_status::in_progress, _force = true), fc::exception); BOOST_TEST_MESSAGE("verifying we can't jump to frozen"); - BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks.id, _status = event_status::frozen, _force = true), fc::exception); + BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks_id, _status = event_status::frozen, _force = true), fc::exception); BOOST_TEST_MESSAGE("verifying we can't jump to settled"); - BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks.id, _status = event_status::settled, _force = true), fc::exception); + BOOST_CHECK_THROW(update_event(capitals_vs_blackhawks_id, _status = event_status::settled, _force = true), fc::exception); BOOST_TEST_MESSAGE("setting the event to canceled"); - update_event(capitals_vs_blackhawks.id, _status = event_status::canceled); + update_event(capitals_vs_blackhawks_id, _status = event_status::canceled); generate_blocks(1); fc::variants objects_from_bookie = bookie_api.get_objects({capitals_vs_blackhawks_id}); @@ -2517,27 +2379,25 @@ BOOST_AUTO_TEST_CASE(event_driven_progression_errors_2) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); graphene::bookie::bookie_api bookie_api(app); - // save the event id for checking after it is deleted - event_id_type capitals_vs_blackhawks_id = capitals_vs_blackhawks.id; BOOST_TEST_MESSAGE("verify everything is in the correct initial state"); - BOOST_REQUIRE(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_REQUIRE(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_REQUIRE(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_REQUIRE(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_REQUIRE(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_REQUIRE(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_REQUIRE(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_REQUIRE(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting the event to finished"); - update_event(capitals_vs_blackhawks.id, _status = event_status::finished); + update_event(capitals_vs_blackhawks_id, _status = event_status::finished); generate_blocks(1); - BOOST_REQUIRE(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_REQUIRE(moneyline_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_REQUIRE(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_REQUIRE(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_REQUIRE(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_REQUIRE(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_REQUIRE(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_REQUIRE(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("grading betting market"); - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); // as soon as a block is generated, the betting market group will settle, and the market @@ -2569,47 +2429,45 @@ BOOST_AUTO_TEST_CASE(betting_market_group_driven_standard_progression) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); graphene::bookie::bookie_api bookie_api(app); - // save the event id for checking after it is deleted - event_id_type capitals_vs_blackhawks_id = capitals_vs_blackhawks.id; BOOST_TEST_MESSAGE("verify everything is in the correct initial state"); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("setting betting market to frozen"); // the event should stay in the upcoming state - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::frozen); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::frozen); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::frozen); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::frozen); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::frozen); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::frozen); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::frozen); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::frozen); BOOST_TEST_MESSAGE("setting the event frozen"); // this should only change the status of the event, just verify that nothing weird happens when // we try to set the bmg to frozen when it's already frozen - update_event(capitals_vs_blackhawks.id, _status = event_status::frozen); + update_event(capitals_vs_blackhawks_id, _status = event_status::frozen); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::frozen); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::frozen); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::frozen); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::frozen); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::frozen); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::frozen); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::frozen); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::frozen); BOOST_TEST_MESSAGE("setting betting market to closed"); // the event should go to finished automatically - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::closed); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::closed); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("grading betting market"); - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); // as soon as a block is generated, the betting market group will settle, and the market @@ -2628,99 +2486,97 @@ BOOST_AUTO_TEST_CASE(multi_betting_market_group_driven_standard_progression) CREATE_EXTENDED_ICE_HOCKEY_BETTING_MARKET(false, 0); graphene::bookie::bookie_api bookie_api(app); - // save the event id for checking after it is deleted - event_id_type capitals_vs_blackhawks_id = capitals_vs_blackhawks.id; BOOST_TEST_MESSAGE("verify everything is in the correct initial state"); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(first_period_result_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(first_period_capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(first_period_blackhawks_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(second_period_result_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(second_period_capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(second_period_blackhawks_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(third_period_result_betting_markets.get_status() == betting_market_group_status::upcoming); - BOOST_CHECK(third_period_capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(third_period_blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(first_period_result_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(first_period_capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(first_period_blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(second_period_result_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(second_period_capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(second_period_blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(third_period_result_betting_markets_id(db).get_status() == betting_market_group_status::upcoming); + BOOST_CHECK(third_period_capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(third_period_blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("the game is starting, setting the main betting market and the first period to in_play"); // the event should stay in the upcoming state - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::in_play); - update_betting_market_group(first_period_result_betting_markets.id, _status = betting_market_group_status::in_play); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::in_play); + update_betting_market_group(first_period_result_betting_markets_id, _status = betting_market_group_status::in_play); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::in_play); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(first_period_result_betting_markets.get_status() == betting_market_group_status::in_play); - BOOST_CHECK(first_period_capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(first_period_blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::in_play); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(first_period_result_betting_markets_id(db).get_status() == betting_market_group_status::in_play); + BOOST_CHECK(first_period_capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(first_period_blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("the first period is over, starting the second period"); - update_betting_market_group(first_period_result_betting_markets.id, _status = betting_market_group_status::closed); - update_betting_market_group(second_period_result_betting_markets.id, _status = betting_market_group_status::in_play); + update_betting_market_group(first_period_result_betting_markets_id, _status = betting_market_group_status::closed); + update_betting_market_group(second_period_result_betting_markets_id, _status = betting_market_group_status::in_play); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::in_play); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(first_period_result_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(first_period_capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(first_period_blackhawks_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(second_period_result_betting_markets.get_status() == betting_market_group_status::in_play); - BOOST_CHECK(second_period_capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(second_period_blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::in_play); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(first_period_result_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(first_period_capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(first_period_blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(second_period_result_betting_markets_id(db).get_status() == betting_market_group_status::in_play); + BOOST_CHECK(second_period_capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(second_period_blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("grading the first period market"); - resolve_betting_market_group(first_period_result_betting_markets.id, - {{first_period_capitals_win_market.id, betting_market_resolution_type::win}, - {first_period_blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(first_period_result_betting_markets_id, + {{first_period_capitals_win_market_id, betting_market_resolution_type::win}, + {first_period_blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); BOOST_TEST_MESSAGE("the second period is over, starting the third period"); - update_betting_market_group(second_period_result_betting_markets.id, _status = betting_market_group_status::closed); - update_betting_market_group(third_period_result_betting_markets.id, _status = betting_market_group_status::in_play); + update_betting_market_group(second_period_result_betting_markets_id, _status = betting_market_group_status::closed); + update_betting_market_group(third_period_result_betting_markets_id, _status = betting_market_group_status::in_play); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::upcoming); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::in_play); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(second_period_result_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(second_period_capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(second_period_blackhawks_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(third_period_result_betting_markets.get_status() == betting_market_group_status::in_play); - BOOST_CHECK(third_period_capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(third_period_blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::upcoming); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::in_play); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(second_period_result_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(second_period_capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(second_period_blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(third_period_result_betting_markets_id(db).get_status() == betting_market_group_status::in_play); + BOOST_CHECK(third_period_capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(third_period_blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("grading the second period market"); - resolve_betting_market_group(second_period_result_betting_markets.id, - {{second_period_capitals_win_market.id, betting_market_resolution_type::win}, - {second_period_blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(second_period_result_betting_markets_id, + {{second_period_capitals_win_market_id, betting_market_resolution_type::win}, + {second_period_blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); BOOST_TEST_MESSAGE("the game is over, closing 3rd period and game"); - update_betting_market_group(third_period_result_betting_markets.id, _status = betting_market_group_status::closed); - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::closed); + update_betting_market_group(third_period_result_betting_markets_id, _status = betting_market_group_status::closed); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::closed); generate_blocks(1); - BOOST_CHECK(capitals_vs_blackhawks.get_status() == event_status::finished); - BOOST_CHECK(moneyline_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(blackhawks_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(third_period_result_betting_markets.get_status() == betting_market_group_status::closed); - BOOST_CHECK(third_period_capitals_win_market.get_status() == betting_market_status::unresolved); - BOOST_CHECK(third_period_blackhawks_win_market.get_status() == betting_market_status::unresolved); + BOOST_CHECK(capitals_vs_blackhawks_id(db).get_status() == event_status::finished); + BOOST_CHECK(moneyline_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(third_period_result_betting_markets_id(db).get_status() == betting_market_group_status::closed); + BOOST_CHECK(third_period_capitals_win_market_id(db).get_status() == betting_market_status::unresolved); + BOOST_CHECK(third_period_blackhawks_win_market_id(db).get_status() == betting_market_status::unresolved); BOOST_TEST_MESSAGE("grading the third period and game"); - resolve_betting_market_group(third_period_result_betting_markets.id, - {{third_period_capitals_win_market.id, betting_market_resolution_type::win}, - {third_period_blackhawks_win_market.id, betting_market_resolution_type::not_win}}); - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(third_period_result_betting_markets_id, + {{third_period_capitals_win_market_id, betting_market_resolution_type::win}, + {third_period_blackhawks_win_market_id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); // as soon as a block is generated, the two betting market groups will settle, and the market @@ -2769,47 +2625,47 @@ BOOST_FIXTURE_TEST_CASE( another_event_group_update_test, database_fixture) transfer(account_id_type(), alice_id, asset(10000000)); transfer(account_id_type(), bob_id, asset(10000000)); - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); fc::optional name = internationalized_string_type({{"en", "IBM"}, {"zh_Hans", "國家冰球聯"}, {"ja", "ナショナルホッケーリー"}}); const sport_object& ice_on_hockey = create_sport({{"en", "Hockey on Ice"}, {"zh_Hans", "冰球"}, {"ja", "アイスホッケー"}}); \ fc::optional sport_id = ice_on_hockey.id; - update_event_group(nhl.id, fc::optional(), name); - update_event_group(nhl.id, sport_id, fc::optional()); - update_event_group(nhl.id, sport_id, name); + update_event_group(nhl_id, fc::optional(), name); + update_event_group(nhl_id, sport_id, fc::optional()); + update_event_group(nhl_id, sport_id, name); //Disabling the below 4 TRY_EXPECT_THROW lines to not throw anything beacuse functioning as expected // trx_state->_is_proposed_trx - //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl.id, fc::optional(), fc::optional(), true), fc::exception); - // TRY_EXPECT_THROW(try_update_event_group(nhl.id, fc::optional(), fc::optional(), true), fc::exception, "_is_proposed_trx"); + //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl_id, fc::optional(), fc::optional(), true), fc::exception); + // TRY_EXPECT_THROW(try_update_event_group(nhl_id, fc::optional(), fc::optional(), true), fc::exception, "_is_proposed_trx"); // #! nothing to change - //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl.id, fc::optional(), fc::optional()), fc::exception); - //TRY_EXPECT_THROW(try_update_event_group(nhl.id, fc::optional(), fc::optional()), fc::exception, "nothing to change"); + //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl_id, fc::optional(), fc::optional()), fc::exception); + //TRY_EXPECT_THROW(try_update_event_group(nhl_id, fc::optional(), fc::optional()), fc::exception, "nothing to change"); // #! sport_id must refer to a sport_id_type - sport_id = capitals_win_market.id; - //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl.id, sport_id, fc::optional()), fc::exception); - //TRY_EXPECT_THROW(try_update_event_group(nhl.id, sport_id, fc::optional()), fc::exception, "sport_id must refer to a sport_id_type"); + sport_id = capitals_win_market_id; + //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl_id, sport_id, fc::optional()), fc::exception); + //TRY_EXPECT_THROW(try_update_event_group(nhl_id, sport_id, fc::optional()), fc::exception, "sport_id must refer to a sport_id_type"); // #! invalid sport specified sport_id = sport_id_type(13); - //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl.id, sport_id, fc::optional()), fc::exception); - //TRY_EXPECT_THROW(try_update_event_group(nhl.id, sport_id, fc::optional()), fc::exception, "invalid sport specified"); + //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl_id, sport_id, fc::optional()), fc::exception); + //TRY_EXPECT_THROW(try_update_event_group(nhl_id, sport_id, fc::optional()), fc::exception, "invalid sport specified"); - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000); BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000); - update_betting_market_group(moneyline_betting_markets.id, _status = betting_market_group_status::closed); + update_betting_market_group(moneyline_betting_markets_id, _status = betting_market_group_status::closed); // caps win - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); uint16_t rake_fee_percentage = db.get_global_properties().parameters.betting_rake_fee_percentage(); @@ -2837,31 +2693,31 @@ BOOST_AUTO_TEST_CASE( wimbledon_2017_gentelmen_singles_sf_test ) transfer(account_id_type(), alice_id, asset(10000000)); transfer(account_id_type(), bob_id, asset(10000000)); - BOOST_TEST_MESSAGE("moneyline_berdych_vs_federer " << fc::variant(moneyline_berdych_vs_federer.id, 1).as(1)); - BOOST_TEST_MESSAGE("moneyline_cilic_vs_querrey " << fc::variant(moneyline_cilic_vs_querrey.id, 1).as(1)); + BOOST_TEST_MESSAGE("moneyline_berdych_vs_federer " << fc::variant(moneyline_berdych_vs_federer_id, 1).as(1)); + BOOST_TEST_MESSAGE("moneyline_cilic_vs_querrey " << fc::variant(moneyline_cilic_vs_querrey_id, 1).as(1)); - BOOST_TEST_MESSAGE("berdych_wins_market " << fc::variant(berdych_wins_market.id, 1).as(1)); - BOOST_TEST_MESSAGE("federer_wins_market " << fc::variant(federer_wins_market.id, 1).as(1)); - BOOST_TEST_MESSAGE("cilic_wins_market " << fc::variant(cilic_wins_market.id, 1).as(1)); - BOOST_TEST_MESSAGE("querrey_wins_market " << fc::variant(querrey_wins_market.id, 1).as(1)); + BOOST_TEST_MESSAGE("berdych_wins_market " << fc::variant(berdych_wins_market_id, 1).as(1)); + BOOST_TEST_MESSAGE("federer_wins_market " << fc::variant(federer_wins_market_id, 1).as(1)); + BOOST_TEST_MESSAGE("cilic_wins_market " << fc::variant(cilic_wins_market_id, 1).as(1)); + BOOST_TEST_MESSAGE("querrey_wins_market " << fc::variant(querrey_wins_market_id, 1).as(1)); - place_bet(alice_id, berdych_wins_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(bob_id, berdych_wins_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, berdych_wins_market_id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, berdych_wins_market_id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000); BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000); - place_bet(alice_id, cilic_wins_market.id, bet_type::back, asset(100000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(bob_id, cilic_wins_market.id, bet_type::lay, asset(100000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, cilic_wins_market_id, bet_type::back, asset(100000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, cilic_wins_market_id, bet_type::lay, asset(100000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 100000); BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 100000); - update_betting_market_group(moneyline_berdych_vs_federer.id, _status = betting_market_group_status::closed); + update_betting_market_group(moneyline_berdych_vs_federer_id, _status = betting_market_group_status::closed); // federer wins - resolve_betting_market_group(moneyline_berdych_vs_federer.id, - {{berdych_wins_market.id, betting_market_resolution_type::not_win}, - {federer_wins_market.id, betting_market_resolution_type::win}}); + resolve_betting_market_group(moneyline_berdych_vs_federer_id, + {{berdych_wins_market_id, betting_market_resolution_type::not_win}, + {federer_wins_market_id, betting_market_resolution_type::win}}); generate_blocks(1); uint32_t bob_rake_value = (-1000000 + 2000000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100; @@ -2870,11 +2726,11 @@ BOOST_AUTO_TEST_CASE( wimbledon_2017_gentelmen_singles_sf_test ) BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 100000); BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 100000 + 2000000 - bob_rake_value); - update_betting_market_group(moneyline_cilic_vs_querrey.id, _status = betting_market_group_status::closed); + update_betting_market_group(moneyline_cilic_vs_querrey_id, _status = betting_market_group_status::closed); // cilic wins - resolve_betting_market_group(moneyline_cilic_vs_querrey.id, - {{cilic_wins_market.id, betting_market_resolution_type::win}, - {querrey_wins_market.id, betting_market_resolution_type::not_win}}); + resolve_betting_market_group(moneyline_cilic_vs_querrey_id, + {{cilic_wins_market_id, betting_market_resolution_type::win}, + {querrey_wins_market_id, betting_market_resolution_type::not_win}}); generate_blocks(1); uint32_t alice_rake_value = (-100000 + 200000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100; @@ -2898,21 +2754,17 @@ BOOST_AUTO_TEST_CASE( wimbledon_2017_gentelmen_singles_final_test ) transfer(account_id_type(), alice_id, asset(10000000)); transfer(account_id_type(), bob_id, asset(10000000)); - BOOST_TEST_MESSAGE("moneyline_cilic_vs_federer " << fc::variant(moneyline_cilic_vs_federer.id, 1).as(1)); + BOOST_TEST_MESSAGE("moneyline_cilic_vs_federer " << fc::variant(moneyline_cilic_vs_federer_id, 1).as(1)); - BOOST_TEST_MESSAGE("federer_wins_final_market " << fc::variant(federer_wins_final_market.id, 1).as(1)); - BOOST_TEST_MESSAGE("cilic_wins_final_market " << fc::variant(cilic_wins_final_market.id, 1).as(1)); + BOOST_TEST_MESSAGE("federer_wins_final_market " << fc::variant(federer_wins_final_market_id, 1).as(1)); + BOOST_TEST_MESSAGE("cilic_wins_final_market " << fc::variant(cilic_wins_final_market_id, 1).as(1)); - betting_market_group_id_type moneyline_cilic_vs_federer_id = moneyline_cilic_vs_federer.id; update_betting_market_group(moneyline_cilic_vs_federer_id, _status = betting_market_group_status::in_play); - place_bet(alice_id, cilic_wins_final_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(bob_id, cilic_wins_final_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, cilic_wins_final_market_id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, cilic_wins_final_market_id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - auto cilic_wins_final_market_id = cilic_wins_final_market.id; - auto federer_wins_final_market_id = federer_wins_final_market.id; - - update_event(cilic_vs_federer.id, _name = internationalized_string_type({{"en", "R. Federer vs. M. Cilic"}})); + update_event(cilic_vs_federer_id, _name = internationalized_string_type({{"en", "R. Federer vs. M. Cilic"}})); generate_blocks(13); diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index cf4fd8ed..1996c267 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -39,7 +39,7 @@ public: fixture_(fixture) { fixture_.init_nathan(); - fixture_.generate_blocks(HARDFORK_SON_TIME); + fixture_.generate_blocks(HARDFORK_SON_FOR_HIVE_TIME); fixture_.generate_block(); } @@ -121,10 +121,12 @@ BOOST_AUTO_TEST_CASE( create_sons ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; + sidechain_public_keys[sidechain_type::hive] = "hive account 1"; sth.create_son("son1account", "http://son1", sidechain_public_keys); sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; + sidechain_public_keys[sidechain_type::hive] = "hive account 2"; sth.create_son("son2account", "http://son2", sidechain_public_keys); auto son1_obj = con.wallet_api_ptr->get_son("son1account"); @@ -153,6 +155,7 @@ BOOST_AUTO_TEST_CASE( cli_update_son ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; + sidechain_public_keys[sidechain_type::hive] = "hive account 1"; son_test_helper sth(*this); sth.create_son("sonmember", "http://sonmember", sidechain_public_keys); @@ -167,6 +170,7 @@ BOOST_AUTO_TEST_CASE( cli_update_son ) // update SON sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; + sidechain_public_keys[sidechain_type::hive] = "hive account 2"; con.wallet_api_ptr->update_son("sonmember", "http://sonmember_updated", "", sidechain_public_keys, true); son_data = con.wallet_api_ptr->get_son("sonmember"); @@ -197,10 +201,12 @@ BOOST_AUTO_TEST_CASE( son_voting ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; + sidechain_public_keys[sidechain_type::hive] = "hive account 1"; sth.create_son("son1account", "http://son1", sidechain_public_keys); sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; + sidechain_public_keys[sidechain_type::hive] = "hive account 2"; sth.create_son("son2account", "http://son2", sidechain_public_keys); BOOST_TEST_MESSAGE("Voting for SONs"); @@ -292,6 +298,7 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture ) { sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); + sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i); sth.create_son("sonaccount" + fc::to_pretty_string(i), "http://son" + fc::to_pretty_string(i), sidechain_public_keys, @@ -366,10 +373,12 @@ BOOST_AUTO_TEST_CASE( list_son ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; + sidechain_public_keys[sidechain_type::hive] = "hive account 1"; sth.create_son("son1account", "http://son1", sidechain_public_keys); sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; + sidechain_public_keys[sidechain_type::hive] = "hive account 2"; sth.create_son("son2account", "http://son2", sidechain_public_keys); auto res = con.wallet_api_ptr->list_sons("", 100); @@ -396,10 +405,12 @@ BOOST_AUTO_TEST_CASE( update_son_votes_test ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; + sidechain_public_keys[sidechain_type::hive] = "hive account 1"; sth.create_son("son1account", "http://son1", sidechain_public_keys); sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; + sidechain_public_keys[sidechain_type::hive] = "hive account 2"; sth.create_son("son2account", "http://son2", sidechain_public_keys); BOOST_TEST_MESSAGE("Vote for 2 accounts with update_son_votes"); @@ -555,10 +566,12 @@ BOOST_AUTO_TEST_CASE( related_functions ) sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 1"; + sidechain_public_keys[sidechain_type::hive] = "hive account 1"; sth.create_son("son1account", "http://son1", sidechain_public_keys); sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address 2"; + sidechain_public_keys[sidechain_type::hive] = "hive account 2"; sth.create_son("son2account", "http://son2", sidechain_public_keys); gpo = con.wallet_api_ptr->get_global_properties(); @@ -592,6 +605,7 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture ) { sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); + sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i); sth.create_son("sonaccount" + fc::to_pretty_string(i), "http://son" + fc::to_pretty_string(i), sidechain_public_keys, @@ -659,6 +673,7 @@ BOOST_AUTO_TEST_CASE( maintenance_test ) { sidechain_public_keys.clear(); sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); + sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i); sth.create_son("sonaccount" + fc::to_pretty_string(i), "http://son" + fc::to_pretty_string(i), sidechain_public_keys, diff --git a/tests/common/betting_test_markets.hpp b/tests/common/betting_test_markets.hpp index f67dc067..e774267b 100644 --- a/tests/common/betting_test_markets.hpp +++ b/tests/common/betting_test_markets.hpp @@ -33,110 +33,110 @@ using namespace graphene::chain; #define CREATE_ICE_HOCKEY_BETTING_MARKET(never_in_play, delay_before_settling) \ create_sport({{"en", "Ice Hockey"}, {"zh_Hans", "冰球"}, {"ja", "アイスホッケー"}}); \ generate_blocks(1); \ - const sport_object& ice_hockey = *db.get_index_type().indices().get().rbegin(); \ - create_event_group({{"en", "NHL"}, {"zh_Hans", "國家冰球聯盟"}, {"ja", "ナショナルホッケーリーグ"}}, ice_hockey.id); \ + const sport_id_type ice_hockey_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_event_group({{"en", "NHL"}, {"zh_Hans", "國家冰球聯盟"}, {"ja", "ナショナルホッケーリーグ"}}, ice_hockey_id); \ generate_blocks(1); \ - const event_group_object& nhl = *db.get_index_type().indices().get().rbegin(); \ - create_event({{"en", "Washington Capitals/Chicago Blackhawks"}, {"zh_Hans", "華盛頓首都隊/芝加哥黑鷹"}, {"ja", "ワシントン・キャピタルズ/シカゴ・ブラックホークス"}}, {{"en", "2016-17"}}, nhl.id); \ + const event_group_id_type nhl_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_event({{"en", "Washington Capitals/Chicago Blackhawks"}, {"zh_Hans", "華盛頓首都隊/芝加哥黑鷹"}, {"ja", "ワシントン・キャピタルズ/シカゴ・ブラックホークス"}}, {{"en", "2016-17"}}, nhl_id); \ generate_blocks(1); \ - const event_object& capitals_vs_blackhawks = *db.get_index_type().indices().get().rbegin(); \ + const event_id_type capitals_vs_blackhawks_id = (*db.get_index_type().indices().get().rbegin()).id; \ create_betting_market_rules({{"en", "NHL Rules v1.0"}}, {{"en", "The winner will be the team with the most points at the end of the game. The team with fewer points will not be the winner."}}); \ generate_blocks(1); \ - const betting_market_rules_object& betting_market_rules = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market_group({{"en", "Moneyline"}}, capitals_vs_blackhawks.id, betting_market_rules.id, asset_id_type(), never_in_play, delay_before_settling); \ + const betting_market_rules_id_type betting_market_rules_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market_group({{"en", "Moneyline"}}, capitals_vs_blackhawks_id, betting_market_rules_id, asset_id_type(), never_in_play, delay_before_settling); \ generate_blocks(1); \ - const betting_market_group_object& moneyline_betting_markets = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_betting_markets.id, {{"en", "Washington Capitals win"}}); \ + const betting_market_group_id_type moneyline_betting_markets_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(moneyline_betting_markets_id, {{"en", "Washington Capitals win"}}); \ generate_blocks(1); \ - const betting_market_object& capitals_win_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_betting_markets.id, {{"en", "Chicago Blackhawks win"}}); \ + const betting_market_id_type capitals_win_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(moneyline_betting_markets_id, {{"en", "Chicago Blackhawks win"}}); \ generate_blocks(1); \ - const betting_market_object& blackhawks_win_market = *db.get_index_type().indices().get().rbegin(); \ - (void)capitals_win_market; (void)blackhawks_win_market; + const betting_market_id_type& blackhawks_win_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + (void)capitals_win_market_id; (void)blackhawks_win_market_id; // create the basic betting market, plus groups for the first, second, and third period results #define CREATE_EXTENDED_ICE_HOCKEY_BETTING_MARKET(never_in_play, delay_before_settling) \ CREATE_ICE_HOCKEY_BETTING_MARKET(never_in_play, delay_before_settling) \ - create_betting_market_group({{"en", "First Period Result"}}, capitals_vs_blackhawks.id, betting_market_rules.id, asset_id_type(), never_in_play, delay_before_settling); \ + create_betting_market_group({{"en", "First Period Result"}}, capitals_vs_blackhawks_id, betting_market_rules_id, asset_id_type(), never_in_play, delay_before_settling); \ generate_blocks(1); \ - const betting_market_group_object& first_period_result_betting_markets = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(first_period_result_betting_markets.id, {{"en", "Washington Capitals win"}}); \ + const betting_market_group_id_type first_period_result_betting_markets_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(first_period_result_betting_markets_id, {{"en", "Washington Capitals win"}}); \ generate_blocks(1); \ - const betting_market_object& first_period_capitals_win_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(first_period_result_betting_markets.id, {{"en", "Chicago Blackhawks win"}}); \ + const betting_market_id_type first_period_capitals_win_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(first_period_result_betting_markets_id, {{"en", "Chicago Blackhawks win"}}); \ generate_blocks(1); \ - const betting_market_object& first_period_blackhawks_win_market = *db.get_index_type().indices().get().rbegin(); \ - (void)first_period_capitals_win_market; (void)first_period_blackhawks_win_market; \ + const betting_market_id_type first_period_blackhawks_win_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + (void)first_period_capitals_win_market_id; (void)first_period_blackhawks_win_market_id; \ \ - create_betting_market_group({{"en", "Second Period Result"}}, capitals_vs_blackhawks.id, betting_market_rules.id, asset_id_type(), never_in_play, delay_before_settling); \ + create_betting_market_group({{"en", "Second Period Result"}}, capitals_vs_blackhawks_id, betting_market_rules_id, asset_id_type(), never_in_play, delay_before_settling); \ generate_blocks(1); \ - const betting_market_group_object& second_period_result_betting_markets = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(second_period_result_betting_markets.id, {{"en", "Washington Capitals win"}}); \ + const betting_market_group_id_type second_period_result_betting_markets_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(second_period_result_betting_markets_id, {{"en", "Washington Capitals win"}}); \ generate_blocks(1); \ - const betting_market_object& second_period_capitals_win_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(second_period_result_betting_markets.id, {{"en", "Chicago Blackhawks win"}}); \ + const betting_market_id_type second_period_capitals_win_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(second_period_result_betting_markets_id, {{"en", "Chicago Blackhawks win"}}); \ generate_blocks(1); \ - const betting_market_object& second_period_blackhawks_win_market = *db.get_index_type().indices().get().rbegin(); \ - (void)second_period_capitals_win_market; (void)second_period_blackhawks_win_market; \ + const betting_market_id_type second_period_blackhawks_win_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + (void)second_period_capitals_win_market_id; (void)second_period_blackhawks_win_market_id; \ \ - create_betting_market_group({{"en", "Third Period Result"}}, capitals_vs_blackhawks.id, betting_market_rules.id, asset_id_type(), never_in_play, delay_before_settling); \ + create_betting_market_group({{"en", "Third Period Result"}}, capitals_vs_blackhawks_id, betting_market_rules_id, asset_id_type(), never_in_play, delay_before_settling); \ generate_blocks(1); \ - const betting_market_group_object& third_period_result_betting_markets = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(third_period_result_betting_markets.id, {{"en", "Washington Capitals win"}}); \ + const betting_market_group_id_type third_period_result_betting_markets_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(third_period_result_betting_markets_id, {{"en", "Washington Capitals win"}}); \ generate_blocks(1); \ - const betting_market_object& third_period_capitals_win_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(third_period_result_betting_markets.id, {{"en", "Chicago Blackhawks win"}}); \ + const betting_market_id_type third_period_capitals_win_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(third_period_result_betting_markets_id, {{"en", "Chicago Blackhawks win"}}); \ generate_blocks(1); \ - const betting_market_object& third_period_blackhawks_win_market = *db.get_index_type().indices().get().rbegin(); \ - (void)third_period_capitals_win_market; (void)third_period_blackhawks_win_market; + const betting_market_id_type third_period_blackhawks_win_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + (void)third_period_capitals_win_market_id; (void)third_period_blackhawks_win_market_id; #define CREATE_TENNIS_BETTING_MARKET() \ create_betting_market_rules({{"en", "Tennis Rules v1.0"}}, {{"en", "The winner is the player who wins the last ball in the match."}}); \ generate_blocks(1); \ - const betting_market_rules_object& tennis_rules = *db.get_index_type().indices().get().rbegin(); \ + const betting_market_rules_id_type tennis_rules_id = (*db.get_index_type().indices().get().rbegin()).id; \ create_sport({{"en", "Tennis"}}); \ generate_blocks(1); \ - const sport_object& tennis = *db.get_index_type().indices().get().rbegin(); \ - create_event_group({{"en", "Wimbledon"}}, tennis.id); \ + const sport_id_type tennis_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_event_group({{"en", "Wimbledon"}}, tennis_id); \ generate_blocks(1); \ - const event_group_object& wimbledon = *db.get_index_type().indices().get().rbegin(); \ - create_event({{"en", "R. Federer/T. Berdych"}}, {{"en", "2017"}}, wimbledon.id); \ + const event_group_id_type wimbledon_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_event({{"en", "R. Federer/T. Berdych"}}, {{"en", "2017"}}, wimbledon_id); \ generate_blocks(1); \ - const event_object& berdych_vs_federer = *db.get_index_type().indices().get().rbegin(); \ - create_event({{"en", "M. Cilic/S. Querrye"}}, {{"en", "2017"}}, wimbledon.id); \ + const event_id_type berdych_vs_federer_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_event({{"en", "M. Cilic/S. Querrye"}}, {{"en", "2017"}}, wimbledon_id); \ generate_blocks(1); \ - const event_object& cilic_vs_querrey = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market_group({{"en", "Moneyline 1st sf"}}, berdych_vs_federer.id, tennis_rules.id, asset_id_type(), false, 0); \ + const event_id_type& cilic_vs_querrey_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market_group({{"en", "Moneyline 1st sf"}}, berdych_vs_federer_id, tennis_rules_id, asset_id_type(), false, 0); \ generate_blocks(1); \ - const betting_market_group_object& moneyline_berdych_vs_federer = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market_group({{"en", "Moneyline 2nd sf"}}, cilic_vs_querrey.id, tennis_rules.id, asset_id_type(), false, 0); \ + const betting_market_group_id_type moneyline_berdych_vs_federer_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market_group({{"en", "Moneyline 2nd sf"}}, cilic_vs_querrey_id, tennis_rules_id, asset_id_type(), false, 0); \ generate_blocks(1); \ - const betting_market_group_object& moneyline_cilic_vs_querrey = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_berdych_vs_federer.id, {{"en", "T. Berdych defeats R. Federer"}}); \ + const betting_market_group_id_type moneyline_cilic_vs_querrey_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(moneyline_berdych_vs_federer_id, {{"en", "T. Berdych defeats R. Federer"}}); \ generate_blocks(1); \ - const betting_market_object& berdych_wins_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_berdych_vs_federer.id, {{"en", "R. Federer defeats T. Berdych"}}); \ + const betting_market_id_type berdych_wins_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(moneyline_berdych_vs_federer_id, {{"en", "R. Federer defeats T. Berdych"}}); \ generate_blocks(1); \ - const betting_market_object& federer_wins_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_cilic_vs_querrey.id, {{"en", "M. Cilic defeats S. Querrey"}}); \ + const betting_market_id_type federer_wins_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(moneyline_cilic_vs_querrey_id, {{"en", "M. Cilic defeats S. Querrey"}}); \ generate_blocks(1); \ - const betting_market_object& cilic_wins_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_cilic_vs_querrey.id, {{"en", "S. Querrey defeats M. Cilic"}});\ + const betting_market_id_type cilic_wins_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(moneyline_cilic_vs_querrey_id, {{"en", "S. Querrey defeats M. Cilic"}});\ generate_blocks(1); \ - const betting_market_object& querrey_wins_market = *db.get_index_type().indices().get().rbegin(); \ - create_event({{"en", "R. Federer/M. Cilic"}}, {{"en", "2017"}}, wimbledon.id); \ + const betting_market_id_type querrey_wins_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_event({{"en", "R. Federer/M. Cilic"}}, {{"en", "2017"}}, wimbledon_id); \ generate_blocks(1); \ - const event_object& cilic_vs_federer = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market_group({{"en", "Moneyline final"}}, cilic_vs_federer.id, tennis_rules.id, asset_id_type(), false, 0); \ + const event_id_type& cilic_vs_federer_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market_group({{"en", "Moneyline final"}}, cilic_vs_federer_id, tennis_rules_id, asset_id_type(), false, 0); \ generate_blocks(1); \ - const betting_market_group_object& moneyline_cilic_vs_federer = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_cilic_vs_federer.id, {{"en", "R. Federer defeats M. Cilic"}}); \ + const betting_market_group_id_type moneyline_cilic_vs_federer_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(moneyline_cilic_vs_federer_id, {{"en", "R. Federer defeats M. Cilic"}}); \ generate_blocks(1); \ - const betting_market_object& federer_wins_final_market = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market(moneyline_cilic_vs_federer.id, {{"en", "M. Cilic defeats R. Federer"}}); \ + const betting_market_id_type federer_wins_final_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market(moneyline_cilic_vs_federer_id, {{"en", "M. Cilic defeats R. Federer"}}); \ generate_blocks(1); \ - const betting_market_object& cilic_wins_final_market = *db.get_index_type().indices().get().rbegin(); \ - (void)federer_wins_market;(void)cilic_wins_market;(void)federer_wins_final_market; (void)cilic_wins_final_market; (void)berdych_wins_market; (void)querrey_wins_market; + const betting_market_id_type cilic_wins_final_market_id = (*db.get_index_type().indices().get().rbegin()).id; \ + (void)federer_wins_market_id;(void)cilic_wins_market_id;(void)federer_wins_final_market_id; (void)cilic_wins_final_market_id; (void)berdych_wins_market_id; (void)querrey_wins_market_id; // set up a fixture that places a series of two matched bets, we'll use this fixture to verify // the result in all three possible outcomes @@ -155,19 +155,18 @@ struct simple_bet_test_fixture : database_fixture { transfer(account_id_type(), bob_id, asset(10000)); // place bets at 10:1 - place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::back, asset(100, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::lay, asset(1000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); // reverse positions at 1:1 - place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(alice_id, capitals_win_market_id, bet_type::lay, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(bob_id, capitals_win_market_id, bet_type::back, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - capitals_win_betting_market_id = capitals_win_market.id; - blackhawks_win_betting_market_id = blackhawks_win_market.id; - moneyline_betting_markets_id = moneyline_betting_markets.id; + capitals_win_betting_market_id = capitals_win_market_id; + blackhawks_win_betting_market_id = blackhawks_win_market_id; // close betting to prepare for the next operation which will be grading or cancel - update_betting_market_group(moneyline_betting_markets.id, graphene::chain::keywords::_status = betting_market_group_status::closed); + update_betting_market_group(moneyline_betting_markets_id, graphene::chain::keywords::_status = betting_market_group_status::closed); generate_blocks(1); } }; diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 42fd6137..a88f0804 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include @@ -203,20 +204,28 @@ database_fixture::database_fixture() } database_fixture::~database_fixture() -{ try { - // If we're unwinding due to an exception, don't do any more checks. - // This way, boost test's last checkpoint tells us approximately where the error was. - if( !std::uncaught_exception() ) - { - verify_asset_supplies(db); - verify_account_history_plugin_index(); - BOOST_CHECK( db.get_node_properties().skip_flags == database::skip_nothing ); - } +{ + try { + // If we're unwinding due to an exception, don't do any more checks. + // This way, boost test's last checkpoint tells us approximately where the error was. + if( !std::uncaught_exception() ) + { + verify_asset_supplies(db); + verify_account_history_plugin_index(); + BOOST_CHECK( db.get_node_properties().skip_flags == database::skip_nothing ); + } - if( data_dir ) - db.close(); - return; -} FC_CAPTURE_AND_RETHROW() } + if( data_dir ) + db.close(); + return; + } catch (fc::exception& ex) { + BOOST_FAIL( std::string("fc::exception in ~database_fixture: ") + ex.to_detail_string() ); + } catch (std::exception& e) { + BOOST_FAIL( std::string("std::exception in ~database_fixture:") + e.what() ); + } catch (...) { + BOOST_FAIL( "Uncaught exception in ~database_fixture" ); + } +} fc::ecc::private_key database_fixture::generate_private_key(string seed) { @@ -327,6 +336,14 @@ void database_fixture::verify_asset_supplies( const database& db ) } } + for (const nft_metadata_object &o : db.get_index_type().indices()) + { + if (o.lottery_data) + { + total_balances[o.get_lottery_jackpot(db).asset_id] += o.get_lottery_jackpot(db).amount; + } + } + uint64_t sweeps_vestings = 0; for( const sweeps_vesting_balance_object& svbo: db.get_index_type< sweeps_vesting_balance_index >().indices() ) sweeps_vestings += svbo.balance; diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 366e707e..cd6ac185 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -127,7 +127,9 @@ extern uint32_t GRAPHENE_TESTING_GENESIS_TIMESTAMP; #define PREP_ACTOR(name) \ fc::ecc::private_key name ## _private_key = generate_private_key(BOOST_PP_STRINGIZE(name)); \ - public_key_type name ## _public_key = name ## _private_key.get_public_key(); + public_key_type name ## _public_key = name ## _private_key.get_public_key(); \ + (void) name ## _private_key; \ + (void) name ## _public_key; #define ACTOR(name) \ PREP_ACTOR(name) \ diff --git a/tests/generate_empty_blocks/CMakeLists.txt b/tests/generate_empty_blocks/CMakeLists.txt index af53ee91..5a585070 100644 --- a/tests/generate_empty_blocks/CMakeLists.txt +++ b/tests/generate_empty_blocks/CMakeLists.txt @@ -4,7 +4,7 @@ if( UNIX AND NOT APPLE ) endif() target_link_libraries( generate_empty_blocks - PRIVATE graphene_app graphene_chain graphene_egenesis_none fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) + PRIVATE graphene_app graphene_egenesis_none ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS generate_empty_blocks diff --git a/tests/peerplays_sidechain/bitcoin_transaction_tests.cpp b/tests/peerplays_sidechain/bitcoin_transaction_tests.cpp index 20fe878c..c749d790 100644 --- a/tests/peerplays_sidechain/bitcoin_transaction_tests.cpp +++ b/tests/peerplays_sidechain/bitcoin_transaction_tests.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/tests/tests/affiliate_tests.cpp b/tests/tests/affiliate_tests.cpp index 804d9e8a..c55c4440 100644 --- a/tests/tests/affiliate_tests.cpp +++ b/tests/tests/affiliate_tests.cpp @@ -524,17 +524,17 @@ BOOST_AUTO_TEST_CASE( bookie_payout_test ) CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); // place bets at 10:1 - place_bet(ath.paula_id, capitals_win_market.id, bet_type::back, asset(10000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(ath.penny_id, capitals_win_market.id, bet_type::lay, asset(100000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(ath.paula_id, capitals_win_market_id, bet_type::back, asset(10000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(ath.penny_id, capitals_win_market_id, bet_type::lay, asset(100000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION); // reverse positions at 1:1 - place_bet(ath.paula_id, capitals_win_market.id, bet_type::lay, asset(110000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(ath.penny_id, capitals_win_market.id, bet_type::back, asset(110000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(ath.paula_id, capitals_win_market_id, bet_type::lay, asset(110000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(ath.penny_id, capitals_win_market_id, bet_type::back, asset(110000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - update_betting_market_group(moneyline_betting_markets.id, graphene::chain::keywords::_status = betting_market_group_status::closed); - resolve_betting_market_group(moneyline_betting_markets.id, - {{capitals_win_market.id, betting_market_resolution_type::win}, - {blackhawks_win_market.id, betting_market_resolution_type::not_win}}); + update_betting_market_group(moneyline_betting_markets_id, graphene::chain::keywords::_status = betting_market_group_status::closed); + resolve_betting_market_group(moneyline_betting_markets_id, + {{capitals_win_market_id, betting_market_resolution_type::win}, + {blackhawks_win_market_id, betting_market_resolution_type::not_win}}); generate_block(); uint16_t rake_fee_percentage = db.get_global_properties().parameters.betting_rake_fee_percentage(); @@ -559,31 +559,31 @@ BOOST_AUTO_TEST_CASE( bookie_payout_test ) issue_uia( ath.paula_id, asset( 1000000, btc_id ) ); issue_uia( ath.petra_id, asset( 1000000, btc_id ) ); - create_event({{"en", "Washington Capitals/Chicago Blackhawks"}, {"zh_Hans", "華盛頓首都隊/芝加哥黑鷹"}, {"ja", "ワシントン・キャピタルズ/シカゴ・ブラックホークス"}}, {{"en", "2016-17"}}, nhl.id); \ + create_event({{"en", "Washington Capitals/Chicago Blackhawks"}, {"zh_Hans", "華盛頓首都隊/芝加哥黑鷹"}, {"ja", "ワシントン・キャピタルズ/シカゴ・ブラックホークス"}}, {{"en", "2016-17"}}, nhl_id); \ generate_blocks(1); \ - const event_object& capitals_vs_blackhawks2 = *db.get_index_type().indices().get().rbegin(); \ - create_betting_market_group({{"en", "Moneyline"}}, capitals_vs_blackhawks2.id, betting_market_rules.id, btc_id, false, 0); + const event_id_type capitals_vs_blackhawks2_id = (*db.get_index_type().indices().get().rbegin()).id; \ + create_betting_market_group({{"en", "Moneyline"}}, capitals_vs_blackhawks2_id, betting_market_rules_id, btc_id, false, 0); generate_blocks(1); - const betting_market_group_object& moneyline_betting_markets2 = *db.get_index_type().indices().get().rbegin(); - create_betting_market(moneyline_betting_markets2.id, {{"en", "Washington Capitals win"}}); + const betting_market_group_id_type moneyline_betting_markets2_id = (*db.get_index_type().indices().get().rbegin()).id; + create_betting_market(moneyline_betting_markets2_id, {{"en", "Washington Capitals win"}}); generate_blocks(1); - const betting_market_object& capitals_win_market2 = *db.get_index_type().indices().get().rbegin(); - create_betting_market(moneyline_betting_markets2.id, {{"en", "Chicago Blackhawks win"}}); + const betting_market_id_type capitals_win_market2_id = (*db.get_index_type().indices().get().rbegin()).id; + create_betting_market(moneyline_betting_markets2_id, {{"en", "Chicago Blackhawks win"}}); generate_blocks(1); - const betting_market_object& blackhawks_win_market2 = *db.get_index_type().indices().get().rbegin(); + const betting_market_id_type blackhawks_win_market2_id = (*db.get_index_type().indices().get().rbegin()).id; // place bets at 10:1 - place_bet(ath.paula_id, capitals_win_market2.id, bet_type::back, asset(10000, btc_id), 11 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(ath.petra_id, capitals_win_market2.id, bet_type::lay, asset(100000, btc_id), 11 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(ath.paula_id, capitals_win_market2_id, bet_type::back, asset(10000, btc_id), 11 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(ath.petra_id, capitals_win_market2_id, bet_type::lay, asset(100000, btc_id), 11 * GRAPHENE_BETTING_ODDS_PRECISION); // reverse positions at 1:1 - place_bet(ath.paula_id, capitals_win_market2.id, bet_type::lay, asset(110000, btc_id), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - place_bet(ath.petra_id, capitals_win_market2.id, bet_type::back, asset(110000, btc_id), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(ath.paula_id, capitals_win_market2_id, bet_type::lay, asset(110000, btc_id), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + place_bet(ath.petra_id, capitals_win_market2_id, bet_type::back, asset(110000, btc_id), 2 * GRAPHENE_BETTING_ODDS_PRECISION); - update_betting_market_group(moneyline_betting_markets2.id, graphene::chain::keywords::_status = betting_market_group_status::closed); - resolve_betting_market_group(moneyline_betting_markets2.id, - {{capitals_win_market2.id, betting_market_resolution_type::not_win}, - {blackhawks_win_market2.id, betting_market_resolution_type::win}}); + update_betting_market_group(moneyline_betting_markets2_id, graphene::chain::keywords::_status = betting_market_group_status::closed); + resolve_betting_market_group(moneyline_betting_markets2_id, + {{capitals_win_market2_id, betting_market_resolution_type::not_win}, + {blackhawks_win_market2_id, betting_market_resolution_type::win}}); generate_block(); rake_value = (-10000 + 0 - 110000 + 220000) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100; diff --git a/tests/tests/basic_tests.cpp b/tests/tests/basic_tests.cpp index da608541..5b4c98cb 100644 --- a/tests/tests/basic_tests.cpp +++ b/tests/tests/basic_tests.cpp @@ -182,21 +182,194 @@ BOOST_AUTO_TEST_CASE( price_test ) BOOST_AUTO_TEST_CASE( memo_test ) { try { - memo_data m; - auto sender = generate_private_key("1"); - auto receiver = generate_private_key("2"); - m.from = sender.get_public_key(); - m.to = receiver.get_public_key(); - m.set_message(sender, receiver.get_public_key(), "Hello, world!", 12345); + auto sender_private_key = generate_private_key("1"); + auto sender_public_key = sender_private_key.get_public_key(); + auto receiver_private_key = generate_private_key("2"); + auto receiver_public_key = receiver_private_key.get_public_key(); + + auto dummy_private_key = private_key_type(); + auto dummy_public_key = public_key_type(); - decltype(fc::digest(m)) hash("8de72a07d093a589f574460deb19023b4aff354b561eb34590d9f4629f51dbf3"); - if( fc::digest(m) != hash ) { - // If this happens, notify the web guys that the memo serialization format changed. - edump((m)(fc::digest(m))); - BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + memo_data m; + m.from = dummy_public_key; + m.to = dummy_public_key; + m.set_message(dummy_private_key, dummy_public_key, "Hello, world!", 12345); + + decltype(fc::digest(m)) hash("b9ad6eb2c466678a911f2f10f29d2a0d98600335b00e4c4ffbeabccb76c77bf0"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, dummy_public_key), "Hello, world!"); } - BOOST_CHECK_EQUAL(m.get_message(receiver, sender.get_public_key()), "Hello, world!"); + + { + memo_data m; + m.from = dummy_public_key; + m.to = receiver_public_key; + m.set_message(dummy_private_key, receiver_public_key, "Hello, world!", 12345); + + decltype(fc::digest(m)) hash("b9ad6eb2c466678a911f2f10f29d2a0d98600335b00e4c4ffbeabccb76c77bf0"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, dummy_public_key), "Hello, world!"); + } + + { + memo_data m; + m.from = sender_public_key; + m.to = dummy_public_key; + m.set_message(sender_private_key, dummy_public_key, "Hello, world!", 12345); + + decltype(fc::digest(m)) hash("b756ef1b27e3bb8e61eea534a0b28e89b0fa72b73f8b7e6bc99b55a92ec3cf9b"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, sender_public_key), "Hello, world!"); + } + + { + memo_data m; + m.from = sender_public_key; + m.to = receiver_public_key; + m.set_message(sender_private_key, receiver_public_key, "Hello, world!", 12345); + + decltype(fc::digest(m)) hash("b756ef1b27e3bb8e61eea534a0b28e89b0fa72b73f8b7e6bc99b55a92ec3cf9b"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, sender_public_key), "Hello, world!"); + } + + { + memo_data m; + m.from = dummy_public_key; + m.to = dummy_public_key; + m.set_message(dummy_private_key, dummy_public_key, "#Hello, world!", 12345); + + decltype(fc::digest(m)) hash("8b17e79255d427b437a8b30beee5d45ca9b0bc8a04afa7a1968a0b73ab6d4b38"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, dummy_public_key), "#Hello, world!"); + } + + { + memo_data m; + m.from = dummy_public_key; + m.to = receiver_public_key; + m.set_message(dummy_private_key, receiver_public_key, "#Hello, world!", 12345); + + decltype(fc::digest(m)) hash("8b17e79255d427b437a8b30beee5d45ca9b0bc8a04afa7a1968a0b73ab6d4b38"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, dummy_public_key), "#Hello, world!"); + } + + { + memo_data m; + m.from = sender_public_key; + m.to = dummy_public_key; + m.set_message(sender_private_key, dummy_public_key, "#Hello, world!", 12345); + + decltype(fc::digest(m)) hash("40dbf5d26ea084d6ab61f9e93de366b7bea6a54eb1203744dd619d878a7d954a"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, sender_public_key), "#Hello, world!"); + } + + { + memo_data m; + m.from = sender_public_key; + m.to = receiver_public_key; + m.set_message(sender_private_key, receiver_public_key, "#Hello, world!", 12345); + + decltype(fc::digest(m)) hash("2f5d44ec922f605663a3b51f1d9633641062c9b669ba4bdd5c60104ceff12c8f"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, sender_public_key), "#Hello, world!"); + } + + { + memo_data m; + m.from = dummy_public_key; + m.to = dummy_public_key; + m.set_message(dummy_private_key, dummy_public_key, "# Hello, world!", 12345); + + decltype(fc::digest(m)) hash("93753b87b409e6532806ea3074553321b04807a675ffc0f41fb270c3141a8af2"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, dummy_public_key), "# Hello, world!"); + } + + { + memo_data m; + m.from = dummy_public_key; + m.to = receiver_public_key; + m.set_message(dummy_private_key, receiver_public_key, "# Hello, world!", 12345); + + decltype(fc::digest(m)) hash("93753b87b409e6532806ea3074553321b04807a675ffc0f41fb270c3141a8af2"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, dummy_public_key), "# Hello, world!"); + } + + { + memo_data m; + m.from = sender_public_key; + m.to = dummy_public_key; + m.set_message(sender_private_key, dummy_public_key, "# Hello, world!", 12345); + + decltype(fc::digest(m)) hash("5a0b4efad48090577a1296fc7221e19bdde4a8067bbbe05faa31c1c9fbdedd19"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(dummy_private_key, sender_public_key), "# Hello, world!"); + } + + { + memo_data m; + m.from = sender_public_key; + m.to = receiver_public_key; + m.set_message(sender_private_key, receiver_public_key, "# Hello, world!", 12345); + + decltype(fc::digest(m)) hash("948b1b3219950dcaf5a376a502ba1b7631825aef85e0c692d192c06d583b2530"); + if( fc::digest(m) != hash ) { + // If this happens, notify the web guys that the memo serialization format changed. + edump((m)(fc::digest(m))); + BOOST_FAIL("Memo format has changed. Notify the web guys and update this test."); + } + BOOST_CHECK_EQUAL(m.get_message(receiver_private_key, sender_public_key), "# Hello, world!"); + } + } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE( witness_rng_test_bits ) diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 9885b548..7571feb6 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -51,7 +51,7 @@ genesis_state_type make_genesis() { auto init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key"))); genesis_state.initial_active_witnesses = 10; - for( int i = 0; i < genesis_state.initial_active_witnesses; ++i ) + for( uint64_t i = 0; i < genesis_state.initial_active_witnesses; ++i ) { auto name = "init"+fc::to_string(i); genesis_state.initial_accounts.emplace_back(name, diff --git a/tests/tests/confidential_tests.cpp b/tests/tests/confidential_tests.cpp index a6a19f06..792a300e 100644 --- a/tests/tests/confidential_tests.cpp +++ b/tests/tests/confidential_tests.cpp @@ -64,7 +64,6 @@ BOOST_AUTO_TEST_CASE( confidential_test ) auto InB1 = fc::sha256::hash("InB1"); auto InB2 = fc::sha256::hash("InB2"); - auto OutB = fc::sha256::hash("InB2"); auto nonce1 = fc::sha256::hash("nonce"); auto nonce2 = fc::sha256::hash("nonce2"); diff --git a/tests/tests/database_tests.cpp b/tests/tests/database_tests.cpp index 9585d4a1..e0644b1b 100644 --- a/tests/tests/database_tests.cpp +++ b/tests/tests/database_tests.cpp @@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE( merge_test ) try { database db; auto ses = db._undo_db.start_undo_session(); - const auto& bal_obj1 = db.create( [&]( account_balance_object& obj ){ + db.create( [&]( account_balance_object& obj ){ obj.balance = 42; }); ses.merge(); diff --git a/tests/tests/dividend_tests.cpp b/tests/tests/dividend_tests.cpp index a3869b36..facf77fb 100644 --- a/tests/tests/dividend_tests.cpp +++ b/tests/tests/dividend_tests.cpp @@ -219,8 +219,6 @@ BOOST_AUTO_TEST_CASE( test_basic_dividend_distribution ) const account_object& alice = get_account("alice"); const account_object& bob = get_account("bob"); const account_object& carol = get_account("carol"); - const account_object& dave = get_account("dave"); - const account_object& frank = get_account("frank"); const auto& test_asset_object = get_asset("TESTB"); auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue) @@ -379,7 +377,6 @@ BOOST_AUTO_TEST_CASE( test_basic_dividend_distribution_to_core_asset ) const account_object& bob = get_account("bob"); const account_object& carol = get_account("carol"); const account_object& dave = get_account("dave"); - const account_object& frank = get_account("frank"); const auto& test_asset_object = get_asset("TESTB"); auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue) @@ -513,28 +510,6 @@ BOOST_AUTO_TEST_CASE( test_basic_dividend_distribution_to_core_asset ) } } -BOOST_AUTO_TEST_CASE( test_dividend_distribution_interval ) -{ - using namespace graphene; - try { - INVOKE( create_dividend_uia ); - - const auto& dividend_holder_asset_object = get_asset("DIVIDEND"); - const auto& dividend_data = dividend_holder_asset_object.dividend_data(db); - const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db); - const account_object& alice = get_account("alice"); - const account_object& bob = get_account("bob"); - const account_object& carol = get_account("carol"); - const account_object& dave = get_account("dave"); - const account_object& frank = get_account("frank"); - const auto& test_asset_object = get_asset("TESTB"); - } catch(fc::exception& e) { - edump((e.to_detail_string())); - throw; - } -} - - BOOST_AUTO_TEST_CASE( check_dividend_corner_cases ) { using namespace graphene; @@ -547,8 +522,6 @@ BOOST_AUTO_TEST_CASE( check_dividend_corner_cases ) const account_object& alice = get_account("alice"); const account_object& bob = get_account("bob"); const account_object& carol = get_account("carol"); - const account_object& dave = get_account("dave"); - const account_object& frank = get_account("frank"); const auto& test_asset_object = get_asset("TESTB"); auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue) @@ -570,16 +543,6 @@ BOOST_AUTO_TEST_CASE( check_dividend_corner_cases ) BOOST_CHECK_EQUAL(pending_balance, expected_balance); }; - auto reserve_asset_from_account = [&](const asset_object& asset_to_reserve, const account_object& from_account, int64_t amount_to_reserve) - { - asset_reserve_operation reserve_op; - reserve_op.payer = from_account.id; - reserve_op.amount_to_reserve = asset(amount_to_reserve, asset_to_reserve.id); - trx.operations.push_back(reserve_op); - set_expiration(db, trx); - PUSH_TX( db, trx, ~0 ); - trx.operations.clear(); - }; auto advance_to_next_payout_time = [&]() { // Advance to the next upcoming payout time BOOST_REQUIRE(dividend_data.options.next_payout_time); diff --git a/tests/tests/gpos_tests.cpp b/tests/tests/gpos_tests.cpp index 14be6fe2..f716281e 100644 --- a/tests/tests/gpos_tests.cpp +++ b/tests/tests/gpos_tests.cpp @@ -79,7 +79,7 @@ struct gpos_fixture: database_fixture op.owner = owner; op.amount = amount; //op.balance_type = type; - + trx.operations.push_back(op); set_expiration(db, trx); trx.validate(); @@ -392,7 +392,7 @@ BOOST_AUTO_TEST_CASE( gpos_basic_dividend_distribution_to_core_asset ) PUSH_TX( db, trx, ~0 ); trx.operations.clear(); } - + // pass hardfork generate_blocks( HARDFORK_GPOS_TIME ); generate_block(); @@ -475,11 +475,11 @@ BOOST_AUTO_TEST_CASE( gpos_basic_dividend_distribution_to_core_asset ) vote_for(dave_id, witness1.vote_id, dave_private_key); // issuing 30000 TESTB to the dividend account - // alice and dave should receive 10000 TESTB as they have gpos vesting and + // alice and dave should receive 10000 TESTB as they have gpos vesting and // participated in voting // bob should not receive any TESTB as he doesn't have gpos vested // carol should not receive any TESTB as she doesn't participated in voting - // remaining 10000 TESTB should be deposited in commitee_accoount. + // remaining 10000 TESTB should be deposited in commitee_accoount. BOOST_TEST_MESSAGE("Issuing 30000 TESTB to the dividend account"); issue_asset_to_account(test_asset_object, dividend_distribution_account, 30000); @@ -531,7 +531,7 @@ BOOST_AUTO_TEST_CASE( gpos_basic_dividend_distribution_to_core_asset ) } catch(fc::exception& e) { edump((e.to_detail_string())); throw; - } + } } BOOST_AUTO_TEST_CASE( votes_on_gpos_activation ) @@ -546,7 +546,6 @@ BOOST_AUTO_TEST_CASE( votes_on_gpos_activation ) generate_block(); // update default gpos - auto now = db.head_block_time(); // 5184000 = 60x60x24x6 = 6 days // 864000 = 60x60x24x1 = 1 days update_gpos_global(518400, 86400, HARDFORK_GPOS_TIME); @@ -574,7 +573,7 @@ BOOST_AUTO_TEST_CASE( votes_on_gpos_activation ) witness2 = witness_id_type(2)(db); BOOST_CHECK_EQUAL(witness1.total_votes, 1000); BOOST_CHECK_EQUAL(witness2.total_votes, 1000); - + update_maintenance_interval(3600); //update maintenance interval to 1hr to evaluate sub-periods BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maintenance_interval, 3600); @@ -671,10 +670,18 @@ BOOST_AUTO_TEST_CASE( voting ) auto witness2 = witness_id_type(2)(db); BOOST_CHECK_EQUAL(witness2.total_votes, 0); + // vesting performance is 0 for both alice and bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 0); + // vote for witness1 and witness2 - sub-period 1 vote_for(alice_id, witness1.vote_id, alice_private_key); vote_for(bob_id, witness2.vote_id, bob_private_key); + // after voting, vesting performance is 1 for both alice and bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 1); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + // go to maint generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); @@ -684,6 +691,10 @@ BOOST_AUTO_TEST_CASE( voting ) BOOST_CHECK_EQUAL(witness1.total_votes, 1000); BOOST_CHECK_EQUAL(witness2.total_votes, 1000); + // vesting performance is 1 for both alice and bob during whole gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 1); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + advance_x_maint(6); witness1 = witness_id_type(1)(db); @@ -691,10 +702,29 @@ BOOST_AUTO_TEST_CASE( voting ) BOOST_CHECK_EQUAL(witness1.total_votes, 100); BOOST_CHECK_EQUAL(witness2.total_votes, 100); - advance_x_maint(4); + // vesting performance is 1 for both alice and bob during whole gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 1); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(3); + + // vesting performance is 1 for both alice and bob during whole gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 1); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(1); + + // new subperiod started, vesting performance is decreased to 5/6 for both alice and bob, until they vote + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 5.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 5.0/6.0); //Bob votes for witness2 - sub-period 2 vote_for(bob_id, witness2.vote_id, bob_private_key); + + // after voting, vesting performance is 5/6 for alice and 1 for bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 5.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + // go to maint generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); // vote decay as time pass @@ -703,10 +733,36 @@ BOOST_AUTO_TEST_CASE( voting ) BOOST_CHECK_EQUAL(witness1.total_votes, 83); BOOST_CHECK_EQUAL(witness2.total_votes, 100); - - advance_x_maint(10); + + // after voting, vesting performance is 5/6 for alice and 1 for bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 5.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(4); + + // vesting performance does not change during gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 5.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(4); + + // vesting performance does not change during gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 5.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(1); + + // new subperiod started, vesting performance is decreased to 4/6 for alice and 5/6 for bob, until they vote + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 4.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 5.0/6.0); + //Bob votes for witness2 - sub-period 3 vote_for(bob_id, witness2.vote_id, bob_private_key); + + // after voting, vesting performance is 4/6 for alice and 1 for bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 4.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); // decay more witness1 = witness_id_type(1)(db); @@ -714,8 +770,28 @@ BOOST_AUTO_TEST_CASE( voting ) BOOST_CHECK_EQUAL(witness1.total_votes, 66); BOOST_CHECK_EQUAL(witness2.total_votes, 100); - advance_x_maint(10); - + // after voting, vesting performance is 4/6 for alice and 1 for bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 4.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(4); + + // vesting performance does not change during gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 4.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(4); + + // vesting performance does not change during gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 4.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(1); + + // new subperiod started, vesting performance is decreased to 3/6 for alice and 5/6 for bob, until they vote + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 3.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 5.0/6.0); + // Bob votes for witness2 - sub-period 4 vote_for(bob_id, witness2.vote_id, bob_private_key); generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); @@ -725,8 +801,28 @@ BOOST_AUTO_TEST_CASE( voting ) BOOST_CHECK_EQUAL(witness1.total_votes, 50); BOOST_CHECK_EQUAL(witness2.total_votes, 100); - advance_x_maint(10); - + // after voting, vesting performance is 3/6 for alice and 1 for bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 3.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(4); + + // vesting performance does not change during gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 3.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(4); + + // vesting performance does not change during gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 3.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(1); + + // new subperiod started, vesting performance is decreased to 2/6 for alice and 5/6 for bob, until they vote + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 2.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 5.0/6.0); + // Bob votes for witness2 - sub-period 5 vote_for(bob_id, witness2.vote_id, bob_private_key); generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); @@ -737,8 +833,28 @@ BOOST_AUTO_TEST_CASE( voting ) BOOST_CHECK_EQUAL(witness1.total_votes, 33); BOOST_CHECK_EQUAL(witness2.total_votes, 100); - advance_x_maint(10); - + // after voting, vesting performance is 2/6 for alice and 1 for bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 2.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(4); + + // vesting performance does not change during gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 2.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(4); + + // vesting performance does not change during gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 2.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(1); + + // new subperiod started, vesting performance is decreased to 1/6 for alice and 5/6 for bob, until they vote + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 1.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 5.0/6.0); + // Bob votes for witness2 - sub-period 6 vote_for(bob_id, witness2.vote_id, bob_private_key); generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); @@ -748,14 +864,31 @@ BOOST_AUTO_TEST_CASE( voting ) BOOST_CHECK_EQUAL(witness1.total_votes, 16); BOOST_CHECK_EQUAL(witness2.total_votes, 100); + // after voting, vesting performance is 1/6 for alice and 1 for bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 1.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + // we are still in gpos period 1 BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), now.sec_since_epoch()); - advance_x_maint(5); + advance_x_maint(8); + + // vesting performance does not change during gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 1.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(1); + // a new GPOS period is in but vote from user is before the start. Whoever votes in 6th sub-period, votes will carry now = db.head_block_time(); BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), HARDFORK_GPOS_TIME.sec_since_epoch() + db.get_global_properties().parameters.gpos_period()); + // new gpos period and his first subperiod started, + // vesting performance is decreased to 0 for alice, as she did not vote + // but stays 1 for bob, as he voted in last subperiod in previous gpos period + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1 ); + generate_block(); // we are in the second GPOS period, at subperiod 1, @@ -763,14 +896,16 @@ BOOST_AUTO_TEST_CASE( voting ) witness2 = witness_id_type(2)(db); BOOST_CHECK_EQUAL(witness1.total_votes, 0); //It's critical here, since bob votes in 6th sub-period of last vesting period, witness2 should retain his votes - BOOST_CHECK_EQUAL(witness2.total_votes, 100); - + BOOST_CHECK_EQUAL(witness2.total_votes, 100); // lets vote here from alice to generate votes for witness 1 //vote from bob to reatin VF 1 vote_for(alice_id, witness1.vote_id, alice_private_key); vote_for(bob_id, witness2.vote_id, bob_private_key); - generate_block(); + + // after voting, vesting performance is 1 for both alice and bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 1); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); // go to maint generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); @@ -781,7 +916,17 @@ BOOST_AUTO_TEST_CASE( voting ) BOOST_CHECK_EQUAL(witness1.total_votes, 100); BOOST_CHECK_EQUAL(witness2.total_votes, 100); - advance_x_maint(10); + advance_x_maint(8); + + // vesting performance does not change during gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 1); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(1); + + // new subperiod started, vesting performance is decreased to 5/6 for both alice and bob, until they vote + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 5.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 5.0/6.0); witness1 = witness_id_type(1)(db); witness2 = witness_id_type(2)(db); @@ -792,7 +937,21 @@ BOOST_AUTO_TEST_CASE( voting ) vote_for(bob_id, witness2.vote_id, bob_private_key); generate_block(); - advance_x_maint(10); + // after voting, vesting performance is 5/6 for alice and 1 for bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 5.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(9); + + // vesting performance does not change during gpos subperiod + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 5.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 1); + + advance_x_maint(1); + + // new subperiod started, vesting performance is decreased to 4/6 for alice and 5/6 for bob, until they vote + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 4.0/6.0); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 5.0/6.0); witness1 = witness_id_type(1)(db); witness2 = witness_id_type(2)(db); @@ -802,6 +961,11 @@ BOOST_AUTO_TEST_CASE( voting ) // alice votes again, now for witness 2, her vote worth 100 now vote_for(alice_id, witness2.vote_id, alice_private_key); + + // after voting, vesting performance is 1 for alice and 5.0/6.0 for bob + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(alice_id(db)), 1); + BOOST_CHECK_EQUAL(db.calculate_vesting_factor(bob_id(db)), 5.0/6.0); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); witness1 = witness_id_type(1)(db); @@ -828,7 +992,7 @@ BOOST_AUTO_TEST_CASE( rolling_period_start ) BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maintenance_interval, 3600); auto vesting_period_1 = db.get_global_properties().parameters.gpos_period_start(); - + auto now = db.head_block_time(); // moving outside period: while( db.head_block_time() <= now + fc::days(6) ) @@ -837,9 +1001,9 @@ BOOST_AUTO_TEST_CASE( rolling_period_start ) } generate_block(); auto vesting_period_2 = db.get_global_properties().parameters.gpos_period_start(); - - //difference between start of two consecutive vesting periods should be 6 days - BOOST_CHECK_EQUAL(vesting_period_1 + 518400, vesting_period_2); + + //difference between start of two consecutive vesting periods should be 6 days + BOOST_CHECK_EQUAL(vesting_period_1 + 518400, vesting_period_2); } catch (fc::exception &e) { edump((e.to_detail_string())); @@ -1067,7 +1231,7 @@ BOOST_AUTO_TEST_CASE( Withdraw_gpos_vesting_balance ) vbo1 = create_vesting(alice_id, core.amount(150), vesting_balance_type::gpos); vbo2 = create_vesting(bob_id, core.amount(99), vesting_balance_type::gpos); generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - + generate_block(); generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); @@ -1080,12 +1244,12 @@ BOOST_AUTO_TEST_CASE( Withdraw_gpos_vesting_balance ) BOOST_CHECK_EQUAL(get_balance(alice_id(db), core), 400); BOOST_CHECK_EQUAL(get_balance(bob_id(db), core), 99); - // Add more 50 and 73 vesting objects and withdraw 90 from + // Add more 50 and 73 vesting objects and withdraw 90 from // total vesting balance of user vbo1 = create_vesting(alice_id, core.amount(50), vesting_balance_type::gpos); vbo2 = create_vesting(alice_id, core.amount(73), vesting_balance_type::gpos); generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - + generate_block(); vector vbos = db_api1.get_vesting_balances("alice"); @@ -1303,13 +1467,13 @@ BOOST_AUTO_TEST_CASE( proxy_voting ) // vote for witness1 auto witness1 = witness_id_type(1)(db); vote_for(bob_id, witness1.vote_id, bob_private_key); - + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - + // check vesting factor of current subperiod BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 1); BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 1); - + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); generate_block(); @@ -1317,7 +1481,7 @@ BOOST_AUTO_TEST_CASE( proxy_voting ) // vesting factor decay BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 0.83333333333333337); BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 0.83333333333333337); - + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); generate_block(); diff --git a/tests/tests/history_api_tests.cpp b/tests/tests/history_api_tests.cpp index f3b46fe7..8c975649 100644 --- a/tests/tests/history_api_tests.cpp +++ b/tests/tests/history_api_tests.cpp @@ -415,6 +415,8 @@ BOOST_AUTO_TEST_CASE(track_account) { // account_id_type() creates alice(not tracked account) const account_object& alice = create_account("alice"); auto alice_id = alice.id; + (void)alice; + (void)alice_id; //account_id_type() creates some ops create_bitasset("CNY", account_id_type()); @@ -423,6 +425,8 @@ BOOST_AUTO_TEST_CASE(track_account) { // account_id_type() creates dan(account tracked) const account_object& dan = create_account("dan"); auto dan_id = dan.id; + (void)dan; + (void)dan_id; // dan makes 1 op create_bitasset("EUR", dan_id); @@ -492,6 +496,8 @@ BOOST_AUTO_TEST_CASE(track_account2) { // account_id_type() creates alice(tracked account) const account_object& alice = create_account("alice"); auto alice_id = alice.id; + (void)alice; + (void)alice_id; //account_id_type() creates some ops create_bitasset("CNY", account_id_type()); @@ -503,6 +509,8 @@ BOOST_AUTO_TEST_CASE(track_account2) { // account_id_type() creates dan(account not tracked) const account_object& dan = create_account("dan"); auto dan_id = dan.id; + (void)dan; + (void)dan_id; generate_block(); diff --git a/tests/tests/lottery_tests.cpp b/tests/tests/lottery_tests.cpp index 063c15c1..c96abc09 100644 --- a/tests/tests/lottery_tests.cpp +++ b/tests/tests/lottery_tests.cpp @@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE( lottery_idx_test ) while( test_itr != test_asset_idx.end() ) { if( !met_not_active && (!test_itr->is_lottery() || !test_itr->lottery_options->is_active) ) met_not_active = true; - FC_ASSERT( !met_not_active || met_not_active && (!test_itr->is_lottery() || !test_itr->lottery_options->is_active), "MET ACTIVE LOTTERY AFTER NOT ACTIVE" ); + FC_ASSERT( (!met_not_active) || (met_not_active && (!test_itr->is_lottery() || !test_itr->lottery_options->is_active)), "MET ACTIVE LOTTERY AFTER NOT ACTIVE" ); ++test_itr; } } catch (fc::exception& e) { @@ -128,7 +128,8 @@ BOOST_AUTO_TEST_CASE( tickets_purchase_test ) trx.operations.clear(); BOOST_CHECK( tpo.amount == db.get_balance( test_asset.get_id() ) ); - BOOST_CHECK( tpo.tickets_to_buy == get_balance( account_id_type(), test_asset.id ) ); + int64_t tickets_to_buy_int64 = tpo.tickets_to_buy; + BOOST_CHECK( tickets_to_buy_int64 == get_balance( account_id_type(), test_asset.id ) ); } catch (fc::exception& e) { edump((e.to_detail_string())); diff --git a/tests/tests/nft_lottery_tests.cpp b/tests/tests/nft_lottery_tests.cpp new file mode 100644 index 00000000..02d8bdc1 --- /dev/null +++ b/tests/tests/nft_lottery_tests.cpp @@ -0,0 +1,842 @@ +/* + * Copyright (c) 2017 PBSA, Inc., 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 + +#include + +#include +#include +#include + +#include "../common/database_fixture.hpp" + +#include +#include + +using namespace graphene::chain; +using namespace graphene::chain::test; + +BOOST_FIXTURE_TEST_SUITE(nft_lottery_tests, database_fixture) + +BOOST_AUTO_TEST_CASE(create_lottery_nft_md_test) +{ + try + { + generate_blocks(HARDFORK_NFT_TIME); + generate_block(); + generate_block(); + set_expiration(db, trx); + // Lottery Options + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + nft_lottery_options lottery_options; + lottery_options.benefactors.push_back(nft_lottery_benefactor(account_id_type(), 25 * GRAPHENE_1_PERCENT)); + lottery_options.end_date = db.head_block_time() + fc::minutes(5); + lottery_options.ticket_price = asset(100); + lottery_options.winning_tickets = {5 * GRAPHENE_1_PERCENT, 5 * GRAPHENE_1_PERCENT, 5 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT}; + //lottery_options.winning_tickets = { 75 * GRAPHENE_1_PERCENT }; + lottery_options.is_active = test_nft_md_id.instance.value % 2 ? false : true; + lottery_options.ending_on_soldout = true; + + { + BOOST_TEST_MESSAGE("Send nft_metadata_create_operation"); + nft_metadata_create_operation op; + op.owner = account_id_type(); + op.symbol = "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value); + op.base_uri = "http://nft.example.com"; + op.is_transferable = true; + op.name = "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value); + op.max_supply = 200; + op.lottery_options = lottery_options; + + trx.operations.push_back(std::move(op)); + PUSH_TX(db, trx, ~0); + } + generate_block(); + + BOOST_TEST_MESSAGE("Check nft_metadata_create_operation results"); + + const auto &obj = test_nft_md_id(db); + BOOST_CHECK(obj.owner == account_id_type()); + BOOST_CHECK(obj.name == "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value)); + BOOST_CHECK(obj.symbol == "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value)); + BOOST_CHECK(obj.base_uri == "http://nft.example.com"); + BOOST_CHECK(obj.max_supply == share_type(200)); + BOOST_CHECK(obj.is_lottery()); + BOOST_CHECK(obj.get_token_current_supply(db) == share_type(0)); + BOOST_CHECK(obj.get_lottery_jackpot(db) == asset()); + BOOST_CHECK(obj.lottery_data->lottery_balance_id(db).sweeps_tickets_sold == share_type(0)); + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(lottery_idx_test) +{ + try + { + // generate loterries with different end_dates and is_active_flag + for (int i = 0; i < 26; ++i) + { + generate_blocks(30); + graphene::chain::test::set_expiration(db, trx); + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + INVOKE(create_lottery_nft_md_test); + auto test_nft_md_obj = test_nft_md_id(db); + } + + auto &test_nft_md_idx = db.get_index_type().indices().get(); + auto test_itr = test_nft_md_idx.begin(); + bool met_not_active = false; + // check sorting + while (test_itr != test_nft_md_idx.end()) + { + if (!met_not_active && (!test_itr->is_lottery() || !test_itr->lottery_data->lottery_options.is_active)) + met_not_active = true; + FC_ASSERT((!met_not_active) || (met_not_active && (!test_itr->is_lottery() || !test_itr->lottery_data->lottery_options.is_active)), "MET ACTIVE LOTTERY AFTER NOT ACTIVE"); + ++test_itr; + } + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(tickets_purchase_test) +{ + try + { + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + nft_id_type test_nft_id = db.get_index().get_next_id(); + INVOKE(create_lottery_nft_md_test); + auto &test_nft_md_obj = test_nft_md_id(db); + + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = account_id_type(); + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = 1; + tpo.amount = asset(100); + trx.operations.push_back(std::move(tpo)); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + generate_block(); + trx.operations.clear(); + auto &test_nft_ticket = test_nft_id(db); + BOOST_CHECK(test_nft_md_obj.get_token_current_supply(db) == tpo.tickets_to_buy); + BOOST_CHECK(test_nft_ticket.owner == tpo.buyer); + BOOST_CHECK(test_nft_ticket.nft_metadata_id == test_nft_md_obj.id); + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(tickets_purchase_fail_test) +{ + try + { + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + INVOKE(create_lottery_nft_md_test); + auto &test_nft_md_obj = test_nft_md_id(db); + + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = account_id_type(); + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = 2; + tpo.amount = asset(100); + trx.operations.push_back(tpo); + BOOST_REQUIRE_THROW(PUSH_TX(db, trx, ~0), fc::exception); // amount/tickets_to_buy != price + trx.operations.clear(); + + tpo.amount = asset(205); + trx.operations.push_back(tpo); + BOOST_REQUIRE_THROW(PUSH_TX(db, trx, ~0), fc::exception); // amount/tickets_to_buy != price + + tpo.amount = asset(200, asset_id_type(1)); + trx.operations.push_back(tpo); + BOOST_REQUIRE_THROW(PUSH_TX(db, trx, ~0), fc::exception); // trying to buy in other asset + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(lottery_end_by_stage_test) +{ + try + { + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + INVOKE(create_lottery_nft_md_test); + auto test_nft_md_obj = test_nft_md_id(db); + for (int i = 1; i < 17; ++i) + { + if (i == 4 || i == 1 || i == 16 || i == 15) + continue; + if (i != 0) + transfer(account_id_type(), account_id_type(i), asset(100000)); + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = account_id_type(i); + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = i; + tpo.amount = asset(100 * (i)); + trx.operations.push_back(std::move(tpo)); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + generate_block(); + trx.operations.clear(); + } + + test_nft_md_obj = test_nft_md_id(db); + uint64_t benefactor_balance_before_end = db.get_balance(account_id_type(), asset_id_type()).amount.value; + uint64_t jackpot = test_nft_md_obj.get_lottery_jackpot(db).amount.value; + uint16_t winners_part = 0; + for (uint16_t win : test_nft_md_obj.lottery_data->lottery_options.winning_tickets) + winners_part += win; + + uint16_t participants_percents_sum = 0; + auto participants = test_nft_md_obj.distribute_winners_part(db); + for (auto p : participants) + { + for (auto e : p.second) + { + participants_percents_sum += e; + } + } + + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(participants_percents_sum == winners_part); + BOOST_CHECK(test_nft_md_obj.get_lottery_jackpot(db).amount.value == (jackpot * (GRAPHENE_100_PERCENT - winners_part) / (double)GRAPHENE_100_PERCENT) + jackpot * winners_part * SWEEPS_DEFAULT_DISTRIBUTION_PERCENTAGE / (double)GRAPHENE_100_PERCENT / (double)GRAPHENE_100_PERCENT); + test_nft_md_obj.distribute_benefactors_part(db); + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(test_nft_md_obj.get_lottery_jackpot(db).amount.value == jackpot * SWEEPS_DEFAULT_DISTRIBUTION_PERCENTAGE / (double)GRAPHENE_100_PERCENT * winners_part / (double)GRAPHENE_100_PERCENT); + test_nft_md_obj.distribute_sweeps_holders_part(db); + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(test_nft_md_obj.get_lottery_jackpot(db).amount.value == 0); + + uint64_t benefactor_recieved = db.get_balance(account_id_type(), asset_id_type()).amount.value - benefactor_balance_before_end; + BOOST_CHECK(jackpot * test_nft_md_obj.lottery_data->lottery_options.benefactors[0].share / GRAPHENE_100_PERCENT == benefactor_recieved); + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(lottery_end_by_stage_with_fractional_test) +{ + + try + { + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + INVOKE(create_lottery_nft_md_test); + db.modify(test_nft_md_id(db), [&](nft_metadata_object &obj) { + obj.lottery_data->lottery_options.is_active = true; + }); + auto test_nft_md_obj = test_nft_md_id(db); + + for (int i = 1; i < 17; ++i) + { + if (i == 4) + continue; + if (i != 0) + transfer(account_id_type(), account_id_type(i), asset(100000)); + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = account_id_type(i); + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = i; + tpo.amount = asset(100 * (i)); + trx.operations.push_back(std::move(tpo)); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + generate_block(); + trx.operations.clear(); + } + test_nft_md_obj = test_nft_md_id(db); + uint64_t benefactor_balance_before_end = db.get_balance(account_id_type(), asset_id_type()).amount.value; + uint64_t jackpot = test_nft_md_obj.get_lottery_jackpot(db).amount.value; + uint16_t winners_part = 0; + for (uint16_t win : test_nft_md_obj.lottery_data->lottery_options.winning_tickets) + winners_part += win; + + uint16_t participants_percents_sum = 0; + auto participants = test_nft_md_obj.distribute_winners_part(db); + for (auto p : participants) + for (auto e : p.second) + participants_percents_sum += e; + + BOOST_CHECK(participants_percents_sum == winners_part); + // balance should be bigger than expected because of rouning during distribution + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(test_nft_md_obj.get_lottery_jackpot(db).amount.value > (jackpot * (GRAPHENE_100_PERCENT - winners_part) / (double)GRAPHENE_100_PERCENT) + jackpot * winners_part * SWEEPS_DEFAULT_DISTRIBUTION_PERCENTAGE / (double)GRAPHENE_100_PERCENT / (double)GRAPHENE_100_PERCENT); + test_nft_md_obj.distribute_benefactors_part(db); + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(test_nft_md_obj.get_lottery_jackpot(db).amount.value > jackpot * SWEEPS_DEFAULT_DISTRIBUTION_PERCENTAGE / (double)GRAPHENE_100_PERCENT * winners_part / (double)GRAPHENE_100_PERCENT); + test_nft_md_obj.distribute_sweeps_holders_part(db); + test_nft_md_obj = test_nft_md_id(db); + // but at the end is always equals 0 + BOOST_CHECK(test_nft_md_obj.get_lottery_jackpot(db).amount.value == 0); + + uint64_t benefactor_recieved = db.get_balance(account_id_type(), asset_id_type()).amount.value - benefactor_balance_before_end; + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(jackpot * test_nft_md_obj.lottery_data->lottery_options.benefactors[0].share / GRAPHENE_100_PERCENT == benefactor_recieved); + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(lottery_end_test) +{ + try + { + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + INVOKE(create_lottery_nft_md_test); + auto test_nft_md_obj = test_nft_md_id(db); + for (int i = 1; i < 17; ++i) + { + if (i == 4 || i == 1 || i == 16 || i == 15) + continue; + if (i != 0) + transfer(account_id_type(), account_id_type(i), asset(100000)); + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = account_id_type(i); + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = i; + tpo.amount = asset(100 * (i)); + trx.operations.push_back(std::move(tpo)); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + } + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + uint64_t creator_balance_before_end = db.get_balance(account_id_type(), asset_id_type()).amount.value; + uint64_t jackpot = test_nft_md_obj.get_lottery_jackpot(db).amount.value; + uint16_t winners_part = 0; + for (uint8_t win : test_nft_md_obj.lottery_data->lottery_options.winning_tickets) + winners_part += win; + + while (db.head_block_time() < (test_nft_md_obj.lottery_data->lottery_options.end_date + fc::seconds(30))) + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(test_nft_md_obj.get_lottery_jackpot(db).amount.value == 0); + uint64_t creator_recieved = db.get_balance(account_id_type(), asset_id_type()).amount.value - creator_balance_before_end; + BOOST_CHECK(jackpot * test_nft_md_obj.lottery_data->lottery_options.benefactors[0].share / GRAPHENE_100_PERCENT == creator_recieved); + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(claim_sweeps_vesting_balance_test) +{ + try + { + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + INVOKE(lottery_end_test); + auto test_nft_md_obj = test_nft_md_id(db); + account_id_type benefactor = test_nft_md_obj.lottery_data->lottery_options.benefactors[0].id; + const auto &svbo_index = db.get_index_type().indices().get(); + auto benefactor_svbo = svbo_index.find(benefactor); + BOOST_CHECK(benefactor_svbo != svbo_index.end()); + + auto balance_before_claim = db.get_balance(benefactor, SWEEPS_DEFAULT_DISTRIBUTION_ASSET); + auto available_for_claim = benefactor_svbo->available_for_claim(); + sweeps_vesting_claim_operation claim; + claim.account = benefactor; + claim.amount_to_claim = available_for_claim; + trx.clear(); + graphene::chain::test::set_expiration(db, trx); + trx.operations.push_back(claim); + PUSH_TX(db, trx, ~0); + generate_block(); + + BOOST_CHECK(db.get_balance(benefactor, SWEEPS_DEFAULT_DISTRIBUTION_ASSET) - balance_before_claim == available_for_claim); + benefactor_svbo = svbo_index.find(benefactor); + BOOST_CHECK(benefactor_svbo->available_for_claim().amount == 0); + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(more_winners_then_participants_test) +{ + try + { + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + INVOKE(create_lottery_nft_md_test); + auto test_nft_md_obj = test_nft_md_id(db); + for (int i = 1; i < 4; ++i) + { + if (i == 4) + continue; + if (i != 0) + transfer(account_id_type(), account_id_type(i), asset(1000000)); + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = account_id_type(i); + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = 1; + tpo.amount = asset(100); + trx.operations.push_back(std::move(tpo)); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + } + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + auto holders = test_nft_md_obj.get_holders(db); + auto participants = test_nft_md_obj.distribute_winners_part(db); + test_nft_md_obj = test_nft_md_id(db); + test_nft_md_obj.distribute_benefactors_part(db); + test_nft_md_obj = test_nft_md_id(db); + test_nft_md_obj.distribute_sweeps_holders_part(db); + test_nft_md_obj = test_nft_md_id(db); + generate_block(); + for (auto p : participants) + { + idump((get_operation_history(p.first))); + } + auto benefactor_history = get_operation_history(account_id_type()); + for (auto h : benefactor_history) + { + idump((h)); + } + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(ending_by_date_test) +{ + try + { + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + INVOKE(create_lottery_nft_md_test); + auto test_nft_md_obj = test_nft_md_id(db); + for (int i = 1; i < 4; ++i) + { + if (i == 4) + continue; + if (i != 0) + transfer(account_id_type(), account_id_type(i), asset(1000000)); + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = account_id_type(i); + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = 1; + tpo.amount = asset(100); + trx.operations.push_back(std::move(tpo)); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + } + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + auto holders = test_nft_md_obj.get_holders(db); + idump((test_nft_md_obj.get_lottery_jackpot(db))); + while (db.head_block_time() < (test_nft_md_obj.lottery_data->lottery_options.end_date + fc::seconds(30))) + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + idump((test_nft_md_obj.get_lottery_jackpot(db))); + vector participants = {account_id_type(1), account_id_type(2), account_id_type(3)}; + for (auto p : participants) + { + idump((get_operation_history(p))); + } + auto benefactor_history = get_operation_history(account_id_type()); + for (auto h : benefactor_history) + { + if (h.op.which() == operation::tag::value) + { + auto reward_op = h.op.get(); + idump((reward_op)); + BOOST_CHECK(reward_op.is_benefactor_reward); + BOOST_CHECK(reward_op.amount.amount.value == 75); + BOOST_CHECK(reward_op.amount.asset_id == test_nft_md_obj.lottery_data->lottery_options.ticket_price.asset_id); + break; + } + } + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(ending_by_participants_count_test) +{ + try + { + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + INVOKE(create_lottery_nft_md_test); + auto test_nft_md_obj = test_nft_md_id(db); + FC_ASSERT(test_nft_md_obj.lottery_data->lottery_options.is_active); + account_id_type buyer(3); + transfer(account_id_type(), buyer, asset(10000000)); + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = buyer; + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = 200; + tpo.amount = asset(200 * 100); + trx.operations.push_back(tpo); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + FC_ASSERT(!test_nft_md_obj.lottery_data->lottery_options.is_active); + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(try_to_end_empty_lottery_test) +{ + try + { + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + INVOKE(create_lottery_nft_md_test); + auto test_nft_md_obj = test_nft_md_id(db); + while (db.head_block_time() < (test_nft_md_obj.lottery_data->lottery_options.end_date + fc::seconds(30))) + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(!test_nft_md_obj.lottery_data->lottery_options.is_active); + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(lottery_winner_ticket_id_test) +{ + try + { + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + INVOKE(create_lottery_nft_md_test); + auto test_nft_md_obj = test_nft_md_id(db); + for (int i = 1; i < 4; ++i) + { + transfer(account_id_type(), account_id_type(i), asset(2000000)); + } + for (int i = 1; i < 4; ++i) + { + if (i == 4) + continue; + nft_lottery_token_purchase_operation tpo; + tpo.buyer = account_id_type(i); + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = 1; + tpo.amount = asset(100); + trx.operations.push_back(std::move(tpo)); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + } + + for (int i = 1; i < 4; ++i) + { + if (i == 4) + continue; + nft_lottery_token_purchase_operation tpo; + tpo.buyer = account_id_type(i); + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = 1; + tpo.amount = asset(100); + trx.operations.push_back(std::move(tpo)); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + } + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + uint64_t creator_balance_before_end = db.get_balance(account_id_type(), asset_id_type()).amount.value; + uint64_t jackpot = test_nft_md_obj.get_lottery_jackpot(db).amount.value; + uint16_t winners_part = 0; + for (uint8_t win : test_nft_md_obj.lottery_data->lottery_options.winning_tickets) + winners_part += win; + + while (db.head_block_time() < (test_nft_md_obj.lottery_data->lottery_options.end_date)) + generate_block(); + auto op_history = get_operation_history(account_id_type(1)); //Can observe operation 79 to verify winner ticket number + for (auto h : op_history) + { + idump((h)); + } + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(test_nft_md_obj.get_lottery_jackpot(db).amount.value == 0); + uint64_t creator_recieved = db.get_balance(account_id_type(), asset_id_type()).amount.value - creator_balance_before_end; + BOOST_CHECK(jackpot * test_nft_md_obj.lottery_data->lottery_options.benefactors[0].share / GRAPHENE_100_PERCENT == creator_recieved); + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(create_lottery_nft_md_delete_tickets_on_draw_test) +{ + try + { + generate_blocks(HARDFORK_NFT_TIME); + generate_block(); + generate_block(); + set_expiration(db, trx); + // Lottery Options + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + nft_lottery_options lottery_options; + lottery_options.benefactors.push_back(nft_lottery_benefactor(account_id_type(), 25 * GRAPHENE_1_PERCENT)); + lottery_options.end_date = db.head_block_time() + fc::minutes(5); + lottery_options.ticket_price = asset(100); + lottery_options.winning_tickets = {5 * GRAPHENE_1_PERCENT, 5 * GRAPHENE_1_PERCENT, 5 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT}; + //lottery_options.winning_tickets = { 75 * GRAPHENE_1_PERCENT }; + lottery_options.is_active = test_nft_md_id.instance.value % 2 ? false : true; + lottery_options.ending_on_soldout = true; + lottery_options.delete_tickets_after_draw = true; + + { + BOOST_TEST_MESSAGE("Send nft_metadata_create_operation"); + nft_metadata_create_operation op; + op.owner = account_id_type(); + op.symbol = "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value); + op.base_uri = "http://nft.example.com"; + op.is_transferable = true; + op.name = "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value); + op.max_supply = 200; + op.lottery_options = lottery_options; + + trx.operations.push_back(std::move(op)); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + } + generate_block(); + + BOOST_TEST_MESSAGE("Check nft_metadata_create_operation results"); + + auto test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(test_nft_md_obj.owner == account_id_type()); + BOOST_CHECK(test_nft_md_obj.name == "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value)); + BOOST_CHECK(test_nft_md_obj.symbol == "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value)); + BOOST_CHECK(test_nft_md_obj.base_uri == "http://nft.example.com"); + BOOST_CHECK(test_nft_md_obj.max_supply == share_type(200)); + BOOST_CHECK(test_nft_md_obj.is_lottery()); + BOOST_CHECK(test_nft_md_obj.get_token_current_supply(db) == share_type(0)); + BOOST_CHECK(test_nft_md_obj.get_lottery_jackpot(db) == asset()); + BOOST_CHECK(test_nft_md_obj.lottery_data->lottery_balance_id(db).sweeps_tickets_sold == share_type(0)); + + BOOST_CHECK(test_nft_md_obj.lottery_data->lottery_options.is_active); + account_id_type buyer(3); + transfer(account_id_type(), buyer, asset(10000000)); + { + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = buyer; + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = 199; + tpo.amount = asset(199 * 100); + trx.operations.push_back(tpo); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + } + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(test_nft_md_obj.lottery_data->lottery_options.is_active); + BOOST_CHECK(test_nft_md_obj.get_token_current_supply(db) == 199); + { + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = buyer; + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = 1; + tpo.amount = asset(1 * 100); + trx.operations.push_back(tpo); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + } + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(!test_nft_md_obj.lottery_data->lottery_options.is_active); + BOOST_CHECK(test_nft_md_obj.get_token_current_supply(db) == 0); + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(create_lottery_nft_with_permission_test) +{ + try + { + generate_blocks(HARDFORK_NFT_TIME); + generate_block(); + generate_block(); + set_expiration(db, trx); + // Lottery Options + nft_metadata_id_type test_nft_md_id = db.get_index().get_next_id(); + nft_lottery_options lottery_options; + lottery_options.benefactors.push_back(nft_lottery_benefactor(account_id_type(), 25 * GRAPHENE_1_PERCENT)); + lottery_options.end_date = db.head_block_time() + fc::minutes(5); + lottery_options.ticket_price = asset(100); + lottery_options.winning_tickets = {5 * GRAPHENE_1_PERCENT, 5 * GRAPHENE_1_PERCENT, 5 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT}; + //lottery_options.winning_tickets = { 75 * GRAPHENE_1_PERCENT }; + lottery_options.is_active = test_nft_md_id.instance.value % 2 ? false : true; + lottery_options.ending_on_soldout = true; + lottery_options.delete_tickets_after_draw = true; + + account_id_type buyer1(3); + account_id_type buyer2(6); + generate_block(); + transfer(account_id_type(), buyer1, asset(1000000)); + transfer(account_id_type(), buyer2, asset(1000000)); + generate_block(); + + { + BOOST_TEST_MESSAGE("Send account_role_create_operation"); + + account_role_create_operation op; + op.owner = account_id_type(); + op.name = "Test Account Role"; + op.metadata = "{\"country\": \"earth\", \"race\": \"human\" }"; + + int ops[] = {operation::tag::value}; + op.allowed_operations.insert(ops, ops + 1); + op.whitelisted_accounts.emplace(buyer1); + op.valid_to = db.head_block_time() + 1000; + + trx.operations.push_back(op); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + } + + { + BOOST_TEST_MESSAGE("Send nft_metadata_create_operation"); + nft_metadata_create_operation op; + op.owner = account_id_type(); + op.symbol = "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value); + op.base_uri = "http://nft.example.com"; + op.is_transferable = true; + op.name = "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value); + op.max_supply = 200; + op.lottery_options = lottery_options; + op.account_role = account_role_id_type(0); + + trx.operations.push_back(std::move(op)); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + } + generate_block(); + + BOOST_TEST_MESSAGE("Check nft_metadata_create_operation results"); + + auto test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(test_nft_md_obj.owner == account_id_type()); + BOOST_CHECK(test_nft_md_obj.name == "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value)); + BOOST_CHECK(test_nft_md_obj.symbol == "NFTLOTTERY" + std::to_string(test_nft_md_id.instance.value)); + BOOST_CHECK(test_nft_md_obj.base_uri == "http://nft.example.com"); + BOOST_CHECK(test_nft_md_obj.max_supply == share_type(200)); + BOOST_CHECK(test_nft_md_obj.is_lottery()); + BOOST_CHECK(test_nft_md_obj.get_token_current_supply(db) == share_type(0)); + BOOST_CHECK(test_nft_md_obj.get_lottery_jackpot(db) == asset()); + BOOST_CHECK(test_nft_md_obj.lottery_data->lottery_balance_id(db).sweeps_tickets_sold == share_type(0)); + BOOST_CHECK(test_nft_md_obj.account_role == account_role_id_type(0)); + + BOOST_CHECK(test_nft_md_obj.lottery_data->lottery_options.is_active); + + { + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = buyer1; + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = 199; + tpo.amount = asset(199 * 100); + trx.operations.push_back(tpo); + set_expiration(db, trx); + PUSH_TX(db, trx, ~0); + trx.operations.clear(); + } + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(test_nft_md_obj.lottery_data->lottery_options.is_active); + BOOST_CHECK(test_nft_md_obj.get_token_current_supply(db) == 199); + { + nft_lottery_token_purchase_operation tpo; + tpo.fee = asset(); + tpo.buyer = buyer2; + tpo.lottery_id = test_nft_md_obj.id; + tpo.tickets_to_buy = 1; + tpo.amount = asset(1 * 100); + trx.operations.push_back(tpo); + set_expiration(db, trx); + BOOST_CHECK_THROW(PUSH_TX(db, trx, ~0), fc::exception); + trx.operations.clear(); + } + generate_block(); + test_nft_md_obj = test_nft_md_id(db); + BOOST_CHECK(test_nft_md_obj.get_token_current_supply(db) == 199); + } + catch (fc::exception &e) + { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 3093f0b0..6caec826 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -1561,7 +1561,6 @@ BOOST_AUTO_TEST_CASE( vesting_balance_create_test ) op.amount = test_asset.amount( 100 ); //op.vesting_seconds = 60*60*24; op.policy = cdd_vesting_policy_initializer{ 60*60*24 }; - op.balance_type == vesting_balance_type::normal; // Fee must be non-negative REQUIRE_OP_VALIDATION_SUCCESS( op, fee, core.amount(1) ); diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 5fee05d5..1e3bb7e4 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -491,12 +491,32 @@ BOOST_AUTO_TEST_CASE( son_pay_test ) // Modify the transaction signed statistics of Alice's SON db.modify( *son_stats_obj1, [&]( son_statistics_object& _s) { - _s.txs_signed = 2; + _s.txs_signed[sidechain_type::bitcoin] = 2; + _s.txs_signed[sidechain_type::hive] = 4; + + _s.total_txs_signed[sidechain_type::bitcoin] = 2; + _s.total_txs_signed[sidechain_type::hive] = 4; + + _s.sidechain_txs_reported[sidechain_type::bitcoin] = 4; + _s.sidechain_txs_reported[sidechain_type::hive] = 8; + + _s.total_sidechain_txs_reported[sidechain_type::bitcoin] = 4; + _s.total_sidechain_txs_reported[sidechain_type::hive] = 8; }); // Modify the transaction signed statistics of Bob's SON db.modify( *son_stats_obj2, [&]( son_statistics_object& _s) { - _s.txs_signed = 3; + _s.txs_signed[sidechain_type::bitcoin] = 3; + _s.txs_signed[sidechain_type::hive] = 6; + + _s.total_txs_signed[sidechain_type::bitcoin] = 3; + _s.total_txs_signed[sidechain_type::hive] = 6; + + _s.sidechain_txs_reported[sidechain_type::bitcoin] = 6; + _s.sidechain_txs_reported[sidechain_type::hive] = 12; + + _s.total_sidechain_txs_reported[sidechain_type::bitcoin] = 6; + _s.total_sidechain_txs_reported[sidechain_type::hive] = 12; }); // Note the balances before the maintenance @@ -506,11 +526,23 @@ BOOST_AUTO_TEST_CASE( son_pay_test ) generate_blocks(dpo.next_maintenance_time); generate_block(); // Check if the signed transaction statistics are reset for both SONs - BOOST_REQUIRE_EQUAL(son_stats_obj1->txs_signed, 0); - BOOST_REQUIRE_EQUAL(son_stats_obj2->txs_signed, 0); + BOOST_REQUIRE_EQUAL(son_stats_obj1->txs_signed.at(sidechain_type::bitcoin), 0); + BOOST_REQUIRE_EQUAL(son_stats_obj1->txs_signed.at(sidechain_type::hive), 0); + BOOST_REQUIRE_EQUAL(son_stats_obj2->txs_signed.at(sidechain_type::bitcoin), 0); + BOOST_REQUIRE_EQUAL(son_stats_obj2->txs_signed.at(sidechain_type::hive), 0); + BOOST_REQUIRE_EQUAL(son_stats_obj1->sidechain_txs_reported.at(sidechain_type::bitcoin), 0); + BOOST_REQUIRE_EQUAL(son_stats_obj1->sidechain_txs_reported.at(sidechain_type::hive), 0); + BOOST_REQUIRE_EQUAL(son_stats_obj2->sidechain_txs_reported.at(sidechain_type::bitcoin), 0); + BOOST_REQUIRE_EQUAL(son_stats_obj2->sidechain_txs_reported.at(sidechain_type::hive), 0); - BOOST_REQUIRE_EQUAL(son_stats_obj1->total_txs_signed, 2); - BOOST_REQUIRE_EQUAL(son_stats_obj2->total_txs_signed, 3); + BOOST_REQUIRE_EQUAL(son_stats_obj1->total_txs_signed.at(sidechain_type::bitcoin), 2); + BOOST_REQUIRE_EQUAL(son_stats_obj1->total_txs_signed.at(sidechain_type::hive), 4); + BOOST_REQUIRE_EQUAL(son_stats_obj2->total_txs_signed.at(sidechain_type::bitcoin), 3); + BOOST_REQUIRE_EQUAL(son_stats_obj2->total_txs_signed.at(sidechain_type::hive), 6); + BOOST_REQUIRE_EQUAL(son_stats_obj1->total_sidechain_txs_reported.at(sidechain_type::bitcoin), 4); + BOOST_REQUIRE_EQUAL(son_stats_obj1->total_sidechain_txs_reported.at(sidechain_type::hive), 8); + BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::bitcoin), 6); + BOOST_REQUIRE_EQUAL(son_stats_obj2->total_sidechain_txs_reported.at(sidechain_type::hive), 12); // Check that Alice and Bob are paid for signing the transactions in the previous day/cycle BOOST_REQUIRE_EQUAL(db.get_balance(obj1->son_account, asset_id_type()).amount.value, 80+obj1_balance); BOOST_REQUIRE_EQUAL(db.get_balance(obj2->son_account, asset_id_type()).amount.value, 120+obj2_balance); diff --git a/tests/tests/voting_tests.cpp b/tests/tests/voting_tests.cpp index 79f80e1f..a6f41675 100644 --- a/tests/tests/voting_tests.cpp +++ b/tests/tests/voting_tests.cpp @@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(last_voting_date_proxy) PUSH_TX( db, trx, ~0 ); } // last_vote_time is not updated - auto round2 = db.head_block_time().sec_since_epoch(); + db.head_block_time().sec_since_epoch(); alice_stats_obj = alice_id(db).statistics(db); BOOST_CHECK_EQUAL(alice_stats_obj.last_vote_time.sec_since_epoch(), round1); diff --git a/tests/tournament/tournament_tests.cpp b/tests/tournament/tournament_tests.cpp index 8aa88479..0593fd79 100644 --- a/tests/tournament/tournament_tests.cpp +++ b/tests/tournament/tournament_tests.cpp @@ -1731,7 +1731,8 @@ BOOST_FIXTURE_TEST_CASE( ties, database_fixture ) share_type rake_amount = (fc::uint128_t(tournament.prize_pool.value) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100).to_uint64(); optional dividend_account = tournament_helper.get_asset_dividend_account(tournament.options.buy_in.asset_id); if (dividend_account.valid()) - players_balances[*dividend_account][tournament.options.buy_in.asset_id] += rake_amount; players_balances[winner_id][tournament.options.buy_in.asset_id] += tournament.prize_pool - rake_amount; + players_balances[*dividend_account][tournament.options.buy_in.asset_id] += rake_amount; + players_balances[winner_id][tournament.options.buy_in.asset_id] += tournament.prize_pool - rake_amount; tournaments.erase(tournament_id); --tournaments_to_complete; @@ -1943,7 +1944,8 @@ BOOST_FIXTURE_TEST_CASE( assets, database_fixture ) share_type rake_amount = (fc::uint128_t(tournament.prize_pool.value) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100).to_uint64(); optional dividend_account = tournament_helper.get_asset_dividend_account(tournament.options.buy_in.asset_id); if (dividend_account.valid()) - players_balances[*dividend_account][tournament.options.buy_in.asset_id] += rake_amount; players_balances[winner_id][tournament.options.buy_in.asset_id] += tournament.prize_pool - rake_amount; + players_balances[*dividend_account][tournament.options.buy_in.asset_id] += rake_amount; + players_balances[winner_id][tournament.options.buy_in.asset_id] += tournament.prize_pool - rake_amount; tournaments.erase(tournament_id); --tournaments_to_complete;