Initial commit
This commit is contained in:
commit
0a945b0257
212 changed files with 96440 additions and 0 deletions
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
*.a
|
||||
*.sw*
|
||||
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
Makefile
|
||||
compile_commands.json
|
||||
|
||||
libraries/utilities/git_revision.cpp
|
||||
|
||||
tests/app_test
|
||||
tests/chain_bench
|
||||
tests/chain_test
|
||||
|
||||
/doxygen
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[submodule "libraries/fc"]
|
||||
path = libraries/fc
|
||||
url = https://github.com/cryptonomex/fc
|
||||
[submodule "libraries/leveldb"]
|
||||
path = libraries/leveldb
|
||||
url = https://github.com/bitcoin/leveldb.git
|
||||
238
CMakeLists.txt
Normal file
238
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
# Defines Graphene library target.
|
||||
project( Graphene )
|
||||
cmake_minimum_required( VERSION 2.8.12 )
|
||||
|
||||
set( BLOCKCHAIN_NAME "Graphene" )
|
||||
|
||||
set( CLI_CLIENT_EXECUTABLE_NAME graphene_client )
|
||||
set( GUI_CLIENT_EXECUTABLE_NAME Graphene )
|
||||
set( CUSTOM_URL_SCHEME "gcs" )
|
||||
set( INSTALLER_APP_ID "68ad7005-8eee-49c9-95ce-9eed97e5b347" )
|
||||
|
||||
# http://stackoverflow.com/a/18369825
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
|
||||
message(FATAL_ERROR "GCC version must be at least 4.8!")
|
||||
endif()
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.3)
|
||||
message(FATAL_ERROR "Clang version must be at least 3.3!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules" )
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS "ON")
|
||||
|
||||
#set (ENABLE_INSTALLER 1)
|
||||
#set (USE_PCH 1)
|
||||
|
||||
if (USE_PCH)
|
||||
include (cotire)
|
||||
endif(USE_PCH)
|
||||
|
||||
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/libraries/fc/CMakeModules" )
|
||||
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/libraries/fc/GitVersionGen" )
|
||||
include( GetGitRevisionDescription )
|
||||
get_git_head_revision( GIT_REFSPEC GIT_SHA2 )
|
||||
|
||||
SET(BOOST_COMPONENTS)
|
||||
LIST(APPEND BOOST_COMPONENTS thread
|
||||
date_time
|
||||
system
|
||||
filesystem
|
||||
program_options
|
||||
signals
|
||||
serialization
|
||||
chrono
|
||||
unit_test_framework
|
||||
context
|
||||
locale)
|
||||
SET( Boost_USE_STATIC_LIBS ON CACHE STRING "ON or OFF" )
|
||||
|
||||
IF( WIN32 )
|
||||
SET(BOOST_ROOT $ENV{BOOST_ROOT})
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
set(BOOST_ALL_DYN_LINK OFF) # force dynamic linking for all libraries
|
||||
ENDIF(WIN32)
|
||||
|
||||
FIND_PACKAGE(Boost 1.53 REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||
# For Boost 1.53 on windows, coroutine was not in BOOST_LIBRARYDIR and do not need it to build, but if boost versin >= 1.54, find coroutine otherwise will cause link errors
|
||||
IF(NOT "${Boost_VERSION}" MATCHES "1.53(.*)")
|
||||
SET(BOOST_LIBRARIES_TEMP ${Boost_LIBRARIES})
|
||||
FIND_PACKAGE(Boost 1.54 REQUIRED COMPONENTS coroutine)
|
||||
LIST(APPEND BOOST_COMPONENTS coroutine)
|
||||
SET(Boost_LIBRARIES ${BOOST_LIBRARIES_TEMP} ${Boost_LIBRARIES})
|
||||
ENDIF()
|
||||
|
||||
set( LEVEL_DB_DIR "${CMAKE_SOURCE_DIR}/libraries/leveldb" )
|
||||
|
||||
file( GLOB LEVEL_DB_SOURCES "${LEVEL_DB_DIR}/db/*.cc"
|
||||
"${LEVEL_DB_DIR}/helpers/memenv/memenv.cc"
|
||||
"${LEVEL_DB_DIR}/table/*.cc"
|
||||
"${LEVEL_DB_DIR}/util/*.cc" )
|
||||
foreach( filename ${LEVEL_DB_SOURCES} )
|
||||
if( ${filename} MATCHES ".*_test.cc" OR ${filename} MATCHES ".*_bench.cc" OR ${filename} MATCHES ".*_main.cc" )
|
||||
list( REMOVE_ITEM LEVEL_DB_SOURCES ${filename} )
|
||||
endif()
|
||||
endforeach()
|
||||
set(LEVELDB_BUILD_DEFINES)
|
||||
set(LEVELDB_BUILD_LIBRARIES)
|
||||
set(LEVELDB_BUILD_PRIVATE_INCLUDES "${LEVEL_DB_DIR}")
|
||||
|
||||
if( WIN32 )
|
||||
message( STATUS "Configuring Graphene on WIN32")
|
||||
set( DB_VERSION 60 )
|
||||
set( BDB_STATIC_LIBS 1 )
|
||||
|
||||
set( ZLIB_LIBRARIES "" )
|
||||
SET( DEFAULT_EXECUTABLE_INSTALL_DIR bin/ )
|
||||
|
||||
set(CRYPTO_LIB)
|
||||
|
||||
#looks like this flag can have different default on some machines.
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
|
||||
|
||||
# Probably cmake has a bug and vcxproj generated for executable in Debug conf. has disabled debug info
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /DEBUG")
|
||||
|
||||
# On windows tcl should be installed to the directory pointed by setenv.bat script
|
||||
SET(TCL_INCLUDE_PATH $ENV{TCL_ROOT}/include)
|
||||
MESSAGE(STATUS "tcl INCLUDE PATH: ${TCL_INCLUDE_PATH}")
|
||||
|
||||
FIND_PACKAGE(TCL)
|
||||
MESSAGE(STATUS "tcl_library: ${TCL_LIBRARY}")
|
||||
|
||||
SET(TCL_LIBS "optimized;${TCL_LIBRARY};debug;")
|
||||
get_filename_component(TCL_LIB_PATH "${TCL_LIBRARY}" PATH)
|
||||
get_filename_component(TCL_LIB_NAME "${TCL_LIBRARY}" NAME_WE)
|
||||
get_filename_component(TCL_LIB_EXT "${TCL_LIBRARY}" EXT)
|
||||
|
||||
SET(TCL_LIBS "${TCL_LIBS}${TCL_LIB_PATH}/${TCL_LIB_NAME}g${TCL_LIB_EXT}")
|
||||
SET(TCL_LIBRARY ${TCL_LIBS})
|
||||
|
||||
SET(LEVELDB_PORT_FILE "${LEVEL_DB_DIR}/port/port_win.cc" )
|
||||
list(APPEND LEVELDB_BUILD_DEFINES OS_WINDOWS LEVELDB_PLATFORM_WINDOWS )
|
||||
list(APPEND LEVELDB_BUILD_LIBRARIES shlwapi.lib)
|
||||
list(INSERT LEVELDB_BUILD_PRIVATE_INCLUDES 0 "${CMAKE_SOURCE_DIR}/libraries/leveldb-msvc/include")
|
||||
else( WIN32 ) # Apple AND Linux
|
||||
SET(LEVELDB_PORT_FILE "${LEVEL_DB_DIR}/port/port_posix.cc" )
|
||||
|
||||
list(APPEND LEVELDB_BUILD_DEFINES LEVELDB_PLATFORM_POSIX LEVELDB_ATOMIC_PRESENT)
|
||||
if( APPLE )
|
||||
list(APPEND LEVELDB_BUILD_DEFINES OS_MACOSX)
|
||||
else() # Linux
|
||||
list(APPEND LEVELDB_BUILD_DEFINES OS_LINUX)
|
||||
list(APPEND LEVELDB_BUILD_LIBRARIES pthread)
|
||||
endif()
|
||||
|
||||
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 Graphene 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 Graphene on Linux" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -Wall" )
|
||||
set( rt_library rt )
|
||||
set( pthread_library pthread)
|
||||
if ( NOT DEFINED crypto_library )
|
||||
# I'm not sure why this is here, I guess someone has openssl and can't detect it with find_package()?
|
||||
# if you have a normal install, you can define crypto_library to the empty string to avoid a build error
|
||||
set( crypto_library crypto)
|
||||
endif ()
|
||||
if ( FULL_STATIC_BUILD )
|
||||
set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc")
|
||||
endif ( FULL_STATIC_BUILD )
|
||||
endif( APPLE )
|
||||
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-builtin-memcmp" )
|
||||
endif()
|
||||
|
||||
if( "${CMAKE_GENERATOR}" STREQUAL "Ninja" )
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics" )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# based on http://www.delorie.com/gnu/docs/gdb/gdb_70.html
|
||||
# uncomment this line to tell GDB about macros (slows compile times)
|
||||
# set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -gdwarf-2 -g3" )
|
||||
|
||||
endif( WIN32 )
|
||||
|
||||
list(APPEND LEVEL_DB_SOURCES "${LEVELDB_PORT_FILE}")
|
||||
add_library( leveldb ${LEVEL_DB_SOURCES} )
|
||||
target_link_libraries( leveldb ${LEVELDB_BUILD_LIBRARIES} )
|
||||
target_include_directories( leveldb PRIVATE ${LEVELDB_BUILD_PRIVATE_INCLUDES}
|
||||
PUBLIC "${LEVEL_DB_DIR}/include" )
|
||||
set_target_properties(leveldb PROPERTIES COMPILE_DEFINITIONS "${LEVELDB_BUILD_DEFINES}")
|
||||
|
||||
find_package( BerkeleyDB )
|
||||
|
||||
set(ENABLE_COVERAGE_TESTING FALSE CACHE BOOL "Build Graphene for code coverage analysis")
|
||||
if(ENABLE_COVERAGE_TESTING)
|
||||
SET(CMAKE_CXX_FLAGS "--coverage ${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
add_subdirectory( libraries )
|
||||
add_subdirectory( programs )
|
||||
add_subdirectory( tests )
|
||||
|
||||
|
||||
if (ENABLE_INSTALLER)
|
||||
|
||||
set(VERSION_MAJOR 0)
|
||||
set(VERSION_MINOR 1)
|
||||
set(VERSION_PATCH 0)
|
||||
|
||||
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
set(CPACK_OUTPUT_FILE_PREFIX ${CMAKE_BINARY_DIR}/packages)
|
||||
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install)
|
||||
|
||||
SET(CPACK_PACKAGE_DIRECTORY "${CMAKE_INSTALL_PREFIX}")
|
||||
set(CPACK_PACKAGE_NAME "graphene")
|
||||
set(CPACK_PACKAGE_VENDOR "Graphene Labs, Inc.")
|
||||
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 Graphene network")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A client for the Graphene network")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.md")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Graphene ${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
if(WIN32)
|
||||
SET(CPACK_GENERATOR "ZIP;NSIS")
|
||||
set(CPACK_PACKAGE_NAME "Graphene") # override above
|
||||
set(CPACK_NSIS_EXECUTABLES_DIRECTORY .)
|
||||
set(CPACK_NSIS_PACKAGE_NAME "Graphene v${CPACK_PACKAGE_VERSION}")
|
||||
set(CPACK_NSIS_DISPLAY_NAME "${CPACK_NSIS_PACKAGE_NAME}")
|
||||
set(CPACK_NSIS_DEFINES " !define MUI_STARTMENUPAGE_DEFAULTFOLDER \\\"Graphene\\\"")
|
||||
# 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)
|
||||
|
||||
include(CPack)
|
||||
endif(WIN32)
|
||||
|
||||
if(APPLE)
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
endif()
|
||||
|
||||
if(LINUX)
|
||||
# Linux gets a .tgz
|
||||
SET(CPACK_GENERATOR "TGZ")
|
||||
SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 1)
|
||||
endif(LINUX)
|
||||
|
||||
endif(ENABLE_INSTALLER)
|
||||
98
CMakeModules/FindBerkeleyDB.cmake
Normal file
98
CMakeModules/FindBerkeleyDB.cmake
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
# Find the BerkeleyDB includes and library
|
||||
# Customizable variables:
|
||||
# BDB_ROOT_DIR
|
||||
# This variable points to the BerkeleyDB root directory. On Windows the
|
||||
# library location typically will have to be provided explicitly using the
|
||||
# -D command-line option. Alternatively, the DBROOTDIR environment variable
|
||||
# can be set.
|
||||
#
|
||||
# BDB_STATIC_LIBS
|
||||
# Should be set to 1 if static version of libraries should be found. Defaults to 0 (shared libs).
|
||||
#
|
||||
# This module defines
|
||||
# BDB_INCLUDE_DIR, where to find db.h, etc.
|
||||
# BDB_LIBRARIES, the libraries needed to use BerkeleyDB.
|
||||
|
||||
IF (NOT DEFINED BDB_ROOT_DIR)
|
||||
SET (BDB_ROOT_DIR $ENV{DBROOTDIR})
|
||||
ENDIF()
|
||||
|
||||
MESSAGE (STATUS "Using ${BDB_ROOT_DIR} as BerkeleyDB root")
|
||||
|
||||
IF(NOT DEFINED BDB_STATIC_LIBS)
|
||||
SET (BDB_STATIC_LIBS 0)
|
||||
ENDIF()
|
||||
|
||||
FIND_PATH(BDB_INCLUDE_DIR NAMES db.h db_cxx.h
|
||||
HINTS "${BDB_ROOT_DIR}/include"
|
||||
PATHS ${BDB_ROOT_DIR}
|
||||
/usr/include/libdb5
|
||||
/usr/include/db5
|
||||
/usr/include/libdb4
|
||||
/usr/include/db4
|
||||
/usr/local/include/libdb5
|
||||
/usr/local/include/db5
|
||||
/usr/local/include/libdb4
|
||||
/usr/local/include/db4
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
IF (WIN32)
|
||||
IF(NOT DEFINED BDB_VERSION)
|
||||
SET (DB_VERSION "60")
|
||||
ENDIF ()
|
||||
|
||||
SET (BDB_LIB_BASENAME "libdb")
|
||||
|
||||
IF (${BDB_STATIC_LIBS} EQUAL 1)
|
||||
SET (BDB_LIBS_SUFFIX_RELEASE "s")
|
||||
SET (BDB_LIBS_SUFFIX_DEBUG "sD")
|
||||
ELSE()
|
||||
SET (BDB_LIBS_SUFFIX_RELEASE "")
|
||||
SET (BDB_LIBS_SUFFIX_DEBUG "D")
|
||||
ENDIF()
|
||||
|
||||
ELSE (WIN32)
|
||||
IF(NOT DEFINED BDB_VERSION)
|
||||
SET (DB_VERSION "-6.0")
|
||||
ENDIF ()
|
||||
|
||||
# On unix library in all versions have the same names.
|
||||
SET (BDB_LIBS_SUFFIX_RELEASE "")
|
||||
SET (BDB_LIBS_SUFFIX_DEBUG "")
|
||||
|
||||
SET (BDB_LIB_BASENAME "db_cxx")
|
||||
ENDIF (WIN32)
|
||||
|
||||
message (STATUS "Looking for: ${BDB_LIB_BASENAME}${DB_VERSION}${BDB_LIBS_SUFFIX_RELEASE}")
|
||||
FIND_LIBRARY(BDB_LIBRARY_RELEASE "${BDB_LIB_BASENAME}${DB_VERSION}${BDB_LIBS_SUFFIX_RELEASE}" "${BDB_LIB_BASENAME}"
|
||||
HINTS "${BDB_ROOT_DIR}/lib" PATHS ${BDB_ROOT_DIR} ${BDB_INCLUDE_DIR} "/usr/local/lib" PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
FIND_LIBRARY(BDB_LIBRARY_DEBUG "${BDB_LIB_BASENAME}${DB_VERSION}${BDB_LIBS_SUFFIX_DEBUG}" "${BDB_LIB_BASENAME}"
|
||||
HINTS "${BDB_ROOT_DIR}/lib" PATHS ${BDB_ROOT_DIR} ${BDB_INCLUDE_DIR} "/usr/local/lib" PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
IF (BDB_LIBRARY_RELEASE AND BDB_LIBRARY_DEBUG )
|
||||
SET (_BDB_LIBRARY
|
||||
debug ${BDB_LIBRARY_DEBUG}
|
||||
optimized ${BDB_LIBRARY_RELEASE}
|
||||
)
|
||||
ELSEIF(BDB_LIBRARY_RELEASE)
|
||||
SET (_BDB_LIBRARY ${BDB_LIBRARY_RELEASE})
|
||||
ELSEIF(BDB_LIBRARY_DEBUG)
|
||||
SET (_BDB_LIBRARY ${BDB_LIBRARY_DEBUG})
|
||||
ENDIF()
|
||||
|
||||
MESSAGE (STATUS ${_BDB_LIBRARY})
|
||||
|
||||
IF(_BDB_LIBRARY)
|
||||
LIST (APPEND BDB_LIBRARIES ${_BDB_LIBRARY})
|
||||
ENDIF()
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(BerkeleyDB
|
||||
FOUND_VAR BerkeleyDB_FOUND
|
||||
REQUIRED_VARS BDB_INCLUDE_DIR BDB_LIBRARIES
|
||||
FAIL_MESSAGE "Could not find Berkeley DB >= 4.1" )
|
||||
|
||||
51
CMakeModules/FindGperftools.cmake
Normal file
51
CMakeModules/FindGperftools.cmake
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Tries to find Gperftools.
|
||||
#
|
||||
# Usage of this module as follows:
|
||||
#
|
||||
# find_package(Gperftools)
|
||||
#
|
||||
# Variables used by this module, they can change the default behaviour and need
|
||||
# to be set before calling find_package:
|
||||
#
|
||||
# Gperftools_ROOT_DIR Set this variable to the root installation of
|
||||
# Gperftools if the module has problems finding
|
||||
# the proper installation path.
|
||||
#
|
||||
# Variables defined by this module:
|
||||
#
|
||||
# GPERFTOOLS_FOUND System has Gperftools libs/headers
|
||||
# GPERFTOOLS_LIBRARIES The Gperftools libraries (tcmalloc & profiler)
|
||||
# GPERFTOOLS_INCLUDE_DIR The location of Gperftools headers
|
||||
|
||||
find_library(GPERFTOOLS_TCMALLOC
|
||||
NAMES tcmalloc
|
||||
HINTS ${Gperftools_ROOT_DIR}/lib)
|
||||
|
||||
find_library(GPERFTOOLS_PROFILER
|
||||
NAMES profiler
|
||||
HINTS ${Gperftools_ROOT_DIR}/lib)
|
||||
|
||||
find_library(GPERFTOOLS_TCMALLOC_AND_PROFILER
|
||||
NAMES tcmalloc_and_profiler
|
||||
HINTS ${Gperftools_ROOT_DIR}/lib)
|
||||
|
||||
find_path(GPERFTOOLS_INCLUDE_DIR
|
||||
NAMES gperftools/heap-profiler.h
|
||||
HINTS ${Gperftools_ROOT_DIR}/include)
|
||||
|
||||
set(GPERFTOOLS_LIBRARIES ${GPERFTOOLS_TCMALLOC_AND_PROFILER})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(
|
||||
Gperftools
|
||||
DEFAULT_MSG
|
||||
GPERFTOOLS_LIBRARIES
|
||||
GPERFTOOLS_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(
|
||||
Gperftools_ROOT_DIR
|
||||
GPERFTOOLS_TCMALLOC
|
||||
GPERFTOOLS_PROFILER
|
||||
GPERFTOOLS_TCMALLOC_AND_PROFILER
|
||||
GPERFTOOLS_LIBRARIES
|
||||
GPERFTOOLS_INCLUDE_DIR)
|
||||
8
CMakeModules/FindLineman.cmake
Normal file
8
CMakeModules/FindLineman.cmake
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
find_program(NPM_EXECUTABLE npm)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args("NPM" DEFAULT_MSG NPM_EXECUTABLE)
|
||||
|
||||
find_program(LINEMAN_EXECUTABLE lineman)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args("Lineman" DEFAULT_MSG LINEMAN_EXECUTABLE)
|
||||
|
||||
4
CMakeModules/FindNodeJs.cmake
Normal file
4
CMakeModules/FindNodeJs.cmake
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
find_program(NODEJS_EXECUTABLE node)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args("NodeJs" DEFAULT_MSG NODEJS_EXECUTABLE)
|
||||
3392
CMakeModules/cotire.cmake
Normal file
3392
CMakeModules/cotire.cmake
Normal file
File diff suppressed because it is too large
Load diff
17
HEADER
Normal file
17
HEADER
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
15
LICENSE
Normal file
15
LICENSE
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
Copyright (c) 2015, Cryptonomex, Inc.
|
||||
All rights reserved.
|
||||
|
||||
This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
|
||||
1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
109
README.md
Normal file
109
README.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
Intro for new developers
|
||||
------------------------
|
||||
|
||||
This is a quick introduction to get new developers up to speed on Graphene.
|
||||
|
||||
Starting Graphene
|
||||
-----------------
|
||||
|
||||
git clone https://gitlab.bitshares.org/dlarimer/graphene
|
||||
cd graphene
|
||||
git submodule update --init --recursive
|
||||
|
||||
TODO: Are recursive flags needed for submodules?
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug .
|
||||
make
|
||||
./programs/witness_node/witness_node
|
||||
|
||||
This will launch the witness node. If you would like to launch the command-line wallet, you must first specify a port for communication with the witness node. To do this, add text to `witness_node_data_dir/config.json` as follows, then restart the node:
|
||||
|
||||
"websocket_endpoint": "127.0.0.1:8090"
|
||||
|
||||
Then, in a separate terminal window, start the command-line wallet `cli_wallet`:
|
||||
|
||||
./programs/cli_wallet/cli_wallet
|
||||
|
||||
If you send private keys over this connection, `websocket_endpoint` should be bound to localhost for security.
|
||||
|
||||
Code coverage testing
|
||||
---------------------
|
||||
|
||||
TODO: Write something here
|
||||
|
||||
Unit testing
|
||||
------------
|
||||
|
||||
TODO: Write something here
|
||||
|
||||
Core mechanics
|
||||
--------------
|
||||
|
||||
- Witnesses
|
||||
- Key members
|
||||
- Price feeds
|
||||
- Global parameters
|
||||
- Voting on witnesses
|
||||
- Voting on key members
|
||||
- Witness pay
|
||||
- Transfers
|
||||
- Markets
|
||||
- Escrow
|
||||
- Recurring payments
|
||||
|
||||
Gotchas
|
||||
-------
|
||||
|
||||
- Key objects can actually contain a key or address
|
||||
|
||||
Witness node
|
||||
------------
|
||||
|
||||
The role of the witness node is to broadcast transactions, download blocks, and optionally sign them.
|
||||
|
||||
TODO: How do you get block signing keys into the witness node?
|
||||
|
||||
How to use fc async to do recurring tasks
|
||||
-----------------------------------------
|
||||
|
||||
_my_task = fc::async( callable, "My Task" );
|
||||
_my_task = fc::schedule( callable, "My Task 2", exec_time );
|
||||
|
||||
Stuff to know about the code
|
||||
----------------------------
|
||||
|
||||
`static_variant<t1, t2>` is a *union type* which says "this variable may be either t1 or t2." It is serializable if t1 and t2 are both serializable (TODO: Is this accurate?)
|
||||
|
||||
The 'operations.hpp` documents the available operations, and `database_fixture.hpp` shows the way to do many things.
|
||||
|
||||
Tests also show the way to do many things, but are often cluttered with code that generates corner cases to try to break things in every possible way.
|
||||
|
||||
Visitors are at the end of `operations.hpp` after the large typedef for `operation` as a `static_variant`. TODO: They should be refactored into a separate header.
|
||||
|
||||
When using `modify()`, you can pass in either an `object_id` or an `object`. Passing in an `object` is faster as it avoids a lookup.
|
||||
|
||||
Downcasting stuff
|
||||
-----------------
|
||||
|
||||
- You have an `object_id_type` and want to downcast it to a `key_id_type` : `key_id_type( object_id )`
|
||||
- You have an `operation_result` and want to downcast it to an `object_id_type` : `op_result.get<object_id_type>()`
|
||||
- Since `operation_result` is a `static_variant`, the above is also how you downcast `static_variant`
|
||||
|
||||
Running specific tests
|
||||
----------------------
|
||||
|
||||
- `tests/chain_tests -t block_tests/name_of_test`
|
||||
|
||||
Debugging FC exceptions with GDB
|
||||
--------------------------------
|
||||
|
||||
- `catch throw`
|
||||
|
||||
TODO: Questions
|
||||
---------------
|
||||
|
||||
This section contains questions for more experienced developers to answer.
|
||||
|
||||
Is there a way to generate help with parameter names and method descriptions?
|
||||
|
||||
Is there a way to allow external program to drive `cli_wallet` via websocket, JSONRPC, or HTTP?# graphene
|
||||
21
build-ubuntu.md
Normal file
21
build-ubuntu.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
The Boost which ships with Ubuntu 14.04 LTS is too old. You need to download the Boost tarball for Boost 1.57.0
|
||||
(Note, 1.58.0 requires C++14 and will not build on Ubuntu LTS; this requirement was an accident, see ). Build Boost as follows:
|
||||
|
||||
# tarball available at http://sourceforge.net/projects/boost/files/boost/1.57.0/boost_1_57_0.tar.bz2/download
|
||||
# sha256sum is 910c8c022a33ccec7f088bd65d4f14b466588dda94ba2124e78b8c57db264967
|
||||
|
||||
BOOST_ROOT=$(echo ~/opt/boost_1_57_0)
|
||||
|
||||
# build Boost from source
|
||||
cd ~/src/boost_1_57_0
|
||||
./bootstrap.sh --prefix=$BOOST_ROOT
|
||||
./b2 link=static variant=debug threading=multi stage
|
||||
./b2 link=static variant=debug threading=multi install
|
||||
|
||||
Then we need to tell `cmake` to use the Boost we just built, instead of using the system-wide Boost:
|
||||
|
||||
cd ~/src/graphene
|
||||
[ -e ./doc/build-ubuntu.md ] && sh -c 'cmake -DBOOST_ROOT="$BOOST_ROOT" -DCMAKE_BUILD_TYPE=Debug .'
|
||||
|
||||
If all goes well, you should see the correct Boost version in the output messages to the above command.
|
||||
14
doc/draft-license/HEADER.draft
Normal file
14
doc/draft-license/HEADER.draft
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* This is draft license text currently under development. This license does not apply to anything right now.
|
||||
*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. No distribution of binaries compiled from modified versions of the code
|
||||
*
|
||||
* 2. Any modifications become property of Cryptonomex, Inc and must be licensed under these same terms
|
||||
*
|
||||
* 3. Any hosting provider is authorized to delete any version of this code at the request Cryptonomex, Inc.
|
||||
*/
|
||||
19
doc/draft-license/LICENSE.draft
Normal file
19
doc/draft-license/LICENSE.draft
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
This is draft license text currently under development. This license does not apply to anything right now.
|
||||
|
||||
Copyright (c) 2015, Cryptonomex, Inc
|
||||
All rights reserved.
|
||||
|
||||
The graphene source code is proprietary and may not be used for any purpose without written permission from Cryptonomex, Inc. The source code is
|
||||
provided publicly for the sole purpose of allowing users to audit the code and compile their own executables. Blockchain technology depends upon
|
||||
a strong consensus on the rules of an open protocol; this source code is provided to completely document the protocol rules (bugs and all).
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. No distribution of binaries compiled from modified versions of the code
|
||||
|
||||
2. Any modifications made to the code become property of Cryptonomex, Inc and must be licensed under these same terms
|
||||
|
||||
3. The software may be forked/cloned on github for the purpose of submitting bug fixes and pull requests. All forked repositories are property of Cryptonomex and by
|
||||
forking you authorize Github.com to delete your fork at the request Cryptonomex, Inc.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
37
doc/witness-rng.md
Normal file
37
doc/witness-rng.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
Witness scheduler RNG
|
||||
---------------------
|
||||
|
||||
The witness scheduler RNG is a random number generator which uses the
|
||||
blockchain random number generator state as its seed.
|
||||
|
||||
The witness scheduler RNG creates an infinite stream of random bytes
|
||||
by computing `sha256( sha256( seed ) + little_endian_64bit(i) )`, increasing
|
||||
`i` from 0 to 1 to 2, etc. The RNG only runs during a scheduling block,
|
||||
and `i` starts from `0` in each scheduling block (relying on different
|
||||
seeds to produce different results).
|
||||
|
||||
This infinite stream of random bytes is equivalent to an infinite
|
||||
stream of random bits in little bit-endian order. Given a bound `B`,
|
||||
the bitstream can be used to produce a random number uniformly
|
||||
distributed in the range `[0, B)` using a sample-and-reject algorithm:
|
||||
|
||||
- Let `n` be the smallest integer such that `2^n >= B`.
|
||||
- Let `x` be the next `n` bits from the bitstream, interpreted as an integer in little bit-endian order.
|
||||
- If `x <= B`, return `x`. Otherwise, throw `x` away and repeat.
|
||||
|
||||
The worst-case running time is unbounded, but each iteration has a
|
||||
termination probability greater than one half. Thus the average-case
|
||||
running time is `2` iterations, and a running time of more than `N`
|
||||
iterations will occur (on average) at most once every `2^N`
|
||||
RNG queries (assuming a worst-case choice of e.g. `B = 2^63+1` for all
|
||||
queries). Since each RNG query schedules a witness, the query rate
|
||||
is (over the long term) equal to the block production rate (although
|
||||
in practice many queries are all performed at once in scheduling
|
||||
blocks). So while it is, in theory, possible for the algorithm to
|
||||
require more than 1000 iterations, in practice this will occur on average
|
||||
only once every `2^1000` blocks (again assuming all queries have
|
||||
worst-case `B`).
|
||||
|
||||
The sample-and-reject algorithm is totally unbiased; every `x` value
|
||||
has equal probability.
|
||||
128
doc/witness-scheduler.md
Normal file
128
doc/witness-scheduler.md
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
|
||||
Turn/Token witness scheduling algorithm
|
||||
---------------------------------------
|
||||
|
||||
The algorithm which determines the order of witnesses is referred
|
||||
to as the *witness scheduling algorithm*.
|
||||
|
||||
This was designed by a community bounty in thread
|
||||
https://bitsharestalk.org/index.php/topic,15547.0
|
||||
however, Graphene has an additional requirement which
|
||||
is not taken into account by the solutions in the thread:
|
||||
|
||||
The membership and length of the list of witnesses may change over
|
||||
time.
|
||||
|
||||
So in this article I'll describe my solution.
|
||||
|
||||
Turns and tokens
|
||||
----------------
|
||||
|
||||
The solution is based on terms of *turns* and *tokens*.
|
||||
|
||||
- Newly inserted witnesses start out with a turn and a token.
|
||||
- In order for a witness to be scheduled, it must have a turn and a token.
|
||||
- The scheduler maintains a FIFO of witnesses without tokens.
|
||||
- If no witness has a turn, then the scheduler gives a turn to all witnesses. This is called "emitting a turn."
|
||||
- While less than half of the witnesses have tokens, give a token to the first witness in the FIFO and remove it from the FIFO.
|
||||
- Schedule a witness by picking randomly from all witnesses with both a turn and token.
|
||||
- When a witness is scheduled, it loses its turn and token.
|
||||
|
||||
The generic scheduler
|
||||
---------------------
|
||||
|
||||
The generic scheduler implements turns and tokens. It only depends
|
||||
on the C++11 stdlib and boost (not even using fc). Types provided
|
||||
by Graphene are template parameters.
|
||||
|
||||
The generic far future scheduler
|
||||
--------------------------------
|
||||
|
||||
The far future scheduler is implemented with the following rules:
|
||||
|
||||
- Run until you emit a turn.
|
||||
- Record all witnesses produced.
|
||||
- Run until you emit a second turn.
|
||||
- The witnesses produced between the emission of the first turn (exclusive)
|
||||
and emission of the second turn (inclusive) are called the *far future schedule*.
|
||||
|
||||
Then the schedule for the rest of time is determined by repeating
|
||||
the future schedule indefinitely. The far future scheduler is required
|
||||
to give the scheduling algorithm bounded runtime and memory usage even
|
||||
in chains involving very long gaps.
|
||||
|
||||
Slots
|
||||
-----
|
||||
|
||||
Due to dynamic block interval, we must carefully keep in mind
|
||||
the difference between schedule slots and timestamps. A
|
||||
*schedule slot number* is a positive integer. A slot number of `n`
|
||||
represents the `n`th next block-interval-aligned timestamp after
|
||||
the head block.
|
||||
|
||||
Note that the mapping between slot numbers and timestamps will change
|
||||
if the block interval changes.
|
||||
|
||||
Scheduling blocks
|
||||
-----------------
|
||||
|
||||
When each block is produced, the blockchain must determine whether
|
||||
the scheduler needs to be run. If fewer than `num_witnesses` are
|
||||
scheduled, the scheduler will run until `2*num_witnesses` are scheduled.
|
||||
A block in which the scheduler runs is called a *scheduling block*.
|
||||
|
||||
Changes in the set of active witnesses do not modify the existing
|
||||
schedule. Rather, they will be incorporated into new schedule entries
|
||||
when the scheduler runs in the next scheduling block. Thus, a witness
|
||||
that has lost an election may still produce 1-2 blocks. Such a witness
|
||||
is called a *lame duck*.
|
||||
|
||||
Near vs. far schedule
|
||||
---------------------
|
||||
|
||||
From a particular chain state, it must be possible to specify a
|
||||
mapping from slots to witnesses, called the *total witness schedule*.
|
||||
The total witness schedule is partitioned into a prefix, called the
|
||||
*near schedule*; the remainder is the *far schedule*.
|
||||
|
||||
When a block occurs, `n` entries are *drained* (removed) from the head
|
||||
of the total schedule, where `n` is the slot number of the new block
|
||||
according to its parent block.
|
||||
|
||||
If the block is a scheduling block, the total schedule is further
|
||||
transformed. The new near schedule contains `2*num_witnesses` entries,
|
||||
with the previous near schedule as a prefix. The rest of the near
|
||||
schedule is determined by the current blockchain RNG.
|
||||
|
||||
The new far schedule is determined by running the far future scheduler,
|
||||
as described above. The far future scheduler also obtains entropy
|
||||
from the current blockchain RNG.
|
||||
|
||||
As an optimization, the implementation does not run the far future
|
||||
scheduler until a far-future slot is actually queried. With this
|
||||
optimization, the only circumstance under which validating nodes must
|
||||
run the far future scheduler is when a block gap longer than `num_witnesses`
|
||||
occurs (an extremely rare condition).
|
||||
|
||||
Minimizing impact of selective dropout
|
||||
--------------------------------------
|
||||
|
||||
The ability of any single malicious witness to affect the results of the
|
||||
shuffle algorithm is limited because the RNG is based on bit commitment
|
||||
of the witnesses. However, a malicious witness *is* able to
|
||||
refuse to produce a block. A run of `m` consecutively scheduled
|
||||
malicious witnesses can independently make `m` independent choices
|
||||
of whether to refuse to produce a block. Basically they are able to
|
||||
control `m` bits of entropy in the shuffle algorithm's output.
|
||||
|
||||
It is difficult-to-impossible to entirely eliminate "the last person
|
||||
being evil" problem in trustless distributed RNG's. But we can at least
|
||||
mitigate this vector by rate-limiting changes to the total witness
|
||||
schedule to a very slow rate.
|
||||
|
||||
If every block schedules a witness, our adversary with `m` malicious
|
||||
witnesses gets `m` chances per round to selectively drop out in order
|
||||
to manipulate the shuffle order, allowing `m` attacks per round.
|
||||
If witnesses are only scheduled once per round,
|
||||
a selective dropout requires the malicious witness to produce the
|
||||
scheduling block, limiting the probability to `m/n` attacks per round.
|
||||
10
libraries/CMakeLists.txt
Normal file
10
libraries/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
add_subdirectory( fc )
|
||||
add_subdirectory( db )
|
||||
add_subdirectory( deterministic_openssl_rand )
|
||||
add_subdirectory( chain )
|
||||
add_subdirectory( net )
|
||||
add_subdirectory( time )
|
||||
add_subdirectory( utilities )
|
||||
add_subdirectory( app )
|
||||
add_subdirectory( plugins )
|
||||
add_subdirectory( wallet )
|
||||
15
libraries/app/CMakeLists.txt
Normal file
15
libraries/app/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
file(GLOB HEADERS "include/graphene/app/*.hpp")
|
||||
|
||||
add_library( graphene_app
|
||||
api.cpp
|
||||
application.cpp
|
||||
plugin.cpp
|
||||
)
|
||||
|
||||
target_link_libraries( graphene_app graphene_chain fc graphene_db graphene_net graphene_time graphene_utilities )
|
||||
target_include_directories( graphene_app
|
||||
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
|
||||
|
||||
if(MSVC)
|
||||
set_source_files_properties( application.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
|
||||
endif(MSVC)
|
||||
433
libraries/app/api.cpp
Normal file
433
libraries/app/api.cpp
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/app/api.hpp>
|
||||
#include <graphene/app/application.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/utilities/key_conversion.hpp>
|
||||
#include <graphene/chain/operation_history_object.hpp>
|
||||
|
||||
#include <fc/crypto/hex.hpp>
|
||||
|
||||
namespace graphene { namespace app {
|
||||
|
||||
database_api::database_api(graphene::chain::database& db):_db(db)
|
||||
{
|
||||
_change_connection = _db.changed_objects.connect([this](const vector<object_id_type>& ids) {
|
||||
on_objects_changed(ids);
|
||||
});
|
||||
_applied_block_connection = _db.applied_block.connect([this](const signed_block&){ on_applied_block(); });
|
||||
}
|
||||
|
||||
fc::variants database_api::get_objects(const vector<object_id_type>& ids)const
|
||||
{
|
||||
fc::variants result;
|
||||
result.reserve(ids.size());
|
||||
|
||||
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 {};
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
optional<block_header> database_api::get_block_header(uint32_t block_num) const
|
||||
{
|
||||
auto result = _db.fetch_block_by_number(block_num);
|
||||
if(result)
|
||||
return *result;
|
||||
return {};
|
||||
}
|
||||
|
||||
optional<signed_block> database_api::get_block(uint32_t block_num)const
|
||||
{
|
||||
return _db.fetch_block_by_number(block_num);
|
||||
}
|
||||
|
||||
vector<optional<account_object>> database_api::lookup_account_names(const vector<string>& account_names)const
|
||||
{
|
||||
const auto& accounts_by_name = _db.get_index_type<account_index>().indices().get<by_name>();
|
||||
vector<optional<account_object> > 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<account_object> {
|
||||
auto itr = accounts_by_name.find(name);
|
||||
return itr == accounts_by_name.end()? optional<account_object>() : *itr;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<optional<asset_object>> database_api::lookup_asset_symbols(const vector<string>& symbols)const
|
||||
{
|
||||
const auto& assets_by_symbol = _db.get_index_type<asset_index>().indices().get<by_symbol>();
|
||||
vector<optional<asset_object> > result;
|
||||
result.reserve(symbols.size());
|
||||
std::transform(symbols.begin(), symbols.end(), std::back_inserter(result),
|
||||
[&assets_by_symbol](const string& symbol) -> optional<asset_object> {
|
||||
auto itr = assets_by_symbol.find(symbol);
|
||||
return itr == assets_by_symbol.end()? optional<asset_object>() : *itr;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
global_property_object database_api::get_global_properties()const
|
||||
{
|
||||
return _db.get(global_property_id_type());
|
||||
}
|
||||
|
||||
dynamic_global_property_object database_api::get_dynamic_global_properties()const
|
||||
{
|
||||
return _db.get(dynamic_global_property_id_type());
|
||||
}
|
||||
|
||||
vector<optional<key_object>> database_api::get_keys(const vector<key_id_type>& key_ids)const
|
||||
{
|
||||
vector<optional<key_object>> result; result.reserve(key_ids.size());
|
||||
std::transform(key_ids.begin(), key_ids.end(), std::back_inserter(result),
|
||||
[this](key_id_type id) -> optional<key_object> {
|
||||
if(auto o = _db.find(id))
|
||||
return *o;
|
||||
return {};
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<optional<account_object>> database_api::get_accounts(const vector<account_id_type>& account_ids)const
|
||||
{
|
||||
vector<optional<account_object>> result; result.reserve(account_ids.size());
|
||||
std::transform(account_ids.begin(), account_ids.end(), std::back_inserter(result),
|
||||
[this](account_id_type id) -> optional<account_object> {
|
||||
if(auto o = _db.find(id))
|
||||
return *o;
|
||||
return {};
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<optional<asset_object>> database_api::get_assets(const vector<asset_id_type>& asset_ids)const
|
||||
{
|
||||
vector<optional<asset_object>> result; result.reserve(asset_ids.size());
|
||||
std::transform(asset_ids.begin(), asset_ids.end(), std::back_inserter(result),
|
||||
[this](asset_id_type id) -> optional<asset_object> {
|
||||
if(auto o = _db.find(id))
|
||||
return *o;
|
||||
return {};
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t database_api::get_account_count()const
|
||||
{
|
||||
return _db.get_index_type<account_index>().indices().size();
|
||||
}
|
||||
|
||||
map<string,account_id_type> database_api::lookup_accounts(const string& lower_bound_name, uint32_t limit)const
|
||||
{
|
||||
FC_ASSERT( limit <= 1000 );
|
||||
const auto& accounts_by_name = _db.get_index_type<account_index>().indices().get<by_name>();
|
||||
map<string,account_id_type> result;
|
||||
|
||||
for( auto itr = accounts_by_name.lower_bound(lower_bound_name);
|
||||
limit-- && itr != accounts_by_name.end();
|
||||
++itr )
|
||||
result.insert(make_pair(itr->name, itr->get_id()));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<asset> database_api::get_account_balances(account_id_type acnt, const flat_set<asset_id_type>& assets)const
|
||||
{
|
||||
vector<asset> result; 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); });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<asset> database_api::get_named_account_balances(const std::string& name, const flat_set<asset_id_type>& assets) const
|
||||
{
|
||||
const auto& accounts_by_name = _db.get_index_type<account_index>().indices().get<by_name>();
|
||||
auto itr = accounts_by_name.find(name);
|
||||
FC_ASSERT( itr != accounts_by_name.end() );
|
||||
return get_account_balances(itr->get_id(), assets);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the limit orders for both sides of the book for the two assets specified up to limit number on each side.
|
||||
*/
|
||||
vector<limit_order_object> database_api::get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const
|
||||
{
|
||||
const auto& limit_order_idx = _db.get_index_type<limit_order_index>();
|
||||
const auto& limit_price_idx = limit_order_idx.indices().get<by_price>();
|
||||
|
||||
vector<limit_order_object> result;
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
result.push_back(*limit_itr);
|
||||
++limit_itr;
|
||||
++count;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<short_order_object> database_api::get_short_orders(asset_id_type a, uint32_t limit)const
|
||||
{
|
||||
const auto& short_order_idx = _db.get_index_type<short_order_index>();
|
||||
const auto& sell_price_idx = short_order_idx.indices().get<by_price>();
|
||||
const asset_object& mia = _db.get(a);
|
||||
|
||||
price index_price = price::min(mia.get_id(), mia.bitasset_data(_db).options.short_backing_asset);
|
||||
|
||||
auto short_itr = sell_price_idx.lower_bound(index_price.max());
|
||||
auto short_end = sell_price_idx.upper_bound(index_price.min());
|
||||
|
||||
return vector<short_order_object>(short_itr, short_end);
|
||||
}
|
||||
|
||||
vector<call_order_object> database_api::get_call_orders(asset_id_type a, uint32_t limit)const
|
||||
{
|
||||
const auto& call_index = _db.get_index_type<call_order_index>().indices().get<by_price>();
|
||||
const asset_object& mia = _db.get(a);
|
||||
price index_price = price::min(mia.bitasset_data(_db).options.short_backing_asset, mia.get_id());
|
||||
|
||||
return vector<call_order_object>(call_index.lower_bound(index_price.min()),
|
||||
call_index.lower_bound(index_price.max()));
|
||||
}
|
||||
|
||||
vector<force_settlement_object> database_api::get_settle_orders(asset_id_type a, uint32_t limit)const
|
||||
{
|
||||
const auto& settle_index = _db.get_index_type<force_settlement_index>().indices().get<by_expiration>();
|
||||
const asset_object& mia = _db.get(a);
|
||||
return vector<force_settlement_object>(settle_index.lower_bound(mia.get_id()),
|
||||
settle_index.upper_bound(mia.get_id()));
|
||||
}
|
||||
|
||||
vector<asset_object> database_api::list_assets(const string& lower_bound_symbol, uint32_t limit)const
|
||||
{
|
||||
FC_ASSERT( limit <= 100 );
|
||||
const auto& assets_by_symbol = _db.get_index_type<asset_index>().indices().get<by_symbol>();
|
||||
vector<asset_object> result;
|
||||
result.reserve(limit);
|
||||
|
||||
auto itr = assets_by_symbol.lower_bound(lower_bound_symbol);
|
||||
while(limit-- && itr != assets_by_symbol.end())
|
||||
result.emplace_back(*itr++);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
login_api::login_api(application& a)
|
||||
:_app(a)
|
||||
{
|
||||
}
|
||||
login_api::~login_api()
|
||||
{
|
||||
}
|
||||
|
||||
bool login_api::login(const string& user, const string& password)
|
||||
{
|
||||
auto db_api = std::make_shared<database_api>(std::ref(*_app.chain_database()));
|
||||
auto net_api = std::make_shared<network_api>(std::ref(_app));
|
||||
auto hist_api = std::make_shared<history_api>(_app);
|
||||
_database_api = db_api;
|
||||
_network_api = net_api;
|
||||
_history_api = hist_api;
|
||||
return true;
|
||||
}
|
||||
|
||||
void network_api::add_node(const fc::ip::endpoint& ep)
|
||||
{
|
||||
_app.p2p_node()->add_node(ep);
|
||||
}
|
||||
|
||||
void network_api::broadcast_transaction(const signed_transaction& trx)
|
||||
{
|
||||
trx.validate();
|
||||
_app.chain_database()->push_transaction(trx);
|
||||
_app.p2p_node()->broadcast_transaction(trx);
|
||||
}
|
||||
|
||||
std::vector<net::peer_status> network_api::get_connected_peers() const
|
||||
{
|
||||
return _app.p2p_node()->get_connected_peers();
|
||||
}
|
||||
|
||||
fc::api<network_api> login_api::network()const
|
||||
{
|
||||
FC_ASSERT(_network_api);
|
||||
return *_network_api;
|
||||
}
|
||||
|
||||
fc::api<database_api> login_api::database()const
|
||||
{
|
||||
FC_ASSERT(_database_api);
|
||||
return *_database_api;
|
||||
}
|
||||
|
||||
fc::api<history_api> login_api::history() const
|
||||
{
|
||||
FC_ASSERT(_history_api);
|
||||
return *_history_api;
|
||||
}
|
||||
|
||||
void database_api::on_objects_changed(const vector<object_id_type>& ids)
|
||||
{
|
||||
vector<object_id_type> my_objects;
|
||||
for(auto id : ids)
|
||||
if(_subscriptions.find(id) != _subscriptions.end())
|
||||
my_objects.push_back(id);
|
||||
|
||||
_broadcast_changes_complete = fc::async([=](){
|
||||
for(auto id : my_objects)
|
||||
{
|
||||
const object* obj = _db.find_object(id);
|
||||
if(obj)
|
||||
{
|
||||
_subscriptions[id](obj->to_variant());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** note: this method cannot yield because it is called in the middle of
|
||||
* apply a block.
|
||||
*/
|
||||
void database_api::on_applied_block()
|
||||
{
|
||||
if(_market_subscriptions.size() == 0)
|
||||
return;
|
||||
|
||||
const auto& ops = _db.get_applied_operations();
|
||||
map< std::pair<asset_id_type,asset_id_type>, vector<pair<operation, operation_result>> > subscribed_markets_ops;
|
||||
for(const auto& op : ops)
|
||||
{
|
||||
std::pair<asset_id_type,asset_id_type> market;
|
||||
switch(op.op.which())
|
||||
{
|
||||
case operation::tag<limit_order_create_operation>::value:
|
||||
market = op.op.get<limit_order_create_operation>().get_market();
|
||||
break;
|
||||
case operation::tag<short_order_create_operation>::value:
|
||||
market = op.op.get<limit_order_create_operation>().get_market();
|
||||
break;
|
||||
case operation::tag<fill_order_operation>::value:
|
||||
market = op.op.get<fill_order_operation>().get_market();
|
||||
break;
|
||||
/*
|
||||
case operation::tag<limit_order_cancel_operation>::value:
|
||||
case operation::tag<short_order_cancel_operation>::value:
|
||||
*/
|
||||
default: break;
|
||||
}
|
||||
if(_market_subscriptions.count(market))
|
||||
subscribed_markets_ops[market].push_back(std::make_pair(op.op, op.result));
|
||||
}
|
||||
fc::async([=](){
|
||||
for(auto item : subscribed_markets_ops)
|
||||
{
|
||||
auto itr = _market_subscriptions.find(item.first);
|
||||
if(itr != _market_subscriptions.end())
|
||||
itr->second(fc::variant(item.second));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
database_api::~database_api()
|
||||
{
|
||||
try {
|
||||
if(_broadcast_changes_complete.valid())
|
||||
{
|
||||
_broadcast_changes_complete.cancel();
|
||||
_broadcast_changes_complete.wait();
|
||||
}
|
||||
} catch (const fc::exception& e)
|
||||
{
|
||||
wlog("${e}", ("e",e.to_detail_string()));
|
||||
}
|
||||
}
|
||||
|
||||
void database_api::subscribe_to_objects( const std::function<void(const fc::variant&)>& callback, const vector<object_id_type>& ids)
|
||||
{
|
||||
for(auto id : ids) _subscriptions[id] = callback;
|
||||
}
|
||||
|
||||
void database_api::unsubscribe_from_objects(const vector<object_id_type>& ids)
|
||||
{
|
||||
for(auto id : ids) _subscriptions.erase(id);
|
||||
}
|
||||
|
||||
void database_api::subscribe_to_market(std::function<void(const variant&)> callback, asset_id_type a, asset_id_type b)
|
||||
{
|
||||
if(a > b) std::swap(a,b);
|
||||
FC_ASSERT(a != b);
|
||||
_market_subscriptions[ std::make_pair(a,b) ] = callback;
|
||||
}
|
||||
|
||||
void database_api::unsubscribe_from_market(asset_id_type a, asset_id_type b)
|
||||
{
|
||||
if(a > b) std::swap(a,b);
|
||||
FC_ASSERT(a != b);
|
||||
_market_subscriptions.erase(std::make_pair(a,b));
|
||||
}
|
||||
|
||||
std::string database_api::get_transaction_hex(const signed_transaction& trx)const
|
||||
{
|
||||
return fc::to_hex(fc::raw::pack(trx));
|
||||
}
|
||||
|
||||
vector<operation_history_object> history_api::get_account_history(account_id_type account, operation_history_id_type stop, int limit, operation_history_id_type start) const
|
||||
{
|
||||
FC_ASSERT(_app.chain_database());
|
||||
const auto& db = *_app.chain_database();
|
||||
FC_ASSERT(limit <= 100);
|
||||
vector<operation_history_object> result;
|
||||
const auto& stats = account(db).statistics(db);
|
||||
if(stats.most_recent_op == account_transaction_history_id_type()) return result;
|
||||
const account_transaction_history_object* node = &stats.most_recent_op(db);
|
||||
if(start == operation_history_id_type())
|
||||
start = node->id;
|
||||
while(node && node->operation_id.instance.value > stop.instance.value && result.size() < limit)
|
||||
{
|
||||
if(node->id.instance() <= start.instance.value)
|
||||
result.push_back(node->operation_id(db));
|
||||
if(node->next == account_transaction_history_id_type())
|
||||
node = nullptr;
|
||||
else node = db.find(node->next);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} } // graphene::app
|
||||
492
libraries/app/application.cpp
Normal file
492
libraries/app/application.cpp
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/app/application.hpp>
|
||||
#include <graphene/app/plugin.hpp>
|
||||
#include <graphene/app/api.hpp>
|
||||
|
||||
#include <graphene/net/core_messages.hpp>
|
||||
|
||||
#include <graphene/time/time.hpp>
|
||||
|
||||
#include <graphene/utilities/key_conversion.hpp>
|
||||
|
||||
#include <fc/rpc/api_connection.hpp>
|
||||
#include <fc/rpc/websocket_api.hpp>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <fc/log/file_appender.hpp>
|
||||
#include <fc/log/logger.hpp>
|
||||
#include <fc/log/logger_config.hpp>
|
||||
|
||||
namespace graphene { namespace app {
|
||||
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 std::vector;
|
||||
|
||||
namespace detail {
|
||||
|
||||
class application_impl : public net::node_delegate
|
||||
{
|
||||
public:
|
||||
fc::optional<fc::temp_file> _lock_file;
|
||||
bool _is_block_producer = false;
|
||||
|
||||
void reset_p2p_node(const fc::path& data_dir)
|
||||
{ try {
|
||||
_p2p_network = std::make_shared<net::node>("Graphene Reference Implementation");
|
||||
|
||||
_p2p_network->load_configuration(data_dir / "p2p");
|
||||
_p2p_network->set_node_delegate(this);
|
||||
|
||||
if( _options->count("seed-node") )
|
||||
{
|
||||
auto seeds = _options->at("seed-node").as<vector<string>>();
|
||||
for( const string& ep : seeds )
|
||||
{
|
||||
fc::ip::endpoint node = fc::ip::endpoint::from_string(ep);
|
||||
ilog("Adding seed node ${ip}", ("ip", node));
|
||||
_p2p_network->add_node(node);
|
||||
_p2p_network->connect_to_endpoint(node);
|
||||
}
|
||||
}
|
||||
|
||||
if( _options->count("p2p-endpoint") )
|
||||
_p2p_network->listen_on_endpoint(fc::ip::endpoint::from_string(_options->at("p2p-endpoint").as<string>()), true);
|
||||
else
|
||||
_p2p_network->listen_on_port(0, false);
|
||||
_p2p_network->listen_to_p2p_network();
|
||||
ilog("Configured p2p node to listen on ${ip}", ("ip", _p2p_network->get_actual_listening_endpoint()));
|
||||
|
||||
_p2p_network->connect_to_p2p_network();
|
||||
_p2p_network->sync_from(net::item_id(net::core_message_type_enum::block_message_type,
|
||||
_chain_db->head_block_id()),
|
||||
std::vector<uint32_t>());
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
void reset_websocket_server()
|
||||
{ try {
|
||||
if( !_options->count("rpc-endpoint") )
|
||||
return;
|
||||
|
||||
_websocket_server = std::make_shared<fc::http::websocket_server>();
|
||||
|
||||
_websocket_server->on_connection([&]( const fc::http::websocket_connection_ptr& c ){
|
||||
auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(*c);
|
||||
auto login = std::make_shared<graphene::app::login_api>( std::ref(*_self) );
|
||||
auto db_api = std::make_shared<graphene::app::database_api>( std::ref(*_self->chain_database()) );
|
||||
wsc->register_api(fc::api<graphene::app::database_api>(db_api));
|
||||
wsc->register_api(fc::api<graphene::app::login_api>(login));
|
||||
c->set_session_data( wsc );
|
||||
});
|
||||
_websocket_server->listen( fc::ip::endpoint::from_string(_options->at("rpc-endpoint").as<string>()) );
|
||||
_websocket_server->start_accept();
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
|
||||
void reset_websocket_tls_server()
|
||||
{ try {
|
||||
if( !_options->count("rpc-tls-endpoint") )
|
||||
return;
|
||||
if( !_options->count("server-pem") )
|
||||
return;
|
||||
|
||||
string password = _options->count("server-pem-password") ? _options->at("server-pem-password").as<string>() : "";
|
||||
_websocket_tls_server = std::make_shared<fc::http::websocket_tls_server>( _options->at("server-pem").as<string>(), password );
|
||||
|
||||
_websocket_tls_server->on_connection([&]( const fc::http::websocket_connection_ptr& c ){
|
||||
auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(*c);
|
||||
auto login = std::make_shared<graphene::app::login_api>( std::ref(*_self) );
|
||||
auto db_api = std::make_shared<graphene::app::database_api>( std::ref(*_self->chain_database()) );
|
||||
wsc->register_api(fc::api<graphene::app::database_api>(db_api));
|
||||
wsc->register_api(fc::api<graphene::app::login_api>(login));
|
||||
c->set_session_data( wsc );
|
||||
});
|
||||
_websocket_tls_server->listen( fc::ip::endpoint::from_string(_options->at("rpc-tls-endpoint").as<string>()) );
|
||||
_websocket_tls_server->start_accept();
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
application_impl(application* self)
|
||||
: _self(self),
|
||||
_chain_db(std::make_shared<chain::database>())
|
||||
{
|
||||
}
|
||||
|
||||
~application_impl()
|
||||
{
|
||||
fc::remove_all(_data_dir / "blockchain/dblock");
|
||||
}
|
||||
|
||||
void startup()
|
||||
{ try {
|
||||
bool clean = !fc::exists(_data_dir / "blockchain/dblock");
|
||||
fc::create_directories(_data_dir / "blockchain/dblock");
|
||||
|
||||
auto nathan_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("nathan")));
|
||||
genesis_allocation initial_allocation = {{graphene::chain::public_key_type(nathan_key.get_public_key()), 1}};
|
||||
if( _options->count("genesis-json") )
|
||||
initial_allocation = fc::json::from_file(_options->at("genesis-json").as<boost::filesystem::path>()).as<genesis_allocation>();
|
||||
else
|
||||
dlog("Allocating all stake to ${key}", ("key", utilities::key_to_wif(nathan_key)));
|
||||
|
||||
if( _options->count("resync-blockchain") )
|
||||
_chain_db->wipe(_data_dir / "blockchain", true);
|
||||
|
||||
if( _options->count("replay-blockchain") )
|
||||
{
|
||||
ilog("Replaying blockchain on user request.");
|
||||
_chain_db->reindex(_data_dir/"blockchain", initial_allocation);
|
||||
} else if( clean )
|
||||
_chain_db->open(_data_dir / "blockchain", initial_allocation);
|
||||
else {
|
||||
wlog("Detected unclean shutdown. Replaying blockchain...");
|
||||
_chain_db->reindex(_data_dir / "blockchain", initial_allocation);
|
||||
}
|
||||
|
||||
reset_p2p_node(_data_dir);
|
||||
reset_websocket_server();
|
||||
reset_websocket_tls_server();
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
/**
|
||||
* 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) ) }
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @returns true if this message caused the blockchain to switch forks, false if it did not
|
||||
*
|
||||
* @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 ) override
|
||||
{ try {
|
||||
ilog("Got block #${n} from network", ("n", blk_msg.block.block_num()));
|
||||
try {
|
||||
return _chain_db->push_block( blk_msg.block, _is_block_producer? database::skip_nothing : database::skip_transaction_signatures );
|
||||
} catch( const fc::exception& e ) {
|
||||
elog("Error when pushing block:\n${e}", ("e", e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW( (blk_msg)(sync_mode) ) }
|
||||
|
||||
virtual bool handle_transaction( const graphene::net::trx_message& trx_msg, bool sync_mode ) override
|
||||
{ try {
|
||||
ilog("Got transaction from network");
|
||||
_chain_db->push_transaction( trx_msg.trx );
|
||||
return false;
|
||||
} FC_CAPTURE_AND_RETHROW( (trx_msg)(sync_mode) ) }
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* On return, remaining_item_count will be set to the number of items
|
||||
* 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<item_hash_t> get_item_ids(uint32_t item_type,
|
||||
const std::vector<item_hash_t>& blockchain_synopsis,
|
||||
uint32_t& remaining_item_count,
|
||||
uint32_t limit ) override
|
||||
{ try {
|
||||
FC_ASSERT( item_type == graphene::net::block_message_type );
|
||||
vector<block_id_type> result;
|
||||
remaining_item_count = 0;
|
||||
if( _chain_db->head_block_num() == 0 )
|
||||
return result;
|
||||
|
||||
result.reserve(limit);
|
||||
block_id_type last_known_block_id;
|
||||
auto itr = blockchain_synopsis.rbegin();
|
||||
while( itr != blockchain_synopsis.rend() )
|
||||
{
|
||||
if( _chain_db->is_known_block( *itr ) || *itr == block_id_type() )
|
||||
{
|
||||
last_known_block_id = *itr;
|
||||
break;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
|
||||
for( auto num = block_header::num_from_id(last_known_block_id);
|
||||
num <= _chain_db->head_block_num() && result.size() < limit;
|
||||
++num )
|
||||
if( num > 0 )
|
||||
result.push_back(_chain_db->get_block_id_for_num(num));
|
||||
|
||||
if( 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());
|
||||
|
||||
idump((blockchain_synopsis)(limit)(result)(remaining_item_count));
|
||||
return result;
|
||||
} 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 )
|
||||
{
|
||||
auto opt_block = _chain_db->fetch_block_by_id( id.item_hash );
|
||||
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() );
|
||||
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 fc::sha256 get_chain_id()const override
|
||||
{
|
||||
return _chain_db->get_global_properties().chain_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a synopsis of the blockchain used for syncing.
|
||||
* This consists of a list of selected item hashes from our current preferred
|
||||
* blockchain, exponentially falling off into the past. Horrible explanation.
|
||||
*
|
||||
* If the blockchain is empty, it will return the empty list.
|
||||
* If the blockchain has one block, it will return a list containing just that block.
|
||||
* If it contains more than one block:
|
||||
* the first element in the list will be the hash of the genesis block
|
||||
* the second element will be the hash of an item at the half way point in the blockchain
|
||||
* the third will be ~3/4 of the way through the block chain
|
||||
* the fourth will be at ~7/8...
|
||||
* &c.
|
||||
* the last item in the list will be the hash of the most recent block on our preferred chain
|
||||
*/
|
||||
virtual std::vector<item_hash_t> get_blockchain_synopsis( uint32_t item_type,
|
||||
const graphene::net::item_hash_t& reference_point,
|
||||
uint32_t number_of_blocks_after_reference_point ) override
|
||||
{ try {
|
||||
std::vector<item_hash_t> result;
|
||||
result.reserve(30);
|
||||
auto head_block_num = _chain_db->head_block_num();
|
||||
result.push_back( _chain_db->head_block_id() );
|
||||
auto current = 1;
|
||||
while( current < head_block_num )
|
||||
{
|
||||
result.push_back( _chain_db->get_block_id_for_num( head_block_num - current ) );
|
||||
current = current*2;
|
||||
}
|
||||
std::reverse( result.begin(), result.end() );
|
||||
idump((reference_point)(number_of_blocks_after_reference_point)(result));
|
||||
return result;
|
||||
} FC_CAPTURE_AND_RETHROW( (reference_point)(number_of_blocks_after_reference_point) ) }
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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) ) }
|
||||
|
||||
/**
|
||||
* 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;
|
||||
return fc::time_point_sec::min();
|
||||
} FC_CAPTURE_AND_RETHROW( (block_id) ) }
|
||||
|
||||
/** returns graphene::time::now() */
|
||||
virtual fc::time_point_sec get_blockchain_now() override
|
||||
{
|
||||
return graphene::time::now();
|
||||
}
|
||||
|
||||
virtual item_hash_t get_head_block_id() const override
|
||||
{
|
||||
return _chain_db->head_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 void error_encountered(const std::string& message, const fc::oexception& error) override
|
||||
{
|
||||
// notify GUI or something cool
|
||||
}
|
||||
|
||||
application* _self;
|
||||
|
||||
fc::path _data_dir;
|
||||
const bpo::variables_map* _options = nullptr;
|
||||
|
||||
std::shared_ptr<graphene::chain::database> _chain_db;
|
||||
std::shared_ptr<graphene::net::node> _p2p_network;
|
||||
std::shared_ptr<fc::http::websocket_server> _websocket_server;
|
||||
std::shared_ptr<fc::http::websocket_tls_server> _websocket_tls_server;
|
||||
|
||||
std::map<string, std::shared_ptr<abstract_plugin>> _plugins;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
application::application()
|
||||
: my(new detail::application_impl(this))
|
||||
{}
|
||||
|
||||
application::~application()
|
||||
{
|
||||
if( my->_p2p_network )
|
||||
{
|
||||
ilog("Closing p2p node");
|
||||
my->_p2p_network->close();
|
||||
my->_p2p_network.reset();
|
||||
}
|
||||
if( my->_chain_db )
|
||||
{
|
||||
ilog("Closing chain database");
|
||||
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<string>(), "Endpoint for P2P node to listen on")
|
||||
("seed-node,s", bpo::value<vector<string>>()->composing(), "P2P nodes to connect to on startup (may specify multiple times)")
|
||||
("rpc-endpoint", bpo::value<string>()->implicit_value("127.0.0.1:8090"), "Endpoint for websocket RPC to listen on")
|
||||
("rpc-tls-endpoint", bpo::value<string>()->implicit_value("127.0.0.1:8089"), "Endpoint for TLS websocket RPC to listen on")
|
||||
("server-pem,p", bpo::value<string>()->implicit_value("server.pem"), "The TLS certificate file for this server")
|
||||
("server-pem-password,P", bpo::value<string>()->implicit_value(""), "Password for this certificate")
|
||||
("genesis-json", bpo::value<boost::filesystem::path>(), "File to read Genesis State from")
|
||||
;
|
||||
command_line_options.add(configuration_file_options);
|
||||
command_line_options.add_options()
|
||||
("replay-blockchain", "Rebuild object graph by replaying all blocks")
|
||||
("resync-blockchain", "Delete all blocks and re-sync with network from scratch")
|
||||
;
|
||||
command_line_options.add(_cli_options);
|
||||
configuration_file_options.add(_cfg_options);
|
||||
}
|
||||
|
||||
void application::initialize(const fc::path& data_dir, const boost::program_options::variables_map& options)
|
||||
{
|
||||
my->_data_dir = data_dir;
|
||||
my->_options = &options;
|
||||
}
|
||||
|
||||
void application::startup()
|
||||
{
|
||||
my->startup();
|
||||
}
|
||||
|
||||
std::shared_ptr<abstract_plugin> application::get_plugin(const string& name) const
|
||||
{
|
||||
return my->_plugins[name];
|
||||
}
|
||||
|
||||
net::node_ptr application::p2p_node()
|
||||
{
|
||||
return my->_p2p_network;
|
||||
}
|
||||
|
||||
std::shared_ptr<chain::database> application::chain_database() const
|
||||
{
|
||||
return my->_chain_db;
|
||||
}
|
||||
|
||||
void application::set_block_production(bool producing_blocks)
|
||||
{
|
||||
my->_is_block_producer = producing_blocks;
|
||||
}
|
||||
|
||||
void graphene::app::application::add_plugin(const string& name, std::shared_ptr<graphene::app::abstract_plugin> p)
|
||||
{
|
||||
my->_plugins[name] = p;
|
||||
}
|
||||
|
||||
void application::shutdown_plugins()
|
||||
{
|
||||
for( auto& entry : my->_plugins )
|
||||
entry.second->plugin_shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
void application::initialize_plugins( const boost::program_options::variables_map& options )
|
||||
{
|
||||
for( auto& entry : my->_plugins )
|
||||
entry.second->plugin_initialize( options );
|
||||
return;
|
||||
}
|
||||
|
||||
void application::startup_plugins()
|
||||
{
|
||||
for( auto& entry : my->_plugins )
|
||||
entry.second->plugin_startup();
|
||||
return;
|
||||
}
|
||||
|
||||
// namespace detail
|
||||
} }
|
||||
363
libraries/app/include/graphene/app/api.hpp
Normal file
363
libraries/app/include/graphene/app/api.hpp
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/types.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/operation_history_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/limit_order_object.hpp>
|
||||
#include <graphene/chain/short_order_object.hpp>
|
||||
#include <graphene/chain/key_object.hpp>
|
||||
#include <graphene/net/node.hpp>
|
||||
#include <fc/api.hpp>
|
||||
|
||||
namespace graphene { namespace app {
|
||||
using namespace graphene::chain;
|
||||
|
||||
class application;
|
||||
|
||||
/**
|
||||
* @brief The database_api class implements the RPC API for the chain database.
|
||||
*
|
||||
* This API exposes accessors on the database which query state tracked by a blockchain validating node. This API is
|
||||
* read-only; all modifications to the database must be performed via transactions. Transactions are broadcast via
|
||||
* the @ref network_api.
|
||||
*/
|
||||
class database_api
|
||||
{
|
||||
public:
|
||||
database_api(graphene::chain::database& db);
|
||||
~database_api();
|
||||
/**
|
||||
* @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<object_id_type>& ids)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<block_header> get_block_header(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<signed_block> get_block(uint32_t block_num)const;
|
||||
/**
|
||||
* @brief Retrieve the current @ref global_property_object
|
||||
*/
|
||||
global_property_object get_global_properties()const;
|
||||
/**
|
||||
* @brief Retrieve the current @ref dynamic_global_property_object
|
||||
*/
|
||||
dynamic_global_property_object get_dynamic_global_properties()const;
|
||||
/**
|
||||
* @brief Get a list of keys by ID
|
||||
* @param key_ids IDs of the keys to retrieve
|
||||
* @return The keys corresponding to the provided IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<key_object>> get_keys(const vector<key_id_type>& key_ids)const;
|
||||
/**
|
||||
* @brief Get a list of accounts by ID
|
||||
* @param account_ids IDs of the accounts to retrieve
|
||||
* @return The accounts corresponding to the provided IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<account_object>> get_accounts(const vector<account_id_type>& account_ids)const;
|
||||
/**
|
||||
* @brief Get a list of assets by ID
|
||||
* @param asset_ids IDs of the assets to retrieve
|
||||
* @return The assets corresponding to the provided IDs
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<asset_object>> get_assets(const vector<asset_id_type>& asset_ids)const;
|
||||
/**
|
||||
* @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<optional<account_object>> lookup_account_names(const vector<string>& account_names)const;
|
||||
/**
|
||||
* @brief Get a list of assets by symbol
|
||||
* @param asset_symbols Symbols of the assets to retrieve
|
||||
* @return The assets corresponding to the provided symbols
|
||||
*
|
||||
* This function has semantics identical to @ref get_objects
|
||||
*/
|
||||
vector<optional<asset_object>> lookup_asset_symbols(const vector<string>& asset_symbols)const;
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @return Balances of the account
|
||||
*/
|
||||
vector<asset> get_account_balances(account_id_type id, const flat_set<asset_id_type>& assets)const;
|
||||
/// Semantically equivalent to @ref get_account_balances, but takes a name instead of an ID.
|
||||
vector<asset> get_named_account_balances(const std::string& name, const flat_set<asset_id_type>& assets)const;
|
||||
/**
|
||||
* @brief Get the total number of accounts registered with the blockchain
|
||||
*/
|
||||
uint64_t get_account_count()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<string,account_id_type> lookup_accounts(const string& lower_bound_name, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @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<limit_order_object> get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const;
|
||||
/**
|
||||
* @brief Get short orders in a given asset
|
||||
* @param a ID of asset being sold
|
||||
* @param limit Maximum number of orders to retrieve
|
||||
* @return The short orders, ordered from least price to greatest
|
||||
*/
|
||||
vector<short_order_object> get_short_orders(asset_id_type a, uint32_t limit)const;
|
||||
/**
|
||||
* @brief Get call orders in a given asset
|
||||
* @param a ID of asset being called
|
||||
* @param limit Maximum number of orders to retrieve
|
||||
* @return The call orders, ordered from earliest to be called to latest
|
||||
*/
|
||||
vector<call_order_object> get_call_orders(asset_id_type a, uint32_t limit)const;
|
||||
/**
|
||||
* @brief Get forced settlement orders in a given asset
|
||||
* @param a ID of asset being settled
|
||||
* @param limit Maximum number of orders to retrieve
|
||||
* @return The settle orders, ordered from earliest settlement date to latest
|
||||
*/
|
||||
vector<force_settlement_object> get_settle_orders(asset_id_type a, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @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<asset_object> list_assets(const string& lower_bound_symbol, uint32_t limit)const;
|
||||
|
||||
/**
|
||||
* @group Push Notification Methods
|
||||
* These methods may be used to get push notifications whenever an object or market is changed
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Request notifications when some object(s) change
|
||||
* @param callback Callback method which is called with the new version of a changed object
|
||||
* @param ids The set of object IDs to watch
|
||||
*/
|
||||
void subscribe_to_objects(const std::function<void(const fc::variant&)>& callback,
|
||||
const vector<object_id_type>& ids);
|
||||
/**
|
||||
* @brief Stop receiving notifications for some object(s)
|
||||
* @param ids The set of object IDs to stop watching
|
||||
*/
|
||||
void unsubscribe_from_objects(const vector<object_id_type>& ids);
|
||||
/**
|
||||
* @brief Request notification when the active orders in the market between two assets changes
|
||||
* @param callback Callback method which is called when the market changes
|
||||
* @param a First asset ID
|
||||
* @param b Second asset ID
|
||||
*
|
||||
* Callback will be passed a variant containing a vector<pair<operation, operation_result>>. The vector will
|
||||
* contain, in order, the operations which changed the market, and their results.
|
||||
*/
|
||||
void subscribe_to_market(std::function<void(const variant&)> callback,
|
||||
asset_id_type a, asset_id_type b);
|
||||
/**
|
||||
* @brief Unsubscribe from updates to a given market
|
||||
* @param a First asset ID
|
||||
* @param b Second asset ID
|
||||
*/
|
||||
void unsubscribe_from_market(asset_id_type a, asset_id_type b);
|
||||
/**
|
||||
* @brief Stop receiving any notifications
|
||||
*
|
||||
* This unsubscribes from all subscribed markets and objects.
|
||||
*/
|
||||
void cancel_all_subscriptions()
|
||||
{ _subscriptions.clear(); _market_subscriptions.clear(); }
|
||||
///@}
|
||||
|
||||
/// @brief Get a hexdump of the serialized binary form of a transaction
|
||||
std::string get_transaction_hex(const signed_transaction& trx)const;
|
||||
private:
|
||||
/** called every time a block is applied to report the objects that were changed */
|
||||
void on_objects_changed(const vector<object_id_type>& ids);
|
||||
void on_applied_block();
|
||||
|
||||
fc::future<void> _broadcast_changes_complete;
|
||||
boost::signals2::scoped_connection _change_connection;
|
||||
boost::signals2::scoped_connection _applied_block_connection;
|
||||
map<object_id_type, std::function<void(const fc::variant&)> > _subscriptions;
|
||||
map< pair<asset_id_type,asset_id_type>, std::function<void(const variant&)> > _market_subscriptions;
|
||||
graphene::chain::database& _db;
|
||||
};
|
||||
|
||||
/**
|
||||
* @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){}
|
||||
|
||||
/**
|
||||
* @brief Get operations relevant to the specificed account
|
||||
* @param account The account whose history should be queried
|
||||
* @param stop ID of the earliest operation to retrieve
|
||||
* @param limit Maximum number of operations to retrieve (must not exceed 100)
|
||||
* @param start ID of the most recent operation to retrieve
|
||||
* @return A list of operations performed by account, ordered from most recent to oldest.
|
||||
*/
|
||||
vector<operation_history_object> get_account_history(account_id_type account,
|
||||
operation_history_id_type stop = operation_history_id_type(),
|
||||
int limit = 100,
|
||||
operation_history_id_type start = operation_history_id_type())const;
|
||||
|
||||
private:
|
||||
application& _app;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The network_api class implements the RPC API for the network
|
||||
*
|
||||
* This API has methods to query the network status, connect to new peers, and send transactions.
|
||||
*/
|
||||
class network_api
|
||||
{
|
||||
public:
|
||||
network_api(application& a):_app(a){}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
/**
|
||||
* @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);
|
||||
/**
|
||||
* @brief Get status of all current connections to peers
|
||||
*/
|
||||
std::vector<net::peer_status> get_connected_peers() const;
|
||||
|
||||
private:
|
||||
application& _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();
|
||||
|
||||
/**
|
||||
* @brief Authenticate to the RPC server
|
||||
* @param user Username to login with
|
||||
* @param password Password to login with
|
||||
* @return True if logged in successfully; false otherwise
|
||||
*
|
||||
* @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 API
|
||||
fc::api<network_api> network()const;
|
||||
/// @brief Retrieve the database API
|
||||
fc::api<database_api> database()const;
|
||||
/// @brief Retrieve the history API
|
||||
fc::api<history_api> history()const;
|
||||
|
||||
private:
|
||||
application& _app;
|
||||
optional< fc::api<database_api> > _database_api;
|
||||
optional< fc::api<network_api> > _network_api;
|
||||
optional< fc::api<history_api> > _history_api;
|
||||
};
|
||||
|
||||
}} // graphene::app
|
||||
|
||||
FC_API(graphene::app::database_api,
|
||||
(get_objects)
|
||||
(get_block_header)
|
||||
(get_block)
|
||||
(get_global_properties)
|
||||
(get_dynamic_global_properties)
|
||||
(get_keys)
|
||||
(get_accounts)
|
||||
(get_assets)
|
||||
(lookup_account_names)
|
||||
(get_account_count)
|
||||
(lookup_accounts)
|
||||
(get_account_balances)
|
||||
(get_named_account_balances)
|
||||
(lookup_asset_symbols)
|
||||
(get_limit_orders)
|
||||
(get_short_orders)
|
||||
(get_call_orders)
|
||||
(get_settle_orders)
|
||||
(list_assets)
|
||||
(subscribe_to_objects)
|
||||
(unsubscribe_from_objects)
|
||||
(subscribe_to_market)
|
||||
(unsubscribe_from_market)
|
||||
(cancel_all_subscriptions)
|
||||
(get_transaction_hex)
|
||||
)
|
||||
FC_API(graphene::app::history_api, (get_account_history))
|
||||
FC_API(graphene::app::network_api, (broadcast_transaction)(add_node)(get_connected_peers))
|
||||
FC_API(graphene::app::login_api,
|
||||
(login)
|
||||
(network)
|
||||
(database)
|
||||
(history)
|
||||
)
|
||||
87
libraries/app/include/graphene/app/application.hpp
Normal file
87
libraries/app/include/graphene/app/application.hpp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/net/node.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
namespace graphene { namespace app {
|
||||
namespace detail { class application_impl; }
|
||||
namespace bpo = boost::program_options;
|
||||
using std::string;
|
||||
|
||||
class abstract_plugin;
|
||||
|
||||
class application
|
||||
{
|
||||
public:
|
||||
application();
|
||||
~application();
|
||||
|
||||
void set_program_options( bpo::options_description& command_line_options,
|
||||
bpo::options_description& configuration_file_options )const;
|
||||
void initialize(const fc::path& data_dir, const bpo::variables_map&options);
|
||||
void initialize_plugins( const bpo::variables_map& options );
|
||||
void startup();
|
||||
void shutdown();
|
||||
void startup_plugins();
|
||||
void shutdown_plugins();
|
||||
|
||||
template<typename PluginType>
|
||||
std::shared_ptr<PluginType> register_plugin()
|
||||
{
|
||||
auto plug = std::make_shared<PluginType>();
|
||||
plug->plugin_set_app(this);
|
||||
|
||||
bpo::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);
|
||||
if( !plugin_cfg_options.options().empty() )
|
||||
_cfg_options.add(plugin_cfg_options);
|
||||
|
||||
add_plugin( plug->plugin_name(), plug );
|
||||
return plug;
|
||||
}
|
||||
std::shared_ptr<abstract_plugin> get_plugin( const string& name )const;
|
||||
|
||||
template<typename PluginType>
|
||||
std::shared_ptr<PluginType> get_plugin( const string& name ) const
|
||||
{
|
||||
std::shared_ptr<abstract_plugin> abs_plugin = get_plugin( name );
|
||||
std::shared_ptr<PluginType> result = std::dynamic_pointer_cast<PluginType>( abs_plugin );
|
||||
FC_ASSERT( result != std::shared_ptr<PluginType>() );
|
||||
return result;
|
||||
}
|
||||
|
||||
net::node_ptr p2p_node();
|
||||
std::shared_ptr<chain::database> chain_database()const;
|
||||
|
||||
void set_block_production(bool producing_blocks);
|
||||
|
||||
private:
|
||||
void add_plugin( const string& name, std::shared_ptr<abstract_plugin> p );
|
||||
std::shared_ptr<detail::application_impl> my;
|
||||
|
||||
bpo::options_description _cli_options;
|
||||
bpo::options_description _cfg_options;
|
||||
};
|
||||
|
||||
} }
|
||||
131
libraries/app/include/graphene/app/plugin.hpp
Normal file
131
libraries/app/include/graphene/app/plugin.hpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/app/application.hpp>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
namespace graphene { namespace app {
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
class abstract_plugin
|
||||
{
|
||||
public:
|
||||
virtual ~abstract_plugin(){}
|
||||
virtual std::string plugin_name()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 bpo::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 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 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(
|
||||
bpo::options_description& command_line_options,
|
||||
bpo::options_description& config_file_options
|
||||
) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides basic default implementations of abstract_plugin functions.
|
||||
*/
|
||||
|
||||
class plugin : public abstract_plugin
|
||||
{
|
||||
public:
|
||||
plugin();
|
||||
virtual ~plugin() override;
|
||||
|
||||
virtual std::string plugin_name()const override;
|
||||
virtual void plugin_initialize( const bpo::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(
|
||||
bpo::options_description& command_line_options,
|
||||
bpo::options_description& config_file_options
|
||||
) override;
|
||||
|
||||
protected:
|
||||
chain::database& database() { return *app().chain_database(); }
|
||||
application& app()const { assert(_app); return *_app; }
|
||||
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<typename T>
|
||||
T dejsonify(const string& s)
|
||||
{
|
||||
return fc::json::from_string(s).as<T>();
|
||||
}
|
||||
|
||||
#define DEFAULT_VALUE_VECTOR(value) default_value({fc::json::to_string(value)}, fc::json::to_string(value))
|
||||
#define LOAD_VALUE_SET(options, name, container, type) \
|
||||
if( options.count(name) ) { \
|
||||
const std::vector<std::string>& ops = options[name].as<std::vector<std::string>>(); \
|
||||
std::transform(ops.begin(), ops.end(), std::inserter(container, container.end()), &graphene::app::dejsonify<type>); \
|
||||
}
|
||||
/// @}
|
||||
|
||||
} } //graphene::app
|
||||
68
libraries/app/plugin.cpp
Normal file
68
libraries/app/plugin.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <graphene/app/plugin.hpp>
|
||||
|
||||
namespace graphene { namespace app {
|
||||
|
||||
plugin::plugin()
|
||||
{
|
||||
_app = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
plugin::~plugin()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string plugin::plugin_name()const
|
||||
{
|
||||
return "<unknown plugin>";
|
||||
}
|
||||
|
||||
void plugin::plugin_initialize( const bpo::variables_map& options )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void plugin::plugin_startup()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void plugin::plugin_shutdown()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void plugin::plugin_set_app( application* app )
|
||||
{
|
||||
_app = app;
|
||||
return;
|
||||
}
|
||||
|
||||
void plugin::plugin_set_program_options(
|
||||
bpo::options_description& command_line_options,
|
||||
bpo::options_description& config_file_options
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
} } // graphene::app
|
||||
59
libraries/chain/CMakeLists.txt
Normal file
59
libraries/chain/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
file(GLOB HEADERS "include/graphene/chain/*.hpp")
|
||||
|
||||
## SORT .cpp by most likely to change / break compile
|
||||
add_library( graphene_chain
|
||||
types.cpp
|
||||
address.cpp
|
||||
asset.cpp
|
||||
|
||||
operations.cpp
|
||||
|
||||
evaluator.cpp
|
||||
global_parameters_evaluator.cpp
|
||||
account_evaluator.cpp
|
||||
witness_evaluator.cpp
|
||||
delegate_evaluator.cpp
|
||||
asset_evaluator.cpp
|
||||
transfer_evaluator.cpp
|
||||
proposal_evaluator.cpp
|
||||
short_order_evaluator.cpp
|
||||
limit_order_evaluator.cpp
|
||||
bond_evaluator.cpp
|
||||
vesting_balance_evaluator.cpp
|
||||
withdraw_permission_evaluator.cpp
|
||||
worker_evaluator.cpp
|
||||
|
||||
key_object.cpp
|
||||
account_object.cpp
|
||||
asset_object.cpp
|
||||
proposal_object.cpp
|
||||
vesting_balance_object.cpp
|
||||
worker_object.cpp
|
||||
|
||||
transaction.cpp
|
||||
block.cpp
|
||||
|
||||
transaction_evaluation_state.cpp
|
||||
fork_database.cpp
|
||||
|
||||
db_balance.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
|
||||
|
||||
${HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries( graphene_chain fc graphene_db leveldb )
|
||||
target_include_directories( graphene_chain
|
||||
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
|
||||
|
||||
if(MSVC)
|
||||
set_source_files_properties( database.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
|
||||
endif(MSVC)
|
||||
227
libraries/chain/account_evaluator.cpp
Normal file
227
libraries/chain/account_evaluator.cpp
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/account_evaluator.hpp>
|
||||
#include <graphene/chain/key_object.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
object_id_type account_create_evaluator::do_evaluate( const account_create_operation& op )
|
||||
{ try {
|
||||
FC_ASSERT( db().find_object(op.voting_account) );
|
||||
FC_ASSERT( is_relative(op.memo_key) || db().find_object(op.memo_key) );
|
||||
|
||||
if( fee_paying_account->is_prime() )
|
||||
{
|
||||
FC_ASSERT( op.referrer(db()).is_prime() );
|
||||
}
|
||||
else
|
||||
{
|
||||
FC_ASSERT( op.referrer == fee_paying_account->referrer );
|
||||
FC_ASSERT( op.referrer_percent == fee_paying_account->referrer_percent, "",
|
||||
("op",op)
|
||||
("fee_paying_account->referral_percent",fee_paying_account->referrer_percent) );
|
||||
}
|
||||
|
||||
const auto& global_props = db().get_global_properties();
|
||||
uint32_t max_vote_id = global_props.next_available_vote_id;
|
||||
const auto& chain_params = global_props.parameters;
|
||||
FC_ASSERT( op.num_witness <= chain_params.maximum_witness_count );
|
||||
FC_ASSERT( op.num_committee <= chain_params.maximum_committee_count );
|
||||
FC_ASSERT( op.owner.auths.size() <= chain_params.maximum_authority_membership );
|
||||
FC_ASSERT( op.active.auths.size() <= chain_params.maximum_authority_membership );
|
||||
for( auto id : op.owner.auths )
|
||||
{
|
||||
FC_ASSERT( is_relative(id.first) || db().find<object>(id.first) );
|
||||
}
|
||||
for( auto id : op.active.auths )
|
||||
{
|
||||
FC_ASSERT( is_relative(id.first) || db().find<object>(id.first) );
|
||||
}
|
||||
safe<uint32_t> counts[vote_id_type::VOTE_TYPE_COUNT];
|
||||
for( auto id : op.vote )
|
||||
{
|
||||
FC_ASSERT( id < max_vote_id );
|
||||
counts[id.type()]++;
|
||||
}
|
||||
FC_ASSERT(counts[vote_id_type::witness] <= op.num_witness,
|
||||
"",
|
||||
("count", counts[vote_id_type::witness])("num", op.num_witness));
|
||||
FC_ASSERT(counts[vote_id_type::committee] <= op.num_committee,
|
||||
"",
|
||||
("count", counts[vote_id_type::committee])("num", op.num_committee));
|
||||
|
||||
auto& acnt_indx = db().get_index_type<account_index>();
|
||||
if( op.name.size() )
|
||||
{
|
||||
auto current_account_itr = acnt_indx.indices().get<by_name>().find( op.name );
|
||||
FC_ASSERT( current_account_itr == acnt_indx.indices().get<by_name>().end() );
|
||||
}
|
||||
|
||||
// TODO: this check can be removed after GRAPHENE_LEGACY_NAME_IMPORT_PERIOD
|
||||
// legacy account check
|
||||
if( db().get_dynamic_global_properties().head_block_number < GRAPHENE_LEGACY_NAME_IMPORT_PERIOD )
|
||||
{
|
||||
auto legacy_account_itr = acnt_indx.indices().get<by_name>().find( "bts-"+op.name );
|
||||
if( legacy_account_itr != acnt_indx.indices().get<by_name>().end() )
|
||||
{
|
||||
FC_ASSERT( fee_paying_account->id == legacy_account_itr->id );
|
||||
}
|
||||
}
|
||||
|
||||
// verify child account authority
|
||||
auto pos = op.name.find( '/' );
|
||||
if( pos != string::npos )
|
||||
{
|
||||
// TODO: lookup account by op.owner.auths[0] and verify the name
|
||||
// this should be a constant time lookup rather than log(N)
|
||||
auto parent_account_itr = acnt_indx.indices().get<by_name>().find( op.name.substr(0,pos) );
|
||||
FC_ASSERT( parent_account_itr != acnt_indx.indices().get<by_name>().end() );
|
||||
FC_ASSERT( verify_authority( *parent_account_itr, authority::owner ) );
|
||||
FC_ASSERT( op.owner.auths.find( parent_account_itr->id ) != op.owner.auths.end() );
|
||||
}
|
||||
|
||||
return object_id_type();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
object_id_type account_create_evaluator::do_apply( const account_create_operation& o )
|
||||
{ try {
|
||||
auto owner = resolve_relative_ids( o.owner );
|
||||
auto active = resolve_relative_ids( o.active );
|
||||
|
||||
const auto& stats_obj = db().create<account_statistics_object>( [&]( account_statistics_object& ){
|
||||
});
|
||||
|
||||
const auto& new_acnt_object = db().create<account_object>( [&]( account_object& obj ){
|
||||
if( fee_paying_account->is_prime() )
|
||||
{
|
||||
obj.registrar = o.registrar;
|
||||
obj.referrer = o.referrer;
|
||||
obj.referrer_percent = o.referrer_percent;
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.registrar = fee_paying_account->registrar;
|
||||
obj.referrer = fee_paying_account->referrer;
|
||||
obj.referrer_percent = fee_paying_account->referrer_percent;
|
||||
}
|
||||
obj.name = o.name;
|
||||
obj.owner = owner;
|
||||
obj.active = active;
|
||||
obj.statistics = stats_obj.id;
|
||||
obj.memo_key = get_relative_id(o.memo_key);
|
||||
obj.voting_account = o.voting_account;
|
||||
obj.votes = o.vote;
|
||||
obj.num_witness = o.num_witness;
|
||||
obj.num_committee = o.num_committee;
|
||||
});
|
||||
|
||||
return new_acnt_object.id;
|
||||
} FC_CAPTURE_AND_RETHROW((o)) }
|
||||
|
||||
|
||||
object_id_type account_update_evaluator::do_evaluate( const account_update_operation& o )
|
||||
{
|
||||
database& d = db();
|
||||
|
||||
FC_ASSERT( !o.memo_key || is_relative(*o.memo_key) || db().find_object(*o.memo_key) );
|
||||
|
||||
const auto& chain_params = db().get_global_properties().parameters;
|
||||
FC_ASSERT( o.num_witness <= chain_params.maximum_witness_count );
|
||||
FC_ASSERT( o.num_committee <= chain_params.maximum_committee_count );
|
||||
if( o.owner )
|
||||
{
|
||||
FC_ASSERT( o.owner->auths.size() <= chain_params.maximum_authority_membership );
|
||||
for( auto id : o.owner->auths )
|
||||
{
|
||||
FC_ASSERT( is_relative(id.first) || db().find<object>(id.first) );
|
||||
}
|
||||
}
|
||||
if( o.active )
|
||||
{
|
||||
FC_ASSERT( o.active->auths.size() <= chain_params.maximum_authority_membership );
|
||||
for( auto id : o.active->auths )
|
||||
{
|
||||
FC_ASSERT( is_relative(id.first) || db().find<object>(id.first) );
|
||||
}
|
||||
}
|
||||
|
||||
acnt = &o.account(d);
|
||||
if( o.upgrade_to_prime ) FC_ASSERT( !acnt->is_prime() );
|
||||
|
||||
if( o.vote )
|
||||
{
|
||||
uint32_t max_vote_id = d.get_global_properties().next_available_vote_id;
|
||||
for( auto id : *o.vote )
|
||||
{
|
||||
FC_ASSERT( id < max_vote_id );
|
||||
}
|
||||
}
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
object_id_type account_update_evaluator::do_apply( const account_update_operation& o )
|
||||
{
|
||||
db().modify( *acnt, [&]( account_object& a ){
|
||||
if( o.owner ) a.owner = *o.owner;
|
||||
if( o.active ) a.active = *o.active;
|
||||
if( o.voting_account ) a.voting_account = *o.voting_account;
|
||||
if( o.memo_key ) a.memo_key = *o.memo_key;
|
||||
if( o.vote ) a.votes = *o.vote;
|
||||
if( o.upgrade_to_prime )
|
||||
{
|
||||
a.referrer_percent = 100;
|
||||
a.referrer = a.id;
|
||||
}
|
||||
a.num_witness = o.num_witness;
|
||||
a.num_committee = o.num_committee;
|
||||
});
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type account_whitelist_evaluator::do_evaluate(const account_whitelist_operation& o)
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
listed_account = &o.account_to_list(d);
|
||||
if( !d.get_global_properties().parameters.allow_non_prime_whitelists )
|
||||
FC_ASSERT(listed_account->is_prime());
|
||||
|
||||
return object_id_type();
|
||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||
|
||||
object_id_type account_whitelist_evaluator::do_apply(const account_whitelist_operation& o)
|
||||
{
|
||||
database& d = db();
|
||||
|
||||
d.modify(*listed_account, [&o](account_object& a) {
|
||||
if( o.new_listing & o.white_listed )
|
||||
a.whitelisting_accounts.insert(o.authorizing_account);
|
||||
else
|
||||
a.whitelisting_accounts.erase(o.authorizing_account);
|
||||
if( o.new_listing & o.black_listed )
|
||||
a.blacklisting_accounts.insert(o.authorizing_account);
|
||||
else
|
||||
a.blacklisting_accounts.erase(o.authorizing_account);
|
||||
});
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
} } // graphene::chain
|
||||
39
libraries/chain/account_object.cpp
Normal file
39
libraries/chain/account_object.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
bool account_object::is_authorized_asset(const asset_object& asset_obj) const {
|
||||
for( const auto id : blacklisting_accounts )
|
||||
if( asset_obj.options.blacklist_authorities.find(id) != asset_obj.options.blacklist_authorities.end() ) return false;
|
||||
|
||||
for( const auto id : whitelisting_accounts )
|
||||
if( asset_obj.options.whitelist_authorities.find(id) != asset_obj.options.whitelist_authorities.end() ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void account_balance_object::adjust_balance(const asset& delta)
|
||||
{
|
||||
assert(delta.asset_id == asset_type);
|
||||
balance += delta.amount;
|
||||
}
|
||||
|
||||
} } // graphene::chain
|
||||
23
libraries/chain/account_operations.cpp
Normal file
23
libraries/chain/account_operations.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/asset_operations.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
} }
|
||||
102
libraries/chain/address.cpp
Normal file
102
libraries/chain/address.cpp
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/address.hpp>
|
||||
#include <graphene/chain/types.hpp>
|
||||
#include <fc/crypto/elliptic.hpp>
|
||||
#include <fc/crypto/base58.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace graphene {
|
||||
namespace chain {
|
||||
address::address(){}
|
||||
|
||||
address::address( const std::string& base58str )
|
||||
{
|
||||
FC_ASSERT( is_valid( base58str ) );
|
||||
std::string prefix( GRAPHENE_ADDRESS_PREFIX );
|
||||
std::vector<char> v = fc::from_base58( base58str.substr( prefix.size() ) );
|
||||
memcpy( (char*)addr._hash, v.data(), std::min<size_t>( v.size()-4, sizeof( addr ) ) );
|
||||
}
|
||||
|
||||
bool address::is_valid( const std::string& base58str, const std::string& prefix )
|
||||
{
|
||||
const size_t prefix_len = prefix.size();
|
||||
if( base58str.size() <= prefix_len )
|
||||
return false;
|
||||
if( base58str.substr( 0, prefix_len ) != prefix )
|
||||
return false;
|
||||
std::vector<char> v;
|
||||
try
|
||||
{
|
||||
v = fc::from_base58( base58str.substr( prefix_len ) );
|
||||
}
|
||||
catch( const fc::parse_error_exception& e )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if( v.size() != sizeof( fc::ripemd160 ) + 4 )
|
||||
return false;
|
||||
const fc::ripemd160 checksum = fc::ripemd160::hash( v.data(), v.size() - 4 );
|
||||
if( memcmp( v.data() + 20, (char*)checksum._hash, 4 ) != 0 )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
address::address( const fc::ecc::public_key& pub )
|
||||
{
|
||||
auto dat = pub.serialize();
|
||||
addr = fc::ripemd160::hash( fc::sha512::hash( dat.data, sizeof( dat ) ) );
|
||||
}
|
||||
|
||||
address::address( const pts_address& ptsaddr )
|
||||
{
|
||||
addr = fc::ripemd160::hash( (char*)&ptsaddr, sizeof( ptsaddr ) );
|
||||
}
|
||||
|
||||
address::address( const fc::ecc::public_key_data& pub )
|
||||
{
|
||||
addr = fc::ripemd160::hash( fc::sha512::hash( pub.data, sizeof( pub ) ) );
|
||||
}
|
||||
|
||||
address::address( const graphene::chain::public_key_type& pub )
|
||||
{
|
||||
addr = fc::ripemd160::hash( fc::sha512::hash( pub.key_data.data, sizeof( pub.key_data ) ) );
|
||||
}
|
||||
|
||||
address::operator std::string()const
|
||||
{
|
||||
fc::array<char,24> bin_addr;
|
||||
memcpy( (char*)&bin_addr, (char*)&addr, sizeof( addr ) );
|
||||
auto checksum = fc::ripemd160::hash( (char*)&addr, sizeof( addr ) );
|
||||
memcpy( ((char*)&bin_addr)+20, (char*)&checksum._hash[0], 4 );
|
||||
return GRAPHENE_ADDRESS_PREFIX + fc::to_base58( bin_addr.data, sizeof( bin_addr ) );
|
||||
}
|
||||
|
||||
} } // namespace graphene::chain
|
||||
|
||||
namespace fc
|
||||
{
|
||||
void to_variant( const graphene::chain::address& var, variant& vo )
|
||||
{
|
||||
vo = std::string(var);
|
||||
}
|
||||
void from_variant( const variant& var, graphene::chain::address& vo )
|
||||
{
|
||||
vo = graphene::chain::address( var.as_string() );
|
||||
}
|
||||
}
|
||||
138
libraries/chain/asset.cpp
Normal file
138
libraries/chain/asset.cpp
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
bool operator < ( const asset& a, const asset& b )
|
||||
{
|
||||
return std::tie( a.asset_id, a.amount ) < std::tie( b.asset_id, b.amount);
|
||||
}
|
||||
bool operator <= ( const asset& a, const asset& b )
|
||||
{
|
||||
return std::tie( a.asset_id, a.amount ) <= std::tie( b.asset_id, b.amount);
|
||||
}
|
||||
bool operator < ( const price& a, const price& b )
|
||||
{
|
||||
if( a.base.asset_id < b.base.asset_id ) return true;
|
||||
if( a.base.asset_id > b.base.asset_id ) return false;
|
||||
if( a.quote.asset_id < b.quote.asset_id ) return true;
|
||||
if( a.quote.asset_id > b.quote.asset_id ) return false;
|
||||
auto amult = fc::uint128(b.quote.amount.value) * a.base.amount.value;
|
||||
auto bmult = fc::uint128(a.quote.amount.value) * b.base.amount.value;
|
||||
assert( (a.to_real() < b.to_real()) == (amult < bmult) );
|
||||
return amult < bmult;
|
||||
}
|
||||
bool operator <= ( const price& a, const price& b )
|
||||
{
|
||||
if( a.base.asset_id < b.base.asset_id ) return true;
|
||||
if( a.base.asset_id > b.base.asset_id ) return false;
|
||||
if( a.quote.asset_id < b.quote.asset_id ) return true;
|
||||
if( a.quote.asset_id > b.quote.asset_id ) return false;
|
||||
auto amult = fc::uint128(b.quote.amount.value) * a.base.amount.value;
|
||||
auto bmult = fc::uint128(a.quote.amount.value) * b.base.amount.value;
|
||||
assert( (a.to_real() <= b.to_real()) == (amult <= bmult) );
|
||||
return amult <= bmult;
|
||||
}
|
||||
bool operator == ( const price& a, const price& b )
|
||||
{
|
||||
if( a.base.asset_id < b.base.asset_id ) return true;
|
||||
if( a.base.asset_id > b.base.asset_id ) return false;
|
||||
if( a.quote.asset_id < b.quote.asset_id ) return true;
|
||||
if( a.quote.asset_id > b.quote.asset_id ) return false;
|
||||
auto amult = fc::uint128(a.quote.amount.value) * b.base.amount.value;
|
||||
auto bmult = fc::uint128(b.quote.amount.value) * a.base.amount.value;
|
||||
return amult == bmult;
|
||||
}
|
||||
bool operator != ( const price& a, const price& b )
|
||||
{
|
||||
return !(a==b);
|
||||
}
|
||||
|
||||
bool operator >= ( const price& a, const price& b )
|
||||
{
|
||||
return !(a < b);
|
||||
}
|
||||
bool operator > ( const price& a, const price& b )
|
||||
{
|
||||
return !(a <= b);
|
||||
}
|
||||
|
||||
asset operator * ( const asset& a, const price& b )
|
||||
{
|
||||
if( a.asset_id == b.base.asset_id )
|
||||
{
|
||||
FC_ASSERT( b.base.amount.value > 0 );
|
||||
auto result = (fc::uint128(a.amount.value) * b.quote.amount.value)/b.base.amount.value;
|
||||
FC_ASSERT( result <= GRAPHENE_MAX_SHARE_SUPPLY );
|
||||
return asset( result.to_uint64(), b.quote.asset_id );
|
||||
}
|
||||
else if( a.asset_id == b.quote.asset_id )
|
||||
{
|
||||
FC_ASSERT( b.quote.amount.value > 0 );
|
||||
auto result = (fc::uint128(a.amount.value) * b.base.amount.value)/b.quote.amount.value;
|
||||
FC_ASSERT( result <= GRAPHENE_MAX_SHARE_SUPPLY );
|
||||
return asset( result.to_uint64(), b.base.asset_id );
|
||||
}
|
||||
FC_ASSERT( !"invalid asset * price", "", ("asset",a)("price",b) );
|
||||
}
|
||||
|
||||
price operator / ( const asset& base, const asset& quote )
|
||||
{
|
||||
FC_ASSERT( base.asset_id != quote.asset_id );
|
||||
return price{base,quote};
|
||||
}
|
||||
price price::max( asset_id_type base, asset_id_type quote ) { return asset( share_type(GRAPHENE_MAX_SHARE_SUPPLY), base ) / asset( share_type(1), quote); }
|
||||
price price::min( asset_id_type base, asset_id_type quote ) { return asset( 1, base ) / asset( GRAPHENE_MAX_SHARE_SUPPLY, quote); }
|
||||
|
||||
price price::call_price(const asset& debt, const asset& collateral, uint16_t collateral_ratio)
|
||||
{
|
||||
fc::uint128 tmp( collateral.amount.value );
|
||||
tmp *= collateral_ratio - 1000;
|
||||
tmp /= 1000;
|
||||
FC_ASSERT( tmp <= GRAPHENE_MAX_SHARE_SUPPLY );
|
||||
return asset( tmp.to_uint64(), collateral.asset_id) / debt;
|
||||
}
|
||||
|
||||
bool price::is_null() const { return *this == price(); }
|
||||
|
||||
void price::validate() const
|
||||
{ try {
|
||||
FC_ASSERT( base.amount > share_type(0) );
|
||||
FC_ASSERT( quote.amount > share_type(0) );
|
||||
FC_ASSERT( base.asset_id != quote.asset_id );
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
void price_feed::validate() const
|
||||
{ try {
|
||||
if( !call_limit.is_null() )
|
||||
call_limit.validate();
|
||||
if( !short_limit.is_null() )
|
||||
short_limit.validate();
|
||||
if( !settlement_price.is_null() )
|
||||
settlement_price.validate();
|
||||
FC_ASSERT( call_limit.is_null() == short_limit.is_null() );
|
||||
FC_ASSERT( call_limit.base.asset_id == short_limit.quote.asset_id );
|
||||
FC_ASSERT( call_limit.quote.asset_id == short_limit.base.asset_id );
|
||||
FC_ASSERT( max_margin_period_sec > 0 );
|
||||
FC_ASSERT( required_maintenance_collateral < required_initial_collateral );
|
||||
FC_ASSERT( required_maintenance_collateral >= 1000 );
|
||||
FC_ASSERT( call_limit.is_null() || call_limit < ~short_limit );
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
} } // graphene::chain
|
||||
401
libraries/chain/asset_evaluator.cpp
Normal file
401
libraries/chain/asset_evaluator.cpp
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/asset_evaluator.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/short_order_object.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
object_id_type asset_create_evaluator::do_evaluate( const asset_create_operation& op )
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
const auto& chain_parameters = d.get_global_properties().parameters;
|
||||
FC_ASSERT( op.common_options.whitelist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities );
|
||||
FC_ASSERT( op.common_options.blacklist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities );
|
||||
|
||||
// Check that all authorities do exist
|
||||
for( auto id : op.common_options.whitelist_authorities )
|
||||
d.get_object(id);
|
||||
for( auto id : op.common_options.blacklist_authorities )
|
||||
d.get_object(id);
|
||||
|
||||
auto& asset_indx = db().get_index_type<asset_index>().indices().get<by_symbol>();
|
||||
auto asset_symbol_itr = asset_indx.find( op.symbol );
|
||||
FC_ASSERT( asset_symbol_itr == asset_indx.end() );
|
||||
|
||||
core_fee_paid -= op.calculate_fee(d.current_fee_schedule()).value/2;
|
||||
assert( core_fee_paid >= 0 );
|
||||
|
||||
if( op.bitasset_options )
|
||||
{
|
||||
const asset_object& backing = op.bitasset_options->short_backing_asset(d);
|
||||
if( backing.is_market_issued() )
|
||||
{
|
||||
const asset_bitasset_data_object& backing_bitasset_data = backing.bitasset_data(d);
|
||||
const asset_object& backing_backing = backing_bitasset_data.options.short_backing_asset(d);
|
||||
FC_ASSERT( !backing_backing.is_market_issued(),
|
||||
"May not create a bitasset backed by a bitasset backed by a bitasset." );
|
||||
}
|
||||
FC_ASSERT( op.bitasset_options->feed_lifetime_sec > chain_parameters.block_interval &&
|
||||
op.bitasset_options->force_settlement_delay_sec > chain_parameters.block_interval );
|
||||
}
|
||||
|
||||
return object_id_type();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
object_id_type asset_create_evaluator::do_apply( const asset_create_operation& op )
|
||||
{
|
||||
const asset_dynamic_data_object& dyn_asset =
|
||||
db().create<asset_dynamic_data_object>( [&]( asset_dynamic_data_object& a ) {
|
||||
a.current_supply = 0;
|
||||
a.fee_pool = op.calculate_fee(db().current_fee_schedule()).value / 2;
|
||||
});
|
||||
|
||||
asset_bitasset_data_id_type bit_asset_id;
|
||||
if( op.bitasset_options.valid() )
|
||||
bit_asset_id = db().create<asset_bitasset_data_object>( [&]( asset_bitasset_data_object& a ) {
|
||||
a.options = *op.bitasset_options;
|
||||
a.is_prediction_market = op.is_prediction_market;
|
||||
}).id;
|
||||
|
||||
auto next_asset_id = db().get_index_type<asset_index>().get_next_id();
|
||||
|
||||
const asset_object& new_asset =
|
||||
db().create<asset_object>( [&]( asset_object& a ) {
|
||||
a.issuer = op.issuer;
|
||||
a.symbol = op.symbol;
|
||||
a.precision = op.precision;
|
||||
a.options = op.common_options;
|
||||
if( a.options.core_exchange_rate.base.asset_id.instance.value == 0 )
|
||||
a.options.core_exchange_rate.quote.asset_id = next_asset_id;
|
||||
else
|
||||
a.options.core_exchange_rate.base.asset_id = next_asset_id;
|
||||
a.dynamic_asset_data_id = dyn_asset.id;
|
||||
if( op.bitasset_options.valid() )
|
||||
a.bitasset_data_id = bit_asset_id;
|
||||
});
|
||||
assert( new_asset.id == next_asset_id );
|
||||
|
||||
return next_asset_id;
|
||||
}
|
||||
|
||||
object_id_type asset_issue_evaluator::do_evaluate( const asset_issue_operation& o )
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
const asset_object& a = o.asset_to_issue.asset_id(d);
|
||||
FC_ASSERT( o.issuer == a.issuer );
|
||||
FC_ASSERT( !a.is_market_issued(), "Cannot manually issue a market-issued asset." );
|
||||
|
||||
to_account = &o.issue_to_account(d);
|
||||
|
||||
if( a.options.flags & white_list )
|
||||
{
|
||||
FC_ASSERT( to_account->is_authorized_asset( a ) );
|
||||
}
|
||||
|
||||
asset_dyn_data = &a.dynamic_asset_data_id(d);
|
||||
FC_ASSERT( (asset_dyn_data->current_supply + o.asset_to_issue.amount) <= a.options.max_supply );
|
||||
|
||||
return object_id_type();
|
||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||
|
||||
object_id_type asset_issue_evaluator::do_apply( const asset_issue_operation& o )
|
||||
{
|
||||
db().adjust_balance( o.issue_to_account, o.asset_to_issue );
|
||||
|
||||
db().modify( *asset_dyn_data, [&]( asset_dynamic_data_object& data ){
|
||||
data.current_supply += o.asset_to_issue.amount;
|
||||
});
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type asset_burn_evaluator::do_evaluate( const asset_burn_operation& o )
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
const asset_object& a = o.amount_to_burn.asset_id(d);
|
||||
FC_ASSERT( !a.is_market_issued() );
|
||||
|
||||
from_account = &o.payer(d);
|
||||
|
||||
if( a.options.flags & white_list )
|
||||
{
|
||||
FC_ASSERT( from_account->is_authorized_asset( a ) );
|
||||
}
|
||||
|
||||
asset_dyn_data = &a.dynamic_asset_data_id(d);
|
||||
FC_ASSERT( (asset_dyn_data->current_supply - o.amount_to_burn.amount) >= 0 );
|
||||
|
||||
return object_id_type();
|
||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||
|
||||
object_id_type asset_burn_evaluator::do_apply( const asset_burn_operation& o )
|
||||
{
|
||||
db().adjust_balance( o.payer, -o.amount_to_burn );
|
||||
|
||||
db().modify( *asset_dyn_data, [&]( asset_dynamic_data_object& data ){
|
||||
data.current_supply -= o.amount_to_burn.amount;
|
||||
});
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type asset_fund_fee_pool_evaluator::do_evaluate(const asset_fund_fee_pool_operation& o)
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
const asset_object& a = o.asset_id(d);
|
||||
|
||||
asset_dyn_data = &a.dynamic_asset_data_id(d);
|
||||
|
||||
return object_id_type();
|
||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||
|
||||
object_id_type asset_fund_fee_pool_evaluator::do_apply(const asset_fund_fee_pool_operation& o)
|
||||
{
|
||||
db().adjust_balance(o.from_account, -o.amount);
|
||||
|
||||
db().modify( *asset_dyn_data, [&]( asset_dynamic_data_object& data ) {
|
||||
data.fee_pool += o.amount;
|
||||
});
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type asset_update_evaluator::do_evaluate(const asset_update_operation& o)
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
if( o.new_issuer ) FC_ASSERT(d.find_object(*o.new_issuer));
|
||||
|
||||
const asset_object& a = o.asset_to_update(d);
|
||||
auto a_copy = a;
|
||||
a_copy.options = o.new_options;
|
||||
a_copy.validate();
|
||||
|
||||
//There must be no bits set in o.permissions which are unset in a.issuer_permissions.
|
||||
FC_ASSERT(!(o.new_options.issuer_permissions & ~a.options.issuer_permissions),
|
||||
"Cannot reinstate previously revoked issuer permissions on an asset.");
|
||||
|
||||
asset_to_update = &a;
|
||||
FC_ASSERT( o.issuer == a.issuer, "", ("o.issuer", o.issuer)("a.issuer", a.issuer) );
|
||||
|
||||
const auto& chain_parameters = d.get_global_properties().parameters;
|
||||
|
||||
FC_ASSERT( o.new_options.whitelist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities );
|
||||
for( auto id : o.new_options.whitelist_authorities )
|
||||
d.get_object(id);
|
||||
FC_ASSERT( o.new_options.blacklist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities );
|
||||
for( auto id : o.new_options.blacklist_authorities )
|
||||
d.get_object(id);
|
||||
|
||||
return object_id_type();
|
||||
} FC_CAPTURE_AND_RETHROW((o)) }
|
||||
|
||||
object_id_type asset_update_evaluator::do_apply(const asset_update_operation& o)
|
||||
{
|
||||
database& d = db();
|
||||
|
||||
// If we are now disabling force settlements, cancel all open force settlement orders
|
||||
if( o.new_options.flags & disable_force_settle && asset_to_update->can_force_settle() )
|
||||
{
|
||||
const auto& idx = d.get_index_type<force_settlement_index>().indices().get<by_expiration>();
|
||||
// Funky iteration code because we're removing objects as we go. We have to re-initialize itr every loop instead
|
||||
// of simply incrementing it.
|
||||
for( auto itr = idx.lower_bound(o.asset_to_update);
|
||||
itr != idx.end() && itr->settlement_asset_id() == o.asset_to_update;
|
||||
itr = idx.lower_bound(o.asset_to_update) )
|
||||
d.cancel_order(*itr);
|
||||
}
|
||||
|
||||
d.modify(*asset_to_update, [&](asset_object& a) {
|
||||
if( o.new_issuer )
|
||||
a.issuer = *o.new_issuer;
|
||||
a.options = o.new_options;
|
||||
});
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type asset_update_bitasset_evaluator::do_evaluate(const asset_update_bitasset_operation& o)
|
||||
{
|
||||
database& d = db();
|
||||
|
||||
const asset_object& a = o.asset_to_update(d);
|
||||
|
||||
FC_ASSERT(a.is_market_issued(), "Cannot update BitAsset-specific settings on a non-BitAsset.");
|
||||
|
||||
const asset_bitasset_data_object& b = a.bitasset_data(d);
|
||||
if( o.new_options.short_backing_asset != b.options.short_backing_asset )
|
||||
{
|
||||
FC_ASSERT(a.dynamic_asset_data_id(d).current_supply == 0);
|
||||
FC_ASSERT(d.find_object(o.new_options.short_backing_asset));
|
||||
}
|
||||
|
||||
bitasset_to_update = &b;
|
||||
FC_ASSERT( o.issuer == a.issuer, "", ("o.issuer", o.issuer)("a.issuer", a.issuer) );
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type asset_update_bitasset_evaluator::do_apply(const asset_update_bitasset_operation& o)
|
||||
{
|
||||
db().modify(*bitasset_to_update, [&o](asset_bitasset_data_object& b) {
|
||||
b.options = o.new_options;
|
||||
});
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type asset_update_feed_producers_evaluator::do_evaluate(const asset_update_feed_producers_evaluator::operation_type& o)
|
||||
{
|
||||
database& d = db();
|
||||
|
||||
FC_ASSERT( o.new_feed_producers.size() <= d.get_global_properties().parameters.maximum_asset_feed_publishers );
|
||||
for( auto id : o.new_feed_producers )
|
||||
d.get_object(id);
|
||||
|
||||
const asset_object& a = o.asset_to_update(d);
|
||||
|
||||
FC_ASSERT(a.is_market_issued(), "Cannot update feed producers on a non-BitAsset.");
|
||||
FC_ASSERT(a.issuer != account_id_type(), "Cannot set feed producers on a genesis-issued asset.");
|
||||
|
||||
const asset_bitasset_data_object& b = a.bitasset_data(d);
|
||||
bitasset_to_update = &b;
|
||||
FC_ASSERT( a.issuer == o.issuer );
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type asset_update_feed_producers_evaluator::do_apply(const asset_update_feed_producers_evaluator::operation_type& o)
|
||||
{
|
||||
db().modify(*bitasset_to_update, [&](asset_bitasset_data_object& a) {
|
||||
//This is tricky because I have a set of publishers coming in, but a map of publisher to feed is stored.
|
||||
//I need to update the map such that the keys match the new publishers, but not munge the old price feeds from
|
||||
//publishers who are being kept.
|
||||
//First, remove any old publishers who are no longer publishers
|
||||
for( auto itr = a.feeds.begin(); itr != a.feeds.end(); )
|
||||
{
|
||||
if( !o.new_feed_producers.count(itr->first) )
|
||||
itr = a.feeds.erase(itr);
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
//Now, add any new publishers
|
||||
for( auto itr = o.new_feed_producers.begin(); itr != o.new_feed_producers.end(); ++itr )
|
||||
if( !a.feeds.count(*itr) )
|
||||
a.feeds[*itr];
|
||||
a.update_median_feeds(db().head_block_time());
|
||||
});
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
|
||||
object_id_type asset_global_settle_evaluator::do_evaluate(const asset_global_settle_evaluator::operation_type& op)
|
||||
{
|
||||
const database& d = db();
|
||||
asset_to_settle = &op.asset_to_settle(d);
|
||||
FC_ASSERT(asset_to_settle->is_market_issued());
|
||||
FC_ASSERT(asset_to_settle->can_global_settle());
|
||||
FC_ASSERT(asset_to_settle->issuer == op.issuer );
|
||||
FC_ASSERT(asset_to_settle->dynamic_data(d).current_supply > 0);
|
||||
const auto& idx = d.get_index_type<call_order_index>().indices().get<by_collateral>();
|
||||
assert( !idx.empty() );
|
||||
auto itr = idx.lower_bound(boost::make_tuple(price::min(asset_to_settle->bitasset_data(d).options.short_backing_asset,
|
||||
op.asset_to_settle)));
|
||||
assert( itr != idx.end() && itr->debt_type() == op.asset_to_settle );
|
||||
const call_order_object& least_collateralized_short = *itr;
|
||||
FC_ASSERT(least_collateralized_short.get_debt() * op.settle_price <= least_collateralized_short.get_collateral(),
|
||||
"Cannot force settle at supplied price: least collateralized short lacks sufficient collateral to settle.");
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type asset_global_settle_evaluator::do_apply(const asset_global_settle_evaluator::operation_type& op)
|
||||
{
|
||||
database& d = db();
|
||||
d.globally_settle_asset( op.asset_to_settle(db()), op.settle_price );
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type asset_settle_evaluator::do_evaluate(const asset_settle_evaluator::operation_type& op)
|
||||
{
|
||||
const database& d = db();
|
||||
asset_to_settle = &op.amount.asset_id(d);
|
||||
FC_ASSERT(asset_to_settle->is_market_issued());
|
||||
FC_ASSERT(asset_to_settle->can_force_settle());
|
||||
FC_ASSERT(d.get_balance(d.get(op.account), *asset_to_settle) >= op.amount);
|
||||
|
||||
return d.get_index_type<force_settlement_index>().get_next_id();
|
||||
}
|
||||
|
||||
object_id_type asset_settle_evaluator::do_apply(const asset_settle_evaluator::operation_type& op)
|
||||
{
|
||||
database& d = db();
|
||||
d.adjust_balance(op.account, -op.amount);
|
||||
return d.create<force_settlement_object>([&](force_settlement_object& s) {
|
||||
s.owner = op.account;
|
||||
s.balance = op.amount;
|
||||
s.settlement_date = d.head_block_time() + asset_to_settle->bitasset_data(d).options.force_settlement_delay_sec;
|
||||
}).id;
|
||||
}
|
||||
|
||||
object_id_type asset_publish_feeds_evaluator::do_evaluate(const asset_publish_feed_operation& o)
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
const asset_object& quote = o.asset_id(d);
|
||||
//Verify that this feed is for a market-issued asset and that asset is backed by the base
|
||||
FC_ASSERT(quote.is_market_issued());
|
||||
|
||||
const asset_bitasset_data_object& bitasset = quote.bitasset_data(d);
|
||||
FC_ASSERT(bitasset.options.short_backing_asset == o.feed.call_limit.base.asset_id);
|
||||
//Verify that the publisher is authoritative to publish a feed
|
||||
if( quote.issuer == account_id_type() )
|
||||
{
|
||||
//It's a delegate-fed asset. Verify that publisher is an active delegate or witness.
|
||||
FC_ASSERT(d.get(account_id_type()).active.auths.count(o.publisher) ||
|
||||
d.get_global_properties().witness_accounts.count(o.publisher));
|
||||
} else {
|
||||
FC_ASSERT(bitasset.feeds.count(o.publisher));
|
||||
}
|
||||
|
||||
return object_id_type();
|
||||
} FC_CAPTURE_AND_RETHROW((o)) }
|
||||
|
||||
object_id_type asset_publish_feeds_evaluator::do_apply(const asset_publish_feed_operation& o)
|
||||
{ try {
|
||||
database& d = db();
|
||||
|
||||
const asset_object& quote = o.asset_id(d);
|
||||
// Store medians for this asset
|
||||
d.modify(quote.bitasset_data(d), [&o,&d](asset_bitasset_data_object& a) {
|
||||
a.feeds[o.publisher] = make_pair(d.head_block_time(), o.feed);
|
||||
a.update_median_feeds(d.head_block_time());
|
||||
});
|
||||
|
||||
return object_id_type();
|
||||
} FC_CAPTURE_AND_RETHROW((o)) }
|
||||
|
||||
} } // graphene::chain
|
||||
187
libraries/chain/asset_object.cpp
Normal file
187
libraries/chain/asset_object.cpp
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace graphene::chain;
|
||||
|
||||
share_type asset_bitasset_data_object::max_force_settlement_volume(share_type current_supply) const
|
||||
{
|
||||
if( options.maximum_force_settlement_volume == 0 )
|
||||
return 0;
|
||||
if( options.maximum_force_settlement_volume == GRAPHENE_100_PERCENT )
|
||||
return current_supply + force_settled_volume;
|
||||
|
||||
fc::uint128 volume = current_supply.value + force_settled_volume.value;
|
||||
volume *= options.maximum_force_settlement_volume;
|
||||
volume /= GRAPHENE_100_PERCENT;
|
||||
return volume.to_uint64();
|
||||
}
|
||||
|
||||
void graphene::chain::asset_bitasset_data_object::update_median_feeds(time_point_sec current_time)
|
||||
{
|
||||
current_feed_publication_time = current_time;
|
||||
vector<std::reference_wrapper<const price_feed>> current_feeds;
|
||||
for( const pair<account_id_type, pair<time_point_sec,price_feed>>& f : feeds )
|
||||
{
|
||||
if( (current_time - f.second.first).to_seconds() < options.feed_lifetime_sec &&
|
||||
f.second.first != time_point_sec() )
|
||||
{
|
||||
current_feeds.emplace_back(f.second.second);
|
||||
current_feed_publication_time = std::min(current_feed_publication_time, f.second.first);
|
||||
}
|
||||
}
|
||||
|
||||
if( current_feeds.empty() )
|
||||
{
|
||||
current_feed_publication_time = current_time;
|
||||
current_feed = price_feed();
|
||||
return;
|
||||
}
|
||||
if( current_feeds.size() == 1 )
|
||||
{
|
||||
current_feed = std::move(current_feeds.front());
|
||||
return;
|
||||
}
|
||||
|
||||
// *** Begin Median Calculations ***
|
||||
price_feed median_feed;
|
||||
const auto median_itr = current_feeds.begin() + current_feeds.size() / 2;
|
||||
#define CALCULATE_MEDIAN_VALUE(r, data, field_name) \
|
||||
std::nth_element( current_feeds.begin(), median_itr, current_feeds.end(), \
|
||||
[](const price_feed& a, const price_feed& b) { \
|
||||
return a.field_name < b.field_name; \
|
||||
}); \
|
||||
median_feed.field_name = median_itr->get().field_name;
|
||||
|
||||
BOOST_PP_SEQ_FOR_EACH( CALCULATE_MEDIAN_VALUE, ~, GRAPHENE_PRICE_FEED_FIELDS )
|
||||
#undef CALCULATE_MEDIAN_VALUE
|
||||
// *** End Median Calculations ***
|
||||
|
||||
current_feed = median_feed;
|
||||
}
|
||||
|
||||
void asset_object::asset_options::validate()const
|
||||
{
|
||||
FC_ASSERT( max_supply > 0 );
|
||||
FC_ASSERT( max_supply <= GRAPHENE_MAX_SHARE_SUPPLY );
|
||||
FC_ASSERT( market_fee_percent <= GRAPHENE_100_PERCENT );
|
||||
FC_ASSERT( max_market_fee >= 0 && max_market_fee <= GRAPHENE_MAX_SHARE_SUPPLY );
|
||||
FC_ASSERT( min_market_fee >= 0 && min_market_fee <= GRAPHENE_MAX_SHARE_SUPPLY );
|
||||
// There must be no high bits in permissions whose meaning is not known.
|
||||
FC_ASSERT( !(issuer_permissions & ~ASSET_ISSUER_PERMISSION_MASK) );
|
||||
// There must be no high bits in flags which are not also high in permissions.
|
||||
FC_ASSERT( !(flags & ~issuer_permissions ) );
|
||||
// The global_settle flag may never be set (this is a permission only)
|
||||
FC_ASSERT( !(flags & global_settle) );
|
||||
core_exchange_rate.validate();
|
||||
FC_ASSERT( core_exchange_rate.base.asset_id.instance.value == 0 ||
|
||||
core_exchange_rate.quote.asset_id.instance.value == 0 );
|
||||
|
||||
if(!whitelist_authorities.empty() || !blacklist_authorities.empty())
|
||||
FC_ASSERT( flags & white_list );
|
||||
for( auto item : whitelist_markets )
|
||||
{
|
||||
FC_ASSERT( blacklist_markets.find(item) == blacklist_markets.end() );
|
||||
}
|
||||
for( auto item : blacklist_markets )
|
||||
{
|
||||
FC_ASSERT( whitelist_markets.find(item) == whitelist_markets.end() );
|
||||
}
|
||||
}
|
||||
|
||||
void asset_object::bitasset_options::validate() const
|
||||
{
|
||||
FC_ASSERT(force_settlement_offset_percent <= GRAPHENE_100_PERCENT);
|
||||
FC_ASSERT(maximum_force_settlement_volume <= GRAPHENE_100_PERCENT);
|
||||
}
|
||||
|
||||
|
||||
asset asset_object::amount_from_string(string amount_string) const
|
||||
{ try {
|
||||
bool negative_found = false;
|
||||
bool decimal_found = false;
|
||||
for( const char c : amount_string )
|
||||
{
|
||||
if( isdigit( c ) )
|
||||
continue;
|
||||
|
||||
if( c == '-' && !negative_found )
|
||||
{
|
||||
negative_found = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( c == '.' && !decimal_found )
|
||||
{
|
||||
decimal_found = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
FC_THROW( (amount_string) );
|
||||
}
|
||||
|
||||
share_type satoshis = 0;
|
||||
|
||||
share_type scaled_precision = 1;
|
||||
for( short i = 0; i < precision; ++i )
|
||||
scaled_precision *= 10;
|
||||
|
||||
const auto decimal_pos = amount_string.find( '.' );
|
||||
const string lhs = amount_string.substr( negative_found, decimal_pos );
|
||||
if( !lhs.empty() )
|
||||
satoshis += fc::safe<int64_t>(std::stoll(lhs)) *= scaled_precision;
|
||||
|
||||
if( decimal_found )
|
||||
{
|
||||
const size_t max_rhs_size = std::to_string( scaled_precision.value ).substr( 1 ).size();
|
||||
|
||||
string rhs = amount_string.substr( decimal_pos + 1 );
|
||||
FC_ASSERT( rhs.size() <= max_rhs_size );
|
||||
|
||||
while( rhs.size() < max_rhs_size )
|
||||
rhs += '0';
|
||||
|
||||
if( !rhs.empty() )
|
||||
satoshis += std::stoll( rhs );
|
||||
}
|
||||
|
||||
FC_ASSERT( satoshis <= GRAPHENE_BLOCKCHAIN_MAX_SHARES );
|
||||
|
||||
if( negative_found )
|
||||
satoshis *= -1;
|
||||
|
||||
return amount(satoshis);
|
||||
} FC_CAPTURE_AND_RETHROW( (amount_string) ) }
|
||||
|
||||
string asset_object::amount_to_string(share_type amount) const
|
||||
{
|
||||
share_type scaled_precision = 1;
|
||||
for( short i = 0; i < precision; ++i )
|
||||
scaled_precision *= 10;
|
||||
assert(scaled_precision > 0);
|
||||
|
||||
string result = fc::to_string(amount.value / scaled_precision.value);
|
||||
auto decimals = amount.value % scaled_precision.value;
|
||||
if( decimals )
|
||||
result += "." + fc::to_string(scaled_precision.value + decimals).erase(0,1);
|
||||
return result;
|
||||
}
|
||||
71
libraries/chain/block.cpp
Normal file
71
libraries/chain/block.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/block.hpp>
|
||||
#include <fc/io/raw.hpp>
|
||||
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
digest_type block_header::digest()const
|
||||
{
|
||||
return digest_type::hash(*this);
|
||||
}
|
||||
|
||||
block_id_type signed_block_header::id()const
|
||||
{
|
||||
auto tmp = fc::sha224::hash( *this );
|
||||
tmp._hash[0] = htonl(block_num()); // store the block num in the ID, 160 bits is plenty for the hash
|
||||
static_assert( sizeof(tmp._hash[0]) == 4, "should be 4 bytes" );
|
||||
block_id_type result;
|
||||
memcpy(result._hash, tmp._hash, std::min(sizeof(result), sizeof(tmp)));
|
||||
return result;
|
||||
}
|
||||
|
||||
fc::ecc::public_key signed_block_header::signee()const
|
||||
{
|
||||
return fc::ecc::public_key( delegate_signature, digest(), true/*enforce canonical*/ );
|
||||
}
|
||||
|
||||
void signed_block_header::sign( const fc::ecc::private_key& signer )
|
||||
{
|
||||
delegate_signature = signer.sign_compact( digest() );
|
||||
}
|
||||
|
||||
bool signed_block_header::validate_signee( const fc::ecc::public_key& expected_signee )const
|
||||
{
|
||||
return signee() == expected_signee;
|
||||
}
|
||||
|
||||
checksum_type signed_block::calculate_merkle_root()const
|
||||
{
|
||||
if( transactions.size() == 0 ) return checksum_type();
|
||||
|
||||
vector<digest_type> ids;
|
||||
ids.resize( ((transactions.size() + 1)/2)*2 );
|
||||
for( uint32_t i = 0; i < transactions.size(); ++i )
|
||||
ids[i] = transactions[i].merkle_digest();
|
||||
|
||||
while( ids.size() > 1 )
|
||||
{
|
||||
for( uint32_t i = 0; i < transactions.size(); i += 2 )
|
||||
ids[i/2] = digest_type::hash( std::make_pair( ids[i], ids[i+1] ) );
|
||||
ids.resize( ids.size() / 2 );
|
||||
}
|
||||
return checksum_type::hash( ids[0] );
|
||||
}
|
||||
|
||||
} }
|
||||
218
libraries/chain/bond_evaluator.cpp
Normal file
218
libraries/chain/bond_evaluator.cpp
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/bond_evaluator.hpp>
|
||||
#include <graphene/chain/bond_object.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
object_id_type bond_create_offer_evaluator::do_evaluate( const bond_create_offer_operation& op )
|
||||
{
|
||||
const auto& d = db();
|
||||
|
||||
const auto& creator_account = op.creator( d );
|
||||
const auto& base_asset = op.collateral_rate.base.asset_id( d );
|
||||
const auto& quote_asset = op.collateral_rate.quote.asset_id( d );
|
||||
|
||||
// TODO: Check asset authorizations and withdrawals
|
||||
|
||||
const auto& amount_asset = (op.amount.asset_id == op.collateral_rate.base.asset_id) ? base_asset : quote_asset;
|
||||
|
||||
FC_ASSERT( !base_asset.is_transfer_restricted() && !quote_asset.is_transfer_restricted() );
|
||||
|
||||
if( base_asset.options.whitelist_markets.size() )
|
||||
FC_ASSERT( base_asset.options.whitelist_markets.find( quote_asset.id ) != base_asset.options.whitelist_markets.end() );
|
||||
if( base_asset.options.blacklist_markets.size() )
|
||||
FC_ASSERT( base_asset.options.blacklist_markets.find( quote_asset.id ) == base_asset.options.blacklist_markets.end() );
|
||||
|
||||
FC_ASSERT( d.get_balance( creator_account, amount_asset ) >= op.amount );
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type bond_create_offer_evaluator::do_apply( const bond_create_offer_operation& op )
|
||||
{
|
||||
db().adjust_balance( op.creator, -op.amount );
|
||||
db().adjust_core_in_orders( op.creator(db()), op.amount );
|
||||
|
||||
const auto& offer = db().create<bond_offer_object>( [&]( bond_offer_object& obj )
|
||||
{
|
||||
obj.offered_by_account = op.creator;
|
||||
obj.offer_to_borrow = op.offer_to_borrow;
|
||||
obj.amount = op.amount;
|
||||
obj.min_match = op.min_match;
|
||||
obj.collateral_rate = op.collateral_rate;
|
||||
obj.min_loan_period_sec = op.min_loan_period_sec;
|
||||
obj.loan_period_sec = op.loan_period_sec;
|
||||
obj.interest_apr = op.interest_apr;
|
||||
} );
|
||||
|
||||
return offer.id;
|
||||
}
|
||||
|
||||
|
||||
object_id_type bond_cancel_offer_evaluator::do_evaluate( const bond_cancel_offer_operation& op )
|
||||
{
|
||||
_offer = &op.offer_id(db());
|
||||
FC_ASSERT( op.creator == _offer->offered_by_account );
|
||||
FC_ASSERT( _offer->amount == op.refund );
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type bond_cancel_offer_evaluator::do_apply( const bond_cancel_offer_operation& op )
|
||||
{
|
||||
assert( _offer != nullptr );
|
||||
db().adjust_balance( op.creator, op.refund );
|
||||
db().adjust_core_in_orders( op.creator(db()), -op.refund );
|
||||
db().remove( *_offer );
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type bond_accept_offer_evaluator::do_evaluate( const bond_accept_offer_operation& op )
|
||||
{ try {
|
||||
_offer = &op.offer_id(db());
|
||||
|
||||
if( _offer->offer_to_borrow )
|
||||
FC_ASSERT( op.amount_borrowed.amount >= _offer->min_match );
|
||||
else
|
||||
FC_ASSERT( op.amount_collateral.amount >= _offer->min_match );
|
||||
|
||||
FC_ASSERT( (op.amount_borrowed / op.amount_collateral == _offer->collateral_rate) ||
|
||||
(op.amount_collateral / op.amount_borrowed == _offer->collateral_rate) );
|
||||
|
||||
return object_id_type();
|
||||
} FC_CAPTURE_AND_RETHROW((op)) }
|
||||
|
||||
object_id_type bond_accept_offer_evaluator::do_apply( const bond_accept_offer_operation& op )
|
||||
{ try {
|
||||
|
||||
if( op.claimer == op.lender )
|
||||
{
|
||||
db().adjust_balance( op.lender, -op.amount_borrowed );
|
||||
}
|
||||
else // claimer == borrower
|
||||
{
|
||||
db().adjust_balance( op.borrower, -op.amount_collateral );
|
||||
db().adjust_core_in_orders( op.borrower(db()), op.amount_collateral );
|
||||
}
|
||||
db().adjust_balance( op.borrower, op.amount_borrowed );
|
||||
|
||||
const auto& bond = db().create<bond_object>( [&]( bond_object& obj )
|
||||
{
|
||||
obj.borrowed = op.amount_borrowed;
|
||||
obj.collateral = op.amount_collateral;
|
||||
obj.borrower = op.borrower;
|
||||
obj.lender = op.lender;
|
||||
|
||||
auto head_time = db().get_dynamic_global_properties().time;
|
||||
obj.interest_apr = _offer->interest_apr;
|
||||
obj.start_date = head_time;
|
||||
obj.due_date = head_time + fc::seconds( _offer->loan_period_sec );
|
||||
obj.earliest_payoff_date = head_time + fc::seconds( _offer->min_loan_period_sec );
|
||||
} );
|
||||
|
||||
if( _offer->offer_to_borrow && op.amount_borrowed < _offer->amount )
|
||||
{
|
||||
db().modify( *_offer, [&]( bond_offer_object& offer ){
|
||||
offer.amount -= op.amount_borrowed;
|
||||
});
|
||||
}
|
||||
else if( !_offer->offer_to_borrow && op.amount_collateral < _offer->amount )
|
||||
{
|
||||
db().modify( *_offer, [&]( bond_offer_object& offer ){
|
||||
offer.amount -= op.amount_collateral;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
db().remove( *_offer );
|
||||
}
|
||||
return bond.id;
|
||||
} FC_CAPTURE_AND_RETHROW((op)) }
|
||||
|
||||
|
||||
|
||||
object_id_type bond_claim_collateral_evaluator::do_evaluate( const bond_claim_collateral_operation& op )
|
||||
{
|
||||
_bond = &op.bond_id(db());
|
||||
auto head_time = db().get_dynamic_global_properties().time;
|
||||
FC_ASSERT( head_time > _bond->earliest_payoff_date );
|
||||
|
||||
|
||||
FC_ASSERT( op.collateral_claimed <= _bond->collateral );
|
||||
if( _bond->borrower == op.claimer )
|
||||
{
|
||||
auto elapsed_time = head_time - _bond->start_date;
|
||||
auto elapsed_days = 1 + elapsed_time.to_seconds() / (60*60*24);
|
||||
|
||||
fc::uint128 tmp = _bond->borrowed.amount.value;
|
||||
tmp *= elapsed_days;
|
||||
tmp *= _bond->interest_apr;
|
||||
tmp /= (365 * GRAPHENE_100_PERCENT);
|
||||
FC_ASSERT( tmp < GRAPHENE_MAX_SHARE_SUPPLY );
|
||||
_interest_due = asset(tmp.to_uint64(), _bond->borrowed.asset_id);
|
||||
|
||||
FC_ASSERT( _interest_due + _bond->borrowed <= op.payoff_amount );
|
||||
|
||||
auto total_debt = _interest_due + _bond->borrowed;
|
||||
|
||||
fc::uint128 max_claim = _bond->collateral.amount.value;
|
||||
max_claim *= op.payoff_amount.amount.value;
|
||||
max_claim /= total_debt.amount.value;
|
||||
|
||||
FC_ASSERT( op.collateral_claimed.amount.value == max_claim.to_uint64() );
|
||||
}
|
||||
else
|
||||
{
|
||||
FC_ASSERT( _bond->lender == op.claimer );
|
||||
FC_ASSERT( head_time > _bond->due_date );
|
||||
FC_ASSERT( _bond->collateral == op.collateral_claimed );
|
||||
FC_ASSERT( op.payoff_amount == asset(0,_bond->borrowed.asset_id ) );
|
||||
}
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type bond_claim_collateral_evaluator::do_apply( const bond_claim_collateral_operation& op )
|
||||
{
|
||||
assert( _bond != nullptr );
|
||||
|
||||
const account_object& claimer = op.claimer(db());
|
||||
|
||||
db().adjust_core_in_orders( _bond->borrower(db()), -op.collateral_claimed );
|
||||
|
||||
if( op.payoff_amount.amount > 0 )
|
||||
{
|
||||
db().adjust_balance( claimer, -op.payoff_amount );
|
||||
db().adjust_balance( op.lender, op.payoff_amount );
|
||||
}
|
||||
db().adjust_balance( claimer, op.collateral_claimed );
|
||||
|
||||
if( op.collateral_claimed == _bond->collateral )
|
||||
db().remove(*_bond);
|
||||
else
|
||||
db().modify( *_bond, [&]( bond_object& bond ){
|
||||
bond.borrowed -= op.payoff_amount + _interest_due;
|
||||
bond.collateral -= op.collateral_claimed;
|
||||
bond.start_date = db().get_dynamic_global_properties().time;
|
||||
});
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
} } // graphene::chain
|
||||
141
libraries/chain/db_balance.cpp
Normal file
141
libraries/chain/db_balance.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/vesting_balance_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
asset database::get_balance(account_id_type owner, asset_id_type asset_id) const
|
||||
{
|
||||
auto& index = get_index_type<account_balance_index>().indices().get<by_balance>();
|
||||
auto itr = index.find(boost::make_tuple(owner, asset_id));
|
||||
if( itr == index.end() )
|
||||
return asset(0, asset_id);
|
||||
return itr->get_balance();
|
||||
}
|
||||
|
||||
asset database::get_balance(const account_object& owner, const asset_object& asset_obj) const
|
||||
{
|
||||
return get_balance(owner.get_id(), asset_obj.get_id());
|
||||
}
|
||||
|
||||
// TODO: this method should be removed
|
||||
asset database::get_balance( const account_object* owner, const asset_object* asset_obj )const
|
||||
{
|
||||
return get_balance(*owner, *asset_obj);
|
||||
}
|
||||
|
||||
void database::adjust_balance(account_id_type account, asset delta )
|
||||
{ try {
|
||||
if( delta.amount == 0 )
|
||||
return;
|
||||
|
||||
auto& index = get_index_type<account_balance_index>().indices().get<by_balance>();
|
||||
auto itr = index.find(boost::make_tuple(account, delta.asset_id));
|
||||
if(itr == index.end())
|
||||
{
|
||||
FC_ASSERT(delta.amount > 0);
|
||||
create<account_balance_object>([account,&delta](account_balance_object& b) {
|
||||
b.owner = account;
|
||||
b.asset_type = delta.asset_id;
|
||||
b.balance = delta.amount.value;
|
||||
});
|
||||
} else {
|
||||
FC_ASSERT(delta.amount > 0 || itr->get_balance() >= -delta);
|
||||
modify(*itr, [delta](account_balance_object& b) {
|
||||
b.adjust_balance(delta);
|
||||
});
|
||||
}
|
||||
|
||||
} FC_CAPTURE_AND_RETHROW( (account)(delta) ) }
|
||||
|
||||
void database::adjust_balance(const account_object& account, asset delta )
|
||||
{
|
||||
adjust_balance( account.id, delta);
|
||||
}
|
||||
|
||||
// TODO: This method should be removed
|
||||
void database::adjust_balance(const account_object* account, asset delta)
|
||||
{
|
||||
adjust_balance(*account, delta);
|
||||
}
|
||||
|
||||
void database::adjust_core_in_orders( const account_object& acnt, asset delta )
|
||||
{
|
||||
if( delta.asset_id == asset_id_type(0) && delta.amount != 0 )
|
||||
{
|
||||
modify( acnt.statistics(*this), [&](account_statistics_object& stat){
|
||||
stat.total_core_in_orders += delta.amount;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void database::deposit_cashback( const account_object& acct, share_type amount )
|
||||
{
|
||||
// If we don't have a VBO, or if it has the wrong maturity
|
||||
// due to a policy change, cut it loose.
|
||||
|
||||
if( amount == 0 )
|
||||
return;
|
||||
|
||||
uint32_t global_vesting_seconds = get_global_properties().parameters.cashback_vesting_period_seconds;
|
||||
fc::time_point_sec now = head_block_time();
|
||||
|
||||
while( true )
|
||||
{
|
||||
if( !acct.cashback_vb.valid() )
|
||||
break;
|
||||
const vesting_balance_object& cashback_vb = (*acct.cashback_vb)(*this);
|
||||
if( cashback_vb.policy.which() != vesting_policy::tag< cdd_vesting_policy >::value )
|
||||
break;
|
||||
if( cashback_vb.policy.get< cdd_vesting_policy >().vesting_seconds != global_vesting_seconds )
|
||||
break;
|
||||
|
||||
modify( cashback_vb, [&]( vesting_balance_object& obj )
|
||||
{
|
||||
obj.deposit( now, amount );
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
const vesting_balance_object& cashback_vb = create< vesting_balance_object >( [&]( vesting_balance_object& obj )
|
||||
{
|
||||
obj.owner = acct.id;
|
||||
obj.balance = amount;
|
||||
|
||||
cdd_vesting_policy policy;
|
||||
policy.vesting_seconds = global_vesting_seconds;
|
||||
policy.coin_seconds_earned = 0;
|
||||
policy.coin_seconds_earned_last_update = now;
|
||||
|
||||
obj.policy = policy;
|
||||
} );
|
||||
|
||||
modify( acct, [&]( account_object& _acct )
|
||||
{
|
||||
_acct.cashback_vb = cashback_vb.id;
|
||||
} );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} }
|
||||
524
libraries/chain/db_block.cpp
Normal file
524
libraries/chain/db_block.cpp
Normal file
|
|
@ -0,0 +1,524 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/block_summary_object.hpp>
|
||||
#include <graphene/chain/global_property_object.hpp>
|
||||
#include <graphene/chain/key_object.hpp>
|
||||
#include <graphene/chain/operation_history_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/transaction_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
bool database::is_known_block( const block_id_type& id )const
|
||||
{
|
||||
return _fork_db.is_known_block(id) || _block_id_to_block.find(id).valid();
|
||||
}
|
||||
/**
|
||||
* Only return true *if* the transaction has not expired or been invalidated. If this
|
||||
* method is called with a VERY old transaction we will return false, they should
|
||||
* query things by blocks if they are that old.
|
||||
*/
|
||||
bool database::is_known_transaction( const transaction_id_type& id )const
|
||||
{
|
||||
const auto& trx_idx = get_index_type<transaction_index>().indices().get<by_trx_id>();
|
||||
return trx_idx.find( id ) != trx_idx.end();
|
||||
}
|
||||
|
||||
block_id_type database::get_block_id_for_num( uint32_t block_num )const
|
||||
{ try {
|
||||
block_id_type lb; lb._hash[0] = htonl(block_num);
|
||||
auto itr = _block_id_to_block.lower_bound( lb );
|
||||
FC_ASSERT( itr.valid() && itr.key()._hash[0] == lb._hash[0] );
|
||||
return itr.key();
|
||||
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
|
||||
|
||||
optional<signed_block> database::fetch_block_by_id( const block_id_type& id )const
|
||||
{
|
||||
auto b = _fork_db.fetch_block( id );
|
||||
if( !b )
|
||||
return _block_id_to_block.fetch_optional(id);
|
||||
return b->data;
|
||||
}
|
||||
|
||||
optional<signed_block> database::fetch_block_by_number( uint32_t num )const
|
||||
{
|
||||
auto results = _fork_db.fetch_block_by_number(num);
|
||||
if( results.size() == 1 )
|
||||
return results[0]->data;
|
||||
else
|
||||
{
|
||||
block_id_type lb; lb._hash[0] = htonl(num);
|
||||
auto itr = _block_id_to_block.lower_bound( lb );
|
||||
if( itr.valid() && itr.key()._hash[0] == lb._hash[0] )
|
||||
return itr.value();
|
||||
}
|
||||
return optional<signed_block>();
|
||||
}
|
||||
|
||||
const signed_transaction& database::get_recent_transaction(const transaction_id_type& trx_id) const
|
||||
{
|
||||
auto& index = get_index_type<transaction_index>().indices().get<by_trx_id>();
|
||||
auto itr = index.find(trx_id);
|
||||
FC_ASSERT(itr != index.end());
|
||||
return itr->trx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push block "may fail" in which case every partial change is unwound. After
|
||||
* push block is successful the block is appended to the chain database on disk.
|
||||
*
|
||||
* @return true if we switched forks as a result of this push.
|
||||
*/
|
||||
bool database::push_block( const signed_block& new_block, uint32_t skip )
|
||||
{ try {
|
||||
if( !(skip&skip_fork_db) )
|
||||
{
|
||||
wdump((new_block.id())(new_block.previous));
|
||||
auto new_head = _fork_db.push_block( new_block );
|
||||
//If the head block from the longest chain does not build off of the current head, we need to switch forks.
|
||||
if( new_head->data.previous != head_block_id() )
|
||||
{
|
||||
edump((new_head->data.previous));
|
||||
//If the newly pushed block is the same height as head, we get head back in new_head
|
||||
//Only switch forks if new_head is actually higher than head
|
||||
if( new_head->data.block_num() > head_block_num() )
|
||||
{
|
||||
auto branches = _fork_db.fetch_branch_from( new_head->data.id(), _pending_block.previous );
|
||||
for( auto item : branches.first )
|
||||
{
|
||||
wdump( ("new")(item->id)(item->data.previous) );
|
||||
}
|
||||
for( auto item : branches.second )
|
||||
{
|
||||
wdump( ("old")(item->id)(item->data.previous) );
|
||||
}
|
||||
|
||||
// pop blocks until we hit the forked block
|
||||
while( head_block_id() != branches.second.back()->data.previous )
|
||||
pop_block();
|
||||
|
||||
// push all blocks on the new fork
|
||||
for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr )
|
||||
{
|
||||
optional<fc::exception> except;
|
||||
try {
|
||||
auto session = _undo_db.start_undo_session();
|
||||
apply_block( (*ritr)->data, skip );
|
||||
_block_id_to_block.store( new_block.id(), (*ritr)->data );
|
||||
session.commit();
|
||||
}
|
||||
catch ( const fc::exception& e ) { except = e; }
|
||||
if( except )
|
||||
{
|
||||
elog( "Encountered error when switching to a longer fork at id ${id}. Going back.",
|
||||
("id", (*ritr)->id) );
|
||||
// remove the rest of branches.first from the fork_db, those blocks are invalid
|
||||
while( ritr != branches.first.rend() )
|
||||
{
|
||||
_fork_db.remove( (*ritr)->data.id() );
|
||||
++ritr;
|
||||
}
|
||||
_fork_db.set_head( branches.second.front() );
|
||||
|
||||
// pop all blocks from the bad fork
|
||||
while( head_block_id() != branches.second.back()->data.previous )
|
||||
pop_block();
|
||||
|
||||
// restore all blocks from the good fork
|
||||
for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr )
|
||||
{
|
||||
auto session = _undo_db.start_undo_session();
|
||||
apply_block( (*ritr)->data, skip );
|
||||
_block_id_to_block.store( new_block.id(), (*ritr)->data );
|
||||
session.commit();
|
||||
}
|
||||
throw *except;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a pending block session, then the database state is dirty with pending transactions.
|
||||
// Drop the pending session to reset the database to a clean head block state.
|
||||
// TODO: Preserve pending transactions, and re-apply any which weren't included in the new block.
|
||||
clear_pending();
|
||||
|
||||
try {
|
||||
auto session = _undo_db.start_undo_session();
|
||||
apply_block( new_block, skip );
|
||||
_block_id_to_block.store( new_block.id(), new_block );
|
||||
session.commit();
|
||||
} catch ( const fc::exception& e ) {
|
||||
elog("Failed to push new block:\n${e}", ("e", e.to_detail_string()));
|
||||
_fork_db.remove(new_block.id());
|
||||
throw;
|
||||
}
|
||||
|
||||
return false;
|
||||
} FC_CAPTURE_AND_RETHROW( (new_block) ) }
|
||||
|
||||
/**
|
||||
* Attempts to push the transaction into the pending queue
|
||||
*
|
||||
* When called to push a locally generated transaction, set the skip_block_size_check bit on the skip argument. This
|
||||
* will allow the transaction to be pushed even if it causes the pending block size to exceed the maximum block size.
|
||||
* Although the transaction will probably not propagate further now, as the peers are likely to have their pending
|
||||
* queues full as well, it will be kept in the queue to be propagated later when a new block flushes out the pending
|
||||
* queues.
|
||||
*/
|
||||
processed_transaction database::push_transaction( const signed_transaction& trx, uint32_t skip )
|
||||
{
|
||||
//wdump((trx.digest())(trx.id()));
|
||||
// If this is the first transaction pushed after applying a block, start a new undo session.
|
||||
// This allows us to quickly rewind to the clean state of the head block, in case a new block arrives.
|
||||
if( !_pending_block_session ) _pending_block_session = _undo_db.start_undo_session();
|
||||
auto session = _undo_db.start_undo_session();
|
||||
auto processed_trx = apply_transaction( trx, skip );
|
||||
_pending_block.transactions.push_back(processed_trx);
|
||||
|
||||
FC_ASSERT( (skip & skip_block_size_check) ||
|
||||
fc::raw::pack_size(_pending_block) <= get_global_properties().parameters.maximum_block_size );
|
||||
|
||||
// The transaction applied successfully. Merge its changes into the pending block session.
|
||||
session.merge();
|
||||
return processed_trx;
|
||||
}
|
||||
|
||||
processed_transaction database::push_proposal(const proposal_object& proposal)
|
||||
{
|
||||
transaction_evaluation_state eval_state(this);
|
||||
eval_state._is_proposed_trx = true;
|
||||
|
||||
//Inject the approving authorities into the transaction eval state
|
||||
std::transform(proposal.required_active_approvals.begin(),
|
||||
proposal.required_active_approvals.end(),
|
||||
std::inserter(eval_state.approved_by, eval_state.approved_by.begin()),
|
||||
[]( account_id_type id ) {
|
||||
return std::make_pair(id, authority::active);
|
||||
});
|
||||
std::transform(proposal.required_owner_approvals.begin(),
|
||||
proposal.required_owner_approvals.end(),
|
||||
std::inserter(eval_state.approved_by, eval_state.approved_by.begin()),
|
||||
[]( account_id_type id ) {
|
||||
return std::make_pair(id, authority::owner);
|
||||
});
|
||||
|
||||
ilog("Attempting to push proposal ${prop}", ("prop", proposal));
|
||||
idump((eval_state.approved_by));
|
||||
|
||||
eval_state.operation_results.reserve(proposal.proposed_transaction.operations.size());
|
||||
processed_transaction ptrx(proposal.proposed_transaction);
|
||||
eval_state._trx = &ptrx;
|
||||
|
||||
auto session = _undo_db.start_undo_session();
|
||||
for( auto& op : proposal.proposed_transaction.operations )
|
||||
eval_state.operation_results.emplace_back(apply_operation(eval_state, op));
|
||||
remove(proposal);
|
||||
session.merge();
|
||||
|
||||
ptrx.operation_results = std::move(eval_state.operation_results);
|
||||
return ptrx;
|
||||
}
|
||||
|
||||
signed_block database::generate_block(
|
||||
fc::time_point_sec when,
|
||||
witness_id_type witness_id,
|
||||
const fc::ecc::private_key& block_signing_private_key,
|
||||
uint32_t skip /* = 0 */
|
||||
)
|
||||
{
|
||||
try {
|
||||
uint32_t slot_num = get_slot_at_time( when );
|
||||
witness_id_type scheduled_witness = get_scheduled_witness( slot_num ).first;
|
||||
FC_ASSERT( scheduled_witness == witness_id );
|
||||
|
||||
const auto& witness_obj = witness_id(*this);
|
||||
|
||||
if( !(skip & skip_delegate_signature) )
|
||||
FC_ASSERT( witness_obj.signing_key(*this).key() == block_signing_private_key.get_public_key() );
|
||||
|
||||
_pending_block.timestamp = when;
|
||||
|
||||
secret_hash_type::encoder last_enc;
|
||||
fc::raw::pack( last_enc, block_signing_private_key );
|
||||
fc::raw::pack( last_enc, witness_obj.last_secret );
|
||||
_pending_block.previous_secret = last_enc.result();
|
||||
|
||||
secret_hash_type::encoder next_enc;
|
||||
fc::raw::pack( next_enc, block_signing_private_key );
|
||||
fc::raw::pack( next_enc, _pending_block.previous_secret );
|
||||
_pending_block.next_secret_hash = secret_hash_type::hash(next_enc.result());
|
||||
|
||||
_pending_block.transaction_merkle_root = _pending_block.calculate_merkle_root();
|
||||
|
||||
_pending_block.witness = witness_id;
|
||||
if( !(skip & skip_delegate_signature) ) _pending_block.sign( block_signing_private_key );
|
||||
|
||||
FC_ASSERT( fc::raw::pack_size(_pending_block) <= get_global_properties().parameters.maximum_block_size );
|
||||
//This line used to std::move(_pending_block) but this is unsafe as _pending_block is later referenced without being
|
||||
//reinitialized. Future optimization could be to move it, then reinitialize it with the values we need to preserve.
|
||||
signed_block tmp = _pending_block;
|
||||
tmp.transaction_merkle_root = tmp.calculate_merkle_root();
|
||||
_pending_block.transactions.clear();
|
||||
push_block( tmp, skip );
|
||||
return tmp;
|
||||
} FC_CAPTURE_AND_RETHROW( (witness_id) ) }
|
||||
|
||||
/**
|
||||
* Removes the most recent block from the database and
|
||||
* undoes any changes it made.
|
||||
*/
|
||||
void database::pop_block()
|
||||
{ try {
|
||||
_pending_block_session.reset();
|
||||
_block_id_to_block.remove( _pending_block.previous );
|
||||
pop_undo();
|
||||
_pending_block.previous = head_block_id();
|
||||
_pending_block.timestamp = head_block_time();
|
||||
_fork_db.pop_block();
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
void database::clear_pending()
|
||||
{ try {
|
||||
_pending_block.transactions.clear();
|
||||
_pending_block_session.reset();
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
uint32_t database::push_applied_operation( const operation& op )
|
||||
{
|
||||
_applied_ops.emplace_back(op);
|
||||
auto& oh = _applied_ops.back();
|
||||
oh.block_num = _current_block_num;
|
||||
oh.trx_in_block = _current_trx_in_block;
|
||||
oh.op_in_trx = _current_op_in_trx;
|
||||
oh.virtual_op = _current_virtual_op++;
|
||||
return _applied_ops.size() - 1;
|
||||
}
|
||||
void database::set_applied_operation_result( uint32_t op_id, const operation_result& result )
|
||||
{
|
||||
assert( op_id < _applied_ops.size() );
|
||||
_applied_ops[op_id].result = result;
|
||||
}
|
||||
|
||||
const vector<operation_history_object>& database::get_applied_operations() const
|
||||
{
|
||||
return _applied_ops;
|
||||
}
|
||||
|
||||
//////////////////// private methods ////////////////////
|
||||
|
||||
void database::apply_block( const signed_block& next_block, uint32_t skip )
|
||||
{ try {
|
||||
_applied_ops.clear();
|
||||
|
||||
FC_ASSERT( (skip & skip_merkle_check) || next_block.transaction_merkle_root == next_block.calculate_merkle_root() );
|
||||
|
||||
const witness_object& signing_witness = validate_block_header(skip, next_block);
|
||||
const auto& global_props = get_global_properties();
|
||||
const auto& dynamic_global_props = get<dynamic_global_property_object>(dynamic_global_property_id_type());
|
||||
|
||||
_current_block_num = next_block.block_num();
|
||||
_current_trx_in_block = 0;
|
||||
|
||||
for( const auto& trx : next_block.transactions )
|
||||
{
|
||||
/* We do not need to push the undo state for each transaction
|
||||
* because they either all apply and are valid or the
|
||||
* entire block fails to apply. We only need an "undo" state
|
||||
* for transactions when validating broadcast transactions or
|
||||
* when building a block.
|
||||
*/
|
||||
apply_transaction( trx, skip | skip_transaction_signatures );
|
||||
++_current_trx_in_block;
|
||||
}
|
||||
|
||||
update_witness_schedule(next_block);
|
||||
update_global_dynamic_data(next_block);
|
||||
update_signing_witness(signing_witness, next_block);
|
||||
|
||||
auto current_block_interval = global_props.parameters.block_interval;
|
||||
|
||||
// Are we at the maintenance interval?
|
||||
if( dynamic_global_props.next_maintenance_time <= next_block.timestamp )
|
||||
// This will update _pending_block.timestamp if the block interval has changed
|
||||
perform_chain_maintenance(next_block, global_props);
|
||||
|
||||
create_block_summary(next_block);
|
||||
clear_expired_transactions();
|
||||
clear_expired_proposals();
|
||||
clear_expired_orders();
|
||||
update_expired_feeds();
|
||||
update_withdraw_permissions();
|
||||
|
||||
// notify observers that the block has been applied
|
||||
applied_block( next_block ); //emit
|
||||
_applied_ops.clear();
|
||||
|
||||
const auto& head_undo = _undo_db.head();
|
||||
vector<object_id_type> changed_ids; changed_ids.reserve(head_undo.old_values.size());
|
||||
for( const auto& item : head_undo.old_values ) changed_ids.push_back(item.first);
|
||||
changed_objects(changed_ids);
|
||||
|
||||
|
||||
update_pending_block(next_block, current_block_interval);
|
||||
} FC_CAPTURE_AND_RETHROW( (next_block.block_num())(skip) ) }
|
||||
|
||||
processed_transaction database::apply_transaction( const signed_transaction& trx, uint32_t skip )
|
||||
{ try {
|
||||
trx.validate();
|
||||
auto& trx_idx = get_mutable_index_type<transaction_index>();
|
||||
auto trx_id = trx.id();
|
||||
FC_ASSERT( (skip & skip_transaction_dupe_check) ||
|
||||
trx_idx.indices().get<by_trx_id>().find(trx_id) == trx_idx.indices().get<by_trx_id>().end() );
|
||||
transaction_evaluation_state eval_state(this, skip&skip_authority_check );
|
||||
const chain_parameters& chain_parameters = get_global_properties().parameters;
|
||||
eval_state._trx = &trx;
|
||||
|
||||
//This check is used only if this transaction has an absolute expiration time.
|
||||
if( !(skip & skip_transaction_signatures) && trx.relative_expiration == 0 )
|
||||
{
|
||||
for( const auto& sig : trx.signatures )
|
||||
{
|
||||
FC_ASSERT( sig.first(*this).key_address() == fc::ecc::public_key( sig.second, trx.digest() ), "",
|
||||
("trx",trx)
|
||||
("digest",trx.digest())
|
||||
("sig.first",sig.first)
|
||||
("key_address",sig.first(*this).key_address())
|
||||
("addr", address(fc::ecc::public_key( sig.second, trx.digest() ))) );
|
||||
}
|
||||
}
|
||||
|
||||
//If we're skipping tapos check, but not dupe check, assume all transactions have maximum expiration time.
|
||||
fc::time_point_sec trx_expiration = _pending_block.timestamp + chain_parameters.maximum_time_until_expiration;
|
||||
|
||||
//Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is
|
||||
//expired, and TaPoS makes no sense as no blocks exist.
|
||||
if( BOOST_LIKELY(head_block_num() > 0) )
|
||||
{
|
||||
if( !(skip & skip_tapos_check) && trx.relative_expiration != 0 )
|
||||
{
|
||||
//Check the TaPoS reference and expiration time
|
||||
//Remember that the TaPoS block number is abbreviated; it contains only the lower 16 bits.
|
||||
//Lookup TaPoS block summary by block number (remember block summary instances are the block numbers)
|
||||
const block_summary_object& tapos_block_summary
|
||||
= static_cast<const block_summary_object&>(get_index<block_summary_object>()
|
||||
.get(block_summary_id_type((head_block_num() & ~0xffff)
|
||||
+ trx.ref_block_num)));
|
||||
|
||||
//This is the signature check for transactions with relative expiration.
|
||||
if( !(skip & skip_transaction_signatures) )
|
||||
{
|
||||
for( const auto& sig : trx.signatures )
|
||||
{
|
||||
address trx_addr = fc::ecc::public_key(sig.second, trx.digest(tapos_block_summary.block_id));
|
||||
FC_ASSERT(sig.first(*this).key_address() == trx_addr,
|
||||
"",
|
||||
("sig.first",sig.first)
|
||||
("key_address",sig.first(*this).key_address())
|
||||
("addr", trx_addr));
|
||||
}
|
||||
}
|
||||
|
||||
//Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
|
||||
FC_ASSERT( trx.ref_block_prefix == tapos_block_summary.block_id._hash[1] );
|
||||
trx_expiration = tapos_block_summary.timestamp + chain_parameters.block_interval*trx.relative_expiration;
|
||||
} else if( trx.relative_expiration == 0 ) {
|
||||
trx_expiration = fc::time_point_sec(trx.ref_block_prefix);
|
||||
FC_ASSERT( trx_expiration <= _pending_block.timestamp + chain_parameters.maximum_time_until_expiration );
|
||||
}
|
||||
FC_ASSERT( _pending_block.timestamp <= trx_expiration );
|
||||
} else if( !(skip & skip_transaction_signatures) ) {
|
||||
FC_ASSERT(trx.relative_expiration == 0, "May not use transactions with a reference block in block 1!");
|
||||
}
|
||||
|
||||
//Insert transaction into unique transactions database.
|
||||
if( !(skip & skip_transaction_dupe_check) )
|
||||
{
|
||||
create<transaction_object>([&](transaction_object& transaction) {
|
||||
transaction.expiration = trx_expiration;
|
||||
transaction.trx_id = trx_id;
|
||||
transaction.trx = trx;
|
||||
});
|
||||
}
|
||||
|
||||
eval_state.operation_results.reserve( trx.operations.size() );
|
||||
|
||||
processed_transaction ptrx(trx);
|
||||
_current_op_in_trx = 0;
|
||||
for( const auto& op : ptrx.operations )
|
||||
{
|
||||
eval_state.operation_results.emplace_back(apply_operation(eval_state, op));
|
||||
++_current_op_in_trx;
|
||||
}
|
||||
ptrx.operation_results = std::move( eval_state.operation_results );
|
||||
|
||||
return ptrx;
|
||||
} FC_CAPTURE_AND_RETHROW( (trx) ) }
|
||||
|
||||
operation_result database::apply_operation(transaction_evaluation_state& eval_state, const operation& op)
|
||||
{
|
||||
int i_which = op.which();
|
||||
uint64_t u_which = uint64_t( i_which );
|
||||
if( i_which < 0 )
|
||||
assert( "Negative operation tag" && false );
|
||||
if( u_which >= _operation_evaluators.size() )
|
||||
assert( "No registered evaluator for this operation" && false );
|
||||
unique_ptr<op_evaluator>& eval = _operation_evaluators[ u_which ];
|
||||
if( !eval )
|
||||
assert( "No registered evaluator for this operation" && false );
|
||||
auto op_id = push_applied_operation( op );
|
||||
auto result = eval->evaluate( eval_state, op, true );
|
||||
set_applied_operation_result( op_id, result );
|
||||
return result;
|
||||
}
|
||||
|
||||
const witness_object& database::validate_block_header( uint32_t skip, const signed_block& next_block )const
|
||||
{
|
||||
FC_ASSERT( _pending_block.previous == next_block.previous, "", ("pending.prev",_pending_block.previous)("next.prev",next_block.previous) );
|
||||
FC_ASSERT( _pending_block.timestamp <= next_block.timestamp, "", ("_pending_block.timestamp",_pending_block.timestamp)("next",next_block.timestamp)("blocknum",next_block.block_num()) );
|
||||
const witness_object& witness = next_block.witness(*this);
|
||||
FC_ASSERT( secret_hash_type::hash(next_block.previous_secret) == witness.next_secret, "",
|
||||
("previous_secret", next_block.previous_secret)("next_secret", witness.next_secret));
|
||||
if( !(skip&skip_delegate_signature) ) FC_ASSERT( next_block.validate_signee( witness.signing_key(*this).key() ) );
|
||||
|
||||
uint32_t slot_num = get_slot_at_time( next_block.timestamp );
|
||||
FC_ASSERT( slot_num > 0 );
|
||||
|
||||
witness_id_type scheduled_witness = get_scheduled_witness( slot_num ).first;
|
||||
FC_ASSERT( next_block.witness == scheduled_witness );
|
||||
|
||||
return witness;
|
||||
}
|
||||
|
||||
void database::create_block_summary(const signed_block& next_block)
|
||||
{
|
||||
const auto& sum = create<block_summary_object>( [&](block_summary_object& p) {
|
||||
p.block_id = next_block.id();
|
||||
p.timestamp = next_block.timestamp;
|
||||
});
|
||||
FC_ASSERT( sum.id.instance() == next_block.block_num(), "", ("summary.id",sum.id)("next.block_num",next_block.block_num()) );
|
||||
}
|
||||
|
||||
} }
|
||||
95
libraries/chain/db_debug.cpp
Normal file
95
libraries/chain/db_debug.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/limit_order_object.hpp>
|
||||
#include <graphene/chain/short_order_object.hpp>
|
||||
#include <graphene/chain/vesting_balance_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* This method dumps the state of the blockchain in a semi-human readable form for the
|
||||
* purpose of tracking down funds and mismatches in currency allocation
|
||||
*/
|
||||
void database::debug_dump()
|
||||
{
|
||||
const auto& db = *this;
|
||||
const asset_dynamic_data_object& core_asset_data = db.get_core_asset().dynamic_asset_data_id(db);
|
||||
|
||||
const auto& balance_index = db.get_index_type<account_balance_index>().indices();
|
||||
const simple_index<account_statistics_object>& statistics_index = db.get_index_type<simple_index<account_statistics_object>>();
|
||||
map<asset_id_type,share_type> total_balances;
|
||||
map<asset_id_type,share_type> total_debts;
|
||||
share_type core_in_orders;
|
||||
share_type reported_core_in_orders;
|
||||
|
||||
for( const account_balance_object& a : balance_index )
|
||||
{
|
||||
idump(("balance")(a));
|
||||
total_balances[a.asset_type] += a.balance;
|
||||
}
|
||||
for( const account_statistics_object& s : statistics_index )
|
||||
{
|
||||
idump(("statistics")(s));
|
||||
reported_core_in_orders += s.total_core_in_orders;
|
||||
}
|
||||
for( const limit_order_object& o : db.get_index_type<limit_order_index>().indices() )
|
||||
{
|
||||
idump(("limit_order")(o));
|
||||
auto for_sale = o.amount_for_sale();
|
||||
if( for_sale.asset_id == asset_id_type() ) core_in_orders += for_sale.amount;
|
||||
total_balances[for_sale.asset_id] += for_sale.amount;
|
||||
}
|
||||
for( const short_order_object& o : db.get_index_type<short_order_index>().indices() )
|
||||
{
|
||||
idump(("short_order")(o));
|
||||
auto col = o.get_collateral();
|
||||
if( col.asset_id == asset_id_type() ) core_in_orders += col.amount;
|
||||
total_balances[col.asset_id] += col.amount;
|
||||
}
|
||||
for( const call_order_object& o : db.get_index_type<call_order_index>().indices() )
|
||||
{
|
||||
idump(("call_order")(o));
|
||||
auto col = o.get_collateral();
|
||||
if( col.asset_id == asset_id_type() ) core_in_orders += col.amount;
|
||||
total_balances[col.asset_id] += col.amount;
|
||||
total_debts[o.get_debt().asset_id] += o.get_debt().amount;
|
||||
}
|
||||
for( const asset_object& asset_obj : db.get_index_type<asset_index>().indices() )
|
||||
{
|
||||
total_balances[asset_obj.id] += asset_obj.dynamic_asset_data_id(db).accumulated_fees;
|
||||
total_balances[asset_id_type()] += asset_obj.dynamic_asset_data_id(db).fee_pool;
|
||||
}
|
||||
for( const witness_object& witness_obj : db.get_index_type<simple_index<witness_object>>() )
|
||||
{
|
||||
//idump((witness_obj));
|
||||
total_balances[asset_id_type()] += witness_obj.accumulated_income;
|
||||
}
|
||||
if( total_balances[asset_id_type()].value != core_asset_data.current_supply.value )
|
||||
{
|
||||
edump( (total_balances[asset_id_type()].value)(core_asset_data.current_supply.value ));
|
||||
}
|
||||
// TODO: Add vesting_balance_object to this method
|
||||
}
|
||||
|
||||
} }
|
||||
66
libraries/chain/db_getter.cpp
Normal file
66
libraries/chain/db_getter.cpp
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/global_property_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
const asset_object& database::get_core_asset() const
|
||||
{
|
||||
return get(asset_id_type());
|
||||
}
|
||||
|
||||
const global_property_object& database::get_global_properties()const
|
||||
{
|
||||
return get( global_property_id_type() );
|
||||
}
|
||||
|
||||
const dynamic_global_property_object&database::get_dynamic_global_properties() const
|
||||
{
|
||||
return get( dynamic_global_property_id_type() );
|
||||
}
|
||||
|
||||
const fee_schedule_type& database::current_fee_schedule()const
|
||||
{
|
||||
return get_global_properties().parameters.current_fees;
|
||||
}
|
||||
|
||||
time_point_sec database::head_block_time()const
|
||||
{
|
||||
return get( dynamic_global_property_id_type() ).time;
|
||||
}
|
||||
|
||||
uint32_t database::head_block_num()const
|
||||
{
|
||||
return get( dynamic_global_property_id_type() ).head_block_number;
|
||||
}
|
||||
|
||||
block_id_type database::head_block_id()const
|
||||
{
|
||||
return get( dynamic_global_property_id_type() ).head_block_id;
|
||||
}
|
||||
|
||||
decltype( chain_parameters::block_interval ) database::block_interval( )const
|
||||
{
|
||||
return get_global_properties().parameters.block_interval;
|
||||
}
|
||||
|
||||
} }
|
||||
334
libraries/chain/db_init.cpp
Normal file
334
libraries/chain/db_init.cpp
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/block_summary_object.hpp>
|
||||
#include <graphene/chain/bond_object.hpp>
|
||||
#include <graphene/chain/delegate_object.hpp>
|
||||
#include <graphene/chain/file_object.hpp>
|
||||
#include <graphene/chain/global_property_object.hpp>
|
||||
#include <graphene/chain/key_object.hpp>
|
||||
#include <graphene/chain/limit_order_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/short_order_object.hpp>
|
||||
#include <graphene/chain/transaction_object.hpp>
|
||||
#include <graphene/chain/vesting_balance_object.hpp>
|
||||
#include <graphene/chain/withdraw_permission_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
#include <graphene/chain/witness_schedule_object.hpp>
|
||||
#include <graphene/chain/worker_object.hpp>
|
||||
|
||||
#include <graphene/chain/account_evaluator.hpp>
|
||||
#include <graphene/chain/asset_evaluator.hpp>
|
||||
#include <graphene/chain/bond_evaluator.hpp>
|
||||
#include <graphene/chain/custom_evaluator.hpp>
|
||||
#include <graphene/chain/delegate_evaluator.hpp>
|
||||
#include <graphene/chain/global_parameters_evaluator.hpp>
|
||||
#include <graphene/chain/key_evaluator.hpp>
|
||||
#include <graphene/chain/limit_order_evaluator.hpp>
|
||||
#include <graphene/chain/proposal_evaluator.hpp>
|
||||
#include <graphene/chain/short_order_evaluator.hpp>
|
||||
#include <graphene/chain/transfer_evaluator.hpp>
|
||||
#include <graphene/chain/vesting_balance_evaluator.hpp>
|
||||
#include <graphene/chain/withdraw_permission_evaluator.hpp>
|
||||
#include <graphene/chain/witness_evaluator.hpp>
|
||||
#include <graphene/chain/worker_evaluator.hpp>
|
||||
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
#include <fc/crypto/digest.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
void database::initialize_evaluators()
|
||||
{
|
||||
_operation_evaluators.resize(255);
|
||||
register_evaluator<key_create_evaluator>();
|
||||
register_evaluator<account_create_evaluator>();
|
||||
register_evaluator<account_update_evaluator>();
|
||||
register_evaluator<account_whitelist_evaluator>();
|
||||
register_evaluator<delegate_create_evaluator>();
|
||||
register_evaluator<custom_evaluator>();
|
||||
register_evaluator<asset_create_evaluator>();
|
||||
register_evaluator<asset_issue_evaluator>();
|
||||
register_evaluator<asset_burn_evaluator>();
|
||||
register_evaluator<asset_update_evaluator>();
|
||||
register_evaluator<asset_update_bitasset_evaluator>();
|
||||
register_evaluator<asset_update_feed_producers_evaluator>();
|
||||
register_evaluator<asset_settle_evaluator>();
|
||||
register_evaluator<asset_global_settle_evaluator>();
|
||||
register_evaluator<limit_order_create_evaluator>();
|
||||
register_evaluator<limit_order_cancel_evaluator>();
|
||||
register_evaluator<short_order_create_evaluator>();
|
||||
register_evaluator<short_order_cancel_evaluator>();
|
||||
register_evaluator<call_order_update_evaluator>();
|
||||
register_evaluator<transfer_evaluator>();
|
||||
register_evaluator<asset_fund_fee_pool_evaluator>();
|
||||
register_evaluator<asset_publish_feeds_evaluator>();
|
||||
register_evaluator<proposal_create_evaluator>();
|
||||
register_evaluator<proposal_update_evaluator>();
|
||||
register_evaluator<proposal_delete_evaluator>();
|
||||
register_evaluator<global_parameters_update_evaluator>();
|
||||
register_evaluator<witness_create_evaluator>();
|
||||
register_evaluator<witness_withdraw_pay_evaluator>();
|
||||
register_evaluator<bond_create_offer_evaluator>();
|
||||
register_evaluator<bond_cancel_offer_evaluator>();
|
||||
register_evaluator<bond_accept_offer_evaluator>();
|
||||
register_evaluator<bond_claim_collateral_evaluator>();
|
||||
register_evaluator<vesting_balance_create_evaluator>();
|
||||
register_evaluator<vesting_balance_withdraw_evaluator>();
|
||||
register_evaluator<withdraw_permission_create_evaluator>();
|
||||
register_evaluator<withdraw_permission_claim_evaluator>();
|
||||
register_evaluator<withdraw_permission_update_evaluator>();
|
||||
register_evaluator<withdraw_permission_delete_evaluator>();
|
||||
register_evaluator<worker_create_evaluator>();
|
||||
}
|
||||
|
||||
void database::initialize_indexes()
|
||||
{
|
||||
reset_indexes();
|
||||
|
||||
//Protocol object indexes
|
||||
add_index< primary_index<asset_index> >();
|
||||
add_index< primary_index<force_settlement_index> >();
|
||||
add_index< primary_index<account_index> >();
|
||||
add_index< primary_index<simple_index<key_object>> >();
|
||||
add_index< primary_index<simple_index<delegate_object>> >();
|
||||
add_index< primary_index<simple_index<witness_object>> >();
|
||||
add_index< primary_index<limit_order_index > >();
|
||||
add_index< primary_index<short_order_index > >();
|
||||
add_index< primary_index<call_order_index > >();
|
||||
add_index< primary_index<proposal_index > >();
|
||||
add_index< primary_index<withdraw_permission_index > >();
|
||||
add_index< primary_index<bond_index > >();
|
||||
add_index< primary_index<bond_offer_index > >();
|
||||
add_index< primary_index<file_object_index> >();
|
||||
add_index< primary_index<simple_index<vesting_balance_object> > >();
|
||||
add_index< primary_index<worker_index> >();
|
||||
|
||||
//Implementation object indexes
|
||||
add_index< primary_index<transaction_index > >();
|
||||
add_index< primary_index<account_balance_index > >();
|
||||
add_index< primary_index<asset_bitasset_data_index > >();
|
||||
add_index< primary_index<simple_index< global_property_object >> >();
|
||||
add_index< primary_index<simple_index< dynamic_global_property_object >> >();
|
||||
add_index< primary_index<simple_index< account_statistics_object >> >();
|
||||
add_index< primary_index<simple_index< asset_dynamic_data_object >> >();
|
||||
add_index< primary_index<flat_index< block_summary_object >> >();
|
||||
add_index< primary_index< simple_index< witness_schedule_object > > >();
|
||||
}
|
||||
|
||||
void database::init_genesis(const genesis_allocation& initial_allocation)
|
||||
{ try {
|
||||
_undo_db.disable();
|
||||
|
||||
fc::ecc::private_key genesis_private_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("genesis")));
|
||||
const key_object& genesis_key =
|
||||
create<key_object>( [&genesis_private_key](key_object& k) {
|
||||
k.key_data = public_key_type(genesis_private_key.get_public_key());
|
||||
});
|
||||
const account_statistics_object& genesis_statistics =
|
||||
create<account_statistics_object>( [&](account_statistics_object& b){
|
||||
});
|
||||
create<account_balance_object>( [](account_balance_object& b) {
|
||||
b.balance = GRAPHENE_INITIAL_SUPPLY;
|
||||
});
|
||||
const account_object& genesis_account =
|
||||
create<account_object>( [&](account_object& n) {
|
||||
n.name = "genesis";
|
||||
n.owner.add_authority(genesis_key.get_id(), 1);
|
||||
n.owner.weight_threshold = 1;
|
||||
n.active = n.owner;
|
||||
n.memo_key = genesis_key.id;
|
||||
n.statistics = genesis_statistics.id;
|
||||
});
|
||||
|
||||
vector<delegate_id_type> init_delegates;
|
||||
vector<witness_id_type> init_witnesses;
|
||||
flat_set<witness_id_type> init_witness_set;
|
||||
|
||||
auto delegates_and_witnesses = std::max(GRAPHENE_MIN_WITNESS_COUNT, GRAPHENE_MIN_DELEGATE_COUNT);
|
||||
for( int i = 0; i < delegates_and_witnesses; ++i )
|
||||
{
|
||||
const account_statistics_object& stats_obj =
|
||||
create<account_statistics_object>( [&](account_statistics_object&){
|
||||
});
|
||||
const account_object& delegate_account =
|
||||
create<account_object>( [&](account_object& a) {
|
||||
a.active = a.owner = genesis_account.owner;
|
||||
a.name = string("init") + fc::to_string(i);
|
||||
a.statistics = stats_obj.id;
|
||||
});
|
||||
const delegate_object& init_delegate = create<delegate_object>( [&](delegate_object& d) {
|
||||
d.delegate_account = delegate_account.id;
|
||||
d.vote_id = i * 2;
|
||||
});
|
||||
init_delegates.push_back(init_delegate.id);
|
||||
|
||||
const witness_object& init_witness = create<witness_object>( [&](witness_object& d) {
|
||||
d.witness_account = delegate_account.id;
|
||||
d.vote_id = i * 2 + 1;
|
||||
secret_hash_type::encoder enc;
|
||||
fc::raw::pack( enc, genesis_private_key );
|
||||
fc::raw::pack( enc, d.last_secret );
|
||||
d.next_secret = secret_hash_type::hash(enc.result());
|
||||
});
|
||||
init_witnesses.push_back(init_witness.id);
|
||||
init_witness_set.insert(init_witness.id);
|
||||
|
||||
}
|
||||
create<block_summary_object>( [&](block_summary_object& p) {
|
||||
});
|
||||
|
||||
const witness_schedule_object& wso =
|
||||
create<witness_schedule_object>( [&]( witness_schedule_object& _wso )
|
||||
{
|
||||
memset( _wso.rng_seed.begin(), 0, _wso.rng_seed.size() );
|
||||
|
||||
witness_scheduler_rng rng( _wso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV );
|
||||
|
||||
_wso.scheduler = witness_scheduler();
|
||||
_wso.scheduler._min_token_count = init_witnesses.size() / 2;
|
||||
_wso.scheduler.update( init_witness_set );
|
||||
|
||||
for( int i=0; i<init_witnesses.size(); i++ )
|
||||
_wso.scheduler.produce_schedule( rng );
|
||||
|
||||
_wso.last_scheduling_block = 0;
|
||||
} ) ;
|
||||
assert( wso.id == witness_schedule_id_type() );
|
||||
|
||||
const global_property_object& properties =
|
||||
create<global_property_object>( [&](global_property_object& p) {
|
||||
p.active_delegates = init_delegates;
|
||||
for( const witness_id_type& wit : init_witnesses )
|
||||
p.active_witnesses.insert( wit );
|
||||
p.next_available_vote_id = delegates_and_witnesses * 2;
|
||||
p.chain_id = fc::digest(initial_allocation);
|
||||
});
|
||||
(void)properties;
|
||||
|
||||
create<dynamic_global_property_object>( [&](dynamic_global_property_object& p) {
|
||||
p.time = fc::time_point_sec( GRAPHENE_GENESIS_TIMESTAMP );
|
||||
});
|
||||
|
||||
const asset_dynamic_data_object& dyn_asset =
|
||||
create<asset_dynamic_data_object>( [&]( asset_dynamic_data_object& a ) {
|
||||
a.current_supply = GRAPHENE_INITIAL_SUPPLY;
|
||||
});
|
||||
|
||||
const asset_object& core_asset =
|
||||
create<asset_object>( [&]( asset_object& a ) {
|
||||
a.symbol = GRAPHENE_SYMBOL;
|
||||
a.options.max_supply = GRAPHENE_INITIAL_SUPPLY;
|
||||
a.precision = GRAPHENE_BLOCKCHAIN_PRECISION_DIGITS;
|
||||
a.options.flags = 0;
|
||||
a.options.issuer_permissions = 0;
|
||||
a.issuer = genesis_account.id;
|
||||
a.options.core_exchange_rate.base.amount = 1;
|
||||
a.options.core_exchange_rate.base.asset_id = 0;
|
||||
a.options.core_exchange_rate.quote.amount = 1;
|
||||
a.options.core_exchange_rate.quote.asset_id = 0;
|
||||
a.dynamic_asset_data_id = dyn_asset.id;
|
||||
});
|
||||
assert( asset_id_type(core_asset.id) == asset().asset_id );
|
||||
assert( get_balance(account_id_type(), asset_id_type()) == asset(dyn_asset.current_supply) );
|
||||
(void)core_asset;
|
||||
|
||||
if( !initial_allocation.empty() )
|
||||
{
|
||||
share_type total_allocation = 0;
|
||||
for( const auto& handout : initial_allocation )
|
||||
total_allocation += handout.second;
|
||||
|
||||
auto mangle_to_name = [](const fc::static_variant<public_key_type, address>& key) {
|
||||
string addr = string(key.which() == std::decay<decltype(key)>::type::tag<address>::value? key.get<address>()
|
||||
: key.get<public_key_type>());
|
||||
string result = "bts";
|
||||
string key_string = string(addr).substr(sizeof(GRAPHENE_ADDRESS_PREFIX)-1);
|
||||
for( char c : key_string )
|
||||
{
|
||||
if( isupper(c) )
|
||||
result += string("-") + char(tolower(c));
|
||||
else
|
||||
result += c;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
fc::time_point start_time = fc::time_point::now();
|
||||
|
||||
for( const auto& handout : initial_allocation )
|
||||
{
|
||||
asset amount(handout.second);
|
||||
amount.amount = ((fc::uint128(amount.amount.value) * GRAPHENE_INITIAL_SUPPLY)/total_allocation.value).to_uint64();
|
||||
if( amount.amount == 0 )
|
||||
{
|
||||
wlog("Skipping zero allocation to ${k}", ("k", handout.first));
|
||||
continue;
|
||||
}
|
||||
|
||||
signed_transaction trx;
|
||||
trx.operations.emplace_back(key_create_operation({asset(), genesis_account.id, handout.first}));
|
||||
relative_key_id_type key_id(0);
|
||||
authority account_authority(1, key_id, 1);
|
||||
account_create_operation cop;
|
||||
cop.name = mangle_to_name(handout.first);
|
||||
cop.registrar = account_id_type(1);
|
||||
cop.active = account_authority;
|
||||
cop.owner = account_authority;
|
||||
cop.memo_key = key_id;
|
||||
trx.operations.push_back(cop);
|
||||
trx.validate();
|
||||
auto ptrx = apply_transaction(trx, ~0);
|
||||
trx = signed_transaction();
|
||||
account_id_type account_id(ptrx.operation_results.back().get<object_id_type>());
|
||||
trx.operations.emplace_back(transfer_operation({ asset(),
|
||||
genesis_account.id,
|
||||
account_id,
|
||||
amount,
|
||||
memo_data()//vector<char>()
|
||||
}));
|
||||
trx.validate();
|
||||
apply_transaction(trx, ~0);
|
||||
}
|
||||
|
||||
asset leftovers = get_balance(account_id_type(), asset_id_type());
|
||||
if( leftovers.amount > 0 )
|
||||
{
|
||||
modify(*get_index_type<account_balance_index>().indices().get<by_balance>().find(boost::make_tuple(account_id_type(), asset_id_type())),
|
||||
[](account_balance_object& b) {
|
||||
b.adjust_balance(-b.get_balance());
|
||||
});
|
||||
modify(core_asset.dynamic_asset_data_id(*this), [&leftovers](asset_dynamic_data_object& d) {
|
||||
d.accumulated_fees += leftovers.amount;
|
||||
});
|
||||
}
|
||||
|
||||
fc::microseconds duration = fc::time_point::now() - start_time;
|
||||
ilog("Finished allocating to ${n} accounts in ${t} milliseconds.",
|
||||
("n", initial_allocation.size())("t", duration.count() / 1000));
|
||||
}
|
||||
|
||||
_undo_db.enable();
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
} }
|
||||
420
libraries/chain/db_maint.cpp
Normal file
420
libraries/chain/db_maint.cpp
Normal file
|
|
@ -0,0 +1,420 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/delegate_object.hpp>
|
||||
#include <graphene/chain/global_property_object.hpp>
|
||||
#include <graphene/chain/vesting_balance_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
#include <graphene/chain/witness_schedule_object.hpp>
|
||||
#include <graphene/chain/worker_object.hpp>
|
||||
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
template<class ObjectType>
|
||||
vector<std::reference_wrapper<const ObjectType>> database::sort_votable_objects(size_t count) const
|
||||
{
|
||||
const auto& all_objects = dynamic_cast<const simple_index<ObjectType>&>(get_index<ObjectType>());
|
||||
count = std::min(count, all_objects.size());
|
||||
vector<std::reference_wrapper<const ObjectType>> refs;
|
||||
refs.reserve(all_objects.size());
|
||||
std::transform(all_objects.begin(), all_objects.end(),
|
||||
std::back_inserter(refs),
|
||||
[](const ObjectType& o) { return std::cref(o); });
|
||||
std::partial_sort( refs.begin(), refs.begin() + count, refs.end(),
|
||||
[this]( const ObjectType& a, const ObjectType& b )->bool {
|
||||
return _vote_tally_buffer[a.vote_id] > _vote_tally_buffer[b.vote_id];
|
||||
});
|
||||
|
||||
refs.resize(count, refs.front());
|
||||
return refs;
|
||||
}
|
||||
|
||||
void database::pay_workers( share_type& budget )
|
||||
{
|
||||
ilog("Processing payroll! Available budget is ${b}", ("b", budget));
|
||||
vector<std::reference_wrapper<const worker_object>> active_workers;
|
||||
get_index_type<worker_index>().inspect_all_objects([this, &active_workers](const object& o) {
|
||||
const worker_object& w = static_cast<const worker_object&>(o);
|
||||
auto now = _pending_block.timestamp;
|
||||
if( w.is_active(now) && w.approving_stake(_vote_tally_buffer) > 0 )
|
||||
active_workers.emplace_back(w);
|
||||
});
|
||||
|
||||
std::sort(active_workers.begin(), active_workers.end(), [this](const worker_object& wa, const worker_object& wb) {
|
||||
return wa.approving_stake(_vote_tally_buffer) > wb.approving_stake(_vote_tally_buffer);
|
||||
});
|
||||
|
||||
for( int i = 0; i < active_workers.size() && budget > 0; ++i )
|
||||
{
|
||||
const worker_object& active_worker = active_workers[i];
|
||||
share_type requested_pay = active_worker.daily_pay;
|
||||
if( _pending_block.timestamp - get_dynamic_global_properties().last_budget_time != fc::days(1) )
|
||||
{
|
||||
fc::uint128 pay(requested_pay.value);
|
||||
pay *= (_pending_block.timestamp - get_dynamic_global_properties().last_budget_time).count();
|
||||
pay /= fc::days(1).count();
|
||||
requested_pay = pay.to_uint64();
|
||||
}
|
||||
|
||||
share_type actual_pay = std::min(budget, requested_pay);
|
||||
ilog(" ==> Paying ${a} to worker ${w}", ("w", active_worker.id)("a", actual_pay));
|
||||
modify(active_worker, [&](worker_object& w) {
|
||||
w.worker.visit(worker_pay_visitor(actual_pay, *this));
|
||||
});
|
||||
|
||||
budget -= actual_pay;
|
||||
}
|
||||
}
|
||||
|
||||
void database::update_active_witnesses()
|
||||
{ try {
|
||||
assert( _witness_count_histogram_buffer.size() > 0 );
|
||||
share_type stake_target = _total_voting_stake / 2;
|
||||
share_type stake_tally = _witness_count_histogram_buffer[0];
|
||||
int witness_count = 0;
|
||||
while( (size_t(witness_count) < _witness_count_histogram_buffer.size())
|
||||
&& (stake_tally <= stake_target) )
|
||||
stake_tally += _witness_count_histogram_buffer[++witness_count];
|
||||
|
||||
auto wits = sort_votable_objects<witness_object>(std::max(witness_count*2+1, GRAPHENE_MIN_WITNESS_COUNT));
|
||||
const global_property_object& gpo = get_global_properties();
|
||||
|
||||
modify( gpo, [&]( global_property_object& gp ){
|
||||
gp.active_witnesses.clear();
|
||||
gp.active_witnesses.reserve( wits.size() );
|
||||
std::transform(wits.begin(), wits.end(),
|
||||
std::inserter(gp.active_witnesses, gp.active_witnesses.end()),
|
||||
[](const witness_object& w) {
|
||||
return w.id;
|
||||
});
|
||||
gp.witness_accounts.clear();
|
||||
gp.witness_accounts.reserve( wits.size() );
|
||||
std::transform(wits.begin(), wits.end(),
|
||||
std::inserter(gp.witness_accounts, gp.witness_accounts.end()),
|
||||
[](const witness_object& w) {
|
||||
return w.witness_account;
|
||||
});
|
||||
});
|
||||
|
||||
const witness_schedule_object& wso = witness_schedule_id_type()(*this);
|
||||
modify( wso, [&]( witness_schedule_object& _wso )
|
||||
{
|
||||
_wso.scheduler.update( gpo.active_witnesses );
|
||||
} );
|
||||
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
void database::update_active_delegates()
|
||||
{ try {
|
||||
assert( _committee_count_histogram_buffer.size() > 0 );
|
||||
uint64_t stake_target = _total_voting_stake / 2;
|
||||
uint64_t stake_tally = _committee_count_histogram_buffer[0];
|
||||
int delegate_count = 0;
|
||||
while( (size_t(delegate_count) < _committee_count_histogram_buffer.size())
|
||||
&& (stake_tally <= stake_target) )
|
||||
stake_tally += _committee_count_histogram_buffer[++delegate_count];
|
||||
|
||||
auto delegates = sort_votable_objects<delegate_object>(std::max(delegate_count*2+1, GRAPHENE_MIN_DELEGATE_COUNT));
|
||||
|
||||
// Update genesis authorities
|
||||
if( !delegates.empty() )
|
||||
modify( get(account_id_type()), [&]( account_object& a ) {
|
||||
uint64_t total_votes = 0;
|
||||
map<account_id_type, uint64_t> weights;
|
||||
a.owner.weight_threshold = 0;
|
||||
a.owner.auths.clear();
|
||||
|
||||
for( const delegate_object& del : delegates )
|
||||
{
|
||||
weights.emplace(del.delegate_account, _vote_tally_buffer[del.vote_id]);
|
||||
total_votes += _vote_tally_buffer[del.vote_id];
|
||||
}
|
||||
|
||||
// total_votes is 64 bits. Subtract the number of leading low bits from 64 to get the number of useful bits,
|
||||
// then I want to keep the most significant 16 bits of what's left.
|
||||
#ifdef __GNUC__
|
||||
int8_t bits_to_drop = std::max(int(64 - __builtin_clzll(total_votes)) - 16, 0);
|
||||
#else
|
||||
int8_t bits_to_drop = std::max(int(boost::multiprecision::detail::find_msb(total_votes.value)) - 15, 0);
|
||||
#endif
|
||||
for( const auto& weight : weights )
|
||||
{
|
||||
// Ensure that everyone has at least one vote. Zero weights aren't allowed.
|
||||
uint16_t votes = std::max((weight.second >> bits_to_drop), uint64_t(1) );
|
||||
a.owner.auths[weight.first] += votes;
|
||||
a.owner.weight_threshold += votes;
|
||||
}
|
||||
|
||||
a.owner.weight_threshold /= 2;
|
||||
a.owner.weight_threshold += 1;
|
||||
a.active = a.owner;
|
||||
});
|
||||
modify( get_global_properties(), [&]( global_property_object& gp ) {
|
||||
gp.active_delegates.clear();
|
||||
std::transform(delegates.begin(), delegates.end(),
|
||||
std::back_inserter(gp.active_delegates),
|
||||
[](const delegate_object& d) { return d.id; });
|
||||
});
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
void database::update_vote_totals(const global_property_object& props)
|
||||
{ try {
|
||||
_vote_tally_buffer.resize(props.next_available_vote_id);
|
||||
_witness_count_histogram_buffer.resize(props.parameters.maximum_witness_count / 2 + 1);
|
||||
_committee_count_histogram_buffer.resize(props.parameters.maximum_committee_count / 2 + 1);
|
||||
|
||||
const account_index& account_idx = get_index_type<account_index>();
|
||||
_total_voting_stake = 0;
|
||||
|
||||
bool count_non_prime_votes = props.parameters.count_non_prime_votes;
|
||||
auto timestamp = fc::time_point::now();
|
||||
for( const account_object& stake_account : account_idx.indices() )
|
||||
{
|
||||
if( count_non_prime_votes || stake_account.is_prime() )
|
||||
{
|
||||
// There may be a difference between the account whose stake is voting and the one specifying opinions.
|
||||
// Usually they're the same, but if the stake account has specified a voting_account, that account is the one
|
||||
// specifying the opinions.
|
||||
const account_object& opinion_account =
|
||||
(stake_account.voting_account == account_id_type())? stake_account
|
||||
: get(stake_account.voting_account);
|
||||
|
||||
const auto& stats = stake_account.statistics(*this);
|
||||
uint64_t voting_stake = stats.total_core_in_orders.value
|
||||
+ (stake_account.cashback_vb.valid() ? (*stake_account.cashback_vb)(*this).balance.amount.value: 0)
|
||||
+ get_balance(stake_account.get_id(), asset_id_type()).amount.value;
|
||||
|
||||
for( vote_id_type id : opinion_account.votes )
|
||||
{
|
||||
uint32_t offset = id.instance();
|
||||
// if they somehow managed to specify an illegal offset, ignore it.
|
||||
if( offset < _vote_tally_buffer.size() )
|
||||
_vote_tally_buffer[ offset ] += voting_stake;
|
||||
}
|
||||
|
||||
if( opinion_account.num_witness <= props.parameters.maximum_witness_count )
|
||||
{
|
||||
uint16_t offset = std::min(size_t(opinion_account.num_witness/2),
|
||||
_witness_count_histogram_buffer.size() - 1);
|
||||
//
|
||||
// votes for a number greater than maximum_witness_count
|
||||
// are turned into votes for maximum_witness_count.
|
||||
//
|
||||
// in particular, this takes care of the case where a
|
||||
// member was voting for a high number, then the
|
||||
// parameter was lowered.
|
||||
//
|
||||
_witness_count_histogram_buffer[ offset ] += voting_stake;
|
||||
}
|
||||
if( opinion_account.num_committee <= props.parameters.maximum_committee_count )
|
||||
{
|
||||
uint16_t offset = std::min(size_t(opinion_account.num_committee/2),
|
||||
_committee_count_histogram_buffer.size() - 1);
|
||||
//
|
||||
// votes for a number greater than maximum_committee_count
|
||||
// are turned into votes for maximum_committee_count.
|
||||
//
|
||||
// same rationale as for witnesses
|
||||
//
|
||||
_committee_count_histogram_buffer[ offset ] += voting_stake;
|
||||
}
|
||||
|
||||
_total_voting_stake += voting_stake;
|
||||
}
|
||||
}
|
||||
ilog("Tallied votes in ${time} milliseconds.", ("time", (fc::time_point::now() - timestamp).count() / 1000.0));
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
share_type database::get_max_budget( fc::time_point_sec now )const
|
||||
{
|
||||
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
||||
const asset_object& core = asset_id_type(0)(*this);
|
||||
const asset_dynamic_data_object& core_dd = core.dynamic_asset_data_id(*this);
|
||||
|
||||
if( (dpo.last_budget_time == fc::time_point_sec())
|
||||
|| (now <= dpo.last_budget_time) )
|
||||
return share_type(0);
|
||||
|
||||
int64_t dt = (now - dpo.last_budget_time).to_seconds();
|
||||
|
||||
// We'll consider accumulated_fees to be burned at the BEGINNING
|
||||
// of the maintenance interval. However, for speed we only
|
||||
// call modify() on the asset_dynamic_data_object once at the
|
||||
// end of the maintenance interval. Thus the accumulated_fees
|
||||
// are available for the budget at this point, but not included
|
||||
// in core.burned().
|
||||
share_type reserve = core.burned(*this) + core_dd.accumulated_fees;
|
||||
|
||||
fc::uint128_t budget_u128 = reserve.value;
|
||||
budget_u128 *= uint64_t(dt);
|
||||
budget_u128 *= GRAPHENE_CORE_ASSET_CYCLE_RATE;
|
||||
//round up to the nearest satoshi -- this is necessary to ensure
|
||||
// there isn't an "untouchable" reserve, and we will eventually
|
||||
// be able to use the entire reserve
|
||||
budget_u128 += ((uint64_t(1) << GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS) - 1);
|
||||
budget_u128 >>= GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS;
|
||||
share_type budget;
|
||||
if( budget_u128 < reserve.value )
|
||||
budget = share_type(budget_u128.to_uint64());
|
||||
else
|
||||
budget = reserve;
|
||||
|
||||
return budget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the budget for witnesses and workers.
|
||||
*/
|
||||
void database::process_budget()
|
||||
{
|
||||
try
|
||||
{
|
||||
const global_property_object& gpo = get_global_properties();
|
||||
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
||||
const asset_dynamic_data_object& core =
|
||||
asset_id_type(0)(*this).dynamic_asset_data_id(*this);
|
||||
fc::time_point_sec now = _pending_block.timestamp;
|
||||
|
||||
int64_t time_to_maint = (dpo.next_maintenance_time - now).to_seconds();
|
||||
//
|
||||
// The code that generates the next maintenance time should
|
||||
// only produce a result in the future. If this assert
|
||||
// fails, then the next maintenance time algorithm is buggy.
|
||||
//
|
||||
assert( time_to_maint > 0 );
|
||||
//
|
||||
// Code for setting chain parameters should validate
|
||||
// block_interval > 0 (as well as the humans proposing /
|
||||
// voting on changes to block interval).
|
||||
//
|
||||
assert( gpo.parameters.block_interval > 0 );
|
||||
uint64_t blocks_to_maint = (uint64_t(time_to_maint) + gpo.parameters.block_interval - 1) / gpo.parameters.block_interval;
|
||||
|
||||
// blocks_to_maint > 0 because time_to_maint > 0,
|
||||
// which means numerator is at least equal to block_interval
|
||||
|
||||
share_type available_funds = get_max_budget( now );
|
||||
|
||||
share_type witness_budget = gpo.parameters.witness_pay_per_block.value * blocks_to_maint;
|
||||
witness_budget = std::min( witness_budget, available_funds );
|
||||
available_funds -= witness_budget;
|
||||
|
||||
fc::uint128_t worker_budget_u128 = gpo.parameters.worker_budget_per_day.value;
|
||||
worker_budget_u128 *= uint64_t(time_to_maint);
|
||||
worker_budget_u128 /= 60*60*24;
|
||||
|
||||
share_type worker_budget;
|
||||
if( worker_budget_u128 >= available_funds.value )
|
||||
worker_budget = available_funds;
|
||||
else
|
||||
worker_budget = worker_budget_u128.to_uint64();
|
||||
available_funds -= worker_budget;
|
||||
|
||||
share_type leftover_worker_funds = worker_budget;
|
||||
pay_workers( leftover_worker_funds );
|
||||
available_funds += leftover_worker_funds;
|
||||
|
||||
modify( core, [&]( asset_dynamic_data_object& _core )
|
||||
{
|
||||
_core.current_supply = (_core.current_supply + witness_budget +
|
||||
worker_budget - leftover_worker_funds -
|
||||
_core.accumulated_fees);
|
||||
_core.accumulated_fees = 0;
|
||||
} );
|
||||
modify( dpo, [&]( dynamic_global_property_object& _dpo )
|
||||
{
|
||||
_dpo.witness_budget = witness_budget;
|
||||
_dpo.last_budget_time = now;
|
||||
} );
|
||||
|
||||
// available_funds is money we could spend, but don't want to.
|
||||
// we simply let it evaporate back into the reserve.
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW()
|
||||
}
|
||||
|
||||
void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props)
|
||||
{
|
||||
update_vote_totals(global_props);
|
||||
|
||||
struct clear_canary {
|
||||
clear_canary(vector<uint64_t>& target): target(target){}
|
||||
~clear_canary() { target.clear(); }
|
||||
private:
|
||||
vector<uint64_t>& target;
|
||||
};
|
||||
clear_canary a(_witness_count_histogram_buffer),
|
||||
b(_committee_count_histogram_buffer),
|
||||
c(_vote_tally_buffer);
|
||||
|
||||
update_active_witnesses();
|
||||
update_active_delegates();
|
||||
|
||||
const global_property_object& global_properties = get_global_properties();
|
||||
if( global_properties.pending_parameters )
|
||||
modify(get_global_properties(), [](global_property_object& p) {
|
||||
p.parameters = std::move(*p.pending_parameters);
|
||||
p.pending_parameters.reset();
|
||||
});
|
||||
|
||||
auto new_block_interval = global_props.parameters.block_interval;
|
||||
|
||||
// if block interval CHANGED during this block *THEN* we cannot simply
|
||||
// add the interval if we want to maintain the invariant that all timestamps are a multiple
|
||||
// of the interval.
|
||||
_pending_block.timestamp = next_block.timestamp + fc::seconds(new_block_interval);
|
||||
uint32_t r = _pending_block.timestamp.sec_since_epoch()%new_block_interval;
|
||||
if( !r )
|
||||
{
|
||||
_pending_block.timestamp -= r;
|
||||
assert( (_pending_block.timestamp.sec_since_epoch() % new_block_interval) == 0 );
|
||||
}
|
||||
|
||||
auto next_maintenance_time = get<dynamic_global_property_object>(dynamic_global_property_id_type()).next_maintenance_time;
|
||||
auto maintenance_interval = get_global_properties().parameters.maintenance_interval;
|
||||
|
||||
if( next_maintenance_time <= next_block.timestamp )
|
||||
{
|
||||
if( next_block.block_num() == 1 )
|
||||
next_maintenance_time = time_point_sec() +
|
||||
(((next_block.timestamp.sec_since_epoch() / maintenance_interval) + 1) * maintenance_interval);
|
||||
else
|
||||
next_maintenance_time += maintenance_interval;
|
||||
assert( next_maintenance_time > next_block.timestamp );
|
||||
}
|
||||
|
||||
modify(get_dynamic_global_properties(), [next_maintenance_time](dynamic_global_property_object& d) {
|
||||
d.next_maintenance_time = next_maintenance_time;
|
||||
});
|
||||
|
||||
// Reset all BitAsset force settlement volumes to zero
|
||||
for( const asset_bitasset_data_object* d : get_index_type<asset_bitasset_data_index>() )
|
||||
modify(*d, [](asset_bitasset_data_object& d) { d.force_settled_volume = 0; });
|
||||
|
||||
// process_budget needs to run at the bottom because
|
||||
// it needs to know the next_maintenance_time
|
||||
process_budget();
|
||||
}
|
||||
|
||||
} }
|
||||
104
libraries/chain/db_management.cpp
Normal file
104
libraries/chain/db_management.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/operation_history_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
database::database()
|
||||
{
|
||||
initialize_indexes();
|
||||
initialize_evaluators();
|
||||
}
|
||||
|
||||
database::~database(){
|
||||
if( _pending_block_session )
|
||||
_pending_block_session->commit();
|
||||
}
|
||||
|
||||
void database::open( const fc::path& data_dir, const genesis_allocation& initial_allocation )
|
||||
{ try {
|
||||
ilog("Open database in ${d}", ("d", data_dir));
|
||||
object_database::open( data_dir );
|
||||
|
||||
_block_id_to_block.open( data_dir / "database" / "block_num_to_block" );
|
||||
|
||||
if( !find(global_property_id_type()) )
|
||||
init_genesis(initial_allocation);
|
||||
|
||||
_pending_block.previous = head_block_id();
|
||||
_pending_block.timestamp = head_block_time();
|
||||
|
||||
auto last_block_itr = _block_id_to_block.last();
|
||||
if( last_block_itr.valid() )
|
||||
_fork_db.start_block( last_block_itr.value() );
|
||||
|
||||
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }
|
||||
|
||||
void database::reindex(fc::path data_dir, const genesis_allocation& initial_allocation)
|
||||
{ try {
|
||||
wipe(data_dir, false);
|
||||
open(data_dir, initial_allocation);
|
||||
|
||||
auto start = fc::time_point::now();
|
||||
auto itr = _block_id_to_block.begin();
|
||||
// TODO: disable undo tracking durring reindex, this currently causes crashes in the benchmark test
|
||||
//_undo_db.disable();
|
||||
while( itr.valid() )
|
||||
{
|
||||
apply_block( itr.value(), skip_delegate_signature |
|
||||
skip_transaction_signatures |
|
||||
skip_undo_block |
|
||||
skip_undo_transaction |
|
||||
skip_transaction_dupe_check |
|
||||
skip_tapos_check |
|
||||
skip_authority_check );
|
||||
++itr;
|
||||
}
|
||||
//_undo_db.enable();
|
||||
auto end = fc::time_point::now();
|
||||
wdump( ((end-start).count()/1000000.0) );
|
||||
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }
|
||||
|
||||
void database::wipe(const fc::path& data_dir, bool include_blocks)
|
||||
{
|
||||
ilog("Wiping database", ("include_blocks", include_blocks));
|
||||
close();
|
||||
object_database::wipe(data_dir);
|
||||
if( include_blocks )
|
||||
fc::remove_all( data_dir / "database" );
|
||||
}
|
||||
|
||||
void database::close(uint32_t blocks_to_rewind)
|
||||
{
|
||||
_pending_block_session.reset();
|
||||
|
||||
for(uint32_t i = 0; i < blocks_to_rewind && head_block_num() > 0; ++i)
|
||||
pop_block();
|
||||
|
||||
object_database::close();
|
||||
|
||||
if( _block_id_to_block.is_open() )
|
||||
_block_id_to_block.close();
|
||||
|
||||
_fork_db.reset();
|
||||
}
|
||||
|
||||
} }
|
||||
681
libraries/chain/db_market.cpp
Normal file
681
libraries/chain/db_market.cpp
Normal file
|
|
@ -0,0 +1,681 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/bond_object.hpp>
|
||||
#include <graphene/chain/limit_order_object.hpp>
|
||||
#include <graphene/chain/short_order_object.hpp>
|
||||
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
for each short order, fill it at settlement price and place funds received into a total
|
||||
calculate the USD->CORE price and convert all USD balances to CORE at that price and subtract CORE from total
|
||||
- any fees accumulated by the issuer in the bitasset are forfeit / not redeemed
|
||||
- cancel all open orders with bitasset in it
|
||||
- any bonds with the bitasset as collateral get converted to CORE as collateral
|
||||
- any bitassets that use this bitasset as collateral are immediately settled at their feed price
|
||||
- convert all balances in bitasset to CORE and subtract from total
|
||||
- any prediction markets with usd as the backing get converted to CORE as the backing
|
||||
any CORE left over due to rounding errors is paid to accumulated fees
|
||||
*/
|
||||
void database::globally_settle_asset( const asset_object& mia, const price& settlement_price )
|
||||
{ try {
|
||||
elog( "BLACK SWAN!" );
|
||||
debug_dump();
|
||||
|
||||
edump( (mia.symbol)(settlement_price) );
|
||||
|
||||
const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this);
|
||||
const asset_object& backing_asset = bitasset.options.short_backing_asset(*this);
|
||||
asset collateral_gathered = backing_asset.amount(0);
|
||||
|
||||
const asset_dynamic_data_object& mia_dyn = mia.dynamic_asset_data_id(*this);
|
||||
auto original_mia_supply = mia_dyn.current_supply;
|
||||
|
||||
const call_order_index& call_index = get_index_type<call_order_index>();
|
||||
const auto& call_price_index = call_index.indices().get<by_price>();
|
||||
|
||||
auto call_itr = call_price_index.lower_bound( price::min( bitasset.options.short_backing_asset, mia.id ) );
|
||||
auto call_end = call_price_index.upper_bound( price::max( bitasset.options.short_backing_asset, mia.id ) );
|
||||
while( call_itr != call_end )
|
||||
{
|
||||
auto pays = call_itr->get_debt() * settlement_price;
|
||||
wdump( (call_itr->get_debt() ) );
|
||||
collateral_gathered += pays;
|
||||
const auto& order = *call_itr;
|
||||
++call_itr;
|
||||
FC_ASSERT( fill_order( order, pays, order.get_debt() ) );
|
||||
}
|
||||
|
||||
const limit_order_index& limit_index = get_index_type<limit_order_index>();
|
||||
const auto& limit_price_index = limit_index.indices().get<by_price>();
|
||||
|
||||
// cancel all orders selling the market issued asset
|
||||
auto limit_itr = limit_price_index.lower_bound(price::max(mia.id, bitasset.options.short_backing_asset));
|
||||
auto limit_end = limit_price_index.upper_bound(~bitasset.current_feed.call_limit);
|
||||
while( limit_itr != limit_end )
|
||||
{
|
||||
const auto& order = *limit_itr;
|
||||
ilog( "CANCEL LIMIT ORDER" );
|
||||
idump((order));
|
||||
++limit_itr;
|
||||
cancel_order( order );
|
||||
}
|
||||
|
||||
limit_itr = limit_price_index.begin();
|
||||
while( limit_itr != limit_end )
|
||||
{
|
||||
if( limit_itr->amount_for_sale().asset_id == mia.id )
|
||||
{
|
||||
const auto& order = *limit_itr;
|
||||
ilog( "CANCEL_AGAIN" );
|
||||
edump((order));
|
||||
++limit_itr;
|
||||
cancel_order( order );
|
||||
}
|
||||
}
|
||||
|
||||
limit_itr = limit_price_index.begin();
|
||||
while( limit_itr != limit_end )
|
||||
{
|
||||
if( limit_itr->amount_for_sale().asset_id == mia.id )
|
||||
{
|
||||
const auto& order = *limit_itr;
|
||||
edump((order));
|
||||
++limit_itr;
|
||||
cancel_order( order );
|
||||
}
|
||||
}
|
||||
|
||||
// settle all balances
|
||||
asset total_mia_settled = mia.amount(0);
|
||||
|
||||
// convert collateral held in bonds
|
||||
const auto& bond_idx = get_index_type<bond_index>().indices().get<by_collateral>();
|
||||
auto bond_itr = bond_idx.find( bitasset.id );
|
||||
while( bond_itr != bond_idx.end() )
|
||||
{
|
||||
if( bond_itr->collateral.asset_id == bitasset.id )
|
||||
{
|
||||
auto settled_amount = bond_itr->collateral * settlement_price;
|
||||
total_mia_settled += bond_itr->collateral;
|
||||
collateral_gathered -= settled_amount;
|
||||
modify( *bond_itr, [&]( bond_object& obj ) {
|
||||
obj.collateral = settled_amount;
|
||||
});
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
// cancel all bond offers holding the bitasset and refund the offer
|
||||
const auto& bond_offer_idx = get_index_type<bond_offer_index>().indices().get<by_asset>();
|
||||
auto bond_offer_itr = bond_offer_idx.find( bitasset.id );
|
||||
while( bond_offer_itr != bond_offer_idx.end() )
|
||||
{
|
||||
if( bond_offer_itr->amount.asset_id == bitasset.id )
|
||||
{
|
||||
adjust_balance( bond_offer_itr->offered_by_account, bond_offer_itr->amount );
|
||||
auto old_itr = bond_offer_itr;
|
||||
bond_offer_itr++;
|
||||
remove( *old_itr );
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
const auto& index = get_index_type<account_balance_index>().indices().get<by_asset>();
|
||||
auto range = index.equal_range(mia.get_id());
|
||||
for( auto itr = range.first; itr != range.second; ++itr )
|
||||
{
|
||||
auto mia_balance = itr->get_balance();
|
||||
if( mia_balance.amount > 0 )
|
||||
{
|
||||
adjust_balance(itr->owner, -mia_balance);
|
||||
auto settled_amount = mia_balance * settlement_price;
|
||||
idump( (mia_balance)(settled_amount)(settlement_price) );
|
||||
adjust_balance(itr->owner, settled_amount);
|
||||
total_mia_settled += mia_balance;
|
||||
collateral_gathered -= settled_amount;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: convert payments held in escrow
|
||||
|
||||
modify( mia_dyn, [&]( asset_dynamic_data_object& obj ){
|
||||
total_mia_settled.amount += obj.accumulated_fees;
|
||||
obj.accumulated_fees = 0;
|
||||
});
|
||||
|
||||
wlog( "====================== AFTER SETTLE BLACK SWAN UNCLAIMED SETTLEMENT FUNDS ==============\n" );
|
||||
wdump((collateral_gathered)(total_mia_settled)(original_mia_supply)(mia_dyn.current_supply));
|
||||
modify( bitasset.options.short_backing_asset(*this).dynamic_asset_data_id(*this), [&]( asset_dynamic_data_object& obj ){
|
||||
obj.accumulated_fees += collateral_gathered.amount;
|
||||
});
|
||||
|
||||
FC_ASSERT( total_mia_settled.amount == original_mia_supply, "", ("total_settled",total_mia_settled)("original",original_mia_supply) );
|
||||
} FC_CAPTURE_AND_RETHROW( (mia)(settlement_price) ) }
|
||||
|
||||
void database::cancel_order(const force_settlement_object& order, bool create_virtual_op)
|
||||
{
|
||||
adjust_balance(order.owner, order.balance);
|
||||
remove(order);
|
||||
|
||||
if( create_virtual_op )
|
||||
{
|
||||
// TODO: create virtual op
|
||||
}
|
||||
}
|
||||
|
||||
void database::cancel_order( const limit_order_object& order, bool create_virtual_op )
|
||||
{
|
||||
auto refunded = order.amount_for_sale();
|
||||
|
||||
modify( order.seller(*this).statistics(*this),[&]( account_statistics_object& obj ){
|
||||
if( refunded.asset_id == asset_id_type() )
|
||||
obj.total_core_in_orders -= refunded.amount;
|
||||
});
|
||||
adjust_balance(order.seller, refunded);
|
||||
|
||||
if( create_virtual_op )
|
||||
{
|
||||
// TODO: create a virtual cancel operation
|
||||
}
|
||||
|
||||
remove( order );
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the two orders,
|
||||
*
|
||||
* @return a bit field indicating which orders were filled (and thus removed)
|
||||
*
|
||||
* 0 - no orders were matched
|
||||
* 1 - bid was filled
|
||||
* 2 - ask was filled
|
||||
* 3 - both were filled
|
||||
*/
|
||||
template<typename OrderType>
|
||||
int database::match( const limit_order_object& usd, const OrderType& core, const price& match_price )
|
||||
{
|
||||
assert( usd.sell_price.quote.asset_id == core.sell_price.base.asset_id );
|
||||
assert( usd.sell_price.base.asset_id == core.sell_price.quote.asset_id );
|
||||
assert( usd.for_sale > 0 && core.for_sale > 0 );
|
||||
|
||||
auto usd_for_sale = usd.amount_for_sale();
|
||||
auto core_for_sale = core.amount_for_sale();
|
||||
|
||||
asset usd_pays, usd_receives, core_pays, core_receives;
|
||||
|
||||
if( usd_for_sale <= core_for_sale * match_price )
|
||||
{
|
||||
core_receives = usd_for_sale;
|
||||
usd_receives = usd_for_sale * match_price;
|
||||
}
|
||||
else
|
||||
{
|
||||
//This line once read: assert( core_for_sale < usd_for_sale * match_price );
|
||||
//This assert is not always true -- see trade_amount_equals_zero in operation_tests.cpp
|
||||
//Although usd_for_sale is greater than core_for_sale * match_price, core_for_sale == usd_for_sale * match_price
|
||||
//Removing the assert seems to be safe -- apparently no asset is created or destroyed.
|
||||
usd_receives = core_for_sale;
|
||||
core_receives = core_for_sale * match_price;
|
||||
}
|
||||
|
||||
core_pays = usd_receives;
|
||||
usd_pays = core_receives;
|
||||
|
||||
assert( usd_pays == usd.amount_for_sale() ||
|
||||
core_pays == core.amount_for_sale() );
|
||||
|
||||
int result = 0;
|
||||
result |= fill_order( usd, usd_pays, usd_receives );
|
||||
result |= fill_order( core, core_pays, core_receives ) << 1;
|
||||
assert( result != 0 );
|
||||
return result;
|
||||
}
|
||||
|
||||
int database::match( const limit_order_object& bid, const limit_order_object& ask, const price& match_price )
|
||||
{
|
||||
return match<limit_order_object>( bid, ask, match_price );
|
||||
}
|
||||
|
||||
int database::match( const limit_order_object& bid, const short_order_object& ask, const price& match_price )
|
||||
{
|
||||
return match<short_order_object>( bid, ask, match_price );
|
||||
}
|
||||
|
||||
asset database::match( const call_order_object& call, const force_settlement_object& settle, const price& match_price,
|
||||
asset max_settlement )
|
||||
{
|
||||
assert(call.get_debt().asset_id == settle.balance.asset_id );
|
||||
assert(call.debt > 0 && call.collateral > 0 && settle.balance.amount > 0);
|
||||
|
||||
auto settle_for_sale = std::min(settle.balance, max_settlement);
|
||||
auto call_debt = call.get_debt();
|
||||
|
||||
asset call_receives = std::min(settle_for_sale, call_debt),
|
||||
call_pays = call_receives * match_price,
|
||||
settle_pays = call_receives,
|
||||
settle_receives = call_pays;
|
||||
|
||||
assert( settle_pays == settle_for_sale || call_receives == call.get_debt() );
|
||||
|
||||
fill_order(call, call_pays, call_receives);
|
||||
fill_order(settle, settle_pays, settle_receives);
|
||||
|
||||
return call_receives;
|
||||
}
|
||||
|
||||
bool database::fill_order( const limit_order_object& order, const asset& pays, const asset& receives )
|
||||
{
|
||||
assert( order.amount_for_sale().asset_id == pays.asset_id );
|
||||
assert( pays.asset_id != receives.asset_id );
|
||||
|
||||
const account_object& seller = order.seller(*this);
|
||||
const asset_object& recv_asset = receives.asset_id(*this);
|
||||
|
||||
auto issuer_fees = pay_market_fees( recv_asset, receives );
|
||||
pay_order( seller, receives - issuer_fees, pays );
|
||||
|
||||
push_applied_operation( fill_order_operation{ order.id, order.seller, pays, receives, issuer_fees } );
|
||||
|
||||
if( pays == order.amount_for_sale() )
|
||||
{
|
||||
remove( order );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
modify( order, [&]( limit_order_object& b ) {
|
||||
b.for_sale -= pays.amount;
|
||||
});
|
||||
/**
|
||||
* There are times when the AMOUNT_FOR_SALE * SALE_PRICE == 0 which means that we
|
||||
* have hit the limit where the seller is asking for nothing in return. When this
|
||||
* happens we must refund any balance back to the seller, it is too small to be
|
||||
* sold at the sale price.
|
||||
*/
|
||||
if( order.amount_to_receive().amount == 0 )
|
||||
{
|
||||
cancel_order(order);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool database::fill_order( const short_order_object& order, const asset& pays, const asset& receives )
|
||||
{ try {
|
||||
assert( order.amount_for_sale().asset_id == pays.asset_id );
|
||||
assert( pays.asset_id != receives.asset_id );
|
||||
|
||||
const call_order_index& call_index = get_index_type<call_order_index>();
|
||||
|
||||
const account_object& seller = order.seller(*this);
|
||||
const asset_object& recv_asset = receives.asset_id(*this);
|
||||
const asset_object& pays_asset = pays.asset_id(*this);
|
||||
assert( pays_asset.is_market_issued() );
|
||||
|
||||
auto issuer_fees = pay_market_fees( recv_asset, receives );
|
||||
|
||||
bool filled = pays == order.amount_for_sale();
|
||||
asset seller_to_collateral;
|
||||
if( (*pays_asset.bitasset_data_id)(*this).is_prediction_market )
|
||||
{
|
||||
assert( pays.amount >= receives.amount );
|
||||
seller_to_collateral = pays.amount - receives.amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
seller_to_collateral = filled ? order.get_collateral() : pays * order.sell_price;
|
||||
}
|
||||
auto buyer_to_collateral = receives - issuer_fees;
|
||||
|
||||
if( receives.asset_id == asset_id_type() )
|
||||
{
|
||||
const auto& statistics = seller.statistics(*this);
|
||||
modify( statistics, [&]( account_statistics_object& b ){
|
||||
b.total_core_in_orders += buyer_to_collateral.amount;
|
||||
});
|
||||
}
|
||||
|
||||
modify( pays_asset.dynamic_asset_data_id(*this), [&]( asset_dynamic_data_object& obj ){
|
||||
obj.current_supply += pays.amount;
|
||||
});
|
||||
|
||||
const auto& call_account_index = call_index.indices().get<by_account>();
|
||||
auto call_itr = call_account_index.find( boost::make_tuple(order.seller, pays.asset_id) );
|
||||
if( call_itr == call_account_index.end() )
|
||||
{
|
||||
create<call_order_object>( [&]( call_order_object& c ){
|
||||
c.borrower = seller.id;
|
||||
c.collateral = seller_to_collateral.amount + buyer_to_collateral.amount;
|
||||
c.debt = pays.amount;
|
||||
c.maintenance_collateral_ratio = order.maintenance_collateral_ratio;
|
||||
c.call_price = price::max(seller_to_collateral.asset_id, pays.asset_id);
|
||||
c.update_call_price();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
modify( *call_itr, [&]( call_order_object& c ){
|
||||
c.debt += pays.amount;
|
||||
c.collateral += seller_to_collateral.amount + buyer_to_collateral.amount;
|
||||
c.maintenance_collateral_ratio = order.maintenance_collateral_ratio;
|
||||
c.update_call_price();
|
||||
});
|
||||
}
|
||||
|
||||
if( filled )
|
||||
{
|
||||
remove( order );
|
||||
}
|
||||
else
|
||||
{
|
||||
modify( order, [&]( short_order_object& b ) {
|
||||
b.for_sale -= pays.amount;
|
||||
b.available_collateral -= seller_to_collateral.amount;
|
||||
assert( b.available_collateral > 0 );
|
||||
assert( b.for_sale > 0 );
|
||||
});
|
||||
|
||||
/**
|
||||
* There are times when the AMOUNT_FOR_SALE * SALE_PRICE == 0 which means that we
|
||||
* have hit the limit where the seller is asking for nothing in return. When this
|
||||
* happens we must refund any balance back to the seller, it is too small to be
|
||||
* sold at the sale price.
|
||||
*/
|
||||
if( order.amount_to_receive().amount == 0 )
|
||||
{
|
||||
adjust_balance(seller.get_id(), order.get_collateral());
|
||||
if( order.get_collateral().asset_id == asset_id_type() )
|
||||
{
|
||||
const auto& statistics = seller.statistics(*this);
|
||||
modify( statistics, [&]( account_statistics_object& b ){
|
||||
b.total_core_in_orders -= order.available_collateral;
|
||||
});
|
||||
}
|
||||
|
||||
remove( order );
|
||||
filled = true;
|
||||
}
|
||||
}
|
||||
|
||||
push_applied_operation( fill_order_operation{ order.id, order.seller, pays, receives, issuer_fees } );
|
||||
|
||||
return filled;
|
||||
} FC_CAPTURE_AND_RETHROW( (order)(pays)(receives) ) }
|
||||
|
||||
bool database::fill_order( const call_order_object& order, const asset& pays, const asset& receives )
|
||||
{ try {
|
||||
idump((pays)(receives)(order));
|
||||
assert( order.get_debt().asset_id == receives.asset_id );
|
||||
assert( order.get_collateral().asset_id == pays.asset_id );
|
||||
assert( order.get_collateral() >= pays );
|
||||
|
||||
optional<asset> collateral_freed;
|
||||
modify( order, [&]( call_order_object& o ){
|
||||
o.debt -= receives.amount;
|
||||
o.collateral -= pays.amount;
|
||||
if( o.debt == 0 )
|
||||
{
|
||||
collateral_freed = o.get_collateral();
|
||||
o.collateral = 0;
|
||||
}
|
||||
});
|
||||
const asset_object& mia = receives.asset_id(*this);
|
||||
assert( mia.is_market_issued() );
|
||||
|
||||
const asset_dynamic_data_object& mia_ddo = mia.dynamic_asset_data_id(*this);
|
||||
|
||||
modify( mia_ddo, [&]( asset_dynamic_data_object& ao ){
|
||||
idump((receives));
|
||||
ao.current_supply -= receives.amount;
|
||||
});
|
||||
|
||||
const account_object& borrower = order.borrower(*this);
|
||||
if( collateral_freed || pays.asset_id == asset_id_type() )
|
||||
{
|
||||
const account_statistics_object& borrower_statistics = borrower.statistics(*this);
|
||||
if( collateral_freed )
|
||||
adjust_balance(borrower.get_id(), *collateral_freed);
|
||||
modify( borrower_statistics, [&]( account_statistics_object& b ){
|
||||
if( collateral_freed && collateral_freed->amount > 0 )
|
||||
b.total_core_in_orders -= collateral_freed->amount;
|
||||
if( pays.asset_id == asset_id_type() )
|
||||
b.total_core_in_orders -= pays.amount;
|
||||
assert( b.total_core_in_orders >= 0 );
|
||||
});
|
||||
}
|
||||
|
||||
if( collateral_freed )
|
||||
{
|
||||
remove( order );
|
||||
}
|
||||
|
||||
push_applied_operation( fill_order_operation{ order.id, order.borrower, pays, receives, asset(0, pays.asset_id) } );
|
||||
|
||||
return collateral_freed.valid();
|
||||
} FC_CAPTURE_AND_RETHROW( (order)(pays)(receives) ) }
|
||||
|
||||
bool database::fill_order(const force_settlement_object& settle, const asset& pays, const asset& receives)
|
||||
{ try {
|
||||
bool filled = false;
|
||||
|
||||
auto issuer_fees = pay_market_fees(get(receives.asset_id), receives);
|
||||
|
||||
if( pays < settle.balance )
|
||||
{
|
||||
modify(settle, [&pays](force_settlement_object& s) {
|
||||
s.balance -= pays;
|
||||
});
|
||||
filled = false;
|
||||
} else {
|
||||
remove(settle);
|
||||
filled = true;
|
||||
}
|
||||
adjust_balance(settle.owner, receives - issuer_fees);
|
||||
|
||||
push_applied_operation( fill_order_operation{ settle.id, settle.owner, pays, receives, issuer_fees } );
|
||||
|
||||
return filled;
|
||||
} FC_CAPTURE_AND_RETHROW( (settle)(pays)(receives) ) }
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bool database::check_call_orders( const asset_object& mia )
|
||||
{ try {
|
||||
if( !mia.is_market_issued() ) return false;
|
||||
const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this);
|
||||
if( bitasset.current_feed.call_limit.is_null() ) return false;
|
||||
if( bitasset.is_prediction_market ) return false;
|
||||
|
||||
const call_order_index& call_index = get_index_type<call_order_index>();
|
||||
const auto& call_price_index = call_index.indices().get<by_price>();
|
||||
|
||||
const limit_order_index& limit_index = get_index_type<limit_order_index>();
|
||||
const auto& limit_price_index = limit_index.indices().get<by_price>();
|
||||
|
||||
const short_order_index& short_index = get_index_type<short_order_index>();
|
||||
const auto& short_price_index = short_index.indices().get<by_price>();
|
||||
|
||||
auto short_itr = short_price_index.lower_bound( price::max( mia.id, bitasset.options.short_backing_asset ) );
|
||||
auto short_end = short_price_index.upper_bound( ~bitasset.current_feed.call_limit );
|
||||
|
||||
auto limit_itr = limit_price_index.lower_bound( price::max( mia.id, bitasset.options.short_backing_asset ) );
|
||||
auto limit_end = limit_price_index.upper_bound( ~bitasset.current_feed.call_limit );
|
||||
|
||||
auto call_itr = call_price_index.lower_bound( price::min( bitasset.options.short_backing_asset, mia.id ) );
|
||||
auto call_end = call_price_index.upper_bound( price::max( bitasset.options.short_backing_asset, mia.id ) );
|
||||
|
||||
bool filled_short_or_limit = false;
|
||||
|
||||
while( call_itr != call_end )
|
||||
{
|
||||
bool current_is_limit = true;
|
||||
bool filled_call = false;
|
||||
price match_price;
|
||||
asset usd_for_sale;
|
||||
if( limit_itr != limit_end )
|
||||
{
|
||||
assert( limit_itr != limit_price_index.end() );
|
||||
if( short_itr != short_end && limit_itr->sell_price < short_itr->sell_price )
|
||||
{
|
||||
assert( short_itr != short_price_index.end() );
|
||||
current_is_limit = false;
|
||||
match_price = short_itr->sell_price;
|
||||
usd_for_sale = short_itr->amount_for_sale();
|
||||
}
|
||||
else
|
||||
{
|
||||
current_is_limit = true;
|
||||
match_price = limit_itr->sell_price;
|
||||
usd_for_sale = limit_itr->amount_for_sale();
|
||||
}
|
||||
}
|
||||
else if( short_itr != short_end )
|
||||
{
|
||||
assert( short_itr != short_price_index.end() );
|
||||
current_is_limit = false;
|
||||
match_price = short_itr->sell_price;
|
||||
usd_for_sale = short_itr->amount_for_sale();
|
||||
}
|
||||
else return filled_short_or_limit;
|
||||
|
||||
match_price.validate();
|
||||
|
||||
if( match_price > ~call_itr->call_price )
|
||||
{
|
||||
return filled_short_or_limit;
|
||||
}
|
||||
|
||||
auto usd_to_buy = call_itr->get_debt();
|
||||
|
||||
if( usd_to_buy * match_price > call_itr->get_collateral() )
|
||||
{
|
||||
elog( "black swan, we do not have enough collateral to cover at this price" );
|
||||
globally_settle_asset( mia, call_itr->get_debt() / call_itr->get_collateral() );
|
||||
return true;
|
||||
}
|
||||
|
||||
asset call_pays, call_receives, order_pays, order_receives;
|
||||
if( usd_to_buy >= usd_for_sale )
|
||||
{ // fill order
|
||||
call_receives = usd_for_sale;
|
||||
order_receives = usd_for_sale * match_price;
|
||||
call_pays = order_receives;
|
||||
order_pays = usd_for_sale;
|
||||
|
||||
filled_short_or_limit = true;
|
||||
filled_call = (usd_to_buy == usd_for_sale);
|
||||
}
|
||||
else // fill call
|
||||
{
|
||||
call_receives = usd_to_buy;
|
||||
order_receives = usd_to_buy * match_price;
|
||||
call_pays = order_receives;
|
||||
order_pays = usd_to_buy;
|
||||
|
||||
filled_call = true;
|
||||
}
|
||||
|
||||
auto old_call_itr = call_itr;
|
||||
if( filled_call ) ++call_itr;
|
||||
fill_order( *old_call_itr, call_pays, call_receives );
|
||||
if( current_is_limit )
|
||||
{
|
||||
auto old_limit_itr = !filled_call ? limit_itr++ : limit_itr;
|
||||
fill_order( *old_limit_itr, order_pays, order_receives );
|
||||
}
|
||||
else
|
||||
{
|
||||
auto old_short_itr = !filled_call ? short_itr++ : short_itr;
|
||||
fill_order( *old_short_itr, order_pays, order_receives );
|
||||
}
|
||||
} // whlie call_itr != call_end
|
||||
|
||||
return filled_short_or_limit;
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
void database::pay_order( const account_object& receiver, const asset& receives, const asset& pays )
|
||||
{
|
||||
const auto& balances = receiver.statistics(*this);
|
||||
modify( balances, [&]( account_statistics_object& b ){
|
||||
if( pays.asset_id == asset_id_type() )
|
||||
b.total_core_in_orders -= pays.amount;
|
||||
});
|
||||
adjust_balance(receiver.get_id(), receives);
|
||||
}
|
||||
|
||||
/**
|
||||
* For Market Issued assets Managed by Delegates, any fees collected in the MIA need
|
||||
* to be sold and converted into CORE by accepting the best offer on the table.
|
||||
*/
|
||||
bool database::convert_fees( const asset_object& mia )
|
||||
{
|
||||
if( mia.issuer != account_id_type() ) return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
asset database::calculate_market_fee( const asset_object& trade_asset, const asset& trade_amount )
|
||||
{
|
||||
assert( trade_asset.id == trade_amount.asset_id );
|
||||
|
||||
if( !trade_asset.charges_market_fees() )
|
||||
return trade_asset.amount(0);
|
||||
if( trade_asset.options.market_fee_percent == 0 )
|
||||
return trade_asset.amount(trade_asset.options.min_market_fee);
|
||||
|
||||
fc::uint128 a(trade_amount.amount.value);
|
||||
a *= trade_asset.options.market_fee_percent;
|
||||
a /= GRAPHENE_100_PERCENT;
|
||||
asset percent_fee = trade_asset.amount(a.to_uint64());
|
||||
|
||||
if( percent_fee.amount > trade_asset.options.max_market_fee )
|
||||
percent_fee.amount = trade_asset.options.max_market_fee;
|
||||
else if( percent_fee.amount < trade_asset.options.min_market_fee )
|
||||
percent_fee.amount = trade_asset.options.min_market_fee;
|
||||
|
||||
return percent_fee;
|
||||
}
|
||||
|
||||
asset database::pay_market_fees( const asset_object& recv_asset, const asset& receives )
|
||||
{
|
||||
auto issuer_fees = calculate_market_fee( recv_asset, receives );
|
||||
assert(issuer_fees <= receives );
|
||||
|
||||
//Don't dirty undo state if not actually collecting any fees
|
||||
if( issuer_fees.amount > 0 )
|
||||
{
|
||||
const auto& recv_dyn_data = recv_asset.dynamic_asset_data_id(*this);
|
||||
modify( recv_dyn_data, [&]( asset_dynamic_data_object& obj ){
|
||||
idump((issuer_fees));
|
||||
obj.accumulated_fees += issuer_fees.amount;
|
||||
});
|
||||
}
|
||||
|
||||
return issuer_fees;
|
||||
}
|
||||
|
||||
} }
|
||||
242
libraries/chain/db_update.cpp
Normal file
242
libraries/chain/db_update.cpp
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/global_property_object.hpp>
|
||||
#include <graphene/chain/limit_order_object.hpp>
|
||||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/short_order_object.hpp>
|
||||
#include <graphene/chain/transaction_object.hpp>
|
||||
#include <graphene/chain/withdraw_permission_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
void database::update_global_dynamic_data( const signed_block& b )
|
||||
{
|
||||
const dynamic_global_property_object& _dgp =
|
||||
dynamic_global_property_id_type(0)(*this);
|
||||
|
||||
//
|
||||
// dynamic global properties updating
|
||||
//
|
||||
modify( _dgp, [&]( dynamic_global_property_object& dgp ){
|
||||
secret_hash_type::encoder enc;
|
||||
fc::raw::pack( enc, dgp.random );
|
||||
fc::raw::pack( enc, b.previous_secret );
|
||||
dgp.random = enc.result();
|
||||
dgp.head_block_number = b.block_num();
|
||||
dgp.head_block_id = b.id();
|
||||
dgp.time = b.timestamp;
|
||||
dgp.current_witness = b.witness;
|
||||
});
|
||||
}
|
||||
|
||||
void database::update_signing_witness(const witness_object& signing_witness, const signed_block& new_block)
|
||||
{
|
||||
const global_property_object& gpo = get_global_properties();
|
||||
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
||||
|
||||
share_type witness_pay = std::min( gpo.parameters.witness_pay_per_block, dpo.witness_budget );
|
||||
|
||||
modify( dpo, [&]( dynamic_global_property_object& _dpo )
|
||||
{
|
||||
_dpo.witness_budget -= witness_pay;
|
||||
} );
|
||||
|
||||
modify( signing_witness, [&]( witness_object& _wit )
|
||||
{
|
||||
_wit.last_secret = new_block.previous_secret;
|
||||
_wit.next_secret = new_block.next_secret_hash;
|
||||
_wit.accumulated_income += witness_pay;
|
||||
} );
|
||||
}
|
||||
|
||||
void database::update_pending_block(const signed_block& next_block, uint8_t current_block_interval)
|
||||
{
|
||||
_pending_block.timestamp = next_block.timestamp + current_block_interval;
|
||||
_pending_block.previous = next_block.id();
|
||||
auto old_pending_trx = std::move(_pending_block.transactions);
|
||||
_pending_block.transactions.clear();
|
||||
for( auto old_trx : old_pending_trx )
|
||||
push_transaction( old_trx );
|
||||
}
|
||||
|
||||
void database::clear_expired_transactions()
|
||||
{
|
||||
//Look for expired transactions in the deduplication list, and remove them.
|
||||
//Transactions must have expired by at least two forking windows in order to be removed.
|
||||
auto& transaction_idx = static_cast<transaction_index&>(get_mutable_index(implementation_ids, impl_transaction_object_type));
|
||||
const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
|
||||
const auto& global_parameters = get_global_properties().parameters;
|
||||
auto forking_window_time = global_parameters.maximum_undo_history * global_parameters.block_interval;
|
||||
while( !dedupe_index.empty()
|
||||
&& head_block_time() - dedupe_index.rbegin()->expiration >= fc::seconds(forking_window_time) )
|
||||
transaction_idx.remove(*dedupe_index.rbegin());
|
||||
}
|
||||
|
||||
void database::clear_expired_proposals()
|
||||
{
|
||||
const auto& proposal_expiration_index = get_index_type<proposal_index>().indices().get<by_expiration>();
|
||||
while( !proposal_expiration_index.empty() && proposal_expiration_index.begin()->expiration_time <= head_block_time() )
|
||||
{
|
||||
const proposal_object& proposal = *proposal_expiration_index.begin();
|
||||
processed_transaction result;
|
||||
try {
|
||||
if( proposal.is_authorized_to_execute(this) )
|
||||
{
|
||||
result = push_proposal(proposal);
|
||||
//TODO: Do something with result so plugins can process it.
|
||||
continue;
|
||||
}
|
||||
} catch( const fc::exception& e ) {
|
||||
elog("Failed to apply proposed transaction on its expiration. Deleting it.\n${proposal}\n${error}",
|
||||
("proposal", proposal)("error", e.to_detail_string()));
|
||||
}
|
||||
remove(proposal);
|
||||
}
|
||||
}
|
||||
|
||||
void database::clear_expired_orders()
|
||||
{
|
||||
transaction_evaluation_state cancel_context(this, true);
|
||||
|
||||
//Cancel expired limit orders
|
||||
auto& limit_index = get_index_type<limit_order_index>().indices().get<by_expiration>();
|
||||
while( !limit_index.empty() && limit_index.begin()->expiration <= head_block_time() )
|
||||
{
|
||||
limit_order_cancel_operation canceler;
|
||||
const limit_order_object& order = *limit_index.begin();
|
||||
canceler.fee_paying_account = order.seller;
|
||||
canceler.order = order.id;
|
||||
apply_operation(cancel_context, canceler);
|
||||
}
|
||||
|
||||
//Cancel expired short orders
|
||||
auto& short_index = get_index_type<short_order_index>().indices().get<by_expiration>();
|
||||
while( !short_index.empty() && short_index.begin()->expiration <= head_block_time() )
|
||||
{
|
||||
const short_order_object& order = *short_index.begin();
|
||||
short_order_cancel_operation canceler;
|
||||
canceler.fee_paying_account = order.seller;
|
||||
canceler.order = order.id;
|
||||
apply_operation(cancel_context, canceler);
|
||||
}
|
||||
|
||||
//Process expired force settlement orders
|
||||
auto& settlement_index = get_index_type<force_settlement_index>().indices().get<by_expiration>();
|
||||
if( !settlement_index.empty() )
|
||||
{
|
||||
asset_id_type current_asset = settlement_index.begin()->settlement_asset_id();
|
||||
asset max_settlement_volume;
|
||||
|
||||
auto next_asset = [¤t_asset, &settlement_index] {
|
||||
auto bound = settlement_index.upper_bound(current_asset);
|
||||
if( bound == settlement_index.end() )
|
||||
return false;
|
||||
current_asset = bound->settlement_asset_id();
|
||||
return true;
|
||||
};
|
||||
|
||||
// At each iteration, we either consume the current order and remove it, or we move to the next asset
|
||||
for( auto itr = settlement_index.lower_bound(current_asset);
|
||||
itr != settlement_index.end();
|
||||
itr = settlement_index.lower_bound(current_asset) )
|
||||
{
|
||||
const force_settlement_object& order = *itr;
|
||||
auto order_id = order.id;
|
||||
current_asset = order.settlement_asset_id();
|
||||
const asset_object& mia_object = get(current_asset);
|
||||
const asset_bitasset_data_object mia = mia_object.bitasset_data(*this);
|
||||
|
||||
// Has this order not reached its settlement date?
|
||||
if( order.settlement_date > head_block_time() )
|
||||
{
|
||||
if( next_asset() )
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
// Can we still settle in this asset?
|
||||
if( mia.current_feed.settlement_price.is_null() )
|
||||
{
|
||||
ilog("Canceling a force settlement in ${asset} because settlement price is null",
|
||||
("asset", mia_object.symbol));
|
||||
cancel_order(order);
|
||||
continue;
|
||||
}
|
||||
if( max_settlement_volume.asset_id != current_asset )
|
||||
max_settlement_volume = mia_object.amount(mia.max_force_settlement_volume(mia_object.dynamic_data(*this).current_supply));
|
||||
if( mia.force_settled_volume >= max_settlement_volume.amount )
|
||||
{
|
||||
ilog("Skipping force settlement in ${asset}; settled ${settled_volume} / ${max_volume}",
|
||||
("asset", mia_object.symbol)("settlement_price_null",mia.current_feed.settlement_price.is_null())
|
||||
("settled_volume", mia.force_settled_volume)("max_volume", max_settlement_volume));
|
||||
if( next_asset() )
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
auto& pays = order.balance;
|
||||
auto receives = (order.balance * mia.current_feed.settlement_price);
|
||||
receives.amount = (fc::uint128_t(receives.amount.value) *
|
||||
(GRAPHENE_100_PERCENT - mia.options.force_settlement_offset_percent) / GRAPHENE_100_PERCENT).to_uint64();
|
||||
assert(receives <= order.balance * mia.current_feed.settlement_price);
|
||||
|
||||
price settlement_price = pays / receives;
|
||||
|
||||
auto& call_index = get_index_type<call_order_index>().indices().get<by_collateral>();
|
||||
asset settled = mia_object.amount(mia.force_settled_volume);
|
||||
// Match against the least collateralized short until the settlement is finished or we reach max settlements
|
||||
while( settled < max_settlement_volume && find_object(order_id) )
|
||||
{
|
||||
auto itr = call_index.lower_bound(boost::make_tuple(price::min(mia_object.bitasset_data(*this).options.short_backing_asset,
|
||||
mia_object.get_id())));
|
||||
// There should always be a call order, since asset exists!
|
||||
assert(itr != call_index.end() && itr->debt_type() == mia_object.get_id());
|
||||
asset max_settlement = max_settlement_volume - settled;
|
||||
settled += match(*itr, order, settlement_price, max_settlement);
|
||||
}
|
||||
modify(mia, [settled](asset_bitasset_data_object& b) {
|
||||
b.force_settled_volume = settled.amount;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void database::update_expired_feeds()
|
||||
{
|
||||
auto& asset_idx = get_index_type<asset_bitasset_data_index>();
|
||||
for( const asset_bitasset_data_object* b : asset_idx )
|
||||
if( b->feed_is_expired(head_block_time()) )
|
||||
modify(*b, [this](asset_bitasset_data_object& a) {
|
||||
a.update_median_feeds(head_block_time());
|
||||
});
|
||||
}
|
||||
|
||||
void database::update_withdraw_permissions()
|
||||
{
|
||||
auto& permit_index = get_index_type<withdraw_permission_index>().indices().get<by_expiration>();
|
||||
while( !permit_index.empty() && permit_index.begin()->expiration <= head_block_time() )
|
||||
remove(*permit_index.begin());
|
||||
}
|
||||
|
||||
} }
|
||||
138
libraries/chain/db_witness_schedule.cpp
Normal file
138
libraries/chain/db_witness_schedule.cpp
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/global_property_object.hpp>
|
||||
#include <graphene/chain/witness_schedule_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
static_assert((GRAPHENE_GENESIS_TIMESTAMP % GRAPHENE_DEFAULT_BLOCK_INTERVAL) == 0,
|
||||
"GRAPHENE_GENESIS_TIMESTAMP must be aligned to a block interval.");
|
||||
|
||||
pair<witness_id_type, bool> database::get_scheduled_witness(uint32_t slot_num)const
|
||||
{
|
||||
if( slot_num == 0 )
|
||||
return pair<witness_id_type, bool>(witness_id_type(), false);
|
||||
|
||||
const witness_schedule_object& wso = witness_schedule_id_type()(*this);
|
||||
|
||||
// ask the near scheduler who goes in the given slot
|
||||
witness_id_type wid;
|
||||
bool slot_is_near = wso.scheduler.get_slot(slot_num, wid);
|
||||
if( ! slot_is_near )
|
||||
{
|
||||
// if the near scheduler doesn't know, we have to extend it to
|
||||
// a far scheduler.
|
||||
// n.b. instantiating it is slow, but block gaps long enough to
|
||||
// need it are likely pretty rare.
|
||||
|
||||
witness_scheduler_rng far_rng(wso.rng_seed.begin(), GRAPHENE_FAR_SCHEDULE_CTR_IV);
|
||||
|
||||
far_future_witness_scheduler far_scheduler =
|
||||
far_future_witness_scheduler(wso.scheduler, far_rng);
|
||||
if( !far_scheduler.get_slot(slot_num, wid) )
|
||||
{
|
||||
// no scheduled witness -- somebody set up us the bomb
|
||||
// n.b. this code path is impossible, the present
|
||||
// implementation of far_future_witness_scheduler
|
||||
// returns true unconditionally
|
||||
assert( false );
|
||||
}
|
||||
}
|
||||
return pair<witness_id_type, bool>(wid, slot_is_near);
|
||||
}
|
||||
|
||||
fc::time_point_sec database::get_slot_time(uint32_t slot_num)const
|
||||
{
|
||||
if( slot_num == 0 )
|
||||
return fc::time_point_sec();
|
||||
|
||||
auto interval = block_interval();
|
||||
auto head_block_abs_slot = head_block_time().sec_since_epoch() / interval;
|
||||
fc::time_point_sec first_slot_time(head_block_abs_slot * interval);
|
||||
return first_slot_time + slot_num * interval;
|
||||
}
|
||||
|
||||
uint32_t database::get_slot_at_time(fc::time_point_sec when)const
|
||||
{
|
||||
fc::time_point_sec first_slot_time = get_slot_time( 1 );
|
||||
if( when < first_slot_time )
|
||||
return 0;
|
||||
return (when - first_slot_time).to_seconds() / block_interval() + 1;
|
||||
}
|
||||
|
||||
vector<witness_id_type> database::get_near_witness_schedule()const
|
||||
{
|
||||
const witness_schedule_object& wso = witness_schedule_id_type()(*this);
|
||||
|
||||
vector<witness_id_type> result;
|
||||
result.reserve(wso.scheduler.size());
|
||||
uint32_t slot_num = 1;
|
||||
witness_id_type wid;
|
||||
|
||||
while( wso.scheduler.get_slot(slot_num++, wid) )
|
||||
result.emplace_back(wid);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void database::update_witness_schedule(signed_block next_block)
|
||||
{
|
||||
const global_property_object& gpo = get_global_properties();
|
||||
const witness_schedule_object& wso = get(witness_schedule_id_type());
|
||||
uint32_t schedule_needs_filled = gpo.active_witnesses.size();
|
||||
uint32_t schedule_slot = get_slot_at_time(next_block.timestamp);
|
||||
|
||||
// We shouldn't be able to generate _pending_block with timestamp
|
||||
// in the past, and incoming blocks from the network with timestamp
|
||||
// in the past shouldn't be able to make it this far without
|
||||
// triggering FC_ASSERT elsewhere
|
||||
|
||||
assert( schedule_slot > 0 );
|
||||
|
||||
witness_id_type wit;
|
||||
|
||||
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
||||
assert( dpo.random.data_size() == witness_scheduler_rng::seed_length );
|
||||
assert( witness_scheduler_rng::seed_length == wso.rng_seed.size() );
|
||||
|
||||
modify(wso, [&](witness_schedule_object& _wso)
|
||||
{
|
||||
_wso.slots_since_genesis += schedule_slot;
|
||||
witness_scheduler_rng rng(wso.rng_seed.data, _wso.slots_since_genesis);
|
||||
|
||||
_wso.scheduler._min_token_count = gpo.active_witnesses.size() / 2;
|
||||
uint32_t drain = schedule_slot;
|
||||
while( drain > 0 )
|
||||
{
|
||||
if( _wso.scheduler.size() == 0 )
|
||||
break;
|
||||
_wso.scheduler.consume_schedule();
|
||||
--drain;
|
||||
}
|
||||
while( !_wso.scheduler.get_slot(schedule_needs_filled, wit) )
|
||||
{
|
||||
if( _wso.scheduler.produce_schedule(rng) & emit_turn )
|
||||
memcpy(_wso.rng_seed.begin(), dpo.random.data(), dpo.random.data_size());
|
||||
}
|
||||
_wso.last_scheduling_block = next_block.block_num();
|
||||
});
|
||||
}
|
||||
} }
|
||||
45
libraries/chain/delegate_evaluator.cpp
Normal file
45
libraries/chain/delegate_evaluator.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/delegate_evaluator.hpp>
|
||||
#include <graphene/chain/delegate_object.hpp>
|
||||
#include <graphene/chain/key_object.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
object_id_type delegate_create_evaluator::do_evaluate( const delegate_create_operation& op )
|
||||
{
|
||||
FC_ASSERT(db().get(op.delegate_account).is_prime());
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type delegate_create_evaluator::do_apply( const delegate_create_operation& op )
|
||||
{
|
||||
vote_id_type vote_id;
|
||||
db().modify(db().get_global_properties(), [&vote_id](global_property_object& p) {
|
||||
vote_id = p.get_next_vote_id(vote_id_type::committee);
|
||||
});
|
||||
|
||||
const auto& new_del_object = db().create<delegate_object>( [&]( delegate_object& obj ){
|
||||
obj.delegate_account = op.delegate_account;
|
||||
obj.vote_id = vote_id;
|
||||
});
|
||||
return new_del_object.id;
|
||||
}
|
||||
|
||||
} } // graphene::chain
|
||||
172
libraries/chain/evaluator.cpp
Normal file
172
libraries/chain/evaluator.cpp
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/transaction_evaluation_state.hpp>
|
||||
#include <graphene/chain/key_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
#include <graphene/chain/delegate_object.hpp>
|
||||
#include <graphene/chain/limit_order_object.hpp>
|
||||
#include <graphene/chain/short_order_object.hpp>
|
||||
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
database& generic_evaluator::db()const { return trx_state->db(); }
|
||||
operation_result generic_evaluator::start_evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply )
|
||||
{
|
||||
trx_state = &eval_state;
|
||||
check_required_authorities(op);
|
||||
auto result = evaluate( op );
|
||||
|
||||
if( apply ) result = this->apply( op );
|
||||
return result;
|
||||
}
|
||||
|
||||
void generic_evaluator::prepare_fee(account_id_type account_id, asset fee)
|
||||
{
|
||||
fee_from_account = fee;
|
||||
FC_ASSERT( fee.amount >= 0 );
|
||||
fee_paying_account = &account_id(db());
|
||||
fee_paying_account_statistics = &fee_paying_account->statistics(db());
|
||||
|
||||
fee_asset = &fee.asset_id(db());
|
||||
fee_asset_dyn_data = &fee_asset->dynamic_asset_data_id(db());
|
||||
|
||||
if( fee_from_account.asset_id == asset_id_type() )
|
||||
core_fee_paid = fee_from_account.amount;
|
||||
else {
|
||||
asset fee_from_pool = fee_from_account * fee_asset->options.core_exchange_rate;
|
||||
FC_ASSERT( fee_from_pool.asset_id == asset_id_type() );
|
||||
core_fee_paid = fee_from_pool.amount;
|
||||
FC_ASSERT( core_fee_paid <= fee_asset_dyn_data->fee_pool );
|
||||
}
|
||||
}
|
||||
|
||||
void generic_evaluator::pay_fee()
|
||||
{ try {
|
||||
asset core_fee_subtotal(core_fee_paid);
|
||||
const auto& gp = db().get_global_properties();
|
||||
share_type bulk_cashback = share_type(0);
|
||||
if( fee_paying_account_statistics->lifetime_fees_paid > gp.parameters.bulk_discount_threshold_min &&
|
||||
fee_paying_account->is_prime() )
|
||||
{
|
||||
uint64_t bulk_discount_percent = 0;
|
||||
if( fee_paying_account_statistics->lifetime_fees_paid > gp.parameters.bulk_discount_threshold_max )
|
||||
bulk_discount_percent = gp.parameters.max_bulk_discount_percent_of_fee;
|
||||
else if(gp.parameters.bulk_discount_threshold_max.value - gp.parameters.bulk_discount_threshold_min.value != 0)
|
||||
{
|
||||
bulk_discount_percent =
|
||||
(gp.parameters.max_bulk_discount_percent_of_fee *
|
||||
(fee_paying_account_statistics->lifetime_fees_paid.value -
|
||||
gp.parameters.bulk_discount_threshold_min.value)) /
|
||||
(gp.parameters.bulk_discount_threshold_max.value - gp.parameters.bulk_discount_threshold_min.value);
|
||||
}
|
||||
assert( bulk_discount_percent <= GRAPHENE_100_PERCENT );
|
||||
assert( bulk_discount_percent >= 0 );
|
||||
|
||||
bulk_cashback = (core_fee_subtotal.amount.value * bulk_discount_percent) / GRAPHENE_100_PERCENT;
|
||||
assert( bulk_cashback <= core_fee_subtotal.amount );
|
||||
}
|
||||
|
||||
share_type core_fee_total = core_fee_subtotal.amount - bulk_cashback;
|
||||
share_type accumulated = (core_fee_total.value * gp.parameters.witness_percent_of_fee)/GRAPHENE_100_PERCENT;
|
||||
share_type burned = (core_fee_total.value * gp.parameters.burn_percent_of_fee)/GRAPHENE_100_PERCENT;
|
||||
share_type referral = core_fee_total.value - accumulated - burned;
|
||||
auto& d = db();
|
||||
|
||||
assert( accumulated + burned <= core_fee_total );
|
||||
|
||||
if( fee_asset->get_id() != asset_id_type() )
|
||||
d.modify(*fee_asset_dyn_data, [this](asset_dynamic_data_object& d) {
|
||||
d.accumulated_fees += fee_from_account.amount;
|
||||
d.fee_pool -= core_fee_paid;
|
||||
});
|
||||
d.modify(dynamic_asset_data_id_type()(d), [burned,accumulated](asset_dynamic_data_object& d) {
|
||||
d.accumulated_fees += accumulated + burned;
|
||||
});
|
||||
|
||||
d.modify(fee_paying_account->statistics(d), [core_fee_total](account_statistics_object& s) {
|
||||
s.lifetime_fees_paid += core_fee_total;
|
||||
});
|
||||
|
||||
d.deposit_cashback( fee_paying_account->referrer(d), referral );
|
||||
d.deposit_cashback( *fee_paying_account, bulk_cashback );
|
||||
|
||||
assert( referral + bulk_cashback + accumulated + burned == core_fee_subtotal.amount );
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
bool generic_evaluator::verify_authority( const account_object& a, authority::classification c )
|
||||
{
|
||||
return trx_state->check_authority( a, c );
|
||||
}
|
||||
void generic_evaluator::check_required_authorities(const operation& op)
|
||||
{
|
||||
flat_set<account_id_type> active_auths;
|
||||
flat_set<account_id_type> owner_auths;
|
||||
op.visit(operation_get_required_auths(active_auths, owner_auths));
|
||||
|
||||
for( auto id : active_auths )
|
||||
{
|
||||
FC_ASSERT(verify_authority(id(db()), authority::active) ||
|
||||
verify_authority(id(db()), authority::owner), "", ("id", id));
|
||||
}
|
||||
for( auto id : owner_auths )
|
||||
{
|
||||
FC_ASSERT(verify_authority(id(db()), authority::owner), "", ("id", id));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bool generic_evaluator::verify_signature( const key_object& k )
|
||||
{
|
||||
return trx_state->_skip_signature_check || trx_state->signed_by( k.id );
|
||||
}
|
||||
*/
|
||||
|
||||
object_id_type generic_evaluator::get_relative_id( object_id_type rel_id )const
|
||||
{
|
||||
if( rel_id.space() == relative_protocol_ids )
|
||||
{
|
||||
FC_ASSERT( rel_id.instance() < trx_state->operation_results.size() );
|
||||
// fetch the object just to make sure it exists.
|
||||
auto r = trx_state->operation_results[rel_id.instance()].get<object_id_type>();
|
||||
db().get_object( r ); // make sure it exists.
|
||||
return r;
|
||||
}
|
||||
return rel_id;
|
||||
}
|
||||
|
||||
authority generic_evaluator::resolve_relative_ids( const authority& a )const
|
||||
{
|
||||
authority result;
|
||||
result.auths.reserve( a.auths.size() );
|
||||
result.weight_threshold = a.weight_threshold;
|
||||
|
||||
for( const auto& item : a.auths )
|
||||
{
|
||||
auto id = get_relative_id( item.first );
|
||||
FC_ASSERT( id.type() == key_object_type || id.type() == account_object_type );
|
||||
result.auths[id] = item.second;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} }
|
||||
140
libraries/chain/fork_database.cpp
Normal file
140
libraries/chain/fork_database.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/fork_database.hpp>
|
||||
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
fork_database::fork_database()
|
||||
{
|
||||
}
|
||||
void fork_database::reset()
|
||||
{
|
||||
_head.reset();
|
||||
_index.clear();
|
||||
}
|
||||
|
||||
void fork_database::pop_block()
|
||||
{
|
||||
if( _head ) _head = _head->prev.lock();
|
||||
}
|
||||
|
||||
void fork_database::start_block( signed_block b )
|
||||
{
|
||||
auto item = std::make_shared<fork_item>( std::move(b) );
|
||||
_index.insert( item );
|
||||
_head = item;
|
||||
}
|
||||
|
||||
shared_ptr<fork_item> fork_database::push_block( signed_block b )
|
||||
{
|
||||
auto item = std::make_shared<fork_item>( std::move(b) );
|
||||
//wdump((item->num)(_head?_head->num:0));
|
||||
|
||||
if( _head && b.previous != block_id_type() )
|
||||
{
|
||||
auto itr = _index.get<block_id>().find( b.previous );
|
||||
FC_ASSERT( itr != _index.get<block_id>().end() );
|
||||
FC_ASSERT( !(*itr)->invalid );
|
||||
item->prev = *itr;
|
||||
}
|
||||
|
||||
_index.insert( item );
|
||||
if( !_head ) _head = item;
|
||||
else if( item->num > _head->num )
|
||||
{
|
||||
_head = item;
|
||||
_index.get<block_num>().erase( _head->num - 1024 );
|
||||
}
|
||||
return _head;
|
||||
}
|
||||
bool fork_database::is_known_block( const block_id_type& id )const
|
||||
{
|
||||
auto& index = _index.get<block_id>();
|
||||
auto itr = index.find(id);
|
||||
return itr != index.end();
|
||||
}
|
||||
item_ptr fork_database::fetch_block( const block_id_type& id )const
|
||||
{
|
||||
auto itr = _index.get<block_id>().find(id);
|
||||
if( itr != _index.get<block_id>().end() )
|
||||
return *itr;
|
||||
return item_ptr();
|
||||
}
|
||||
vector<item_ptr> fork_database::fetch_block_by_number( uint32_t num )const
|
||||
{
|
||||
vector<item_ptr> result;
|
||||
auto itr = _index.get<block_num>().find(num);
|
||||
while( itr != _index.get<block_num>().end() )
|
||||
{
|
||||
if( (*itr)->num == num )
|
||||
result.push_back( *itr );
|
||||
else
|
||||
break;
|
||||
++itr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
pair<fork_database::branch_type,fork_database::branch_type>
|
||||
fork_database::fetch_branch_from( block_id_type first, block_id_type second )const
|
||||
{ try {
|
||||
pair<branch_type,branch_type> result;
|
||||
auto first_branch_itr = _index.get<block_id>().find(first);
|
||||
FC_ASSERT( first_branch_itr != _index.get<block_id>().end() );
|
||||
auto first_branch = *first_branch_itr;
|
||||
|
||||
auto second_branch_itr = _index.get<block_id>().find(second);
|
||||
FC_ASSERT( second_branch_itr != _index.get<block_id>().end() );
|
||||
auto second_branch = *second_branch_itr;
|
||||
|
||||
|
||||
while( first_branch->data.block_num() > second_branch->data.block_num() )
|
||||
{
|
||||
result.first.push_back( first_branch );
|
||||
first_branch = first_branch->prev.lock(); FC_ASSERT( first_branch );
|
||||
}
|
||||
while( second_branch->data.block_num() > first_branch->data.block_num() )
|
||||
{
|
||||
result.second.push_back( second_branch );
|
||||
second_branch = second_branch->prev.lock(); FC_ASSERT( second_branch );
|
||||
}
|
||||
while( first_branch->data.previous != second_branch->data.previous )
|
||||
{
|
||||
result.first.push_back( first_branch );
|
||||
result.second.push_back( second_branch );
|
||||
first_branch = first_branch->prev.lock(); FC_ASSERT( first_branch );
|
||||
second_branch = second_branch->prev.lock(); FC_ASSERT( second_branch );
|
||||
}
|
||||
if( first_branch && second_branch )
|
||||
{
|
||||
result.first.push_back( first_branch );
|
||||
result.second.push_back( second_branch );
|
||||
}
|
||||
return result;
|
||||
} FC_CAPTURE_AND_RETHROW( (first)(second) ) }
|
||||
void fork_database::set_head( shared_ptr<fork_item> h )
|
||||
{
|
||||
_head = h;
|
||||
}
|
||||
|
||||
void fork_database::remove( block_id_type id )
|
||||
{
|
||||
_index.get<block_id>().erase(id);
|
||||
}
|
||||
|
||||
} } // graphene::chain
|
||||
40
libraries/chain/global_parameters_evaluator.cpp
Normal file
40
libraries/chain/global_parameters_evaluator.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <graphene/chain/global_parameters_evaluator.hpp>
|
||||
#include <graphene/chain/transaction_evaluation_state.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
object_id_type global_parameters_update_evaluator::do_evaluate(const global_parameters_update_operation& o)
|
||||
{
|
||||
FC_ASSERT(trx_state->_is_proposed_trx);
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type global_parameters_update_evaluator::do_apply(const global_parameters_update_operation& o)
|
||||
{
|
||||
db().modify(db().get_global_properties(), [&o](global_property_object& p) {
|
||||
p.pending_parameters = o.new_parameters;
|
||||
});
|
||||
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
} } // graphene::chain
|
||||
55
libraries/chain/include/graphene/chain/account_evaluator.hpp
Normal file
55
libraries/chain/include/graphene/chain/account_evaluator.hpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/account_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class account_create_evaluator : public evaluator<account_create_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef account_create_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const account_create_operation& o );
|
||||
object_id_type do_apply( const account_create_operation& o ) ;
|
||||
};
|
||||
|
||||
class account_update_evaluator : public evaluator<account_update_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef account_update_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const account_update_operation& o );
|
||||
object_id_type do_apply( const account_update_operation& o );
|
||||
|
||||
const account_object* acnt;
|
||||
};
|
||||
|
||||
class account_whitelist_evaluator : public evaluator<account_whitelist_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef account_whitelist_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const account_whitelist_operation& o);
|
||||
object_id_type do_apply( const account_whitelist_operation& o);
|
||||
|
||||
const account_object* listed_account;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
274
libraries/chain/include/graphene/chain/account_object.hpp
Normal file
274
libraries/chain/include/graphene/chain/account_object.hpp
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/authority.hpp>
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
#include <boost/multi_index/composite_key.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* @class account_statistics_object
|
||||
* @ingroup object
|
||||
* @ingroup implementation
|
||||
*
|
||||
* This object contains regularly updated statistical data about an account. It is provided for the purpose of
|
||||
* separating the account data that changes frequently from the account data that is mostly static, which will
|
||||
* minimize the amount of data that must be backed up as part of the undo history everytime a transfer is made.
|
||||
*/
|
||||
class account_statistics_object : public graphene::db::abstract_object<account_statistics_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_account_statistics_object_type;
|
||||
|
||||
/**
|
||||
* Keep the most recent operation as a root pointer to
|
||||
* a linked list of the transaction history. This field is
|
||||
* not required by core validation and could in theory be
|
||||
* made an annotation on the account object, but because
|
||||
* transaction history is so common and this object is already
|
||||
* cached in the undo buffer (because it likely affected the
|
||||
* balances of this account) it is convienent to simply
|
||||
* track this data here. Account balance objects don't currenty
|
||||
* inherit from annotated object.
|
||||
*/
|
||||
account_transaction_history_id_type most_recent_op;
|
||||
|
||||
/**
|
||||
* When calculating votes it is necessary to know how much is
|
||||
* stored in orders (and thus unavailable for transfers). Rather
|
||||
* than maintaining an index of [asset,owner,order_id] we will
|
||||
* simply maintain the running total here and update it every
|
||||
* time an order is created or modified.
|
||||
*/
|
||||
share_type total_core_in_orders;
|
||||
|
||||
/**
|
||||
* Tracks the total fees paid by this account for the purpose
|
||||
* of calculating bulk discounts.
|
||||
*/
|
||||
share_type lifetime_fees_paid;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Tracks the balance of a single account/asset pair
|
||||
* @ingroup object
|
||||
*
|
||||
* This object is indexed on owner and asset_type so that black swan
|
||||
* events in asset_type can be processed quickly.
|
||||
*/
|
||||
class account_balance_object : public abstract_object<account_balance_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_account_balance_object_type;
|
||||
|
||||
account_id_type owner;
|
||||
asset_id_type asset_type;
|
||||
share_type balance;
|
||||
|
||||
asset get_balance()const { return asset(balance, asset_type); }
|
||||
void adjust_balance(const asset& delta);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief This class represents an account on the object graph
|
||||
* @ingroup object
|
||||
* @ingroup protocol
|
||||
*
|
||||
* Accounts are the primary unit of authority on the graphene system. Users must have an account in order to use
|
||||
* assets, trade in the markets, vote for delegates, etc.
|
||||
*/
|
||||
class account_object : public graphene::db::annotated_object<account_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = account_object_type;
|
||||
/**
|
||||
* The account that paid the fee to register this account, this account is
|
||||
* known as the primary referrer and is entitled to a percent of transaction
|
||||
* fees.
|
||||
*/
|
||||
account_id_type registrar;
|
||||
|
||||
/**
|
||||
* The registrar may be a faucet with its own revenue sharing model that allows
|
||||
* users to refer each other.
|
||||
*/
|
||||
account_id_type referrer;
|
||||
|
||||
/**
|
||||
* Any referral fees not paid to referrer are paid to registrar
|
||||
*/
|
||||
uint8_t referrer_percent = 0;
|
||||
|
||||
|
||||
/// The account's name. This name must be unique among all account names on the graph. The name may be empty.
|
||||
string name;
|
||||
|
||||
/**
|
||||
* The owner authority represents absolute control over the account. Usually the keys in this authority will
|
||||
* be kept in cold storage, as they should not be needed very often and compromise of these keys constitutes
|
||||
* complete and irrevocable loss of the account. Generally the only time the owner authority is required is to
|
||||
* update the active authority.
|
||||
*/
|
||||
authority owner;
|
||||
|
||||
/// The owner authority contains the hot keys of the account. This authority has control over nearly all
|
||||
/// operations the account may perform.
|
||||
authority active;
|
||||
|
||||
/// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non-
|
||||
/// validated account activities. This field is here to prevent confusion if the active authority has zero or
|
||||
/// multiple keys in it.
|
||||
key_id_type memo_key;
|
||||
|
||||
/// If this field is set to an account ID other than 0, this account's votes will be ignored and its stake
|
||||
/// will be counted as voting for the referenced account's selected votes instead.
|
||||
account_id_type voting_account;
|
||||
|
||||
|
||||
uint16_t num_witness = 0;
|
||||
uint16_t num_committee = 0;
|
||||
|
||||
/// This is the list of vote IDs this account votes for. The weight of these votes is determined by this
|
||||
/// account's balance of core asset.
|
||||
flat_set<vote_id_type> votes;
|
||||
|
||||
/// The reference implementation records the account's statistics in a separate object. This field contains the
|
||||
/// ID of that object.
|
||||
account_statistics_id_type statistics;
|
||||
|
||||
/**
|
||||
* This is a set of all accounts which have 'whitelisted' this account. Whitelisting is only used in core
|
||||
* validation for the purpose of authorizing accounts to hold and transact in whitelisted assets. This
|
||||
* account cannot update this set, except by transferring ownership of the account, which will clear it. Other
|
||||
* accounts may add or remove their IDs from this set.
|
||||
*/
|
||||
flat_set<account_id_type> whitelisting_accounts;
|
||||
|
||||
/**
|
||||
* This is a set of all accounts which have 'blacklisted' this account. Blacklisting is only used in core
|
||||
* validation for the purpose of forbidding accounts from holding and transacting in whitelisted assets. This
|
||||
* account cannot update this set, and it will be preserved even if the account is transferred. Other accounts
|
||||
* may add or remove their IDs from this set.
|
||||
*/
|
||||
flat_set<account_id_type> blacklisting_accounts;
|
||||
|
||||
/**
|
||||
* Vesting balance which receives cashback_reward deposits.
|
||||
*/
|
||||
optional<vesting_balance_id_type> cashback_vb;
|
||||
|
||||
/**
|
||||
* @return true if this is a prime account, false otherwise.
|
||||
*/
|
||||
bool is_prime()const
|
||||
{
|
||||
return get_id() == referrer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this account is whitelisted and not blacklisted to transact in the provided asset; false
|
||||
* otherwise.
|
||||
*/
|
||||
bool is_authorized_asset(const asset_object& asset_obj)const;
|
||||
|
||||
account_id_type get_id()const { return id; }
|
||||
};
|
||||
|
||||
/**
|
||||
* This object is attached as the meta annotation on the account object, this information is not relevant to
|
||||
* validation.
|
||||
*/
|
||||
class meta_account_object : public graphene::db::abstract_object<meta_account_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = meta_account_object_type;
|
||||
|
||||
key_id_type memo_key;
|
||||
delegate_id_type delegate_id; // optional
|
||||
};
|
||||
|
||||
struct by_asset;
|
||||
struct by_account;
|
||||
struct by_balance;
|
||||
/**
|
||||
* @ingroup object_index
|
||||
*/
|
||||
typedef multi_index_container<
|
||||
account_balance_object,
|
||||
indexed_by<
|
||||
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
hashed_unique< tag<by_balance>, composite_key<
|
||||
account_balance_object,
|
||||
member<account_balance_object, account_id_type, &account_balance_object::owner>,
|
||||
member<account_balance_object, asset_id_type, &account_balance_object::asset_type> >
|
||||
>,
|
||||
ordered_non_unique< tag<by_account>, member<account_balance_object, account_id_type, &account_balance_object::owner> >,
|
||||
ordered_non_unique< tag<by_asset>, member<account_balance_object, asset_id_type, &account_balance_object::asset_type> >
|
||||
>
|
||||
> account_balance_object_multi_index_type;
|
||||
|
||||
/**
|
||||
* @ingroup object_index
|
||||
*/
|
||||
typedef generic_index<account_balance_object, account_balance_object_multi_index_type> account_balance_index;
|
||||
|
||||
struct by_name{};
|
||||
|
||||
/**
|
||||
* @ingroup object_index
|
||||
*/
|
||||
typedef multi_index_container<
|
||||
account_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
ordered_non_unique< tag<by_name>, member<account_object, string, &account_object::name> >
|
||||
>
|
||||
> account_object_multi_index_type;
|
||||
|
||||
/**
|
||||
* @ingroup object_index
|
||||
*/
|
||||
typedef generic_index<account_object, account_object_multi_index_type> account_index;
|
||||
|
||||
}}
|
||||
FC_REFLECT_DERIVED( graphene::chain::account_object,
|
||||
(graphene::db::annotated_object<graphene::chain::account_object>),
|
||||
(registrar)(referrer)(referrer_percent)(name)(owner)(active)(memo_key)(voting_account)(num_witness)(num_committee)(votes)
|
||||
(statistics)(whitelisting_accounts)(blacklisting_accounts)(cashback_vb) )
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::account_balance_object,
|
||||
(graphene::db::object),
|
||||
(owner)(asset_type)(balance) )
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::meta_account_object,
|
||||
(graphene::db::object),
|
||||
(memo_key)(delegate_id) )
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::account_statistics_object, (graphene::chain::object),
|
||||
(most_recent_op)
|
||||
(total_core_in_orders)
|
||||
(lifetime_fees_paid)
|
||||
)
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
87
libraries/chain/include/graphene/chain/address.hpp
Normal file
87
libraries/chain/include/graphene/chain/address.hpp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/chain/config.hpp>
|
||||
#include <graphene/chain/pts_address.hpp>
|
||||
|
||||
#include <fc/array.hpp>
|
||||
#include <fc/crypto/ripemd160.hpp>
|
||||
|
||||
namespace fc { namespace ecc {
|
||||
class public_key;
|
||||
typedef fc::array<char,33> public_key_data;
|
||||
} } // fc::ecc
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
struct public_key_type;
|
||||
|
||||
/**
|
||||
* @brief a 160 bit hash of a public key
|
||||
*
|
||||
* An address can be converted to or from a base58 string with 32 bit checksum.
|
||||
*
|
||||
* An address is calculated as ripemd160( sha512( compressed_ecc_public_key ) )
|
||||
*
|
||||
* When converted to a string, checksum calculated as the first 4 bytes ripemd160( address ) is
|
||||
* appended to the binary address before converting to base58.
|
||||
*/
|
||||
class address
|
||||
{
|
||||
public:
|
||||
address(); ///< constructs empty / null address
|
||||
explicit address( const std::string& base58str ); ///< converts to binary, validates checksum
|
||||
address( const fc::ecc::public_key& pub ); ///< converts to binary
|
||||
explicit address( const fc::ecc::public_key_data& pub ); ///< converts to binary
|
||||
address( const pts_address& pub ); ///< converts to binary
|
||||
address( const public_key_type& pubkey );
|
||||
|
||||
static bool is_valid( const std::string& base58str, const std::string& prefix = GRAPHENE_ADDRESS_PREFIX );
|
||||
|
||||
explicit operator std::string()const; ///< converts to base58 + checksum
|
||||
|
||||
fc::ripemd160 addr;
|
||||
};
|
||||
inline bool operator == ( const address& a, const address& b ) { return a.addr == b.addr; }
|
||||
inline bool operator != ( const address& a, const address& b ) { return a.addr != b.addr; }
|
||||
inline bool operator < ( const address& a, const address& b ) { return a.addr < b.addr; }
|
||||
|
||||
} } // namespace graphene::chain
|
||||
|
||||
namespace fc
|
||||
{
|
||||
void to_variant( const graphene::chain::address& var, fc::variant& vo );
|
||||
void from_variant( const fc::variant& var, graphene::chain::address& vo );
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct hash<graphene::chain::address>
|
||||
{
|
||||
public:
|
||||
size_t operator()(const graphene::chain::address &a) const
|
||||
{
|
||||
return (uint64_t(a.addr._hash[0])<<32) | uint64_t( a.addr._hash[0] );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
FC_REFLECT( graphene::chain::address, (addr) )
|
||||
196
libraries/chain/include/graphene/chain/asset.hpp
Normal file
196
libraries/chain/include/graphene/chain/asset.hpp
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/types.hpp>
|
||||
#include <graphene/chain/config.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
struct asset
|
||||
{
|
||||
asset( share_type a = 0, asset_id_type id = asset_id_type() )
|
||||
:amount(a),asset_id(id){}
|
||||
|
||||
share_type amount;
|
||||
asset_id_type asset_id;
|
||||
|
||||
asset& operator += ( const asset& o )
|
||||
{
|
||||
FC_ASSERT( asset_id == o.asset_id );
|
||||
amount += o.amount;
|
||||
return *this;
|
||||
}
|
||||
asset& operator -= ( const asset& o )
|
||||
{
|
||||
FC_ASSERT( asset_id == o.asset_id );
|
||||
amount -= o.amount;
|
||||
return *this;
|
||||
}
|
||||
asset operator -()const { return asset( -amount, asset_id ); }
|
||||
friend bool operator == ( const asset& a, const asset& b )
|
||||
{
|
||||
return tie(a.asset_id,a.amount) == tie(b.asset_id,b.amount);
|
||||
}
|
||||
friend bool operator >= ( const asset& a, const asset& b )
|
||||
{
|
||||
FC_ASSERT( a.asset_id == b.asset_id );
|
||||
return a.amount >= b.amount;
|
||||
}
|
||||
friend bool operator > ( const asset& a, const asset& b )
|
||||
{
|
||||
FC_ASSERT( a.asset_id == b.asset_id );
|
||||
return a.amount > b.amount;
|
||||
}
|
||||
friend asset operator - ( const asset& a, const asset& b )
|
||||
{
|
||||
FC_ASSERT( a.asset_id == b.asset_id );
|
||||
return asset( a.amount - b.amount, a.asset_id );
|
||||
}
|
||||
friend asset operator + ( const asset& a, const asset& b )
|
||||
{
|
||||
FC_ASSERT( a.asset_id == b.asset_id );
|
||||
return asset( a.amount + b.amount, a.asset_id );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The price struct stores asset prices in the Graphene system.
|
||||
*
|
||||
* A price is defined as a ratio between two assets, and represents a possible exchange rate between those two
|
||||
* assets. prices are generally not stored in any simplified form, i.e. a price of (1000 CORE)/(20 USD) is perfectly
|
||||
* normal.
|
||||
*
|
||||
* The assets within a price are labeled base and quote. Throughout the Graphene code base, the convention used is
|
||||
* that the base asset is the asset being sold, and the quote asset is the asset being purchased, where the price is
|
||||
* represented as base/quote, so in the example price above the seller is looking to sell CORE asset and get USD in
|
||||
* return.
|
||||
*/
|
||||
struct price
|
||||
{
|
||||
price(const asset& base = asset(), const asset quote = asset())
|
||||
: base(base),quote(quote){}
|
||||
|
||||
asset base;
|
||||
asset quote;
|
||||
|
||||
static price max(asset_id_type base, asset_id_type quote );
|
||||
static price min(asset_id_type base, asset_id_type quote );
|
||||
|
||||
static price call_price(const asset& debt, const asset& collateral, uint16_t collateral_ratio);
|
||||
|
||||
/// The unit price for an asset type A is defined to be a price such that for any asset m, m*A=m
|
||||
static price unit_price(asset_id_type a = asset_id_type()) { return price(asset(1, a), asset(1, a)); }
|
||||
|
||||
price max()const { return price::max( base.asset_id, quote.asset_id ); }
|
||||
price min()const { return price::min( base.asset_id, quote.asset_id ); }
|
||||
|
||||
double to_real()const { return double(base.amount.value)/double(quote.amount.value); }
|
||||
|
||||
bool is_null()const;
|
||||
void validate()const;
|
||||
};
|
||||
|
||||
price operator / ( const asset& base, const asset& quote );
|
||||
inline price operator~( const price& p ) { return price{p.quote,p.base}; }
|
||||
|
||||
bool operator < ( const asset& a, const asset& b );
|
||||
bool operator <= ( const asset& a, const asset& b );
|
||||
bool operator < ( const price& a, const price& b );
|
||||
bool operator <= ( const price& a, const price& b );
|
||||
bool operator > ( const price& a, const price& b );
|
||||
bool operator >= ( const price& a, const price& b );
|
||||
bool operator == ( const price& a, const price& b );
|
||||
bool operator != ( const price& a, const price& b );
|
||||
asset operator * ( const asset& a, const price& b );
|
||||
|
||||
/**
|
||||
* @class price_feed
|
||||
* @brief defines market parameters for shorts and margin positions
|
||||
*/
|
||||
struct price_feed
|
||||
{
|
||||
/**
|
||||
* This is the lowest price at which margin positions will be forced to sell their collateral. This does not
|
||||
* directly affect the price at which margin positions will be called; it is only a safety to prevent calls at
|
||||
* unreasonable prices.
|
||||
*/
|
||||
price call_limit;
|
||||
/**
|
||||
* Short orders will only be matched against bids above this price.
|
||||
*/
|
||||
price short_limit;
|
||||
/**
|
||||
* Forced settlements will evaluate using this price.
|
||||
*/
|
||||
price settlement_price;
|
||||
/**
|
||||
* Maximum number of seconds margin positions should be able to remain open.
|
||||
*/
|
||||
uint32_t max_margin_period_sec = GRAPHENE_DEFAULT_MARGIN_PERIOD_SEC;
|
||||
|
||||
/**
|
||||
* Required maintenance collateral is defined
|
||||
* as a fixed point number with a maximum value of 10.000
|
||||
* and a minimum value of 1.000.
|
||||
*
|
||||
* This value must be greater than required_maintenance_collateral or
|
||||
* a margin call would be triggered immediately.
|
||||
*
|
||||
* Default requirement is $2 of collateral per $1 of debt based
|
||||
* upon the premise that both parties to every trade should bring
|
||||
* equal value to the table.
|
||||
*/
|
||||
uint16_t required_initial_collateral = GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO;
|
||||
|
||||
/**
|
||||
* Required maintenance collateral is defined
|
||||
* as a fixed point number with a maximum value of 10.000
|
||||
* and a minimum value of 1.000.
|
||||
*
|
||||
* A black swan event occurs when value_of_collateral equals
|
||||
* value_of_debt, to avoid a black swan a margin call is
|
||||
* executed when value_of_debt * required_maintenance_collateral
|
||||
* equals value_of_collateral using rate.
|
||||
*
|
||||
* Default requirement is $1.75 of collateral per $1 of debt
|
||||
*/
|
||||
uint16_t required_maintenance_collateral = GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO;
|
||||
|
||||
friend bool operator < ( const price_feed& a, const price_feed& b )
|
||||
{
|
||||
return std::tie( a.call_limit.base.asset_id, a.call_limit.quote.asset_id ) <
|
||||
std::tie( b.call_limit.base.asset_id, b.call_limit.quote.asset_id );
|
||||
}
|
||||
|
||||
friend bool operator == ( const price_feed& a, const price_feed& b )
|
||||
{
|
||||
return std::tie( a.call_limit.base.asset_id, a.call_limit.quote.asset_id ) ==
|
||||
std::tie( b.call_limit.base.asset_id, b.call_limit.quote.asset_id );
|
||||
}
|
||||
|
||||
void validate() const;
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
FC_REFLECT( graphene::chain::asset, (amount)(asset_id) )
|
||||
FC_REFLECT( graphene::chain::price, (base)(quote) )
|
||||
#define GRAPHENE_PRICE_FEED_FIELDS (call_limit)(short_limit)(settlement_price)(max_margin_period_sec)\
|
||||
(required_initial_collateral)(required_maintenance_collateral)
|
||||
FC_REFLECT( graphene::chain::price_feed, GRAPHENE_PRICE_FEED_FIELDS )
|
||||
133
libraries/chain/include/graphene/chain/asset_evaluator.hpp
Normal file
133
libraries/chain/include/graphene/chain/asset_evaluator.hpp
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/operations.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class asset_create_evaluator : public evaluator<asset_create_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef asset_create_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const asset_create_operation& o );
|
||||
object_id_type do_apply( const asset_create_operation& o );
|
||||
};
|
||||
|
||||
class asset_issue_evaluator : public evaluator<asset_issue_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef asset_issue_operation operation_type;
|
||||
object_id_type do_evaluate( const asset_issue_operation& o );
|
||||
object_id_type do_apply( const asset_issue_operation& o );
|
||||
|
||||
const asset_dynamic_data_object* asset_dyn_data = nullptr;
|
||||
const account_object* to_account = nullptr;
|
||||
};
|
||||
|
||||
class asset_burn_evaluator : public evaluator<asset_burn_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef asset_burn_operation operation_type;
|
||||
object_id_type do_evaluate( const asset_burn_operation& o );
|
||||
object_id_type do_apply( const asset_burn_operation& o );
|
||||
|
||||
const asset_dynamic_data_object* asset_dyn_data = nullptr;
|
||||
const account_object* from_account = nullptr;
|
||||
};
|
||||
|
||||
|
||||
class asset_update_evaluator : public evaluator<asset_update_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef asset_update_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const asset_update_operation& o );
|
||||
object_id_type do_apply( const asset_update_operation& o );
|
||||
|
||||
const asset_object* asset_to_update = nullptr;
|
||||
};
|
||||
|
||||
class asset_update_bitasset_evaluator : public evaluator<asset_update_bitasset_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef asset_update_bitasset_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const asset_update_bitasset_operation& o );
|
||||
object_id_type do_apply( const asset_update_bitasset_operation& o );
|
||||
|
||||
const asset_bitasset_data_object* bitasset_to_update = nullptr;
|
||||
};
|
||||
|
||||
class asset_update_feed_producers_evaluator : public evaluator<asset_update_feed_producers_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef asset_update_feed_producers_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const operation_type& o );
|
||||
object_id_type do_apply( const operation_type& o );
|
||||
|
||||
const asset_bitasset_data_object* bitasset_to_update = nullptr;
|
||||
};
|
||||
|
||||
class asset_fund_fee_pool_evaluator : public evaluator<asset_fund_fee_pool_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef asset_fund_fee_pool_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate(const asset_fund_fee_pool_operation& op);
|
||||
object_id_type do_apply(const asset_fund_fee_pool_operation& op);
|
||||
|
||||
const asset_dynamic_data_object* asset_dyn_data = nullptr;
|
||||
};
|
||||
|
||||
class asset_global_settle_evaluator : public evaluator<asset_global_settle_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef asset_global_settle_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate(const operation_type& op);
|
||||
object_id_type do_apply(const operation_type& op);
|
||||
|
||||
const asset_object* asset_to_settle = nullptr;
|
||||
};
|
||||
class asset_settle_evaluator : public evaluator<asset_settle_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef asset_settle_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate(const operation_type& op);
|
||||
object_id_type do_apply(const operation_type& op);
|
||||
|
||||
const asset_object* asset_to_settle = nullptr;
|
||||
};
|
||||
|
||||
class asset_publish_feeds_evaluator : public evaluator<asset_publish_feeds_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef asset_publish_feed_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const asset_publish_feed_operation& o );
|
||||
object_id_type do_apply( const asset_publish_feed_operation& o );
|
||||
|
||||
std::map<std::pair<asset_id_type,asset_id_type>,price_feed> median_feed_values;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
327
libraries/chain/include/graphene/chain/asset_object.hpp
Normal file
327
libraries/chain/include/graphene/chain/asset_object.hpp
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <boost/multi_index/composite_key.hpp>
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/flat_index.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
/**
|
||||
* @defgroup prediction_market Prediction Market
|
||||
*
|
||||
* A prediction market is a specialized BitAsset such that total debt and total collateral are always equal amounts
|
||||
* (although asset IDs differ). No margin calls or force settlements may be performed on a prediction market asset. A
|
||||
* prediction market is globally settled by the issuer after the event being predicted resolves, thus a prediction
|
||||
* market must always have the @ref global_settle permission enabled. The maximum price for global settlement or short
|
||||
* sale of a prediction market asset is 1-to-1.
|
||||
*/
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
class account_object;
|
||||
using namespace graphene::db;
|
||||
|
||||
/**
|
||||
* @brief tracks the asset information that changes frequently
|
||||
* @ingroup object
|
||||
* @ingroup implementation
|
||||
*
|
||||
* Because the asset_object is very large it doesn't make sense to save an undo state
|
||||
* for all of the parameters that never change. This object factors out the parameters
|
||||
* of an asset that change in almost every transaction that involves the asset.
|
||||
*
|
||||
* This object exists as an implementation detail and its ID should never be referenced by
|
||||
* a blockchain operation.
|
||||
*/
|
||||
class asset_dynamic_data_object : public abstract_object<asset_dynamic_data_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_asset_dynamic_data_type;
|
||||
|
||||
/// The number of shares currently in existence
|
||||
share_type current_supply;
|
||||
share_type accumulated_fees; ///< fees accumulate to be paid out over time
|
||||
share_type fee_pool; ///< in core asset
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief tracks the parameters of an asset
|
||||
* @ingroup object
|
||||
*
|
||||
* All assets have a globally unique symbol name that controls how they are traded and an issuer who
|
||||
* has authority over the parameters of the asset.
|
||||
*/
|
||||
class asset_object : public graphene::db::annotated_object<asset_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = asset_object_type;
|
||||
|
||||
/// This function does not check if any registered asset has this symbol or not; it simply checks whether the
|
||||
/// symbol would be valid.
|
||||
/// @return true if symbol is a valid ticker symbol; false otherwise.
|
||||
static bool is_valid_symbol( const string& symbol );
|
||||
|
||||
/// @return true if accounts must be on a whitelist in order to hold this asset; false otherwise.
|
||||
bool enforce_white_list()const { return options.flags & white_list; }
|
||||
/// @return true if this is a market-issued asset; false otherwise.
|
||||
bool is_market_issued()const { return bitasset_data_id.valid(); }
|
||||
/// @return true if users may request force-settlement of this market-issued asset; false otherwise
|
||||
bool can_force_settle()const { return !(options.flags & disable_force_settle); }
|
||||
/// @return true if the issuer of this market-issued asset may globally settle the asset; false otherwise
|
||||
bool can_global_settle()const { return options.issuer_permissions & global_settle; }
|
||||
/// @return true if this asset charges a fee for the issuer on market operations; false otherwise
|
||||
bool charges_market_fees()const { return options.flags & charge_market_fee; }
|
||||
/// @return true if this asset may only be transferred to/from the issuer or market orders
|
||||
bool is_transfer_restricted()const { return options.flags & transfer_restricted; }
|
||||
|
||||
/// Helper function to get an asset object with the given amount in this asset's type
|
||||
asset amount(share_type a)const { return asset(a, id); }
|
||||
/// Convert a string amount (i.e. "123.45") to an asset object with this asset's type
|
||||
/// The string may have a decimal and/or a negative sign.
|
||||
asset amount_from_string(string amount_string)const;
|
||||
/// Convert an asset to a textual representation, i.e. "123.45"
|
||||
string amount_to_string(share_type amount)const;
|
||||
/// Convert an asset to a textual representation, i.e. "123.45"
|
||||
string amount_to_string(const asset& amount)const
|
||||
{ FC_ASSERT(amount.asset_id == id); return amount_to_string(amount.amount); }
|
||||
/// Convert an asset to a textual representation with symbol, i.e. "123.45 USD"
|
||||
string amount_to_pretty_string(share_type amount)const
|
||||
{ return amount_to_string(amount) + " " + symbol; }
|
||||
/// Convert an asset to a textual representation with symbol, i.e. "123.45 USD"
|
||||
string amount_to_pretty_string(const asset &amount)const
|
||||
{ FC_ASSERT(amount.asset_id == id); return amount_to_pretty_string(amount.amount); }
|
||||
|
||||
/// Ticker symbol for this asset, i.e. "USD"
|
||||
string symbol;
|
||||
/// Maximum number of digits after the decimal point
|
||||
uint64_t precision;
|
||||
/// ID of the account which issued this asset.
|
||||
account_id_type issuer;
|
||||
|
||||
/**
|
||||
* @brief The asset_options struct contains options available on all assets in the network
|
||||
*
|
||||
* @note Changes to this struct will break protocol compatibility
|
||||
*/
|
||||
struct asset_options {
|
||||
/// The maximum supply of this asset which may exist at any given time. This can be as large as
|
||||
/// GRAPHENE_MAX_SHARE_SUPPLY
|
||||
share_type max_supply = GRAPHENE_MAX_SHARE_SUPPLY;
|
||||
/// When this asset is traded on the markets, this percentage of the total traded will be exacted and paid
|
||||
/// to the issuer. This is a fixed point value, representing hundredths of a percent, i.e. a value of 100
|
||||
/// in this field means a 1% fee is charged on market trades of this asset.
|
||||
uint16_t market_fee_percent = 0;
|
||||
share_type max_market_fee = GRAPHENE_MAX_SHARE_SUPPLY;
|
||||
share_type min_market_fee;
|
||||
|
||||
/// The flags which the issuer has permission to update. See @ref asset_issuer_permission_flags
|
||||
uint16_t issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
|
||||
/// The currently active flags on this permission. See @ref asset_issuer_permission_flags
|
||||
uint16_t flags = 0;
|
||||
|
||||
/// When a non-core asset is used to pay a fee, the blockchain must convert that asset to core asset in
|
||||
/// order to accept the fee. If this asset's fee pool is funded, the chain will automatically deposite fees
|
||||
/// in this asset to its accumulated fees, and withdraw from the fee pool the same amount as converted at
|
||||
/// the core exchange rate.
|
||||
price core_exchange_rate;
|
||||
|
||||
/// A set of accounts which maintain whitelists to consult for this asset. If enforce_white_list() returns
|
||||
/// true, an account may only send, receive, trade, etc. in this asset if one of these accounts appears in
|
||||
/// its account_object::whitelisting_accounts field.
|
||||
flat_set<account_id_type> whitelist_authorities;
|
||||
/// A set of accounts which maintain blacklists to consult for this asset. If enforce_white_list() returns
|
||||
/// true, an account may only send, receive, trade, etc. in this asset if none of these accounts appears in
|
||||
/// its account_object::blacklisting_accounts field. If the account is blacklisted, it may not transact in
|
||||
/// this asset even if it is also whitelisted.
|
||||
flat_set<account_id_type> blacklist_authorities;
|
||||
|
||||
/** defines the assets that this asset may be traded against in the market */
|
||||
flat_set<asset_id_type> whitelist_markets;
|
||||
/** defines the assets that this asset may not be traded against in the market, must not overlap whitelist */
|
||||
flat_set<asset_id_type> blacklist_markets;
|
||||
|
||||
/// Perform internal consistency checks.
|
||||
/// @throws fc::exception if any check fails
|
||||
void validate()const;
|
||||
} options;
|
||||
/**
|
||||
* @brief The bitasset_options struct contains configurable options available only to BitAssets.
|
||||
*
|
||||
* @note Changes to this struct will break protocol compatibility
|
||||
*/
|
||||
struct bitasset_options {
|
||||
/// Time before a price feed expires
|
||||
uint32_t feed_lifetime_sec = GRAPHENE_DEFAULT_PRICE_FEED_LIFETIME;
|
||||
/// This is the delay between the time a long requests settlement and the chain evaluates the settlement
|
||||
uint32_t force_settlement_delay_sec = GRAPHENE_DEFAULT_FORCE_SETTLEMENT_DELAY;
|
||||
/// This is the percent to adjust the feed price in the short's favor in the event of a forced settlement
|
||||
uint16_t force_settlement_offset_percent = GRAPHENE_DEFAULT_FORCE_SETTLEMENT_OFFSET;
|
||||
/// Force settlement volume can be limited such that only a certain percentage of the total existing supply
|
||||
/// of the asset may be force-settled within any given chain maintenance interval. This field stores the
|
||||
/// percentage of the current supply which may be force settled within the current maintenance interval. If
|
||||
/// force settlements come due in an interval in which the maximum volume has already been settled, the new
|
||||
/// settlements will be enqueued and processed at the beginning of the next maintenance interval.
|
||||
uint16_t maximum_force_settlement_volume = GRAPHENE_DEFAULT_FORCE_SETTLEMENT_MAX_VOLUME;
|
||||
/// This speicifies which asset type is used to collateralize short sales
|
||||
/// This field may only be updated if the current supply of the asset is zero.
|
||||
asset_id_type short_backing_asset;
|
||||
|
||||
/// Perform internal consistency checks.
|
||||
/// @throws fc::exception if any check fails
|
||||
void validate()const;
|
||||
};
|
||||
|
||||
/// Current supply, fee pool, and collected fees are stored in a separate object as they change frequently.
|
||||
dynamic_asset_data_id_type dynamic_asset_data_id;
|
||||
/// Extra data associated with BitAssets. This field is non-null if and only if is_market_issued() returns true
|
||||
optional<asset_bitasset_data_id_type> bitasset_data_id;
|
||||
|
||||
asset_id_type get_id()const { return id; }
|
||||
|
||||
void validate()const
|
||||
{
|
||||
// UIAs may not be prediction markets, have force settlement, or global settlements
|
||||
if( !is_market_issued() )
|
||||
{
|
||||
FC_ASSERT(!(options.flags & disable_force_settle || options.flags & global_settle));
|
||||
FC_ASSERT(!(options.issuer_permissions & disable_force_settle || options.issuer_permissions & global_settle));
|
||||
}
|
||||
}
|
||||
|
||||
template<class DB>
|
||||
const asset_bitasset_data_object& bitasset_data(const DB& db)const
|
||||
{ assert(bitasset_data_id); return db.get(*bitasset_data_id); }
|
||||
|
||||
template<class DB>
|
||||
const asset_dynamic_data_object& dynamic_data(const DB& db)const
|
||||
{ return db.get(dynamic_asset_data_id); }
|
||||
|
||||
template<class DB>
|
||||
share_type burned( const DB& db )const
|
||||
{ return options.max_supply - dynamic_data(db).current_supply; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief contains properties that only apply to bitassets (market issued assets)
|
||||
*
|
||||
* @ingroup object
|
||||
* @ingroup implementation
|
||||
*/
|
||||
class asset_bitasset_data_object : public abstract_object<asset_bitasset_data_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_asset_bitasset_data_type;
|
||||
|
||||
/// The tunable options for BitAssets are stored in this field.
|
||||
asset_object::bitasset_options options;
|
||||
|
||||
/// Feeds published for this asset. If issuer is not genesis, the keys in this map are the feed publishing
|
||||
/// accounts; otherwise, the feed publishers are the currently active delegates and witnesses and this map
|
||||
/// should be treated as an implementation detail. The timestamp on each feed is the time it was published.
|
||||
flat_map<account_id_type, pair<time_point_sec,price_feed>> feeds;
|
||||
/// This is the currently active price feed, calculated as the median of values from the currently active
|
||||
/// feeds.
|
||||
price_feed current_feed;
|
||||
/// This is the publication time of the oldest feed which was factored into current_feed.
|
||||
time_point_sec current_feed_publication_time;
|
||||
|
||||
/// True if this asset implements a @ref prediction_market
|
||||
bool is_prediction_market = false;
|
||||
|
||||
/// This is the volume of this asset which has been force-settled this maintanence interval
|
||||
share_type force_settled_volume;
|
||||
/// Calculate the maximum force settlement volume per maintenance interval, given the current share supply
|
||||
share_type max_force_settlement_volume(share_type current_supply)const;
|
||||
|
||||
time_point_sec feed_expiration_time()const
|
||||
{ return current_feed_publication_time + options.feed_lifetime_sec; }
|
||||
bool feed_is_expired(time_point_sec current_time)const
|
||||
{ return feed_expiration_time() >= current_time; }
|
||||
void update_median_feeds(time_point_sec current_time);
|
||||
};
|
||||
|
||||
|
||||
struct by_feed_expiration;
|
||||
typedef multi_index_container<
|
||||
asset_bitasset_data_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
ordered_non_unique< tag<by_feed_expiration>,
|
||||
const_mem_fun< asset_bitasset_data_object, time_point_sec, &asset_bitasset_data_object::feed_expiration_time >
|
||||
>
|
||||
>
|
||||
> asset_bitasset_data_object_multi_index_type;
|
||||
typedef flat_index<asset_bitasset_data_object> asset_bitasset_data_index;
|
||||
|
||||
struct by_symbol;
|
||||
typedef multi_index_container<
|
||||
asset_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
ordered_unique< tag<by_symbol>, member<asset_object, string, &asset_object::symbol> >
|
||||
>
|
||||
> asset_object_multi_index_type;
|
||||
typedef generic_index<asset_object, asset_object_multi_index_type> asset_index;
|
||||
|
||||
|
||||
} } // graphene::chain
|
||||
FC_REFLECT_DERIVED( graphene::chain::asset_dynamic_data_object, (graphene::db::object),
|
||||
(current_supply)(accumulated_fees)(fee_pool) )
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::asset_bitasset_data_object, (graphene::db::object),
|
||||
(feeds)
|
||||
(current_feed)
|
||||
(current_feed_publication_time)
|
||||
(options)
|
||||
(force_settled_volume)
|
||||
(is_prediction_market)
|
||||
)
|
||||
|
||||
FC_REFLECT( graphene::chain::asset_object::asset_options,
|
||||
(max_supply)
|
||||
(market_fee_percent)
|
||||
(max_market_fee)
|
||||
(min_market_fee)
|
||||
(issuer_permissions)
|
||||
(flags)
|
||||
(core_exchange_rate)
|
||||
(whitelist_authorities)
|
||||
(blacklist_authorities)
|
||||
(whitelist_markets)
|
||||
(blacklist_markets)
|
||||
)
|
||||
FC_REFLECT( graphene::chain::asset_object::bitasset_options,
|
||||
(feed_lifetime_sec)
|
||||
(force_settlement_delay_sec)
|
||||
(force_settlement_offset_percent)
|
||||
(maximum_force_settlement_volume)
|
||||
(short_backing_asset)
|
||||
)
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::asset_object,
|
||||
(graphene::db::annotated_object<graphene::chain::asset_object>),
|
||||
(symbol)
|
||||
(precision)
|
||||
(issuer)
|
||||
(options)
|
||||
(dynamic_asset_data_id)
|
||||
(bitasset_data_id)
|
||||
)
|
||||
|
||||
91
libraries/chain/include/graphene/chain/authority.hpp
Normal file
91
libraries/chain/include/graphene/chain/authority.hpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <fc/io/varint.hpp>
|
||||
#include <graphene/chain/types.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* @class authority
|
||||
* @brief Identifies a weighted set of keys and accounts that must approve operations.
|
||||
*/
|
||||
struct authority
|
||||
{
|
||||
authority(){}
|
||||
template<class ...Args>
|
||||
authority(uint32_t threshhold, Args... auths)
|
||||
: weight_threshold(threshhold)
|
||||
{
|
||||
add_authorities(auths...);
|
||||
}
|
||||
|
||||
enum classification
|
||||
{
|
||||
/** the key that is authorized to change owner, active, and voting keys */
|
||||
owner = 0,
|
||||
/** the key that is able to perform normal operations */
|
||||
active = 1,
|
||||
key = 2
|
||||
};
|
||||
void add_authority( key_id_type k, weight_type w )
|
||||
{
|
||||
auths[k] = w;
|
||||
}
|
||||
void add_authority( account_id_type k, weight_type w )
|
||||
{
|
||||
auths[k] = w;
|
||||
}
|
||||
void add_authority( relative_key_id_type k, weight_type w )
|
||||
{
|
||||
auths[k] = w;
|
||||
}
|
||||
|
||||
template<typename AuthType>
|
||||
void add_authorities(AuthType k, weight_type w)
|
||||
{
|
||||
add_authority(k, w);
|
||||
}
|
||||
template<typename AuthType, class ...Args>
|
||||
void add_authorities(AuthType k, weight_type w, Args... auths)
|
||||
{
|
||||
add_authority(k, w);
|
||||
add_authorities(auths...);
|
||||
}
|
||||
|
||||
vector<key_id_type> get_keys() const
|
||||
{
|
||||
vector<key_id_type> result;
|
||||
result.reserve( auths.size() );
|
||||
for( const pair<object_id_type, weight_type>& item : auths )
|
||||
{
|
||||
if( item.first.type() == key_object_type )
|
||||
result.push_back( item.first );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t weight_threshold = 0;
|
||||
flat_map<object_id_type,weight_type> auths;
|
||||
};
|
||||
|
||||
} } // namespace graphene::chain
|
||||
|
||||
FC_REFLECT( graphene::chain::authority, (weight_threshold)(auths) )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::authority::classification )
|
||||
FC_REFLECT_ENUM( graphene::chain::authority::classification, (owner)(active)(key) )
|
||||
64
libraries/chain/include/graphene/chain/block.hpp
Normal file
64
libraries/chain/include/graphene/chain/block.hpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/types.hpp>
|
||||
#include <graphene/chain/transaction.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
struct void_header{};
|
||||
typedef fc::static_variant<void_header> header_extension;
|
||||
|
||||
struct block_header
|
||||
{
|
||||
digest_type digest()const;
|
||||
block_id_type previous;
|
||||
uint32_t block_num()const { return num_from_id(previous) + 1; }
|
||||
fc::time_point_sec timestamp;
|
||||
witness_id_type witness;
|
||||
secret_hash_type next_secret_hash;
|
||||
secret_hash_type previous_secret;
|
||||
checksum_type transaction_merkle_root;
|
||||
vector<header_extension> extensions;
|
||||
|
||||
static uint32_t num_from_id(const block_id_type& id) { return htonl(id._hash[0]); }
|
||||
};
|
||||
|
||||
struct signed_block_header : public block_header
|
||||
{
|
||||
block_id_type id()const;
|
||||
fc::ecc::public_key signee()const;
|
||||
void sign( const fc::ecc::private_key& signer );
|
||||
bool validate_signee( const fc::ecc::public_key& expected_signee )const;
|
||||
|
||||
signature_type delegate_signature;
|
||||
};
|
||||
|
||||
struct signed_block : public signed_block_header
|
||||
{
|
||||
checksum_type calculate_merkle_root()const;
|
||||
vector<processed_transaction> transactions;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT( graphene::chain::void_header, )
|
||||
FC_REFLECT( graphene::chain::block_header, (previous)(timestamp)(witness)
|
||||
(next_secret_hash)(previous_secret)(transaction_merkle_root)(extensions) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::signed_block_header, (graphene::chain::block_header), (delegate_signature) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::signed_block, (graphene::chain::signed_block_header), (transactions) )
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/db/object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
|
||||
/**
|
||||
* @brief tracks minimal information about past blocks to implement TaPOS
|
||||
* @ingroup object
|
||||
*
|
||||
* When attempting to calculate the validity of a transaction we need to
|
||||
* lookup a past block and check its block hash and the time it occurred
|
||||
* so we can calculate whether the current transaction is valid and at
|
||||
* what time it should expire.
|
||||
*/
|
||||
class block_summary_object : public abstract_object<block_summary_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_block_summary_object_type;
|
||||
|
||||
block_id_type block_id;
|
||||
fc::time_point_sec timestamp;
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::block_summary_object, (graphene::db::object), (block_id) )
|
||||
68
libraries/chain/include/graphene/chain/bond_evaluator.hpp
Normal file
68
libraries/chain/include/graphene/chain/bond_evaluator.hpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class bond_create_offer_evaluator : public evaluator<bond_create_offer_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef bond_create_offer_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const bond_create_offer_operation& op );
|
||||
object_id_type do_apply( const bond_create_offer_operation& op );
|
||||
};
|
||||
|
||||
class bond_cancel_offer_evaluator : public evaluator<bond_cancel_offer_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef bond_cancel_offer_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const bond_cancel_offer_operation& op );
|
||||
object_id_type do_apply( const bond_cancel_offer_operation& op );
|
||||
|
||||
const bond_offer_object* _offer = nullptr;
|
||||
};
|
||||
|
||||
class bond_accept_offer_evaluator : public evaluator<bond_accept_offer_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef bond_accept_offer_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const bond_accept_offer_operation& op );
|
||||
object_id_type do_apply( const bond_accept_offer_operation& op );
|
||||
|
||||
const bond_offer_object* _offer = nullptr;
|
||||
asset _fill_amount;
|
||||
};
|
||||
|
||||
class bond_claim_collateral_evaluator : public evaluator<bond_claim_collateral_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef bond_claim_collateral_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const bond_claim_collateral_operation& op );
|
||||
object_id_type do_apply( const bond_claim_collateral_operation& op );
|
||||
|
||||
const bond_object* _bond = nullptr;
|
||||
asset _interest_due;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
111
libraries/chain/include/graphene/chain/bond_object.hpp
Normal file
111
libraries/chain/include/graphene/chain/bond_object.hpp
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#pragma once
|
||||
#include <graphene/chain/authority.hpp>
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* @ingroup object
|
||||
*/
|
||||
class bond_object : public graphene::db::abstract_object<bond_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = bond_object_type;
|
||||
|
||||
asset_id_type collateral_type()const { return collateral.asset_id; }
|
||||
|
||||
account_id_type borrower;
|
||||
account_id_type lender;
|
||||
asset borrowed;
|
||||
/** if collateral is the core asset, then voting rights belong to the borrower
|
||||
* because the borrower is owner of the collateral until they default
|
||||
*/
|
||||
asset collateral;
|
||||
uint16_t interest_apr = 0;
|
||||
time_point_sec start_date;
|
||||
/** after this date the lender can collect the collateral at will or let it float */
|
||||
time_point_sec due_date;
|
||||
/** the loan cannot be paid off before this date */
|
||||
time_point_sec earliest_payoff_date;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup object
|
||||
*/
|
||||
class bond_offer_object : public graphene::db::abstract_object<bond_offer_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = bond_offer_object_type;
|
||||
|
||||
asset_id_type asset_type()const { return amount.asset_id; }
|
||||
|
||||
account_id_type offered_by_account;
|
||||
bool offer_to_borrow = false; // Offer to borrow if true, and offer to lend otherwise
|
||||
asset amount;
|
||||
share_type min_match; ///< asset type same as ammount.asset_id
|
||||
price collateral_rate;
|
||||
uint32_t min_loan_period_sec = 0;
|
||||
uint32_t loan_period_sec = 0;
|
||||
uint16_t interest_apr = 0;
|
||||
};
|
||||
|
||||
struct by_borrower;
|
||||
struct by_lender;
|
||||
struct by_offerer;
|
||||
struct by_collateral; /// needed for blackswan resolution
|
||||
struct by_asset; /// needed for blackswan resolution
|
||||
|
||||
typedef multi_index_container<
|
||||
bond_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
ordered_non_unique< tag<by_borrower>, member<bond_object, account_id_type, &bond_object::borrower> >,
|
||||
ordered_non_unique< tag<by_lender>, member<bond_object, account_id_type, &bond_object::lender> >,
|
||||
hashed_non_unique< tag<by_collateral>, const_mem_fun<bond_object, asset_id_type, &bond_object::collateral_type> >
|
||||
>
|
||||
> bond_object_multi_index_type;
|
||||
|
||||
typedef generic_index<bond_object, bond_object_multi_index_type> bond_index;
|
||||
|
||||
/**
|
||||
* Todo: consider adding index of tuple<collateral_type,loan_asset_type,interest_rate>
|
||||
* Todo: consider adding index of tuple<collateral_type,loan_asset_type,period>
|
||||
*/
|
||||
typedef multi_index_container<
|
||||
bond_offer_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
ordered_non_unique< tag<by_offerer>, member<bond_offer_object, account_id_type, &bond_offer_object::offered_by_account> >,
|
||||
hashed_non_unique< tag<by_asset>, const_mem_fun<bond_offer_object, asset_id_type, &bond_offer_object::asset_type> >
|
||||
>
|
||||
> bond_offer_object_multi_index_type;
|
||||
|
||||
typedef generic_index<bond_offer_object, bond_offer_object_multi_index_type> bond_offer_index;
|
||||
|
||||
}} // graphene::chain
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::bond_object, (graphene::db::object),
|
||||
(borrower)(lender)(borrowed)(collateral)(interest_apr)(start_date)(due_date)(earliest_payoff_date) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::bond_offer_object, (graphene::db::object), (offered_by_account)(offer_to_borrow)(amount)(min_match)(collateral_rate)(min_loan_period_sec)(loan_period_sec)(interest_apr) )
|
||||
114
libraries/chain/include/graphene/chain/config.hpp
Normal file
114
libraries/chain/include/graphene/chain/config.hpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define GRAPHENE_SYMBOL "CORE"
|
||||
#define GRAPHENE_ADDRESS_PREFIX "GPH"
|
||||
#define GRAPHENE_MAX_SYMBOL_NAME_LENGTH 16
|
||||
#define GRAPHENE_MAX_ASSET_NAME_LENGTH 127
|
||||
#define GRAPHENE_MAX_SHARE_SUPPLY int64_t(1000000000000ll)
|
||||
#define GRAPHENE_MAX_PAY_RATE 10000 /* 100% */
|
||||
#define GRAPHENE_MAX_SIG_CHECK_DEPTH 2
|
||||
#define GRAPHENE_MIN_WITNESS_COUNT 10
|
||||
#define GRAPHENE_MIN_DELEGATE_COUNT 10
|
||||
/**
|
||||
* Don't allow the delegates to publish a limit that would
|
||||
* make the network unable to operate.
|
||||
*/
|
||||
#define GRAPHENE_MIN_TRANSACTION_SIZE_LIMIT 1024
|
||||
#define GRAPHENE_MAX_BLOCK_INTERVAL 30 /* seconds */
|
||||
|
||||
#define GRAPHENE_DEFAULT_BLOCK_INTERVAL 5 /* seconds */
|
||||
#define GRAPHENE_DEFAULT_MAX_TRANSACTION_SIZE 2048
|
||||
#define GRAPHENE_DEFAULT_MAX_BLOCK_SIZE (GRAPHENE_DEFAULT_MAX_TRANSACTION_SIZE*GRAPHENE_DEFAULT_BLOCK_INTERVAL*200000)
|
||||
#define GRAPHENE_DEFAULT_MAX_TIME_UNTIL_EXPIRATION (60*60*24) // seconds, aka: 1 day
|
||||
#define GRAPHENE_DEFAULT_MAINTENANCE_INTERVAL (60*60*24) // seconds, aka: 1 day
|
||||
#define GRAPHENE_DEFAULT_MAX_UNDO_HISTORY 1024
|
||||
|
||||
#define GRAPHENE_MIN_BLOCK_SIZE_LIMIT (GRAPHENE_MIN_TRANSACTION_SIZE_LIMIT*5) // 5 transactions per block
|
||||
#define GRAPHENE_MIN_TRANSACTION_EXPIRATION_LIMIT (GRAPHENE_MAX_BLOCK_INTERVAL * 5) // 5 transactions per block
|
||||
#define GRAPHENE_BLOCKCHAIN_MAX_SHARES (1000*1000*int64_t(1000)*1000*int64_t(1000))
|
||||
#define GRAPHENE_BLOCKCHAIN_PRECISION 100000
|
||||
#define GRAPHENE_BLOCKCHAIN_PRECISION_DIGITS 5
|
||||
#define GRAPHENE_INITIAL_SUPPLY GRAPHENE_BLOCKCHAIN_MAX_SHARES
|
||||
#define GRAPHENE_DEFAULT_TRANSFER_FEE (1*GRAPHENE_BLOCKCHAIN_PRECISION)
|
||||
#define GRAPHENE_MAX_INSTANCE_ID (uint64_t(-1)>>16)
|
||||
#define GRAPHENE_100_PERCENT 10000
|
||||
/** NOTE: making this a power of 2 (say 2^15) would greatly accelerate fee calcs */
|
||||
#define GRAPHENE_MAX_MARKET_FEE_PERCENT GRAPHENE_100_PERCENT
|
||||
#define GRAPHENE_DEFAULT_FORCE_SETTLEMENT_DELAY (60*60*24) ///< 1 day
|
||||
#define GRAPHENE_DEFAULT_FORCE_SETTLEMENT_OFFSET 0 ///< 1%
|
||||
#define GRAPHENE_DEFAULT_FORCE_SETTLEMENT_MAX_VOLUME 2000 ///< 20%
|
||||
#define GRAPHENE_DEFAULT_PRICE_FEED_LIFETIME (60*60*24) ///< 1 day
|
||||
#define GRAPHENE_MAX_FEED_PRODUCERS 200
|
||||
#define GRAPHENE_DEFAULT_MAX_AUTHORITY_MEMBERSHIP 10
|
||||
#define GRAPHENE_DEFAULT_MAX_ASSET_WHITELIST_AUTHORITIES 10
|
||||
#define GRAPHENE_DEFAULT_MAX_ASSET_FEED_PUBLISHERS 10
|
||||
|
||||
#define GRAPHENE_MIN_COLLATERAL_RATIO 1001 // lower than this could result in divide by 0
|
||||
#define GRAPHENE_MAX_COLLATERAL_RATIO 32000 // higher than this is unnecessary and may exceed int16 storage
|
||||
#define GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO 2000
|
||||
#define GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO 1750
|
||||
#define GRAPHENE_DEFAULT_MARGIN_PERIOD_SEC (30*60*60*24)
|
||||
|
||||
#define GRAPHENE_DEFAULT_NUM_WITNESSES (101)
|
||||
#define GRAPHENE_DEFAULT_NUM_COMMITTEE (11)
|
||||
#define GRAPHENE_DEFAULT_MAX_WITNESSES (1001) // SHOULD BE ODD
|
||||
#define GRAPHENE_DEFAULT_MAX_COMMITTEE (1001) // SHOULD BE ODD
|
||||
#define GRAPHENE_DEFAULT_MAX_PROPOSAL_LIFETIME_SEC (60*60*24*7*4) // Four weeks
|
||||
#define GRAPHENE_DEFAULT_GENESIS_PROPOSAL_REVIEW_PERIOD_SEC (60*60*24*7*2) // Two weeks
|
||||
#define GRAPHENE_DEFAULT_WITNESS_PERCENT (10000/100) // 1%
|
||||
#define GRAPHENE_DEFAULT_MAX_BULK_DISCOUNT_PERCENT (10000/2) // 50%
|
||||
#define GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN ( GRAPHENE_BLOCKCHAIN_PRECISION*int64_t(1000) )
|
||||
#define GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX ( GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN*int64_t(100) )
|
||||
#define GRAPHENE_DEFAULT_CASHBACK_VESTING_PERIOD_SEC (60*60*24*365) ///< 1 year
|
||||
#define GRAPHENE_DEFAULT_BURN_PERCENT_OF_FEE (10000/5) // 20%
|
||||
#define GRAPHENE_DEFAULT_WITNESS_PAY_PERCENT_OF_ACCUMULATED ( 1728000) /// gives a half life of 1 year assuming 1 second blocks
|
||||
#define GRAPHENE_WITNESS_PAY_PERCENT_PRECISION (1000000000)
|
||||
#define GRAPHENE_GENESIS_TIMESTAMP (1431700000) /// Should be divisible by GRAPHENE_DEFAULT_BLOCK_INTERVAL
|
||||
|
||||
// counter initialization values used to derive near and far future seeds for shuffling witnesses
|
||||
// we use the fractional bits of sqrt(2) in hex
|
||||
#define GRAPHENE_NEAR_SCHEDULE_CTR_IV ( (uint64_t( 0x6a09 ) << 0x30) \
|
||||
| (uint64_t( 0xe667 ) << 0x20) \
|
||||
| (uint64_t( 0xf3bc ) << 0x10) \
|
||||
| (uint64_t( 0xc908 ) ) )
|
||||
|
||||
// and the fractional bits of sqrt(3) in hex
|
||||
#define GRAPHENE_FAR_SCHEDULE_CTR_IV ( (uint64_t( 0xbb67 ) << 0x30) \
|
||||
| (uint64_t( 0xae85 ) << 0x20) \
|
||||
| (uint64_t( 0x84ca ) << 0x10) \
|
||||
| (uint64_t( 0xa73b ) ) )
|
||||
|
||||
// counter used to determine bits of entropy
|
||||
// must be less than or equal to secret_hash_type::data_length()
|
||||
#define GRAPHENE_RNG_SEED_LENGTH (224 / 8)
|
||||
|
||||
/**
|
||||
* every second, the fraction of burned core asset which cycles is
|
||||
* GRAPHENE_CORE_ASSET_CYCLE_RATE / (1 << GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS)
|
||||
*/
|
||||
#define GRAPHENE_CORE_ASSET_CYCLE_RATE 17
|
||||
#define GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS 32
|
||||
|
||||
#define GRAPHENE_DEFAULT_WITNESS_PAY_PER_BLOCK (GRAPHENE_BLOCKCHAIN_PRECISION * int64_t( 10) )
|
||||
#define GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY (GRAPHENE_BLOCKCHAIN_PRECISION * int64_t(500) * 1000 )
|
||||
|
||||
#define GRAPHENE_MAX_INTEREST_APR uint16_t( 10000 )
|
||||
#define GRAPHENE_LEGACY_NAME_IMPORT_PERIOD 3000000 /** 3 million blocks */
|
||||
|
||||
33
libraries/chain/include/graphene/chain/custom_evaluator.hpp
Normal file
33
libraries/chain/include/graphene/chain/custom_evaluator.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/operations.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class custom_evaluator : public evaluator<custom_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef custom_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const custom_operation& o ){ return object_id_type(); }
|
||||
object_id_type do_apply( const custom_operation& o ){ return object_id_type(); }
|
||||
};
|
||||
} }
|
||||
397
libraries/chain/include/graphene/chain/database.hpp
Normal file
397
libraries/chain/include/graphene/chain/database.hpp
Normal file
|
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/block.hpp>
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/chain/global_property_object.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/fork_database.hpp>
|
||||
|
||||
#include <graphene/db/object_database.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
#include <graphene/db/level_map.hpp>
|
||||
#include <graphene/db/level_pod_map.hpp>
|
||||
#include <graphene/db/simple_index.hpp>
|
||||
#include <fc/signals.hpp>
|
||||
|
||||
#include <fc/log/logger.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using graphene::db::abstract_object;
|
||||
using graphene::db::object;
|
||||
|
||||
typedef vector<std::pair<fc::static_variant<address, public_key_type>, share_type >> genesis_allocation;
|
||||
|
||||
/**
|
||||
* @class database
|
||||
* @brief tracks the blockchain state in an extensible manner
|
||||
*/
|
||||
class database : public object_database
|
||||
{
|
||||
public:
|
||||
//////////////////// db_management.cpp ////////////////////
|
||||
|
||||
database();
|
||||
~database();
|
||||
|
||||
enum validation_steps
|
||||
{
|
||||
skip_nothing = 0x00,
|
||||
skip_delegate_signature = 0x01, ///< used while reindexing
|
||||
skip_transaction_signatures = 0x02, ///< used by non delegate nodes
|
||||
skip_undo_block = 0x04, ///< used while reindexing
|
||||
skip_undo_transaction = 0x08, ///< used while applying block
|
||||
skip_transaction_dupe_check = 0x10, ///< used while reindexing
|
||||
skip_fork_db = 0x20, ///< used while reindexing
|
||||
skip_block_size_check = 0x40, ///< used when applying locally generated transactions
|
||||
skip_tapos_check = 0x80, ///< used while reindexing -- note this skips expiration check as well
|
||||
skip_authority_check = 0x100, ///< used while reindexing -- disables any checking of authority on transactions
|
||||
skip_merkle_check = 0x200 ///< used while reindexing
|
||||
};
|
||||
|
||||
void open(const fc::path& data_dir, const genesis_allocation& initial_allocation = genesis_allocation());
|
||||
/**
|
||||
* @brief Rebuild object graph from block history and open detabase
|
||||
*
|
||||
* This method may be called after or instead of @ref database::open, and will rebuild the object graph by
|
||||
* replaying blockchain history. When this method exits successfully, the database will be open.
|
||||
*/
|
||||
void reindex(fc::path data_dir, const genesis_allocation& initial_allocation = genesis_allocation());
|
||||
|
||||
/**
|
||||
* @brief wipe Delete database from disk, and potentially the raw chain as well.
|
||||
* @param include_blocks If true, delete the raw chain as well as the database.
|
||||
*
|
||||
* Will close the database before wiping. Database will be closed when this function returns.
|
||||
*/
|
||||
void wipe(const fc::path& data_dir, bool include_blocks);
|
||||
void close(uint32_t blocks_to_rewind = 0);
|
||||
|
||||
//////////////////// db_block.cpp ////////////////////
|
||||
|
||||
/**
|
||||
* @return true if the block is in our fork DB or saved to disk as
|
||||
* part of the official chain, otherwise return false
|
||||
*/
|
||||
bool is_known_block( const block_id_type& id )const;
|
||||
bool is_known_transaction( const transaction_id_type& id )const;
|
||||
block_id_type get_block_id_for_num( uint32_t block_num )const;
|
||||
optional<signed_block> fetch_block_by_id( const block_id_type& id )const;
|
||||
optional<signed_block> fetch_block_by_number( uint32_t num )const;
|
||||
const signed_transaction& get_recent_transaction( const transaction_id_type& trx_id )const;
|
||||
|
||||
bool push_block( const signed_block& b, uint32_t skip = skip_nothing );
|
||||
processed_transaction push_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing );
|
||||
///@throws fc::exception if the proposed transaction fails to apply.
|
||||
processed_transaction push_proposal( const proposal_object& proposal );
|
||||
|
||||
signed_block generate_block(
|
||||
const fc::time_point_sec when,
|
||||
witness_id_type witness_id,
|
||||
const fc::ecc::private_key& block_signing_private_key,
|
||||
uint32_t skip = 0
|
||||
);
|
||||
|
||||
void pop_block();
|
||||
void clear_pending();
|
||||
|
||||
/**
|
||||
* This method is used to track appied operations during the evaluation of a block, these
|
||||
* operations should include any operation actually included in a transaction as well
|
||||
* as any implied/virtual operations that resulted, such as filling an order. The
|
||||
* applied operations is cleared after applying each block and calling the block
|
||||
* observers which may want to index these operations.
|
||||
*
|
||||
* @return the op_id which can be used to set the result after it has finished being applied.
|
||||
*/
|
||||
uint32_t push_applied_operation( const operation& op );
|
||||
void set_applied_operation_result( uint32_t op_id, const operation_result& r );
|
||||
const vector<operation_history_object>& get_applied_operations()const;
|
||||
|
||||
/**
|
||||
* This signal is emitted after all operations and virtual operation for a
|
||||
* block have been applied but before the get_applied_operations() are cleared.
|
||||
*
|
||||
* You may not yield from this callback because the blockchain is holding
|
||||
* the write lock and may be in an "inconstant state" until after it is
|
||||
* released.
|
||||
*/
|
||||
fc::signal<void(const signed_block&)> applied_block;
|
||||
|
||||
/**
|
||||
* After a block has been applied and committed. The callback
|
||||
* should not yield and should execute quickly.
|
||||
*/
|
||||
fc::signal<void(const vector<object_id_type>&)> changed_objects;
|
||||
|
||||
//////////////////// db_witness_schedule.cpp ////////////////////
|
||||
|
||||
/**
|
||||
* @brief Get the witness scheduled for block production in a slot.
|
||||
*
|
||||
* slot_num always corresponds to a time in the future.
|
||||
*
|
||||
* If slot_num == 1, returns the next scheduled witness.
|
||||
* If slot_num == 2, returns the next scheduled witness after
|
||||
* 1 block gap.
|
||||
*
|
||||
* Use the get_slot_time() and get_slot_at_time() functions
|
||||
* to convert between slot_num and timestamp.
|
||||
*
|
||||
* Passing slot_num == 0 returns (witness_id_type(), false)
|
||||
*
|
||||
* The bool value is true if near schedule, false if far schedule.
|
||||
*/
|
||||
pair<witness_id_type, bool> get_scheduled_witness(uint32_t slot_num)const;
|
||||
|
||||
/**
|
||||
* Get the time at which the given slot occurs.
|
||||
*
|
||||
* If slot_num == 0, return time_point_sec().
|
||||
*
|
||||
* If slot_num == N for N > 0, return the Nth next
|
||||
* block-interval-aligned time greater than head_block_time().
|
||||
*/
|
||||
fc::time_point_sec get_slot_time(uint32_t slot_num)const;
|
||||
|
||||
/**
|
||||
* Get the last slot which occurs AT or BEFORE the given time.
|
||||
*
|
||||
* The return value is the greatest value N such that
|
||||
* get_slot_time( N ) <= when.
|
||||
*
|
||||
* If no such N exists, return 0.
|
||||
*/
|
||||
uint32_t get_slot_at_time(fc::time_point_sec when)const;
|
||||
|
||||
/**
|
||||
* Get the near schedule.
|
||||
*/
|
||||
vector<witness_id_type> get_near_witness_schedule()const;
|
||||
|
||||
//////////////////// db_getter.cpp ////////////////////
|
||||
|
||||
const asset_object& get_core_asset()const;
|
||||
const global_property_object& get_global_properties()const;
|
||||
const dynamic_global_property_object& get_dynamic_global_properties()const;
|
||||
const fee_schedule_type& current_fee_schedule()const;
|
||||
|
||||
time_point_sec head_block_time()const;
|
||||
uint32_t head_block_num()const;
|
||||
block_id_type head_block_id()const;
|
||||
|
||||
decltype( chain_parameters::block_interval ) block_interval( )const;
|
||||
|
||||
//////////////////// db_init.cpp ////////////////////
|
||||
|
||||
void initialize_evaluators();
|
||||
/// Reset the object graph in-memory
|
||||
void initialize_indexes();
|
||||
void init_genesis(const genesis_allocation& initial_allocation = genesis_allocation());
|
||||
|
||||
template<typename EvaluatorType>
|
||||
void register_evaluator()
|
||||
{
|
||||
_operation_evaluators[
|
||||
operation::tag<typename EvaluatorType::operation_type>::value].reset( new op_evaluator_impl<EvaluatorType>() );
|
||||
}
|
||||
|
||||
template<typename EvaluatorType>
|
||||
void register_evaluation_observer( evaluation_observer& observer )
|
||||
{
|
||||
unique_ptr<op_evaluator>& op_eval = _operation_evaluators[operation::tag<typename EvaluatorType::operation_type>::value];
|
||||
op_eval->eval_observers.push_back( &observer );
|
||||
return;
|
||||
}
|
||||
|
||||
//////////////////// db_balance.cpp ////////////////////
|
||||
|
||||
/**
|
||||
* @brief Retrieve a particular account's balance in a given asset
|
||||
* @param owner Account whose balance should be retrieved
|
||||
* @param asset_id ID of the asset to get balance in
|
||||
* @return owner's balance in asset
|
||||
*/
|
||||
asset get_balance(account_id_type owner, asset_id_type asset_id)const;
|
||||
/// This is an overloaded method.
|
||||
asset get_balance(const account_object& owner, const asset_object& asset_obj)const;
|
||||
/// This is an overloaded method.
|
||||
asset get_balance(const account_object* owner, const asset_object* asset_obj)const;
|
||||
|
||||
/**
|
||||
* @brief Adjust a particular account's balance in a given asset by a delta
|
||||
* @param account ID of account whose balance should be adjusted
|
||||
* @param delta Asset ID and amount to adjust balance by
|
||||
*/
|
||||
void adjust_balance(account_id_type account, asset delta);
|
||||
/// This is an overloaded method.
|
||||
void adjust_balance(const account_object& account, asset delta);
|
||||
/// This is an overloaded method.
|
||||
void adjust_balance(const account_object* account, asset delta);
|
||||
|
||||
/**
|
||||
* If delta.asset_id is a core asset, adjusts account statistics
|
||||
*/
|
||||
void adjust_core_in_orders( const account_object& acnt, asset delta );
|
||||
|
||||
// helper to handle cashback rewards
|
||||
void deposit_cashback( const account_object& acct, share_type amount );
|
||||
|
||||
//////////////////// db_debug.cpp ////////////////////
|
||||
|
||||
void debug_dump();
|
||||
|
||||
//////////////////// db_market.cpp ////////////////////
|
||||
|
||||
/// @{ @group Market Helpers
|
||||
void globally_settle_asset( const asset_object& bitasset, const price& settle_price );
|
||||
void cancel_order(const force_settlement_object& order, bool create_virtual_op = true);
|
||||
void cancel_order(const limit_order_object& order, bool create_virtual_op = true);
|
||||
|
||||
/**
|
||||
* Matches the two orders,
|
||||
*
|
||||
* @return a bit field indicating which orders were filled (and thus removed)
|
||||
*
|
||||
* 0 - no orders were matched
|
||||
* 1 - bid was filled
|
||||
* 2 - ask was filled
|
||||
* 3 - both were filled
|
||||
*/
|
||||
///@{
|
||||
template<typename OrderType>
|
||||
int match( const limit_order_object& bid, const OrderType& ask, const price& match_price );
|
||||
int match( const limit_order_object& bid, const limit_order_object& ask, const price& trade_price );
|
||||
int match( const limit_order_object& bid, const short_order_object& ask, const price& trade_price );
|
||||
/// @return the amount of asset settled
|
||||
asset match(const call_order_object& call,
|
||||
const force_settlement_object& settle,
|
||||
const price& match_price,
|
||||
asset max_settlement);
|
||||
///@}
|
||||
|
||||
/**
|
||||
* @return true if the order was completely filled and thus freed.
|
||||
*/
|
||||
bool fill_order( const limit_order_object& order, const asset& pays, const asset& receives );
|
||||
bool fill_order( const short_order_object& order, const asset& pays, const asset& receives );
|
||||
bool fill_order( const call_order_object& order, const asset& pays, const asset& receives );
|
||||
bool fill_order( const force_settlement_object& settle, const asset& pays, const asset& receives );
|
||||
|
||||
bool check_call_orders( const asset_object& mia );
|
||||
|
||||
// helpers to fill_order
|
||||
void pay_order( const account_object& receiver, const asset& receives, const asset& pays );
|
||||
|
||||
bool convert_fees( const asset_object& mia );
|
||||
asset calculate_market_fee(const asset_object& recv_asset, const asset& trade_amount);
|
||||
asset pay_market_fees( const asset_object& recv_asset, const asset& receives );
|
||||
|
||||
///@}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
protected:
|
||||
//Mark pop_undo() as protected -- we do not want outside calling pop_undo(); it should call pop_block() instead
|
||||
void pop_undo() { object_database::pop_undo(); }
|
||||
|
||||
private:
|
||||
optional<undo_database::session> _pending_block_session;
|
||||
vector< unique_ptr<op_evaluator> > _operation_evaluators;
|
||||
|
||||
template<class ObjectType>
|
||||
vector<std::reference_wrapper<const ObjectType>> sort_votable_objects(size_t count)const;
|
||||
|
||||
//////////////////// db_block.cpp ////////////////////
|
||||
|
||||
void apply_block( const signed_block& next_block, uint32_t skip = skip_nothing );
|
||||
processed_transaction apply_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing );
|
||||
operation_result apply_operation( transaction_evaluation_state& eval_state, const operation& op );
|
||||
|
||||
///Steps involved in applying a new block
|
||||
///@{
|
||||
|
||||
const witness_object& validate_block_header( uint32_t skip, const signed_block& next_block )const;
|
||||
void create_block_summary(const signed_block& next_block);
|
||||
|
||||
//////////////////// db_update.cpp ////////////////////
|
||||
void update_global_dynamic_data( const signed_block& b );
|
||||
void update_signing_witness(const witness_object& signing_witness, const signed_block& new_block);
|
||||
void update_pending_block(const signed_block& next_block, uint8_t current_block_interval);
|
||||
void clear_expired_transactions();
|
||||
void clear_expired_proposals();
|
||||
void clear_expired_orders();
|
||||
void update_expired_feeds();
|
||||
void update_withdraw_permissions();
|
||||
|
||||
//////////////////// db_witness_schedule.cpp ////////////////////
|
||||
void update_witness_schedule(signed_block next_block); /// no-op except for scheduling blocks
|
||||
|
||||
///Steps performed only at maintenance intervals
|
||||
///@{
|
||||
|
||||
//////////////////// db_maint.cpp ////////////////////
|
||||
|
||||
share_type get_max_budget( fc::time_point_sec now )const;
|
||||
void process_budget();
|
||||
void pay_workers( share_type& budget );
|
||||
void perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props);
|
||||
void update_active_witnesses();
|
||||
void update_active_delegates();
|
||||
void update_vote_totals(const global_property_object& props);
|
||||
///@}
|
||||
///@}
|
||||
|
||||
signed_block _pending_block;
|
||||
fork_database _fork_db;
|
||||
|
||||
/**
|
||||
* Note: we can probably store blocks by block num rather than
|
||||
* block id because after the undo window is past the block ID
|
||||
* is no longer relevant and its number is irreversible.
|
||||
*
|
||||
* During the "fork window" we can cache blocks in memory
|
||||
* until the fork is resolved. This should make maintaining
|
||||
* the fork tree relatively simple.
|
||||
*/
|
||||
graphene::db::level_map<block_id_type, signed_block> _block_id_to_block;
|
||||
|
||||
/**
|
||||
* Contains the set of ops that are in the process of being applied from
|
||||
* the current block. It contains real and virtual operations in the
|
||||
* order they occur and is cleared after the applied_block signal is
|
||||
* emited.
|
||||
*/
|
||||
vector<operation_history_object> _applied_ops;
|
||||
|
||||
uint32_t _current_block_num = 0;
|
||||
uint16_t _current_trx_in_block = 0;
|
||||
uint16_t _current_op_in_trx = 0;
|
||||
uint16_t _current_virtual_op = 0;
|
||||
|
||||
vector<uint64_t> _vote_tally_buffer;
|
||||
vector<uint64_t> _witness_count_histogram_buffer;
|
||||
vector<uint64_t> _committee_count_histogram_buffer;
|
||||
uint64_t _total_voting_stake;
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/delegate_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class delegate_create_evaluator : public evaluator<delegate_create_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef delegate_create_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const delegate_create_operation& o );
|
||||
object_id_type do_apply( const delegate_create_operation& o );
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
52
libraries/chain/include/graphene/chain/delegate_object.hpp
Normal file
52
libraries/chain/include/graphene/chain/delegate_object.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
|
||||
class account_object;
|
||||
|
||||
/**
|
||||
* @brief tracks information about a delegate account.
|
||||
* @ingroup object
|
||||
*
|
||||
* A delegate is responsible for setting blockchain parameters and has
|
||||
* dynamic multi-sig control over the genesis account. The current set of
|
||||
* active delegates has control.
|
||||
*
|
||||
* Delegates were separated into a separate object to make iterating over
|
||||
* the set of delegate easy.
|
||||
*/
|
||||
class delegate_object : public abstract_object<delegate_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = delegate_object_type;
|
||||
|
||||
account_id_type delegate_account;
|
||||
vote_id_type vote_id;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::delegate_object, (graphene::db::object),
|
||||
(delegate_account)
|
||||
(vote_id) )
|
||||
215
libraries/chain/include/graphene/chain/evaluator.hpp
Normal file
215
libraries/chain/include/graphene/chain/evaluator.hpp
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/operations.hpp>
|
||||
#include <graphene/chain/authority.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class database;
|
||||
class generic_evaluator;
|
||||
class transaction_evaluation_state;
|
||||
|
||||
/**
|
||||
* Observes evaluation events, providing
|
||||
* pre- and post-evaluation hooks.
|
||||
*
|
||||
* Every call to pre_evaluate() is followed by
|
||||
* a call to either post_evaluate() or evaluation_failed().
|
||||
*
|
||||
* A subclass which needs to do a "diff" can gather some
|
||||
* "before" state into its members in pre_evaluate(),
|
||||
* then post_evaluate() will have both "before"
|
||||
* and "after" state, and will be able to do the diff.
|
||||
*
|
||||
* evaluation_failed() is a cleanup method which notifies
|
||||
* the subclass to "throw away" the diff.
|
||||
*/
|
||||
class evaluation_observer
|
||||
{
|
||||
public:
|
||||
virtual ~evaluation_observer(){}
|
||||
|
||||
virtual void pre_evaluate(
|
||||
const transaction_evaluation_state& eval_state,
|
||||
const operation& op,
|
||||
bool apply,
|
||||
generic_evaluator* ge ) {}
|
||||
|
||||
virtual void post_evaluate(
|
||||
const transaction_evaluation_state& eval_state,
|
||||
const operation& op,
|
||||
bool apply,
|
||||
generic_evaluator* ge,
|
||||
const operation_result& result ) {}
|
||||
|
||||
virtual void evaluation_failed(
|
||||
const transaction_evaluation_state& eval_state,
|
||||
const operation& op,
|
||||
bool apply,
|
||||
generic_evaluator* ge,
|
||||
const operation_result& result ) {}
|
||||
};
|
||||
|
||||
class generic_evaluator
|
||||
{
|
||||
public:
|
||||
virtual ~generic_evaluator(){}
|
||||
|
||||
virtual int get_type()const = 0;
|
||||
virtual operation_result start_evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply );
|
||||
|
||||
/** @note derived classes should ASSUME that the default validation that is
|
||||
* indepenent of chain state should be performed by op.validate() and should
|
||||
* not perform these extra checks.
|
||||
*/
|
||||
virtual operation_result evaluate( const operation& op ) = 0;
|
||||
virtual operation_result apply( const operation& op ) = 0;
|
||||
|
||||
database& db()const;
|
||||
|
||||
void check_required_authorities(const operation& op);
|
||||
protected:
|
||||
/**
|
||||
* @brief Fetch objects relevant to fee payer and set pointer members
|
||||
* @param account_id Account which is paying the fee
|
||||
* @param fee The fee being paid. May be in assets other than core.
|
||||
*
|
||||
* This method verifies that the fee is valid and sets the object pointer members and the fee fields. It should
|
||||
* be called during do_evaluate.
|
||||
*/
|
||||
void prepare_fee(account_id_type account_id, asset fee);
|
||||
/// Pays the fee and returns the number of CORE asset that were paid.
|
||||
void pay_fee();
|
||||
|
||||
bool verify_authority( const account_object&, authority::classification );
|
||||
//bool verify_signature( const key_object& );
|
||||
|
||||
object_id_type get_relative_id( object_id_type rel_id )const;
|
||||
|
||||
authority resolve_relative_ids( const authority& a )const;
|
||||
|
||||
asset fee_from_account;
|
||||
share_type core_fee_paid;
|
||||
const account_object* fee_paying_account = nullptr;
|
||||
const account_statistics_object* fee_paying_account_statistics = nullptr;
|
||||
const asset_object* fee_asset = nullptr;
|
||||
const asset_dynamic_data_object* fee_asset_dyn_data = nullptr;
|
||||
transaction_evaluation_state* trx_state;
|
||||
};
|
||||
|
||||
class op_evaluator
|
||||
{
|
||||
public:
|
||||
virtual ~op_evaluator(){}
|
||||
virtual operation_result evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply ) = 0;
|
||||
|
||||
vector< evaluation_observer* > eval_observers;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class op_evaluator_impl : public op_evaluator
|
||||
{
|
||||
public:
|
||||
virtual operation_result evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply = true ) override
|
||||
{
|
||||
// fc::exception from observers are suppressed.
|
||||
// fc::exception from evaluation is deferred (re-thrown
|
||||
// after all observers receive evaluation_failed)
|
||||
|
||||
T eval;
|
||||
optional< fc::exception > evaluation_exception;
|
||||
size_t observer_count = 0;
|
||||
operation_result result;
|
||||
|
||||
for( const auto& obs : eval_observers )
|
||||
{
|
||||
try
|
||||
{
|
||||
obs->pre_evaluate( eval_state, op, apply, &eval );
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
elog( "suppressed exception in observer pre method:\n${e}", ( "e", e.to_detail_string() ) );
|
||||
}
|
||||
observer_count++;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
result = eval.start_evaluate( eval_state, op, apply );
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
evaluation_exception = e;
|
||||
}
|
||||
|
||||
while( observer_count > 0 )
|
||||
{
|
||||
--observer_count;
|
||||
const auto& obs = eval_observers[ observer_count ];
|
||||
try
|
||||
{
|
||||
if( !evaluation_exception.valid() )
|
||||
obs->post_evaluate( eval_state, op, apply, &eval, result );
|
||||
else
|
||||
obs->evaluation_failed( eval_state, op, apply, &eval, result );
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
elog( "suppressed exception in observer post method:\n${e}", ( "e", e.to_detail_string() ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( evaluation_exception.valid() )
|
||||
throw *evaluation_exception;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename DerivedEvaluator>
|
||||
class evaluator : public generic_evaluator
|
||||
{
|
||||
public:
|
||||
virtual int get_type()const { return operation::tag<typename DerivedEvaluator::operation_type>::value; }
|
||||
|
||||
virtual operation_result evaluate( const operation& o ) final override
|
||||
{
|
||||
auto* eval = static_cast<DerivedEvaluator*>(this);
|
||||
const auto& op = o.get<typename DerivedEvaluator::operation_type>();
|
||||
|
||||
prepare_fee(op.fee_payer(), op.fee);
|
||||
FC_ASSERT( core_fee_paid >= op.calculate_fee(db().current_fee_schedule()) );
|
||||
|
||||
return eval->do_evaluate( op );
|
||||
}
|
||||
virtual operation_result apply( const operation& o ) final override
|
||||
{
|
||||
auto* eval = static_cast<DerivedEvaluator*>(this);
|
||||
const auto& op = o.get<typename DerivedEvaluator::operation_type>();
|
||||
|
||||
pay_fee();
|
||||
|
||||
auto result = eval->do_apply( op );
|
||||
|
||||
db().adjust_balance(op.fee_payer(), -fee_from_account);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
} }
|
||||
113
libraries/chain/include/graphene/chain/exceptions.hpp
Normal file
113
libraries/chain/include/graphene/chain/exceptions.hpp
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <fc/exception/exception.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
// registered in chain_database.cpp
|
||||
|
||||
FC_DECLARE_EXCEPTION( chain_exception, 30000, "Blockchain Exception" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_pts_address, graphene::chain::chain_exception, 30001, "invalid pts address" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( addition_overflow, graphene::chain::chain_exception, 30002, "addition overflow" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( subtraction_overflow, graphene::chain::chain_exception, 30003, "subtraction overflow" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( asset_type_mismatch, graphene::chain::chain_exception, 30004, "asset/price mismatch" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unsupported_chain_operation, graphene::chain::chain_exception, 30005, "unsupported chain operation" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unknown_transaction, graphene::chain::chain_exception, 30006, "unknown transaction" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( duplicate_transaction, graphene::chain::chain_exception, 30007, "duplicate transaction" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( zero_amount, graphene::chain::chain_exception, 30008, "zero amount" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( zero_price, graphene::chain::chain_exception, 30009, "zero price" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( asset_divide_by_self, graphene::chain::chain_exception, 30010, "asset divide by self" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( asset_divide_by_zero, graphene::chain::chain_exception, 30011, "asset divide by zero" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( new_database_version, graphene::chain::chain_exception, 30012, "new database version" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unlinkable_block, graphene::chain::chain_exception, 30013, "unlinkable block" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( price_out_of_range, graphene::chain::chain_exception, 30014, "price out of range" );
|
||||
|
||||
FC_DECLARE_DERIVED_EXCEPTION( block_numbers_not_sequential, graphene::chain::chain_exception, 30015, "block numbers not sequential" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_previous_block_id, graphene::chain::chain_exception, 30016, "invalid previous block" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_block_time, graphene::chain::chain_exception, 30017, "invalid block time" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( time_in_past, graphene::chain::chain_exception, 30018, "time is in the past" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( time_in_future, graphene::chain::chain_exception, 30019, "time is in the future" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_block_digest, graphene::chain::chain_exception, 30020, "invalid block digest" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_delegate_signee, graphene::chain::chain_exception, 30021, "invalid delegate signee" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( failed_checkpoint_verification, graphene::chain::chain_exception, 30022, "failed checkpoint verification" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( wrong_chain_id, graphene::chain::chain_exception, 30023, "wrong chain id" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unknown_block, graphene::chain::chain_exception, 30024, "unknown block" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( block_older_than_undo_history, graphene::chain::chain_exception, 30025, "block is older than our undo history allows us to process" );
|
||||
|
||||
FC_DECLARE_EXCEPTION( evaluation_error, 31000, "Evaluation Error" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( negative_deposit, graphene::chain::evaluation_error, 31001, "negative deposit" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( not_a_delegate, graphene::chain::evaluation_error, 31002, "not a delegate" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unknown_balance_record, graphene::chain::evaluation_error, 31003, "unknown balance record" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( insufficient_funds, graphene::chain::evaluation_error, 31004, "insufficient funds" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( missing_signature, graphene::chain::evaluation_error, 31005, "missing signature" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_claim_password, graphene::chain::evaluation_error, 31006, "invalid claim password" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_withdraw_condition, graphene::chain::evaluation_error, 31007, "invalid withdraw condition" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( negative_withdraw, graphene::chain::evaluation_error, 31008, "negative withdraw" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( not_an_active_delegate, graphene::chain::evaluation_error, 31009, "not an active delegate" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( expired_transaction, graphene::chain::evaluation_error, 31010, "expired transaction" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_transaction_expiration, graphene::chain::evaluation_error, 31011, "invalid transaction expiration" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( oversized_transaction, graphene::chain::evaluation_error, 31012, "transaction exceeded the maximum transaction size" );
|
||||
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_account_name, graphene::chain::evaluation_error, 32001, "invalid account name" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unknown_account_id, graphene::chain::evaluation_error, 32002, "unknown account id" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unknown_account_name, graphene::chain::evaluation_error, 32003, "unknown account name" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( missing_parent_account_signature, graphene::chain::evaluation_error, 32004, "missing parent account signature" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( parent_account_retracted, graphene::chain::evaluation_error, 32005, "parent account retracted" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( account_expired, graphene::chain::evaluation_error, 32006, "account expired" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( account_already_registered, graphene::chain::evaluation_error, 32007, "account already registered" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( account_key_in_use, graphene::chain::evaluation_error, 32008, "account key already in use" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( account_retracted, graphene::chain::evaluation_error, 32009, "account retracted" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unknown_parent_account_name, graphene::chain::evaluation_error, 32010, "unknown parent account name" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unknown_delegate_slate, graphene::chain::evaluation_error, 32011, "unknown delegate slate" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( too_may_delegates_in_slate, graphene::chain::evaluation_error, 32012, "too many delegates in slate" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( pay_balance_remaining, graphene::chain::evaluation_error, 32013, "pay balance remaining" );
|
||||
|
||||
FC_DECLARE_DERIVED_EXCEPTION( not_a_delegate_signature, graphene::chain::evaluation_error, 33002, "not delegates signature" );
|
||||
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_precision, graphene::chain::evaluation_error, 35001, "invalid precision" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_asset_symbol, graphene::chain::evaluation_error, 35002, "invalid asset symbol" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unknown_asset_id, graphene::chain::evaluation_error, 35003, "unknown asset id" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( asset_symbol_in_use, graphene::chain::evaluation_error, 35004, "asset symbol in use" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_asset_amount, graphene::chain::evaluation_error, 35005, "invalid asset amount" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( negative_issue, graphene::chain::evaluation_error, 35006, "negative issue" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( over_issue, graphene::chain::evaluation_error, 35007, "over issue" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unknown_asset_symbol, graphene::chain::evaluation_error, 35008, "unknown asset symbol" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( asset_id_in_use, graphene::chain::evaluation_error, 35009, "asset id in use" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( not_user_issued, graphene::chain::evaluation_error, 35010, "not user issued" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_asset_name, graphene::chain::evaluation_error, 35011, "invalid asset name" );
|
||||
|
||||
FC_DECLARE_DERIVED_EXCEPTION( delegate_vote_limit, graphene::chain::evaluation_error, 36001, "delegate_vote_limit" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( insufficient_fee, graphene::chain::evaluation_error, 36002, "insufficient fee" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( negative_fee, graphene::chain::evaluation_error, 36003, "negative fee" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( missing_deposit, graphene::chain::evaluation_error, 36004, "missing deposit" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( insufficient_relay_fee, graphene::chain::evaluation_error, 36005, "insufficient relay fee" );
|
||||
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_market, graphene::chain::evaluation_error, 37001, "invalid market" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unknown_market_order, graphene::chain::evaluation_error, 37002, "unknown market order" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( shorting_base_shares, graphene::chain::evaluation_error, 37003, "shorting base shares" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( insufficient_collateral, graphene::chain::evaluation_error, 37004, "insufficient collateral" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( insufficient_depth, graphene::chain::evaluation_error, 37005, "insufficient depth" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( insufficient_feeds, graphene::chain::evaluation_error, 37006, "insufficient feeds" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_feed_price, graphene::chain::evaluation_error, 37007, "invalid feed price" );
|
||||
|
||||
FC_DECLARE_DERIVED_EXCEPTION( price_multiplication_overflow, graphene::chain::evaluation_error, 38001, "price multiplication overflow" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( price_multiplication_underflow, graphene::chain::evaluation_error, 38002, "price multiplication underflow" );
|
||||
FC_DECLARE_DERIVED_EXCEPTION( price_multiplication_undefined, graphene::chain::evaluation_error, 38003, "price multiplication undefined product 0*inf" );
|
||||
|
||||
} } // graphene::chain
|
||||
117
libraries/chain/include/graphene/chain/file_object.hpp
Normal file
117
libraries/chain/include/graphene/chain/file_object.hpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
|
||||
/**
|
||||
* @brief provides for persistant storage of arbitrary data
|
||||
*
|
||||
* Smart contracts need data to be stored persistantly that can be shared with
|
||||
* other smart contracts. There is a cost associated with storing data, especially if
|
||||
* that data will be kept in RAM.
|
||||
*
|
||||
* File objects allow smart contracts to interact with persistant storage much like
|
||||
* traditional programs interact with files on disk. The cost of accessing a file
|
||||
* object to modify it is much higher than the cost to simply read it because the
|
||||
* the database must make a backup of the file for the undo history in the event
|
||||
* of a blockchain reorganization or failure in evaluation. For this reason files
|
||||
* are limited to 2^16 bytes and smart contracts will have to use multiple files if
|
||||
* they need to store additional data.
|
||||
*
|
||||
* Every file has an automatic expiration date at which point in time it will be
|
||||
* deleted unless a fee is paid to extend its life time.
|
||||
*
|
||||
* The contents of all files are public, but not to scripts. A smart contract attempting
|
||||
* to access the contents of a file must have permission to read the file. The purpose
|
||||
* of this restriction is to help users monetize the trust associated with publishing
|
||||
* data. Anyone could re-publish the data under a new file, but the trust in the
|
||||
* quality of the data would not be the same as the original file.
|
||||
*/
|
||||
class file_object : public graphene::db::annotated_object<file_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = file_object_type;
|
||||
|
||||
/**
|
||||
* @brief sets bits that control the permissions granted to smart contracts regarding this data.
|
||||
*/
|
||||
enum permision_flags
|
||||
{
|
||||
owner_read = 0x01,
|
||||
owner_write = 0x02,
|
||||
group_read = 0x04,
|
||||
group_write = 0x08,
|
||||
all_read = 0x10,
|
||||
execute = 0x20 ///< set if data contains virtual machine instructions
|
||||
};
|
||||
|
||||
/**
|
||||
* The owner can access this file based upon the @ref permissions flags
|
||||
*
|
||||
* @note - if the owner removes write permission from himself then the file
|
||||
* will be imutable thereafter.
|
||||
*/
|
||||
account_id_type owner;
|
||||
/** any account that has been white listed by this group can read/write
|
||||
* @ref data based upon the @ref permissions flags.
|
||||
*/
|
||||
account_id_type group;
|
||||
/**
|
||||
* Bits set according to @ref permission_flags
|
||||
*/
|
||||
uint8_t permissions = owner_read | owner_write | all_read;
|
||||
|
||||
/**
|
||||
* Files consume memory and thus are cleaned up unless a fee is paid to
|
||||
* keep them alive.
|
||||
*/
|
||||
time_point_sec expiration;
|
||||
|
||||
/**
|
||||
* The maximum data size for a file is 2^16 bytes so that the
|
||||
* undo history doesn't have to backup larger files. If a smart contract
|
||||
* requires more data then it can create more file objects.
|
||||
*/
|
||||
vector<char> data;
|
||||
};
|
||||
|
||||
struct by_expiration;
|
||||
struct by_owner;
|
||||
struct by_group;
|
||||
/**
|
||||
* @ingroup object_index
|
||||
*/
|
||||
typedef multi_index_container<
|
||||
file_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
hashed_non_unique< tag<by_owner>, member< file_object, account_id_type, &file_object::owner > >,
|
||||
hashed_non_unique< tag<by_group>, member< file_object, account_id_type, &file_object::group > >,
|
||||
ordered_non_unique< tag<by_expiration>, member<file_object, time_point_sec, &file_object::expiration> >
|
||||
>
|
||||
> file_object_multi_index_type;
|
||||
|
||||
typedef generic_index<file_object, file_object_multi_index_type> file_object_index;
|
||||
|
||||
} }
|
||||
|
||||
FC_REFLECT_ENUM( graphene::chain::file_object::permision_flags, (owner_read)(owner_write)(group_read)(group_write)(all_read)(execute) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::file_object, (graphene::db::object), (owner)(group)(permissions)(expiration)(data) )
|
||||
98
libraries/chain/include/graphene/chain/fork_database.hpp
Normal file
98
libraries/chain/include/graphene/chain/fork_database.hpp
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/block.hpp>
|
||||
#include <graphene/chain/types.hpp>
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using boost::multi_index_container;
|
||||
using namespace boost::multi_index;
|
||||
|
||||
struct fork_item
|
||||
{
|
||||
fork_item( signed_block d )
|
||||
:num(d.block_num()),id(d.id()),data( std::move(d) ){}
|
||||
|
||||
weak_ptr< fork_item > prev;
|
||||
uint32_t num;
|
||||
/**
|
||||
* Used to flag a block as invalid and prevent other blocks from
|
||||
* building on top of it.
|
||||
*/
|
||||
bool invalid = false;
|
||||
block_id_type id;
|
||||
signed_block data;
|
||||
};
|
||||
typedef shared_ptr<fork_item> item_ptr;
|
||||
|
||||
/**
|
||||
* As long as blocks are pushed in order the fork
|
||||
* database will maintain a linked tree of all blocks
|
||||
* that branch from the start_block. The tree will
|
||||
* have a maximum depth of 1024 blocks after which
|
||||
* the database will start lopping off forks.
|
||||
*
|
||||
* Every time a block is pushed into the fork DB the
|
||||
* block with the highest block_num will be returned.
|
||||
*/
|
||||
class fork_database
|
||||
{
|
||||
public:
|
||||
typedef vector<item_ptr> branch_type;
|
||||
|
||||
fork_database();
|
||||
void reset();
|
||||
|
||||
void start_block( signed_block b );
|
||||
void remove( block_id_type b );
|
||||
void set_head( shared_ptr<fork_item> h );
|
||||
bool is_known_block( const block_id_type& id )const;
|
||||
shared_ptr<fork_item> fetch_block( const block_id_type& id )const;
|
||||
vector<item_ptr> fetch_block_by_number( uint32_t n )const;
|
||||
shared_ptr<fork_item> push_block( signed_block b );
|
||||
shared_ptr<fork_item> head()const { return _head; }
|
||||
void pop_block();
|
||||
|
||||
|
||||
/**
|
||||
* Given two head blocks, return two branches of the fork graph that
|
||||
* end with a common ancestor (same prior block)
|
||||
*/
|
||||
pair< branch_type, branch_type > fetch_branch_from( block_id_type first,
|
||||
block_id_type second )const;
|
||||
|
||||
struct block_id{};
|
||||
struct block_num{};
|
||||
typedef multi_index_container<
|
||||
item_ptr,
|
||||
indexed_by<
|
||||
hashed_unique< tag<block_id>, member< fork_item, block_id_type, &fork_item::id>, std::hash<fc::ripemd160> >,
|
||||
ordered_non_unique< tag<block_num>, member<fork_item,uint32_t,&fork_item::num> >
|
||||
>
|
||||
> fork_multi_index_type;
|
||||
|
||||
private:
|
||||
fork_multi_index_type _index;
|
||||
shared_ptr<fork_item> _head;
|
||||
};
|
||||
} } // graphene::chain
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class global_parameters_update_evaluator : public evaluator<global_parameters_update_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef global_parameters_update_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const global_parameters_update_operation& o );
|
||||
object_id_type do_apply( const global_parameters_update_operation& o );
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/authority.hpp>
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* @class global_property_object
|
||||
* @brief Maintains global state information (delegate list, current fees)
|
||||
* @ingroup object
|
||||
* @ingroup implementation
|
||||
*
|
||||
* This is an implementation detail. The values here are set by delegates to tune the blockchain parameters.
|
||||
*/
|
||||
class global_property_object : public graphene::db::abstract_object<global_property_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_global_property_object_type;
|
||||
|
||||
chain_parameters parameters;
|
||||
optional<chain_parameters> pending_parameters;
|
||||
|
||||
uint32_t next_available_vote_id = 0;
|
||||
vector<delegate_id_type> active_delegates; // updated once per maintenance interval
|
||||
flat_set<witness_id_type> active_witnesses; // updated once per maintenance interval
|
||||
// n.b. witness scheduling is done by witness_schedule object
|
||||
flat_set<account_id_type> witness_accounts; // updated once per maintenance interval
|
||||
|
||||
fc::sha256 chain_id;
|
||||
|
||||
vote_id_type get_next_vote_id(vote_id_type::vote_type type) {
|
||||
return vote_id_type(type, next_available_vote_id++);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class dynamic_global_property_object
|
||||
* @brief Maintains global state information (delegate list, current fees)
|
||||
* @ingroup object
|
||||
* @ingroup implementation
|
||||
*
|
||||
* This is an implementation detail. The values here are calculated during normal chain operations and reflect the
|
||||
* current values of global blockchain properties.
|
||||
*/
|
||||
class dynamic_global_property_object : public abstract_object<dynamic_global_property_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_dynamic_global_property_object_type;
|
||||
|
||||
secret_hash_type random;
|
||||
uint32_t head_block_number = 0;
|
||||
block_id_type head_block_id;
|
||||
time_point_sec time;
|
||||
witness_id_type current_witness;
|
||||
time_point_sec next_maintenance_time;
|
||||
time_point_sec last_budget_time;
|
||||
share_type witness_budget;
|
||||
};
|
||||
}}
|
||||
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene::db::object),
|
||||
(random)
|
||||
(head_block_number)
|
||||
(head_block_id)
|
||||
(time)
|
||||
(current_witness)
|
||||
(next_maintenance_time)
|
||||
(witness_budget)
|
||||
)
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::global_property_object, (graphene::db::object),
|
||||
(parameters)
|
||||
(pending_parameters)
|
||||
(next_available_vote_id)
|
||||
(active_delegates)
|
||||
(active_witnesses)
|
||||
(chain_id)
|
||||
)
|
||||
45
libraries/chain/include/graphene/chain/key_evaluator.hpp
Normal file
45
libraries/chain/include/graphene/chain/key_evaluator.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class key_create_evaluator : public evaluator<key_create_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef key_create_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const key_create_operation& op )
|
||||
{
|
||||
return object_id_type();
|
||||
}
|
||||
|
||||
object_id_type do_apply( const key_create_operation& op )
|
||||
{
|
||||
new_key_object = &db().create<key_object>( [&]( key_object& obj ){
|
||||
obj.key_data = op.key_data;
|
||||
});
|
||||
|
||||
return new_key_object->id;
|
||||
}
|
||||
|
||||
const key_object* new_key_object = nullptr;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
45
libraries/chain/include/graphene/chain/key_object.hpp
Normal file
45
libraries/chain/include/graphene/chain/key_object.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/db/object.hpp>
|
||||
#include <graphene/chain/address.hpp>
|
||||
#include <fc/static_variant.hpp>
|
||||
#include <graphene/chain/types.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
/**
|
||||
* @class key_object
|
||||
* @brief maps an ID to a public key or address
|
||||
* @ingroup object
|
||||
* @ingroup protocol
|
||||
*/
|
||||
class key_object : public graphene::db::abstract_object<key_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = key_object_type;
|
||||
|
||||
key_id_type get_id()const { return key_id_type( id.instance() ); }
|
||||
address key_address()const;
|
||||
const public_key_type& key()const { return key_data.get<public_key_type>(); }
|
||||
|
||||
static_variant<address,public_key_type> key_data;
|
||||
};
|
||||
} }
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::key_object, (graphene::db::object), (key_data) )
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/operations.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class limit_order_create_evaluator : public evaluator<limit_order_create_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef limit_order_create_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const limit_order_create_operation& o );
|
||||
object_id_type do_apply( const limit_order_create_operation& o );
|
||||
|
||||
asset calculate_market_fee( const asset_object* aobj, const asset& trade_amount );
|
||||
|
||||
const limit_order_create_operation* _op = nullptr;
|
||||
const account_object* _seller = nullptr;
|
||||
const asset_object* _sell_asset = nullptr;
|
||||
const asset_object* _receive_asset = nullptr;
|
||||
};
|
||||
|
||||
class limit_order_cancel_evaluator : public evaluator<limit_order_cancel_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef limit_order_cancel_operation operation_type;
|
||||
|
||||
asset do_evaluate( const limit_order_cancel_operation& o );
|
||||
asset do_apply( const limit_order_cancel_operation& o );
|
||||
|
||||
const limit_order_object* _order;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/db/object.hpp>
|
||||
#include <graphene/chain/authority.hpp>
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
#include <boost/multi_index/composite_key.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
|
||||
/**
|
||||
* @brief an offer to sell a amount of a asset at a specified exchange rate by a certain time
|
||||
* @ingroup object
|
||||
* @ingroup protocol
|
||||
* @ingroup market
|
||||
*
|
||||
* This limit_order_objects are indexed by @ref expiration and is automatically deleted on the first block after expiration.
|
||||
*/
|
||||
class limit_order_object : public abstract_object<limit_order_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = limit_order_object_type;
|
||||
|
||||
time_point_sec expiration;
|
||||
account_id_type seller;
|
||||
share_type for_sale; ///< asset id is sell_price.base.asset_id
|
||||
price sell_price;
|
||||
|
||||
asset amount_for_sale()const { return asset( for_sale, sell_price.base.asset_id ); }
|
||||
asset amount_to_receive()const { return amount_for_sale() * sell_price; }
|
||||
};
|
||||
|
||||
struct by_id;
|
||||
struct by_price;
|
||||
struct by_expiration;
|
||||
typedef multi_index_container<
|
||||
limit_order_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>,
|
||||
member< object, object_id_type, &object::id > >,
|
||||
ordered_non_unique< tag<by_expiration>, member< limit_order_object, time_point_sec, &limit_order_object::expiration> >,
|
||||
ordered_unique< tag<by_price>,
|
||||
composite_key< limit_order_object,
|
||||
member< limit_order_object, price, &limit_order_object::sell_price>,
|
||||
member< object, object_id_type, &object::id>
|
||||
>,
|
||||
composite_key_compare< std::greater<price>, std::less<object_id_type> >
|
||||
>
|
||||
>
|
||||
> limit_order_multi_index_type;
|
||||
|
||||
typedef generic_index<limit_order_object, limit_order_multi_index_type> limit_order_index;
|
||||
|
||||
} }
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::limit_order_object,
|
||||
(graphene::db::object),
|
||||
(expiration)(seller)(for_sale)(sell_price)
|
||||
)
|
||||
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/db/object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* @brief tracks the history of all logical operations on blockchain state
|
||||
* @ingroup object
|
||||
* @ingroup implementation
|
||||
*
|
||||
* All operations and virtual operations result in the creation of an
|
||||
* operation_history_object that is maintained on disk as a stack. Each
|
||||
* real or virtual operation is assigned a unique ID / sequence number that
|
||||
* it can be referenced by.
|
||||
*
|
||||
* @note by default these objects are not tracked, the account_history_plugin must
|
||||
* be loaded fore these objects to be maintained.
|
||||
*
|
||||
* @note this object is READ ONLY it can never be modified
|
||||
*/
|
||||
class operation_history_object : public abstract_object<operation_history_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = operation_history_object_type;
|
||||
|
||||
operation_history_object( const operation& o ):op(o){}
|
||||
operation_history_object(){}
|
||||
|
||||
operation op;
|
||||
operation_result result;
|
||||
/** the block that caused this operation */
|
||||
uint32_t block_num = 0;
|
||||
/** the transaction in the block */
|
||||
uint16_t trx_in_block = 0;
|
||||
/** the operation within the transaction */
|
||||
uint16_t op_in_trx = 0;
|
||||
/** any virtual operations implied by operation in block */
|
||||
uint16_t virtual_op = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief a node in a linked list of operation_history_objects
|
||||
* @ingroup implementation
|
||||
* @ingroup object
|
||||
*
|
||||
* Account history is important for users and wallets even though it is
|
||||
* not part of "core validation". Account history is maintained as
|
||||
* a linked list stored on disk in a stack. Each account will point to the
|
||||
* most recent account history object by ID. When a new operation relativent
|
||||
* to that account is processed a new account history object is allcoated at
|
||||
* the end of the stack and intialized to point to the prior object.
|
||||
*
|
||||
* This data is never accessed as part of chain validation and therefore
|
||||
* can be kept on disk as a memory mapped file. Using a memory mapped file
|
||||
* will help the operating system better manage / cache / page files and
|
||||
* also accelerates load time.
|
||||
*
|
||||
* When the transaction history for a particular account is requested the
|
||||
* linked list can be traversed with relatively effecient disk access because
|
||||
* of the use of a memory mapped stack.
|
||||
*/
|
||||
class account_transaction_history_object : public abstract_object<account_transaction_history_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_account_transaction_history_object_type;
|
||||
operation_history_id_type operation_id;
|
||||
account_transaction_history_id_type next;
|
||||
};
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::operation_history_object, (graphene::chain::object),
|
||||
(op)(result)(block_num)(trx_in_block)(op_in_trx)(virtual_op) )
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::account_transaction_history_object, (graphene::chain::object),
|
||||
(operation_id)(next) )
|
||||
1849
libraries/chain/include/graphene/chain/operations.hpp
Normal file
1849
libraries/chain/include/graphene/chain/operations.hpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/operations.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/transaction_evaluation_state.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class proposal_create_evaluator : public evaluator<proposal_create_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef proposal_create_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const proposal_create_operation& o );
|
||||
object_id_type do_apply( const proposal_create_operation& o );
|
||||
|
||||
transaction _proposed_trx;
|
||||
};
|
||||
|
||||
class proposal_update_evaluator : public evaluator<proposal_update_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef proposal_update_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const proposal_update_operation& o );
|
||||
object_id_type do_apply( const proposal_update_operation& o );
|
||||
|
||||
const proposal_object* _proposal = nullptr;
|
||||
processed_transaction _processed_transaction;
|
||||
bool _executed_proposal = false;
|
||||
bool _proposal_failed = false;
|
||||
};
|
||||
|
||||
class proposal_delete_evaluator : public evaluator<proposal_delete_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef proposal_delete_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const proposal_delete_operation& o );
|
||||
object_id_type do_apply(const proposal_delete_operation&);
|
||||
|
||||
const proposal_object* _proposal = nullptr;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
67
libraries/chain/include/graphene/chain/proposal_object.hpp
Normal file
67
libraries/chain/include/graphene/chain/proposal_object.hpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/chain/types.hpp>
|
||||
#include <graphene/chain/transaction.hpp>
|
||||
#include <graphene/chain/transaction_evaluation_state.hpp>
|
||||
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
|
||||
/**
|
||||
* @brief tracks the approval of a partially approved transaction
|
||||
* @ingroup object
|
||||
* @ingroup protocol
|
||||
*/
|
||||
class proposal_object : public abstract_object<proposal_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = proposal_object_type;
|
||||
|
||||
time_point_sec expiration_time;
|
||||
optional<time_point_sec> review_period_time;
|
||||
transaction proposed_transaction;
|
||||
flat_set<account_id_type> required_active_approvals;
|
||||
flat_set<account_id_type> available_active_approvals;
|
||||
flat_set<account_id_type> required_owner_approvals;
|
||||
flat_set<account_id_type> available_owner_approvals;
|
||||
flat_set<key_id_type> available_key_approvals;
|
||||
|
||||
bool is_authorized_to_execute(database* db)const;
|
||||
};
|
||||
|
||||
struct by_expiration{};
|
||||
typedef boost::multi_index_container<
|
||||
proposal_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag< by_id >, member< object, object_id_type, &object::id > >,
|
||||
ordered_non_unique< tag< by_expiration >, member< proposal_object, time_point_sec, &proposal_object::expiration_time > >
|
||||
>
|
||||
> proposal_multi_index_container;
|
||||
typedef generic_index<proposal_object, proposal_multi_index_container> proposal_index;
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::proposal_object, (graphene::chain::object),
|
||||
(expiration_time)(review_period_time)(proposed_transaction)(required_active_approvals)
|
||||
(available_active_approvals)(required_owner_approvals)(available_owner_approvals)
|
||||
(available_key_approvals) )
|
||||
72
libraries/chain/include/graphene/chain/pts_address.hpp
Normal file
72
libraries/chain/include/graphene/chain/pts_address.hpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <fc/array.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace fc { namespace ecc { class public_key; } }
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* Implements address stringification and validation from PTS
|
||||
*/
|
||||
struct pts_address
|
||||
{
|
||||
pts_address(); ///< constructs empty / null address
|
||||
pts_address( const std::string& base58str ); ///< converts to binary, validates checksum
|
||||
pts_address( const fc::ecc::public_key& pub, bool compressed = true, uint8_t version=56 ); ///< converts to binary
|
||||
|
||||
uint8_t version()const { return addr.at(0); }
|
||||
bool is_valid()const;
|
||||
|
||||
operator std::string()const; ///< converts to base58 + checksum
|
||||
|
||||
fc::array<char,25> addr; ///< binary representation of address
|
||||
};
|
||||
|
||||
inline bool operator == ( const pts_address& a, const pts_address& b ) { return a.addr == b.addr; }
|
||||
inline bool operator != ( const pts_address& a, const pts_address& b ) { return a.addr != b.addr; }
|
||||
inline bool operator < ( const pts_address& a, const pts_address& b ) { return a.addr < b.addr; }
|
||||
|
||||
} } // namespace graphene::chain
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct hash<graphene::chain::pts_address>
|
||||
{
|
||||
public:
|
||||
size_t operator()(const graphene::chain::pts_address &a) const
|
||||
{
|
||||
size_t s;
|
||||
memcpy( (char*)&s, &a.addr.data[sizeof(a)-sizeof(s)], sizeof(s) );
|
||||
return s;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
FC_REFLECT( graphene::chain::pts_address, (addr) )
|
||||
|
||||
namespace fc
|
||||
{
|
||||
void to_variant( const graphene::chain::pts_address& var, fc::variant& vo );
|
||||
void from_variant( const fc::variant& var, graphene::chain::pts_address& vo );
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/operations.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class short_order_create_evaluator : public evaluator<short_order_create_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef short_order_create_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const short_order_create_operation& o );
|
||||
object_id_type do_apply( const short_order_create_operation& o );
|
||||
|
||||
const short_order_create_operation* _op = nullptr;
|
||||
const account_object* _seller = nullptr;
|
||||
const asset_object* _sell_asset = nullptr;
|
||||
const asset_object* _receive_asset = nullptr;
|
||||
share_type _priority_fee = 0;
|
||||
};
|
||||
|
||||
class short_order_cancel_evaluator : public evaluator<short_order_cancel_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef short_order_cancel_operation operation_type;
|
||||
|
||||
asset do_evaluate( const short_order_cancel_operation& o );
|
||||
asset do_apply( const short_order_cancel_operation& o );
|
||||
|
||||
const short_order_object* _order;
|
||||
};
|
||||
|
||||
class call_order_update_evaluator : public evaluator<call_order_update_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef call_order_update_operation operation_type;
|
||||
|
||||
asset do_evaluate( const call_order_update_operation& o );
|
||||
asset do_apply( const call_order_update_operation& o );
|
||||
|
||||
bool _closing_order = false;
|
||||
const asset_object* _debt_asset = nullptr;
|
||||
const account_object* _paying_account = nullptr;
|
||||
const call_order_object* _order = nullptr;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
198
libraries/chain/include/graphene/chain/short_order_object.hpp
Normal file
198
libraries/chain/include/graphene/chain/short_order_object.hpp
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
#include <graphene/chain/types.hpp>
|
||||
#include <graphene/chain/authority.hpp>
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <boost/multi_index/composite_key.hpp>
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
|
||||
/**
|
||||
* @class short_order_object
|
||||
* @brief maintains state about requests to short an asset
|
||||
*
|
||||
* Short orders are only valid if their sell price is above the
|
||||
* fair market value of the asset at the feed price. Users can
|
||||
* place shorts at any price but their order will be ignored
|
||||
* beyond the feed.
|
||||
*
|
||||
* All shorts have a minimial initial collateral ratio requirement that is
|
||||
* defined by the network, but individuals may choose to have a higher
|
||||
* initial collateral to avoid the risk of being margin called.
|
||||
*
|
||||
* All shorts have a maintenance collateral ratio that must be kept or
|
||||
* the network will automatically cover the short order. Users can
|
||||
* specify a higher maintenance collateral ratio as a form of "stop loss"
|
||||
* and to potentially get ahead of a short squeeze.
|
||||
*/
|
||||
class short_order_object : public abstract_object<short_order_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = short_order_object_type;
|
||||
|
||||
time_point_sec expiration;
|
||||
account_id_type seller;
|
||||
share_type for_sale;
|
||||
share_type available_collateral; ///< asset_id == sell_price.quote.asset_id
|
||||
price sell_price; ///< the price the short is currently at = min(limit_price,feed)
|
||||
price call_price; ///< the price that will be used to trigger margin calls after match, must be 1:1 if prediction market
|
||||
uint16_t initial_collateral_ratio = 0; ///< may be higher than the network requires
|
||||
uint16_t maintenance_collateral_ratio = 0; ///< may optionally be higher than the network requires
|
||||
|
||||
asset get_collateral()const { return asset( available_collateral, sell_price.quote.asset_id ); }
|
||||
/** if the initial_collateral_ratio is 0, then this is a prediction market order which means the
|
||||
* amount for sale depends upon price and available collateral.
|
||||
*/
|
||||
asset amount_for_sale()const { return asset( for_sale, sell_price.base.asset_id ); }
|
||||
asset amount_to_receive()const { return amount_for_sale() * sell_price; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @class call_order_object
|
||||
* @brief tracks debt and call price information
|
||||
*
|
||||
* There should only be one call_order_object per asset pair per account and
|
||||
* they will all have the same call price.
|
||||
*/
|
||||
class call_order_object : public abstract_object<call_order_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = call_order_object_type;
|
||||
|
||||
asset get_collateral()const { return asset( collateral, call_price.base.asset_id ); }
|
||||
asset get_debt()const { return asset( debt, debt_type() ); }
|
||||
asset amount_to_receive()const { return get_debt(); }
|
||||
asset_id_type debt_type()const { return call_price.quote.asset_id; }
|
||||
price collateralization()const { return get_collateral() / get_debt(); }
|
||||
|
||||
void update_call_price() { call_price = price::call_price(get_debt(), get_collateral(), maintenance_collateral_ratio); }
|
||||
|
||||
account_id_type borrower;
|
||||
share_type collateral; ///< call_price.base.asset_id, access via get_collateral
|
||||
share_type debt; ///< call_price.quote.asset_id, access via get_collateral
|
||||
price call_price;
|
||||
uint16_t maintenance_collateral_ratio;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief tracks bitassets scheduled for force settlement at some point in the future.
|
||||
*
|
||||
* On the @ref settlement_date the @ref balance will be converted to the collateral asset
|
||||
* and paid to @ref owner and then this object will be deleted.
|
||||
*/
|
||||
class force_settlement_object : public graphene::db::annotated_object<force_settlement_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = force_settlement_object_type;
|
||||
|
||||
account_id_type owner;
|
||||
asset balance;
|
||||
time_point_sec settlement_date;
|
||||
|
||||
asset_id_type settlement_asset_id()const
|
||||
{ return balance.asset_id; }
|
||||
};
|
||||
|
||||
struct by_id;
|
||||
struct by_price;
|
||||
struct by_account;
|
||||
struct by_expiration;
|
||||
struct by_collateral;
|
||||
typedef multi_index_container<
|
||||
short_order_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>,
|
||||
member< object, object_id_type, &object::id > >,
|
||||
ordered_non_unique< tag<by_expiration>, member< short_order_object, time_point_sec, &short_order_object::expiration> >,
|
||||
ordered_unique< tag<by_price>,
|
||||
composite_key< short_order_object,
|
||||
member< short_order_object, price, &short_order_object::sell_price>,
|
||||
member< object, object_id_type, &object::id>
|
||||
>,
|
||||
composite_key_compare< std::greater<price>, std::less<object_id_type> >
|
||||
>
|
||||
>
|
||||
> short_order_multi_index_type;
|
||||
|
||||
typedef multi_index_container<
|
||||
call_order_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>,
|
||||
member< object, object_id_type, &object::id > >,
|
||||
ordered_unique< tag<by_price>,
|
||||
composite_key< call_order_object,
|
||||
member< call_order_object, price, &call_order_object::call_price>,
|
||||
member< object, object_id_type, &object::id>
|
||||
>,
|
||||
composite_key_compare< std::less<price>, std::less<object_id_type> >
|
||||
>,
|
||||
ordered_unique< tag<by_account>,
|
||||
composite_key< call_order_object,
|
||||
member< call_order_object, account_id_type, &call_order_object::borrower >,
|
||||
const_mem_fun< call_order_object, asset_id_type, &call_order_object::debt_type>
|
||||
>
|
||||
>,
|
||||
ordered_unique< tag<by_collateral>,
|
||||
composite_key< call_order_object,
|
||||
const_mem_fun< call_order_object, price, &call_order_object::collateralization >,
|
||||
member< object, object_id_type, &object::id >
|
||||
>
|
||||
>
|
||||
>
|
||||
> call_order_multi_index_type;
|
||||
|
||||
struct by_account;
|
||||
struct by_expiration;
|
||||
typedef multi_index_container<
|
||||
force_settlement_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
ordered_non_unique< tag<by_account>,
|
||||
member<force_settlement_object, account_id_type, &force_settlement_object::owner>
|
||||
>,
|
||||
ordered_non_unique< tag<by_expiration>,
|
||||
composite_key< force_settlement_object,
|
||||
const_mem_fun<force_settlement_object, asset_id_type, &force_settlement_object::settlement_asset_id>,
|
||||
member<force_settlement_object, time_point_sec, &force_settlement_object::settlement_date>
|
||||
>
|
||||
>
|
||||
>
|
||||
> force_settlement_object_multi_index_type;
|
||||
|
||||
|
||||
typedef generic_index<short_order_object, short_order_multi_index_type> short_order_index;
|
||||
typedef generic_index<call_order_object, call_order_multi_index_type> call_order_index;
|
||||
typedef generic_index<force_settlement_object, force_settlement_object_multi_index_type> force_settlement_index;
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::short_order_object, (graphene::db::object),
|
||||
(expiration)(seller)(for_sale)(available_collateral)(sell_price)
|
||||
(call_price)(initial_collateral_ratio)(maintenance_collateral_ratio)
|
||||
)
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::call_order_object, (graphene::db::object),
|
||||
(borrower)(collateral)(debt)(call_price)(maintenance_collateral_ratio) )
|
||||
|
||||
FC_REFLECT( graphene::chain::force_settlement_object, (owner)(balance)(settlement_date) )
|
||||
180
libraries/chain/include/graphene/chain/transaction.hpp
Normal file
180
libraries/chain/include/graphene/chain/transaction.hpp
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/types.hpp>
|
||||
#include <graphene/chain/operations.hpp>
|
||||
|
||||
// this is for htonl() and ntohl() functions
|
||||
// TODO: write and use FC wrappers for these functions
|
||||
#ifndef WIN32
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* @defgroup transactions Transactions
|
||||
*
|
||||
* All transactions are sets of operations that must be applied atomically. Transactions must refer to a recent
|
||||
* block that defines the context of the operation so that they assert a known binding to the object id's referenced
|
||||
* in the transaction.
|
||||
*
|
||||
* Rather than specify a full block number, we only specify the lower 16 bits of the block number which means you
|
||||
* can reference any block within the last 65,536 blocks which is 3.5 days with a 5 second block interval or 18
|
||||
* hours with a 1 second interval.
|
||||
*
|
||||
* All transactions must expire so that the network does not have to maintain a permanent record of all transactions
|
||||
* ever published. There are two accepted ways to specify the transaction's expiration time. The first is to choose
|
||||
* a reference block, which is generally the most recent block the wallet is aware of when it signs the transaction,
|
||||
* and specify a number of block intervals after the reference block until the transaction expires. The second
|
||||
* expiration mechanism is to explicitly specify a timestamp of expiration.
|
||||
*
|
||||
* Note: The number of block intervals is different than the number of blocks. In effect the maximum period that a
|
||||
* transaction is theoretically valid is 18 hours (1 sec interval) to 3.5 days (5 sec interval) if the reference
|
||||
* block was the most recent block.
|
||||
*
|
||||
* If a transaction is to expire after a number of block intervals from a reference block, the reference block
|
||||
* should be identified in the transaction header using the @ref ref_block_num, @ref ref_block_prefix, and @ref
|
||||
* relative_expiration fields. If the transaction is instead to expire at an absolute timestamp, @ref
|
||||
* ref_block_prefix should be treated as a 32-bit timestamp of the expiration time, and @ref ref_block_num and @ref
|
||||
* relative_expiration must both be set to zero.
|
||||
*
|
||||
* The block prefix is the first 4 bytes of the block hash of the reference block number, which is the second 4
|
||||
* bytes of the @ref block_id_type (the first 4 bytes of the block ID are the block number)
|
||||
*
|
||||
* Note: A transaction which selects a reference block cannot be migrated between forks outside the period of
|
||||
* ref_block_num.time to (ref_block_num.time + rel_exp * interval). This fact can be used to protect market orders
|
||||
* which should specify a relatively short re-org window of perhaps less than 1 minute. Normal payments should
|
||||
* probably have a longer re-org window to ensure their transaction can still go through in the event of a momentary
|
||||
* disruption in service.
|
||||
*
|
||||
* @note It is not recommended to set the @ref ref_block_num, @ref ref_block_prefix, and @ref relative_expiration
|
||||
* fields manually. Call the appropriate overload of @ref set_expiration instead.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief groups operations that should be applied atomically
|
||||
*/
|
||||
struct transaction
|
||||
{
|
||||
/**
|
||||
* Least significant 16 bits from the reference block number. If @ref relative_expiration is zero, this field
|
||||
* must be zero as well.
|
||||
*/
|
||||
uint16_t ref_block_num = 0;
|
||||
/**
|
||||
* The first non-block-number 32-bits of the reference block ID. Recall that block IDs have 32 bits of block
|
||||
* number followed by the actual block hash, so this field should be set using the second 32 bits in the
|
||||
* @ref block_id_type
|
||||
*/
|
||||
uint32_t ref_block_prefix = 0;
|
||||
/**
|
||||
* This field specifies the number of block intervals after the reference block until this transaction becomes
|
||||
* invalid. If this field is set to zero, the @ref ref_block_prefix is interpreted as an absolute timestamp of
|
||||
* the time the transaction becomes invalid.
|
||||
*/
|
||||
uint16_t relative_expiration = 1;
|
||||
vector<operation> operations;
|
||||
|
||||
/// Calculate the digest for a transaction with a reference block
|
||||
/// @param ref_block_id Full block ID of the reference block
|
||||
digest_type digest(const block_id_type& ref_block_id)const;
|
||||
/// Calculate the digest for a transaction with an absolute expiration time
|
||||
digest_type digest()const;
|
||||
transaction_id_type id()const;
|
||||
void validate() const;
|
||||
|
||||
void set_expiration( fc::time_point_sec expiration_time )
|
||||
{
|
||||
ref_block_num = 0;
|
||||
relative_expiration = 0;
|
||||
ref_block_prefix = expiration_time.sec_since_epoch();
|
||||
block_id_cache.reset();
|
||||
}
|
||||
void set_expiration( const block_id_type& reference_block, unsigned_int lifetime_intervals = 3 )
|
||||
{
|
||||
ref_block_num = ntohl(reference_block._hash[0]);
|
||||
ref_block_prefix = reference_block._hash[1];
|
||||
relative_expiration = lifetime_intervals;
|
||||
block_id_cache = reference_block;
|
||||
}
|
||||
|
||||
/// visit all operations
|
||||
template<typename Visitor>
|
||||
void visit( Visitor&& visitor )
|
||||
{
|
||||
for( auto& op : operations )
|
||||
op.visit( std::forward<Visitor>( visitor ) );
|
||||
}
|
||||
|
||||
protected:
|
||||
// Intentionally unreflected: does not go on wire
|
||||
optional<block_id_type> block_id_cache;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief adds a signature to a transaction
|
||||
*/
|
||||
struct signed_transaction : public transaction
|
||||
{
|
||||
signed_transaction( const transaction& trx = transaction() )
|
||||
: transaction(trx){}
|
||||
|
||||
void sign( key_id_type id, const private_key_type& key );
|
||||
flat_map<key_id_type,signature_type> signatures;
|
||||
|
||||
/// Removes all operations and signatures
|
||||
void clear() { operations.clear(); signatures.clear(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief captures the result of evaluating the operations contained in the transaction
|
||||
*
|
||||
* When processing a transaction some operations generate
|
||||
* new object IDs and these IDs cannot be known until the
|
||||
* transaction is actually included into a block. When a
|
||||
* block is produced these new ids are captured and included
|
||||
* with every transaction. The index in operation_results should
|
||||
* correspond to the same index in operations.
|
||||
*
|
||||
* If an operation did not create any new object IDs then 0
|
||||
* should be returned.
|
||||
*/
|
||||
struct processed_transaction : public signed_transaction
|
||||
{
|
||||
processed_transaction( const signed_transaction& trx = signed_transaction() )
|
||||
: signed_transaction(trx){}
|
||||
|
||||
vector<operation_result> operation_results;
|
||||
|
||||
digest_type merkle_digest()const;
|
||||
};
|
||||
|
||||
/// @} transactions group
|
||||
|
||||
|
||||
} }
|
||||
|
||||
FC_REFLECT( graphene::chain::transaction, (ref_block_num)(ref_block_prefix)(relative_expiration)(operations) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::signed_transaction, (graphene::chain::transaction), (signatures) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::processed_transaction, (graphene::chain::signed_transaction), (operation_results) )
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/operations.hpp>
|
||||
#include <graphene/chain/authority.hpp>
|
||||
#include <graphene/chain/asset.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
class database;
|
||||
struct signed_transaction;
|
||||
|
||||
/**
|
||||
* Place holder for state tracked while processing a
|
||||
* transaction. This class provides helper methods
|
||||
* that are common to many different operations and
|
||||
* also tracks which keys have signed the transaction
|
||||
*/
|
||||
class transaction_evaluation_state
|
||||
{
|
||||
public:
|
||||
transaction_evaluation_state( database* db = nullptr, bool skip_authority_check = false )
|
||||
:_db(db),_skip_authority_check(skip_authority_check){}
|
||||
|
||||
bool check_authority( const account_object&, authority::classification auth_class = authority::active, int depth = 0 );
|
||||
|
||||
database& db()const { FC_ASSERT( _db ); return *_db; }
|
||||
|
||||
bool signed_by( key_id_type id )const;
|
||||
|
||||
/** derived from signatures on transaction
|
||||
flat_set<address> signed_by;
|
||||
*/
|
||||
/** cached approval (accounts and keys) */
|
||||
flat_set< pair<object_id_type,authority::classification> > approved_by;
|
||||
|
||||
/**
|
||||
* Used to lookup new objects using transaction relative IDs
|
||||
*/
|
||||
vector<operation_result> operation_results;
|
||||
|
||||
const signed_transaction* _trx = nullptr;
|
||||
database* _db = nullptr;
|
||||
bool _skip_authority_check = false;
|
||||
bool _is_proposed_trx = false;
|
||||
};
|
||||
} } // namespace graphene::chain
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <fc/io/raw.hpp>
|
||||
|
||||
#include <graphene/chain/transaction.hpp>
|
||||
#include <graphene/db/index.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/mem_fun.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
using boost::multi_index_container;
|
||||
using namespace boost::multi_index;
|
||||
/**
|
||||
* The purpose of this object is to enable the detection
|
||||
* of duplicate transactions. When a transaction is
|
||||
* included in a block a transaction_object is
|
||||
* added. At the end of block processing all
|
||||
* transaction_objects that have expired can
|
||||
* be removed from the index.
|
||||
*/
|
||||
class transaction_object : public abstract_object<transaction_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_transaction_object_type;
|
||||
|
||||
signed_transaction trx;
|
||||
time_point_sec expiration;
|
||||
transaction_id_type trx_id;
|
||||
};
|
||||
|
||||
|
||||
struct by_expiration;
|
||||
struct by_id;
|
||||
struct by_trx_id;
|
||||
typedef multi_index_container<
|
||||
transaction_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
hashed_unique< tag<by_trx_id>, BOOST_MULTI_INDEX_MEMBER(transaction_object, transaction_id_type, trx_id), std::hash<transaction_id_type> >,
|
||||
ordered_non_unique< tag<by_expiration>, BOOST_MULTI_INDEX_MEMBER(transaction_object, time_point_sec, expiration)>
|
||||
>
|
||||
> transaction_multi_index_type;
|
||||
|
||||
typedef generic_index<transaction_object, transaction_multi_index_type> transaction_index;
|
||||
|
||||
} }
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::transaction_object, (graphene::db::object), (trx)(expiration) )
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/operations.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class transfer_evaluator : public evaluator<transfer_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef transfer_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const transfer_operation& o );
|
||||
object_id_type do_apply( const transfer_operation& o );
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
702
libraries/chain/include/graphene/chain/types.hpp
Normal file
702
libraries/chain/include/graphene/chain/types.hpp
Normal file
|
|
@ -0,0 +1,702 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <fc/container/flat_fwd.hpp>
|
||||
#include <fc/io/varint.hpp>
|
||||
#include <fc/io/raw_fwd.hpp>
|
||||
#include <fc/io/enum_type.hpp>
|
||||
#include <fc/crypto/sha224.hpp>
|
||||
#include <fc/crypto/elliptic.hpp>
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
#include <fc/reflect/variant.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
#include <fc/safe.hpp>
|
||||
#include <fc/container/flat.hpp>
|
||||
#include <fc/string.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <graphene/chain/address.hpp>
|
||||
#include <graphene/db/object_id.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
|
||||
using std::map;
|
||||
using std::vector;
|
||||
using std::unordered_map;
|
||||
using std::string;
|
||||
using std::deque;
|
||||
using std::shared_ptr;
|
||||
using std::weak_ptr;
|
||||
using std::unique_ptr;
|
||||
using std::set;
|
||||
using std::pair;
|
||||
using std::enable_shared_from_this;
|
||||
using std::tie;
|
||||
using std::make_pair;
|
||||
|
||||
using fc::variant_object;
|
||||
using fc::variant;
|
||||
using fc::enum_type;
|
||||
using fc::optional;
|
||||
using fc::unsigned_int;
|
||||
using fc::signed_int;
|
||||
using fc::time_point_sec;
|
||||
using fc::time_point;
|
||||
using fc::safe;
|
||||
using fc::flat_map;
|
||||
using fc::flat_set;
|
||||
using fc::static_variant;
|
||||
|
||||
typedef fc::ecc::private_key private_key_type;
|
||||
|
||||
enum asset_issuer_permission_flags
|
||||
{
|
||||
charge_market_fee = 0x01, /**< an issuer-specified percentage of all market trades in this asset is paid to the issuer */
|
||||
white_list = 0x02, /**< accounts must be whitelisted in order to hold this asset */
|
||||
override_authority = 0x04, /**< @todo issuer may transfer asset back to himself */
|
||||
transfer_restricted = 0x08, /**< require the issuer to be one party to every transfer */
|
||||
disable_force_settle = 0x10, /**< disable force settling */
|
||||
global_settle = 0x20 /**< allow the bitasset issuer to force a global settling -- this may be set in permissions, but not flags */
|
||||
};
|
||||
const static uint32_t ASSET_ISSUER_PERMISSION_MASK = charge_market_fee|white_list|override_authority|transfer_restricted|disable_force_settle|global_settle;
|
||||
const static uint32_t UIA_ASSET_ISSUER_PERMISSION_MASK = charge_market_fee|white_list|override_authority|transfer_restricted;
|
||||
|
||||
enum reserved_spaces
|
||||
{
|
||||
relative_protocol_ids = 0,
|
||||
protocol_ids = 1,
|
||||
implementation_ids = 2
|
||||
};
|
||||
|
||||
inline bool is_relative( object_id_type o ){ return o.space() == 0; }
|
||||
/**
|
||||
* There are many types of fees charged by the network
|
||||
* for different operations. These fees are published by
|
||||
* the delegates and can change over time.
|
||||
*/
|
||||
enum fee_type
|
||||
{
|
||||
key_create_fee_type, ///< the cost to register a public key with the blockchain
|
||||
account_create_fee_type, ///< the cost to register the cheapest non-free account
|
||||
account_len8_fee_type,
|
||||
account_len7_fee_type,
|
||||
account_len6_fee_type,
|
||||
account_len5_fee_type,
|
||||
account_len4_fee_type,
|
||||
account_len3_fee_type,
|
||||
account_premium_fee_type, ///< accounts on the reserved list of top 100K domains
|
||||
account_whitelist_fee_type, ///< the fee to whitelist an account
|
||||
delegate_create_fee_type, ///< fixed fee for registering as a delegate, used to discourage frivioulous delegates
|
||||
witness_withdraw_pay_fee_type, ///< fee for withdrawing witness pay
|
||||
transfer_fee_type, ///< fee for transferring some asset
|
||||
limit_order_fee_type, ///< fee for placing a limit order in the markets
|
||||
short_order_fee_type, ///< fee for placing a short order in the markets
|
||||
publish_feed_fee_type, ///< fee for publishing a price feed
|
||||
asset_create_fee_type, ///< the cost to register the cheapest asset
|
||||
asset_update_fee_type, ///< the cost to modify a registered asset
|
||||
asset_issue_fee_type, ///< the cost to modify a registered asset
|
||||
asset_fund_fee_pool_fee_type, ///< the cost to add funds to an asset's fee pool
|
||||
asset_settle_fee_type, ///< the cost to trigger a forced settlement of a market-issued asset
|
||||
market_fee_type, ///< a percentage charged on market orders
|
||||
transaction_fee_type, ///< a base price for every transaction
|
||||
data_fee_type, ///< a price per 1024 bytes of user data
|
||||
signature_fee_type, ///< a surcharge on transactions with more than 2 signatures.
|
||||
global_parameters_update_fee_type, ///< the cost to update the global parameters
|
||||
prime_upgrade_fee_type, ///< the cost to upgrade an account to prime
|
||||
withdraw_permission_update_fee_type, ///< the cost to create/update a withdraw permission
|
||||
create_bond_offer_fee_type,
|
||||
cancel_bond_offer_fee_type,
|
||||
accept_bond_offer_fee_type,
|
||||
claim_bond_collateral_fee_type,
|
||||
file_storage_fee_per_day_type, ///< the cost of leasing a file with 2^16 bytes for 1 day
|
||||
vesting_balance_create_fee_type,
|
||||
vesting_balance_withdraw_fee_type,
|
||||
global_settle_fee_type,
|
||||
worker_create_fee_type, ///< the cost to create a new worker
|
||||
worker_delete_fee_type, ///< the cost to delete a worker
|
||||
FEE_TYPE_COUNT ///< Sentry value which contains the number of different fee types
|
||||
};
|
||||
|
||||
/**
|
||||
* List all object types from all namespaces here so they can
|
||||
* be easily reflected and displayed in debug output. If a 3rd party
|
||||
* wants to extend the core code then they will have to change the
|
||||
* packed_object::type field from enum_type to uint16 to avoid
|
||||
* warnings when converting packed_objects to/from json.
|
||||
*/
|
||||
enum object_type
|
||||
{
|
||||
null_object_type,
|
||||
base_object_type,
|
||||
key_object_type,
|
||||
account_object_type,
|
||||
asset_object_type,
|
||||
force_settlement_object_type,
|
||||
delegate_object_type,
|
||||
witness_object_type,
|
||||
limit_order_object_type,
|
||||
short_order_object_type,
|
||||
call_order_object_type,
|
||||
custom_object_type,
|
||||
proposal_object_type,
|
||||
operation_history_object_type,
|
||||
withdraw_permission_object_type,
|
||||
bond_offer_object_type,
|
||||
bond_object_type,
|
||||
file_object_type,
|
||||
vesting_balance_object_type,
|
||||
worker_object_type,
|
||||
OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types
|
||||
};
|
||||
|
||||
enum impl_object_type
|
||||
{
|
||||
impl_global_property_object_type,
|
||||
impl_dynamic_global_property_object_type,
|
||||
impl_index_meta_object_type,
|
||||
impl_asset_dynamic_data_type,
|
||||
impl_asset_bitasset_data_type,
|
||||
impl_delegate_feeds_object_type,
|
||||
impl_account_balance_object_type,
|
||||
impl_account_statistics_object_type,
|
||||
impl_account_debt_object_type,
|
||||
impl_transaction_object_type,
|
||||
impl_block_summary_object_type,
|
||||
impl_account_transaction_history_object_type,
|
||||
impl_witness_schedule_object_type
|
||||
};
|
||||
|
||||
enum meta_info_object_type
|
||||
{
|
||||
meta_asset_object_type,
|
||||
meta_account_object_type
|
||||
};
|
||||
|
||||
|
||||
//typedef fc::unsigned_int object_id_type;
|
||||
//typedef uint64_t object_id_type;
|
||||
class account_object;
|
||||
class delegate_object;
|
||||
class witness_object;
|
||||
class asset_object;
|
||||
class force_settlement_object;
|
||||
class key_object;
|
||||
class limit_order_object;
|
||||
class short_order_object;
|
||||
class call_order_object;
|
||||
class custom_object;
|
||||
class proposal_object;
|
||||
class operation_history_object;
|
||||
class withdraw_permission_object;
|
||||
class bond_object;
|
||||
class bond_offer_object;
|
||||
class file_object;
|
||||
class vesting_balance_object;
|
||||
class witness_schedule_object;
|
||||
class worker_object;
|
||||
|
||||
typedef object_id< protocol_ids, key_object_type, key_object> key_id_type;
|
||||
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;
|
||||
typedef object_id< protocol_ids, force_settlement_object_type, force_settlement_object> force_settlement_id_type;
|
||||
typedef object_id< protocol_ids, delegate_object_type, delegate_object> delegate_id_type;
|
||||
typedef object_id< protocol_ids, witness_object_type, witness_object> witness_id_type;
|
||||
typedef object_id< protocol_ids, limit_order_object_type, limit_order_object> limit_order_id_type;
|
||||
typedef object_id< protocol_ids, short_order_object_type, short_order_object> short_order_id_type;
|
||||
typedef object_id< protocol_ids, call_order_object_type, call_order_object> call_order_id_type;
|
||||
typedef object_id< protocol_ids, custom_object_type, custom_object> custom_id_type;
|
||||
typedef object_id< protocol_ids, proposal_object_type, proposal_object> proposal_id_type;
|
||||
typedef object_id< protocol_ids, operation_history_object_type, operation_history_object> operation_history_id_type;
|
||||
typedef object_id< protocol_ids, withdraw_permission_object_type,withdraw_permission_object> withdraw_permission_id_type;
|
||||
typedef object_id< protocol_ids, bond_offer_object_type, bond_offer_object> bond_offer_id_type;
|
||||
typedef object_id< protocol_ids, bond_object_type, bond_object> bond_id_type;
|
||||
typedef object_id< protocol_ids, file_object_type, file_object> file_id_type;
|
||||
typedef object_id< protocol_ids, vesting_balance_object_type, vesting_balance_object> vesting_balance_id_type;
|
||||
typedef object_id< protocol_ids, worker_object_type, worker_object> worker_id_type;
|
||||
|
||||
typedef object_id< relative_protocol_ids, key_object_type, key_object> relative_key_id_type;
|
||||
typedef object_id< relative_protocol_ids, account_object_type, account_object> relative_account_id_type;
|
||||
|
||||
// implementation types
|
||||
class global_property_object;
|
||||
class dynamic_global_property_object;
|
||||
class index_meta_object;
|
||||
class asset_dynamic_data_object;
|
||||
class asset_bitasset_data_object;
|
||||
class account_balance_object;
|
||||
class account_statistics_object;
|
||||
class account_debt_object;
|
||||
class transaction_object;
|
||||
class block_summary_object;
|
||||
class account_transaction_history_object;
|
||||
|
||||
typedef object_id< implementation_ids, impl_global_property_object_type, global_property_object> global_property_id_type;
|
||||
typedef object_id< implementation_ids, impl_dynamic_global_property_object_type, dynamic_global_property_object> dynamic_global_property_id_type;
|
||||
typedef object_id< implementation_ids, impl_asset_dynamic_data_type, asset_dynamic_data_object> dynamic_asset_data_id_type;
|
||||
typedef object_id< implementation_ids, impl_asset_bitasset_data_type, asset_bitasset_data_object> asset_bitasset_data_id_type;
|
||||
typedef object_id< implementation_ids, impl_account_balance_object_type, account_balance_object> account_balance_id_type;
|
||||
typedef object_id< implementation_ids, impl_account_statistics_object_type,account_statistics_object> account_statistics_id_type;
|
||||
typedef object_id< implementation_ids, impl_account_debt_object_type, account_debt_object> account_debt_id_type;
|
||||
typedef object_id< implementation_ids, impl_transaction_object_type, transaction_object> transaction_obj_id_type;
|
||||
typedef object_id< implementation_ids, impl_block_summary_object_type, block_summary_object> block_summary_id_type;
|
||||
|
||||
typedef object_id< implementation_ids,
|
||||
impl_account_transaction_history_object_type,
|
||||
account_transaction_history_object> account_transaction_history_id_type;
|
||||
typedef object_id< implementation_ids, impl_witness_schedule_object_type, witness_schedule_object > witness_schedule_id_type;
|
||||
|
||||
typedef fc::array<char,GRAPHENE_MAX_SYMBOL_NAME_LENGTH> symbol_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 safe<int64_t> share_type;
|
||||
typedef fc::sha224 secret_hash_type;
|
||||
typedef uint16_t weight_type;
|
||||
|
||||
/**
|
||||
* @brief An ID for some votable object
|
||||
*
|
||||
* This class stores an ID for a votable object. The ID is comprised of two fields: a type, and an instance. The
|
||||
* type field stores which kind of object is being voted on, and the instance stores which specific object of that
|
||||
* type is being referenced by this ID.
|
||||
*
|
||||
* A value of vote_id_type is implicitly convertible to an unsigned 32-bit integer containing only the instance. It
|
||||
* may also be implicitly assigned from a uint32_t, which will update the instance. It may not, however, be
|
||||
* implicitly constructed from a uint32_t, as in this case, the type would be unknown.
|
||||
*
|
||||
* On the wire, a vote_id_type is represented as a 32-bit integer with the type in the lower 8 bits and the instance
|
||||
* in the upper 24 bits. This means that types may never exceed 8 bits, and instances may never exceed 24 bits.
|
||||
*
|
||||
* In JSON, a vote_id_type is represented as a string "type:instance", i.e. "1:5" would be type 1 and instance 5.
|
||||
*
|
||||
* @note In the Graphene protocol, vote_id_type instances are unique across types; that is to say, if an object of
|
||||
* type 1 has instance 4, an object of type 0 may not also have instance 4. In other words, the type is not a
|
||||
* namespace for instances; it is only an informational field.
|
||||
*/
|
||||
struct vote_id_type
|
||||
{
|
||||
/// Lower 8 bits are type; upper 24 bits are instance
|
||||
uint32_t content;
|
||||
|
||||
enum vote_type
|
||||
{
|
||||
committee,
|
||||
witness,
|
||||
worker,
|
||||
VOTE_TYPE_COUNT
|
||||
};
|
||||
|
||||
/// Default constructor. Sets type and instance to 0
|
||||
vote_id_type():content(0){}
|
||||
/// Construct this vote_id_type with provided type and instance
|
||||
vote_id_type(vote_type type, uint32_t instance = 0)
|
||||
: content(instance<<8 | type)
|
||||
{}
|
||||
/// Construct this vote_id_type from a serial string in the form "type:instance"
|
||||
explicit vote_id_type(const std::string& serial)
|
||||
{
|
||||
auto colon = serial.find(':');
|
||||
if( colon != string::npos )
|
||||
*this = vote_id_type(vote_type(std::stoul(serial.substr(0, colon))), std::stoul(serial.substr(colon+1)));
|
||||
}
|
||||
|
||||
/// Set the type of this vote_id_type
|
||||
void set_type(vote_type type)
|
||||
{
|
||||
content &= 0xffffff00;
|
||||
content |= type & 0xff;
|
||||
}
|
||||
/// Get the type of this vote_id_type
|
||||
vote_type type()const
|
||||
{
|
||||
return vote_type(content & 0xff);
|
||||
}
|
||||
|
||||
/// Set the instance of this vote_id_type
|
||||
void set_instance(uint32_t instance)
|
||||
{
|
||||
assert(instance < 0x01000000);
|
||||
content &= 0xff;
|
||||
content |= instance << 8;
|
||||
}
|
||||
/// Get the instance of this vote_id_type
|
||||
uint32_t instance()const
|
||||
{
|
||||
return content >> 8;
|
||||
}
|
||||
|
||||
vote_id_type& operator =(vote_id_type other)
|
||||
{
|
||||
content = other.content;
|
||||
return *this;
|
||||
}
|
||||
/// Set the instance of this vote_id_type
|
||||
vote_id_type& operator =(uint32_t instance)
|
||||
{
|
||||
set_instance(instance);
|
||||
return *this;
|
||||
}
|
||||
/// Get the instance of this vote_id_type
|
||||
operator uint32_t()const
|
||||
{
|
||||
return instance();
|
||||
}
|
||||
|
||||
/// Convert this vote_id_type to a serial string in the form "type:instance"
|
||||
explicit operator std::string()const
|
||||
{
|
||||
return std::to_string(type()) + ":" + std::to_string(instance());
|
||||
}
|
||||
};
|
||||
|
||||
struct fee_schedule_type
|
||||
{
|
||||
fee_schedule_type()
|
||||
{
|
||||
memset( (char*)this, 0, sizeof(*this) );
|
||||
}
|
||||
void set( uint32_t f, share_type v ){ FC_ASSERT( f < FEE_TYPE_COUNT && v.value <= uint32_t(-1) ); *(&key_create_fee + f) = v.value; }
|
||||
const share_type at( uint32_t f )const { FC_ASSERT( f < FEE_TYPE_COUNT ); return *(&key_create_fee + f); }
|
||||
size_t size()const{ return FEE_TYPE_COUNT; }
|
||||
|
||||
|
||||
uint32_t key_create_fee; ///< the cost to register a public key with the blockchain
|
||||
uint32_t account_create_fee; ///< the cost to register the cheapest non-free account
|
||||
uint32_t account_len8_fee;
|
||||
uint32_t account_len7_fee;
|
||||
uint32_t account_len6_fee;
|
||||
uint32_t account_len5_fee;
|
||||
uint32_t account_len4_fee;
|
||||
uint32_t account_len3_fee;
|
||||
uint32_t account_premium_fee; ///< accounts on the reserved list of top 100K domains
|
||||
uint32_t account_whitelist_fee; ///< the fee to whitelist an account
|
||||
uint32_t delegate_create_fee; ///< fixed fee for registering as a delegate; used to discourage frivioulous delegates
|
||||
uint32_t witness_withdraw_pay_fee; ///< fee for withdrawing witness pay
|
||||
uint32_t transfer_fee; ///< fee for transferring some asset
|
||||
uint32_t limit_order_fee; ///< fee for placing a limit order in the markets
|
||||
uint32_t short_order_fee; ///< fee for placing a short order in the markets
|
||||
uint32_t publish_feed_fee; ///< fee for publishing a price feed
|
||||
uint32_t asset_create_fee; ///< the cost to register the cheapest asset
|
||||
uint32_t asset_update_fee; ///< the cost to modify a registered asset
|
||||
uint32_t asset_issue_fee; ///< the cost to modify a registered asset
|
||||
uint32_t asset_fund_fee_pool_fee; ///< the cost to add funds to an asset's fee pool
|
||||
uint32_t asset_settle_fee; ///< the cost to trigger a forced settlement of a market-issued asset
|
||||
uint32_t market_fee; ///< a percentage charged on market orders
|
||||
uint32_t transaction_fee; ///< a base price for every transaction
|
||||
uint32_t data_fee; ///< a price per 1024 bytes of user data
|
||||
uint32_t signature_fee; ///< a surcharge on transactions with more than 2 signatures.
|
||||
uint32_t global_parameters_update_fee; ///< the cost to update the global parameters
|
||||
uint32_t prime_upgrade_fee; ///< the cost to upgrade an account to prime
|
||||
uint32_t withdraw_permission_update_fee; ///< the cost to create/update a withdraw permission
|
||||
uint32_t create_bond_offer_fee;
|
||||
uint32_t cancel_bond_offer_fee;
|
||||
uint32_t accept_bond_offer_fee;
|
||||
uint32_t claim_bond_collateral_fee;
|
||||
uint32_t file_storage_fee_per_day; ///< the cost of leasing a file with 2^16 bytes for 1 day
|
||||
uint32_t vesting_balance_create_fee;
|
||||
uint32_t vesting_balance_withdraw_fee;
|
||||
uint32_t global_settle_fee;
|
||||
uint32_t worker_create_fee; ///< the cost to create a new worker
|
||||
uint32_t worker_delete_fee; ///< the cost to delete a worker
|
||||
};
|
||||
|
||||
|
||||
struct public_key_type
|
||||
{
|
||||
struct binary_key
|
||||
{
|
||||
binary_key():check(0){}
|
||||
uint32_t check;
|
||||
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);
|
||||
};
|
||||
|
||||
struct chain_parameters
|
||||
{
|
||||
fee_schedule_type current_fees; ///< current schedule of fees, indexed by @ref fee_type
|
||||
uint32_t witness_pay_percent_of_accumulated = GRAPHENE_DEFAULT_WITNESS_PAY_PERCENT_OF_ACCUMULATED; ///< percentage of accumulated fees in core asset to pay to witnesses for block production
|
||||
uint8_t block_interval = GRAPHENE_DEFAULT_BLOCK_INTERVAL; ///< interval in seconds between blocks
|
||||
uint32_t maintenance_interval = GRAPHENE_DEFAULT_MAINTENANCE_INTERVAL; ///< interval in sections between blockchain maintenance events
|
||||
uint32_t maximum_transaction_size = GRAPHENE_DEFAULT_MAX_TRANSACTION_SIZE; ///< maximum allowable size in bytes for a transaction
|
||||
uint32_t maximum_block_size = GRAPHENE_DEFAULT_MAX_BLOCK_SIZE; ///< maximum allowable size in bytes for a block
|
||||
uint32_t maximum_undo_history = GRAPHENE_DEFAULT_MAX_UNDO_HISTORY; ///< maximum number of undo states to keep in RAM
|
||||
uint32_t maximum_time_until_expiration = GRAPHENE_DEFAULT_MAX_TIME_UNTIL_EXPIRATION; ///< maximum lifetime in seconds for transactions to be valid, before expiring
|
||||
uint32_t maximum_proposal_lifetime = GRAPHENE_DEFAULT_MAX_PROPOSAL_LIFETIME_SEC; ///< maximum lifetime in seconds for proposed transactions to be kept, before expiring
|
||||
uint32_t genesis_proposal_review_period = GRAPHENE_DEFAULT_GENESIS_PROPOSAL_REVIEW_PERIOD_SEC; ///< minimum time in seconds that a proposed transaction requiring genesis authority may not be signed, prior to expiration
|
||||
uint8_t maximum_asset_whitelist_authorities = GRAPHENE_DEFAULT_MAX_ASSET_WHITELIST_AUTHORITIES; ///< maximum number of accounts which an asset may list as authorities for its whitelist OR blacklist
|
||||
uint8_t maximum_asset_feed_publishers = GRAPHENE_DEFAULT_MAX_ASSET_FEED_PUBLISHERS; ///< the maximum number of feed publishers for a given asset
|
||||
uint16_t maximum_witness_count = GRAPHENE_DEFAULT_MAX_WITNESSES; ///< maximum number of active witnesses
|
||||
uint16_t maximum_committee_count = GRAPHENE_DEFAULT_MAX_COMMITTEE; ///< maximum number of active delegates
|
||||
uint16_t maximum_authority_membership = GRAPHENE_DEFAULT_MAX_AUTHORITY_MEMBERSHIP; ///< largest number of keys/accounts an authority can have
|
||||
uint16_t burn_percent_of_fee = GRAPHENE_DEFAULT_BURN_PERCENT_OF_FEE; ///< the percentage of every fee that is taken out of circulation
|
||||
uint16_t witness_percent_of_fee = GRAPHENE_DEFAULT_WITNESS_PERCENT; ///< percent of revenue paid to witnesses
|
||||
uint32_t cashback_vesting_period_seconds = GRAPHENE_DEFAULT_CASHBACK_VESTING_PERIOD_SEC; ///< time after cashback rewards are accrued before they become liquid
|
||||
uint16_t max_bulk_discount_percent_of_fee = GRAPHENE_DEFAULT_MAX_BULK_DISCOUNT_PERCENT; ///< the maximum percentage discount for bulk discounts
|
||||
share_type bulk_discount_threshold_min = GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN; ///< the minimum amount of fees paid to qualify for bulk discounts
|
||||
share_type bulk_discount_threshold_max = GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX; ///< the amount of fees paid to qualify for the max bulk discount percent
|
||||
bool count_non_prime_votes = true; ///< set to false to restrict voting privlegages to prime accounts
|
||||
bool allow_non_prime_whitelists = false; ///< true if non-prime accounts may set whitelists and blacklists; false otherwise
|
||||
share_type witness_pay_per_block = GRAPHENE_DEFAULT_WITNESS_PAY_PER_BLOCK; ///< CORE to be allocated to witnesses (per block)
|
||||
share_type worker_budget_per_day = GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY; ///< CORE to be allocated to workers (per day)
|
||||
|
||||
void validate()const
|
||||
{
|
||||
FC_ASSERT( witness_percent_of_fee <= GRAPHENE_100_PERCENT );
|
||||
FC_ASSERT( burn_percent_of_fee <= GRAPHENE_100_PERCENT );
|
||||
FC_ASSERT( max_bulk_discount_percent_of_fee <= GRAPHENE_100_PERCENT );
|
||||
FC_ASSERT( burn_percent_of_fee + witness_percent_of_fee <= GRAPHENE_100_PERCENT );
|
||||
FC_ASSERT( bulk_discount_threshold_min <= bulk_discount_threshold_max );
|
||||
FC_ASSERT( bulk_discount_threshold_min > 0 );
|
||||
|
||||
FC_ASSERT( witness_pay_percent_of_accumulated < GRAPHENE_WITNESS_PAY_PERCENT_PRECISION );
|
||||
FC_ASSERT( block_interval <= GRAPHENE_MAX_BLOCK_INTERVAL );
|
||||
FC_ASSERT( block_interval > 0 );
|
||||
FC_ASSERT( maintenance_interval > block_interval,
|
||||
"Maintenance interval must be longer than block interval" );
|
||||
FC_ASSERT( maintenance_interval % block_interval == 0,
|
||||
"Maintenance interval must be a multiple of block interval" );
|
||||
FC_ASSERT( maximum_transaction_size >= GRAPHENE_MIN_TRANSACTION_SIZE_LIMIT,
|
||||
"Transaction size limit is too low" );
|
||||
FC_ASSERT( maximum_block_size >= GRAPHENE_MIN_BLOCK_SIZE_LIMIT,
|
||||
"Block size limit is too low" );
|
||||
FC_ASSERT( maximum_time_until_expiration > block_interval,
|
||||
"Maximum transaction expiration time must be greater than a block interval" );
|
||||
FC_ASSERT( maximum_proposal_lifetime - genesis_proposal_review_period > block_interval,
|
||||
"Genesis proposal review period must be less than the maximum proposal lifetime" );
|
||||
for( uint32_t i = 0; i < FEE_TYPE_COUNT; ++i ) { FC_ASSERT( current_fees.at(i) >= 0 ); }
|
||||
}
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
namespace fc
|
||||
{
|
||||
void to_variant( const graphene::chain::public_key_type& var, fc::variant& vo );
|
||||
void from_variant( const fc::variant& var, graphene::chain::public_key_type& vo );
|
||||
void to_variant( const graphene::chain::vote_id_type& var, fc::variant& vo );
|
||||
void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo );
|
||||
}
|
||||
|
||||
FC_REFLECT_TYPENAME( graphene::chain::vote_id_type::vote_type )
|
||||
FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(VOTE_TYPE_COUNT) )
|
||||
FC_REFLECT( graphene::chain::vote_id_type, (content) )
|
||||
|
||||
FC_REFLECT( graphene::chain::public_key_type, (key_data) )
|
||||
FC_REFLECT( graphene::chain::public_key_type::binary_key, (data)(check) )
|
||||
|
||||
FC_REFLECT_ENUM( graphene::chain::object_type,
|
||||
(null_object_type)
|
||||
(base_object_type)
|
||||
(key_object_type)
|
||||
(account_object_type)
|
||||
(force_settlement_object_type)
|
||||
(asset_object_type)
|
||||
(delegate_object_type)
|
||||
(witness_object_type)
|
||||
(limit_order_object_type)
|
||||
(short_order_object_type)
|
||||
(call_order_object_type)
|
||||
(custom_object_type)
|
||||
(proposal_object_type)
|
||||
(operation_history_object_type)
|
||||
(withdraw_permission_object_type)
|
||||
(bond_offer_object_type)
|
||||
(bond_object_type)
|
||||
(file_object_type)
|
||||
(vesting_balance_object_type)
|
||||
(worker_object_type)
|
||||
(OBJECT_TYPE_COUNT)
|
||||
)
|
||||
FC_REFLECT_ENUM( graphene::chain::impl_object_type,
|
||||
(impl_global_property_object_type)
|
||||
(impl_dynamic_global_property_object_type)
|
||||
(impl_index_meta_object_type)
|
||||
(impl_asset_dynamic_data_type)
|
||||
(impl_asset_bitasset_data_type)
|
||||
(impl_delegate_feeds_object_type)
|
||||
(impl_account_balance_object_type)
|
||||
(impl_account_statistics_object_type)
|
||||
(impl_account_debt_object_type)
|
||||
(impl_transaction_object_type)
|
||||
(impl_block_summary_object_type)
|
||||
(impl_account_transaction_history_object_type)
|
||||
(impl_witness_schedule_object_type)
|
||||
)
|
||||
|
||||
FC_REFLECT_ENUM( graphene::chain::meta_info_object_type, (meta_account_object_type)(meta_asset_object_type) )
|
||||
|
||||
|
||||
FC_REFLECT( graphene::chain::fee_schedule_type,
|
||||
(key_create_fee)
|
||||
(account_create_fee)
|
||||
(account_len8_fee)
|
||||
(account_len7_fee)
|
||||
(account_len6_fee)
|
||||
(account_len5_fee)
|
||||
(account_len4_fee)
|
||||
(account_len3_fee)
|
||||
(account_premium_fee)
|
||||
(account_whitelist_fee)
|
||||
(delegate_create_fee)
|
||||
(witness_withdraw_pay_fee)
|
||||
(transfer_fee)
|
||||
(limit_order_fee)
|
||||
(short_order_fee)
|
||||
(publish_feed_fee)
|
||||
(asset_create_fee)
|
||||
(asset_update_fee)
|
||||
(asset_issue_fee)
|
||||
(asset_fund_fee_pool_fee)
|
||||
(asset_settle_fee)
|
||||
(market_fee)
|
||||
(transaction_fee)
|
||||
(data_fee)
|
||||
(signature_fee)
|
||||
(global_parameters_update_fee)
|
||||
(prime_upgrade_fee)
|
||||
(withdraw_permission_update_fee)
|
||||
(create_bond_offer_fee)
|
||||
(cancel_bond_offer_fee)
|
||||
(accept_bond_offer_fee)
|
||||
(claim_bond_collateral_fee)
|
||||
(file_storage_fee_per_day)
|
||||
(vesting_balance_create_fee)
|
||||
(vesting_balance_withdraw_fee)
|
||||
(global_settle_fee)
|
||||
(worker_create_fee)
|
||||
(worker_delete_fee)
|
||||
)
|
||||
|
||||
|
||||
FC_REFLECT_ENUM( graphene::chain::fee_type,
|
||||
(key_create_fee_type)
|
||||
(account_create_fee_type)
|
||||
(account_len8_fee_type)
|
||||
(account_len7_fee_type)
|
||||
(account_len6_fee_type)
|
||||
(account_len5_fee_type)
|
||||
(account_len4_fee_type)
|
||||
(account_len3_fee_type)
|
||||
(account_premium_fee_type)
|
||||
(account_whitelist_fee_type)
|
||||
(delegate_create_fee_type)
|
||||
(witness_withdraw_pay_fee_type)
|
||||
(transfer_fee_type)
|
||||
(limit_order_fee_type)
|
||||
(short_order_fee_type)
|
||||
(publish_feed_fee_type)
|
||||
(asset_create_fee_type)
|
||||
(asset_update_fee_type)
|
||||
(asset_issue_fee_type)
|
||||
(asset_fund_fee_pool_fee_type)
|
||||
(asset_settle_fee_type)
|
||||
(market_fee_type)
|
||||
(transaction_fee_type)
|
||||
(data_fee_type)
|
||||
(signature_fee_type)
|
||||
(global_parameters_update_fee_type)
|
||||
(prime_upgrade_fee_type)
|
||||
(withdraw_permission_update_fee_type)
|
||||
(create_bond_offer_fee_type)
|
||||
(cancel_bond_offer_fee_type)
|
||||
(accept_bond_offer_fee_type)
|
||||
(claim_bond_collateral_fee_type)
|
||||
(file_storage_fee_per_day_type)
|
||||
(vesting_balance_create_fee_type)
|
||||
(vesting_balance_withdraw_fee_type)
|
||||
(global_settle_fee_type)
|
||||
(worker_create_fee_type)
|
||||
(worker_delete_fee_type)
|
||||
(FEE_TYPE_COUNT)
|
||||
)
|
||||
|
||||
FC_REFLECT( graphene::chain::chain_parameters,
|
||||
(current_fees)
|
||||
(witness_pay_percent_of_accumulated)
|
||||
(block_interval)
|
||||
(maintenance_interval)
|
||||
(maximum_transaction_size)
|
||||
(maximum_block_size)
|
||||
(maximum_undo_history)
|
||||
(maximum_time_until_expiration)
|
||||
(maximum_proposal_lifetime)
|
||||
(maximum_asset_whitelist_authorities)
|
||||
(maximum_asset_feed_publishers)
|
||||
(maximum_authority_membership)
|
||||
(burn_percent_of_fee)
|
||||
(witness_percent_of_fee)
|
||||
(max_bulk_discount_percent_of_fee)
|
||||
(cashback_vesting_period_seconds)
|
||||
(bulk_discount_threshold_min)
|
||||
(bulk_discount_threshold_max)
|
||||
(count_non_prime_votes)
|
||||
(allow_non_prime_whitelists)
|
||||
(witness_pay_per_block)
|
||||
(worker_budget_per_day)
|
||||
)
|
||||
|
||||
FC_REFLECT_TYPENAME( graphene::chain::key_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::account_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::asset_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::force_settlement_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::delegate_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::witness_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::limit_order_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::short_order_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::call_order_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::custom_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::proposal_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::operation_history_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::withdraw_permission_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::bond_offer_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::bond_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::file_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::vesting_balance_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::worker_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::relative_key_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::relative_account_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::global_property_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::dynamic_global_property_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::dynamic_asset_data_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::asset_bitasset_data_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::account_balance_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::account_statistics_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::account_debt_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::transaction_obj_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::block_summary_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::account_transaction_history_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::witness_schedule_id_type )
|
||||
|
||||
FC_REFLECT_ENUM( graphene::chain::asset_issuer_permission_flags, (charge_market_fee)(white_list)(transfer_restricted)(override_authority)(disable_force_settle)(global_settle) )
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class vesting_balance_create_evaluator;
|
||||
class vesting_balance_withdraw_evaluator;
|
||||
|
||||
class vesting_balance_create_evaluator : public evaluator<vesting_balance_create_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef vesting_balance_create_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const vesting_balance_create_operation& op );
|
||||
object_id_type do_apply( const vesting_balance_create_operation& op );
|
||||
};
|
||||
|
||||
class vesting_balance_withdraw_evaluator : public evaluator<vesting_balance_withdraw_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef vesting_balance_withdraw_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const vesting_balance_withdraw_operation& op );
|
||||
object_id_type do_apply( const vesting_balance_withdraw_operation& op );
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <fc/static_variant.hpp>
|
||||
#include <fc/uint128.hpp>
|
||||
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
|
||||
class vesting_balance_object;
|
||||
|
||||
struct vesting_policy_context
|
||||
{
|
||||
vesting_policy_context(
|
||||
asset _balance,
|
||||
fc::time_point_sec _now,
|
||||
asset _amount )
|
||||
: balance( _balance ), now( _now ), amount( _amount ) {}
|
||||
|
||||
asset balance;
|
||||
fc::time_point_sec now;
|
||||
asset amount;
|
||||
};
|
||||
|
||||
/**
|
||||
* Linear vesting balance.
|
||||
*/
|
||||
struct linear_vesting_policy
|
||||
{
|
||||
uint32_t vesting_seconds; // must be greater than zero
|
||||
fc::time_point_sec begin_date;
|
||||
share_type begin_balance; // same asset as balance
|
||||
share_type total_withdrawn; // same asset as balance
|
||||
|
||||
asset get_allowed_withdraw( const vesting_policy_context& ctx )const;
|
||||
bool is_deposit_allowed( const vesting_policy_context& ctx )const;
|
||||
bool is_withdraw_allowed( const vesting_policy_context& ctx )const;
|
||||
void on_deposit( const vesting_policy_context& ctx );
|
||||
void on_withdraw( const vesting_policy_context& ctx );
|
||||
};
|
||||
|
||||
struct cdd_vesting_policy
|
||||
{
|
||||
uint32_t vesting_seconds;
|
||||
fc::uint128_t coin_seconds_earned;
|
||||
fc::time_point_sec coin_seconds_earned_last_update;
|
||||
|
||||
/**
|
||||
* Compute coin_seconds_earned. Used to
|
||||
* non-destructively figure out how many coin seconds
|
||||
* are available.
|
||||
*/
|
||||
fc::uint128_t compute_coin_seconds_earned( const vesting_policy_context& ctx )const;
|
||||
|
||||
/**
|
||||
* Update coin_seconds_earned and
|
||||
* coin_seconds_earned_last_update fields; called by both
|
||||
* on_deposit() and on_withdraw().
|
||||
*/
|
||||
void update_coin_seconds_earned( const vesting_policy_context& ctx );
|
||||
|
||||
asset get_allowed_withdraw( const vesting_policy_context& ctx )const;
|
||||
bool is_deposit_allowed( const vesting_policy_context& ctx )const;
|
||||
bool is_withdraw_allowed( const vesting_policy_context& ctx )const;
|
||||
void on_deposit( const vesting_policy_context& ctx );
|
||||
void on_withdraw( const vesting_policy_context& ctx );
|
||||
};
|
||||
|
||||
typedef fc::static_variant<
|
||||
linear_vesting_policy,
|
||||
cdd_vesting_policy
|
||||
> vesting_policy;
|
||||
|
||||
/**
|
||||
* Timelocked balance object is a balance that is locked by the
|
||||
* blockchain for a period of time.
|
||||
*/
|
||||
class vesting_balance_object : public abstract_object<vesting_balance_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = vesting_balance_object_type;
|
||||
|
||||
account_id_type owner;
|
||||
asset balance;
|
||||
vesting_policy policy;
|
||||
|
||||
vesting_balance_object() {}
|
||||
|
||||
/**
|
||||
* Used to increase existing vesting balances.
|
||||
*/
|
||||
void deposit( const fc::time_point_sec& now, const asset& amount );
|
||||
bool is_deposit_allowed( const fc::time_point_sec& now, const asset& amount )const;
|
||||
|
||||
/**
|
||||
* Used to remove a vesting balance from the VBO. As well
|
||||
* as the balance field, coin_seconds_earned and
|
||||
* coin_seconds_earned_last_update fields are updated.
|
||||
*
|
||||
* The money doesn't "go" anywhere; the caller is responsible
|
||||
* for crediting it to the proper account.
|
||||
*/
|
||||
void withdraw( const fc::time_point_sec& now, const asset& amount );
|
||||
bool is_withdraw_allowed( const fc::time_point_sec& now, const asset& amount )const;
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT( graphene::chain::linear_vesting_policy,
|
||||
(vesting_seconds)
|
||||
(begin_date)
|
||||
(begin_balance)
|
||||
(total_withdrawn)
|
||||
)
|
||||
|
||||
FC_REFLECT( graphene::chain::cdd_vesting_policy,
|
||||
(vesting_seconds)
|
||||
(coin_seconds_earned)
|
||||
(coin_seconds_earned_last_update)
|
||||
)
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::vesting_balance_object, (graphene::db::object),
|
||||
(owner)
|
||||
(balance)
|
||||
(policy)
|
||||
)
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class withdraw_permission_create_evaluator : public evaluator<withdraw_permission_create_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef withdraw_permission_create_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const operation_type& op );
|
||||
object_id_type do_apply( const operation_type& op );
|
||||
};
|
||||
|
||||
class withdraw_permission_claim_evaluator : public evaluator<withdraw_permission_claim_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef withdraw_permission_claim_operation operation_type;
|
||||
|
||||
void_result do_evaluate( const operation_type& op );
|
||||
void_result do_apply( const operation_type& op );
|
||||
};
|
||||
|
||||
class withdraw_permission_update_evaluator : public evaluator<withdraw_permission_update_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef withdraw_permission_update_operation operation_type;
|
||||
|
||||
void_result do_evaluate( const operation_type& op );
|
||||
void_result do_apply( const operation_type& op );
|
||||
};
|
||||
|
||||
class withdraw_permission_delete_evaluator : public evaluator<withdraw_permission_delete_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef withdraw_permission_delete_operation operation_type;
|
||||
|
||||
void_result do_evaluate( const operation_type& op );
|
||||
void_result do_apply( const operation_type& op );
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/authority.hpp>
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* @class withdraw_permission_object
|
||||
* @brief Grants another account authority to withdraw a limited amount of funds per interval
|
||||
*
|
||||
* The primary purpose of this object is to enable recurring payments on the blockchain. An account which wishes to
|
||||
* process a recurring payment may use a @ref withdraw_permission_claim_operation to reference an object of this type
|
||||
* and withdraw up to @ref withdrawal_limit from @ref withdraw_from_account. Only @ref authorized_account may do this.
|
||||
* Any number of withdraws may be made so long as the total amount withdrawn is less than the limit for any given
|
||||
* period.
|
||||
*/
|
||||
class withdraw_permission_object : public graphene::db::abstract_object<withdraw_permission_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = withdraw_permission_object_type;
|
||||
|
||||
/// The account authorizing @ref authorized_account to withdraw from it
|
||||
account_id_type withdraw_from_account;
|
||||
/// The account authorized to make withdrawals from @ref withdraw_from_account
|
||||
account_id_type authorized_account;
|
||||
/// The maximum amount which may be withdrawn per period. All withdrawals must be of this asset type
|
||||
asset withdrawal_limit;
|
||||
/// The duration of a withdrawal period in seconds
|
||||
uint32_t withdrawal_period_sec = 0;
|
||||
/// The beginning of the next withdrawal period
|
||||
time_point_sec period_start_time;
|
||||
/// The time at which this withdraw permission expires
|
||||
time_point_sec expiration;
|
||||
|
||||
/// tracks the total amount
|
||||
share_type claimed_this_period;
|
||||
/// True if the permission may still be claimed for this period; false if it has already been used
|
||||
asset available_this_period( fc::time_point_sec current_time )const
|
||||
{
|
||||
if( current_time >= period_start_time + withdrawal_period_sec )
|
||||
return withdrawal_limit;
|
||||
return asset(
|
||||
( withdrawal_limit.amount > claimed_this_period )
|
||||
? withdrawal_limit.amount - claimed_this_period
|
||||
: 0, withdrawal_limit.asset_id );
|
||||
}
|
||||
};
|
||||
|
||||
struct by_from;
|
||||
struct by_authorized;
|
||||
struct by_expiration;
|
||||
|
||||
typedef multi_index_container<
|
||||
withdraw_permission_object,
|
||||
indexed_by<
|
||||
hashed_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
hashed_non_unique< tag<by_from>, member<withdraw_permission_object, account_id_type, &withdraw_permission_object::withdraw_from_account> >,
|
||||
hashed_non_unique< tag<by_authorized>, member<withdraw_permission_object, account_id_type, &withdraw_permission_object::authorized_account> >,
|
||||
ordered_non_unique< tag<by_expiration>, member<withdraw_permission_object, time_point_sec, &withdraw_permission_object::expiration> >
|
||||
>
|
||||
> withdraw_permission_object_multi_index_type;
|
||||
|
||||
typedef generic_index<withdraw_permission_object, withdraw_permission_object_multi_index_type> withdraw_permission_index;
|
||||
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::withdraw_permission_object, (graphene::db::object),
|
||||
(withdraw_from_account)
|
||||
(authorized_account)
|
||||
(withdrawal_limit)
|
||||
(withdrawal_period_sec)
|
||||
(period_start_time)
|
||||
(expiration)
|
||||
)
|
||||
44
libraries/chain/include/graphene/chain/witness_evaluator.hpp
Normal file
44
libraries/chain/include/graphene/chain/witness_evaluator.hpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class witness_create_evaluator : public evaluator<witness_create_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef witness_create_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const witness_create_operation& o );
|
||||
object_id_type do_apply( const witness_create_operation& o );
|
||||
};
|
||||
|
||||
class witness_withdraw_pay_evaluator : public evaluator<witness_withdraw_pay_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef witness_withdraw_pay_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const operation_type& o );
|
||||
object_id_type do_apply( const operation_type& o );
|
||||
|
||||
const witness_object* witness;
|
||||
const account_object* to_account;
|
||||
};
|
||||
} } // graphene::chain
|
||||
52
libraries/chain/include/graphene/chain/witness_object.hpp
Normal file
52
libraries/chain/include/graphene/chain/witness_object.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
|
||||
class witness_object;
|
||||
|
||||
class witness_object : public abstract_object<witness_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = witness_object_type;
|
||||
|
||||
account_id_type witness_account;
|
||||
key_id_type signing_key;
|
||||
secret_hash_type next_secret;
|
||||
secret_hash_type last_secret;
|
||||
share_type accumulated_income;
|
||||
vote_id_type vote_id;
|
||||
|
||||
witness_object() : vote_id(vote_id_type::witness) {}
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::witness_object, (graphene::db::object),
|
||||
(witness_account)
|
||||
(signing_key)
|
||||
(next_secret)
|
||||
(last_secret)
|
||||
(accumulated_income)
|
||||
(vote_id) )
|
||||
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// needed to serialize witness_scheduler
|
||||
#include <fc/container/deque.hpp>
|
||||
|
||||
#include <graphene/chain/types.hpp>
|
||||
#include <graphene/chain/witness_scheduler.hpp>
|
||||
#include <graphene/chain/witness_scheduler_rng.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
typedef hash_ctr_rng<
|
||||
/* HashClass = */ fc::sha256,
|
||||
/* SeedLength = */ GRAPHENE_RNG_SEED_LENGTH
|
||||
> witness_scheduler_rng;
|
||||
|
||||
typedef generic_witness_scheduler<
|
||||
/* WitnessID = */ witness_id_type,
|
||||
/* RNG = */ witness_scheduler_rng,
|
||||
/* CountType = */ decltype( chain_parameters::maximum_witness_count ),
|
||||
/* OffsetType = */ uint32_t,
|
||||
/* debug = */ true
|
||||
> witness_scheduler;
|
||||
|
||||
typedef generic_far_future_witness_scheduler<
|
||||
/* WitnessID = */ witness_id_type,
|
||||
/* RNG = */ witness_scheduler_rng,
|
||||
/* CountType = */ decltype( chain_parameters::maximum_witness_count ),
|
||||
/* OffsetType = */ uint32_t,
|
||||
/* debug = */ true
|
||||
> far_future_witness_scheduler;
|
||||
|
||||
class witness_schedule_object : public abstract_object<witness_schedule_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = implementation_ids;
|
||||
static const uint8_t type_id = impl_witness_schedule_object_type;
|
||||
|
||||
witness_scheduler scheduler;
|
||||
uint32_t last_scheduling_block;
|
||||
uint64_t slots_since_genesis = 0;
|
||||
fc::array< char, GRAPHENE_RNG_SEED_LENGTH > rng_seed;
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
FC_REFLECT( graphene::chain::witness_scheduler,
|
||||
(_turns)
|
||||
(_tokens)
|
||||
(_min_token_count)
|
||||
(_ineligible_waiting_for_token)
|
||||
(_ineligible_no_turn)
|
||||
(_eligible)
|
||||
(_schedule)
|
||||
(_lame_duck)
|
||||
)
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::witness_schedule_object, (graphene::chain::object),
|
||||
(scheduler)
|
||||
(last_scheduling_block)
|
||||
(slots_since_genesis)
|
||||
(rng_seed)
|
||||
)
|
||||
381
libraries/chain/include/graphene/chain/witness_scheduler.hpp
Normal file
381
libraries/chain/include/graphene/chain/witness_scheduler.hpp
Normal file
|
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/container/flat_set.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
using boost::container::flat_set;
|
||||
|
||||
enum witness_scheduler_relax_flags
|
||||
{
|
||||
emit_turn = 0x01,
|
||||
emit_token = 0x02
|
||||
};
|
||||
|
||||
template< typename WitnessID, typename RNG, typename CountType, typename OffsetType, bool debug = true >
|
||||
class generic_witness_scheduler
|
||||
{
|
||||
public:
|
||||
void check_invariant() const
|
||||
{
|
||||
CountType tokens = _ineligible_no_turn.size() + _eligible.size();
|
||||
CountType turns = _eligible.size();
|
||||
for( const std::pair< WitnessID, bool >& item : _ineligible_waiting_for_token )
|
||||
turns += (item.second ? 1 : 0 );
|
||||
|
||||
assert( _tokens == tokens );
|
||||
assert( _turns == turns );
|
||||
|
||||
|
||||
flat_set< WitnessID > witness_set;
|
||||
// make sure each witness_id occurs only once among the three states
|
||||
auto process_id = [&]( WitnessID item )
|
||||
{
|
||||
assert( witness_set.find( item ) == witness_set.end() );
|
||||
witness_set.insert( item );
|
||||
} ;
|
||||
|
||||
for( const std::pair< WitnessID, bool >& item : _ineligible_waiting_for_token )
|
||||
process_id( item.first );
|
||||
for( const WitnessID& item : _ineligible_no_turn )
|
||||
process_id( item );
|
||||
for( const WitnessID& item : _eligible )
|
||||
process_id( item );
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deterministically evolve over time
|
||||
*/
|
||||
uint32_t relax()
|
||||
{
|
||||
uint32_t relax_flags = 0;
|
||||
|
||||
if( debug ) check_invariant();
|
||||
assert( _min_token_count > 0 );
|
||||
|
||||
// turn distribution
|
||||
if( _turns == 0 )
|
||||
{
|
||||
relax_flags |= emit_turn;
|
||||
for( const WitnessID& item : _ineligible_no_turn )
|
||||
_eligible.push_back( item );
|
||||
_turns += _ineligible_no_turn.size();
|
||||
_ineligible_no_turn.clear();
|
||||
if( debug ) check_invariant();
|
||||
|
||||
for( std::pair< WitnessID, bool >& item : _ineligible_waiting_for_token )
|
||||
{
|
||||
assert( item.second == false );
|
||||
item.second = true;
|
||||
}
|
||||
_turns += _ineligible_waiting_for_token.size();
|
||||
if( debug ) check_invariant();
|
||||
}
|
||||
|
||||
// token distribution
|
||||
while( true )
|
||||
{
|
||||
if( _ineligible_waiting_for_token.empty() )
|
||||
{
|
||||
// eligible must be non-empty
|
||||
assert( !_eligible.empty() );
|
||||
return relax_flags;
|
||||
}
|
||||
|
||||
if( _tokens >= _min_token_count )
|
||||
{
|
||||
if( !_eligible.empty() )
|
||||
return relax_flags;
|
||||
}
|
||||
|
||||
const std::pair< WitnessID, bool >& item = _ineligible_waiting_for_token.front();
|
||||
if( item.second )
|
||||
_eligible.push_back( item.first );
|
||||
else
|
||||
_ineligible_no_turn.push_back( item.first );
|
||||
_ineligible_waiting_for_token.pop_front();
|
||||
relax_flags |= emit_token;
|
||||
_tokens++;
|
||||
if( debug ) check_invariant();
|
||||
}
|
||||
|
||||
return relax_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add another element to _schedule
|
||||
*/
|
||||
uint32_t produce_schedule( RNG& rng )
|
||||
{
|
||||
uint32_t relax_flags = relax();
|
||||
if( debug ) check_invariant();
|
||||
if( _eligible.empty() )
|
||||
return relax_flags;
|
||||
|
||||
decltype( rng( _eligible.size() ) ) pos = rng( _eligible.size() );
|
||||
assert( (pos >= 0) && (pos < _eligible.size()) );
|
||||
auto it = _eligible.begin() + pos;
|
||||
_schedule.push_back( *it );
|
||||
_ineligible_waiting_for_token.emplace_back( *it, false );
|
||||
_eligible.erase( it );
|
||||
_turns--;
|
||||
_tokens--;
|
||||
if( debug ) check_invariant();
|
||||
return relax_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull an element from _schedule
|
||||
*/
|
||||
WitnessID consume_schedule()
|
||||
{
|
||||
assert( _schedule.size() > 0 );
|
||||
|
||||
WitnessID result = _schedule.front();
|
||||
_schedule.pop_front();
|
||||
|
||||
auto it = _lame_duck.find( result );
|
||||
if( it != _lame_duck.end() )
|
||||
_lame_duck.erase( it );
|
||||
if( debug ) check_invariant();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all witnesses in the removal_set from
|
||||
* future scheduling (but not from the current schedule).
|
||||
*/
|
||||
template< typename T >
|
||||
void remove_all( const T& removal_set )
|
||||
{
|
||||
if( debug ) check_invariant();
|
||||
|
||||
_ineligible_waiting_for_token.erase(
|
||||
std::remove_if(
|
||||
_ineligible_waiting_for_token.begin(),
|
||||
_ineligible_waiting_for_token.end(),
|
||||
[&]( const std::pair< WitnessID, bool >& item ) -> bool
|
||||
{
|
||||
bool found = removal_set.find( item.first ) != removal_set.end();
|
||||
_turns -= (found & item.second) ? 1 : 0;
|
||||
return found;
|
||||
} ),
|
||||
_ineligible_waiting_for_token.end() );
|
||||
if( debug ) check_invariant();
|
||||
|
||||
_ineligible_no_turn.erase(
|
||||
std::remove_if(
|
||||
_ineligible_no_turn.begin(),
|
||||
_ineligible_no_turn.end(),
|
||||
[&]( WitnessID item ) -> bool
|
||||
{
|
||||
bool found = (removal_set.find( item ) != removal_set.end());
|
||||
_tokens -= (found ? 1 : 0);
|
||||
return found;
|
||||
} ),
|
||||
_ineligible_no_turn.end() );
|
||||
if( debug ) check_invariant();
|
||||
|
||||
_eligible.erase(
|
||||
std::remove_if(
|
||||
_eligible.begin(),
|
||||
_eligible.end(),
|
||||
[&]( WitnessID item ) -> bool
|
||||
{
|
||||
bool found = (removal_set.find( item ) != removal_set.end());
|
||||
_tokens -= (found ? 1 : 0);
|
||||
_turns -= (found ? 1 : 0);
|
||||
return found;
|
||||
} ),
|
||||
_eligible.end() );
|
||||
if( debug ) check_invariant();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to call insert_all() and remove_all()
|
||||
* as needed to update to the given revised_set.
|
||||
*/
|
||||
template< typename T >
|
||||
void insert_all( const T& insertion_set )
|
||||
{
|
||||
if( debug ) check_invariant();
|
||||
for( const WitnessID wid : insertion_set )
|
||||
{
|
||||
_eligible.push_back( wid );
|
||||
}
|
||||
_turns += insertion_set.size();
|
||||
_tokens += insertion_set.size();
|
||||
if( debug ) check_invariant();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to call insert_all() and remove_all()
|
||||
* as needed to update to the given revised_set.
|
||||
*
|
||||
* This function calls find() on revised_set for all current
|
||||
* witnesses. Running time is O(n*log(n)) if the revised_set
|
||||
* implementation of find() is O(log(n)).
|
||||
*
|
||||
* TODO: Rewriting to use std::set_difference may marginally
|
||||
* increase efficiency, but a benchmark is needed to justify this.
|
||||
*/
|
||||
template< typename T >
|
||||
void update( const T& revised_set )
|
||||
{
|
||||
flat_set< WitnessID > current_set;
|
||||
flat_set< WitnessID > schedule_set;
|
||||
|
||||
current_set.reserve(
|
||||
_ineligible_waiting_for_token.size()
|
||||
+ _ineligible_no_turn.size()
|
||||
+ _eligible.size()
|
||||
+ _schedule.size() );
|
||||
for( const auto& item : _ineligible_waiting_for_token )
|
||||
current_set.insert( item.first );
|
||||
for( const WitnessID& item : _ineligible_no_turn )
|
||||
current_set.insert( item );
|
||||
for( const WitnessID& item : _eligible )
|
||||
current_set.insert( item );
|
||||
for( const WitnessID& item : _schedule )
|
||||
{
|
||||
current_set.insert( item );
|
||||
schedule_set.insert( item );
|
||||
}
|
||||
|
||||
flat_set< WitnessID > insertion_set;
|
||||
insertion_set.reserve( revised_set.size() );
|
||||
for( const WitnessID& item : revised_set )
|
||||
{
|
||||
if( current_set.find( item ) == current_set.end() )
|
||||
insertion_set.insert( item );
|
||||
}
|
||||
|
||||
flat_set< WitnessID > removal_set;
|
||||
removal_set.reserve( current_set.size() );
|
||||
for( const WitnessID& item : current_set )
|
||||
{
|
||||
if( revised_set.find( item ) == revised_set.end() )
|
||||
{
|
||||
if( schedule_set.find( item ) == schedule_set.end() )
|
||||
removal_set.insert( item );
|
||||
else
|
||||
_lame_duck.insert( item );
|
||||
}
|
||||
}
|
||||
|
||||
insert_all( insertion_set );
|
||||
remove_all( removal_set );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of scheduled witnesses
|
||||
*/
|
||||
|
||||
size_t size( )const
|
||||
{
|
||||
return _schedule.size();
|
||||
}
|
||||
|
||||
bool get_slot( OffsetType offset, WitnessID& wit )const
|
||||
{
|
||||
if( offset >= _schedule.size() )
|
||||
return false;
|
||||
wit = _schedule[ offset ];
|
||||
return true;
|
||||
}
|
||||
|
||||
// keep track of total turns / tokens in existence
|
||||
CountType _turns = 0;
|
||||
CountType _tokens = 0;
|
||||
|
||||
// new tokens handed out when _tokens < _min_token_count
|
||||
CountType _min_token_count;
|
||||
|
||||
// WitnessID appears in exactly one of the following:
|
||||
// has no token; second indicates whether we have a turn or not:
|
||||
std::deque < std::pair< WitnessID, bool > > _ineligible_waiting_for_token; // ".." | "T."
|
||||
// has token, but no turn
|
||||
std::vector< WitnessID > _ineligible_no_turn; // ".t"
|
||||
// has token and turn
|
||||
std::vector< WitnessID > _eligible; // "Tt"
|
||||
|
||||
// scheduled
|
||||
std::deque < WitnessID > _schedule;
|
||||
|
||||
// in _schedule, but not to be replaced
|
||||
flat_set< WitnessID > _lame_duck;
|
||||
};
|
||||
|
||||
template< typename WitnessID, typename RNG, typename CountType, typename OffsetType, bool debug = true >
|
||||
class generic_far_future_witness_scheduler
|
||||
{
|
||||
public:
|
||||
generic_far_future_witness_scheduler(
|
||||
const generic_witness_scheduler< WitnessID, RNG, CountType, OffsetType, debug >& base_scheduler,
|
||||
RNG rng
|
||||
)
|
||||
{
|
||||
generic_witness_scheduler< WitnessID, RNG, CountType, OffsetType, debug > extended_scheduler = base_scheduler;
|
||||
_begin_offset = base_scheduler.size()+1;
|
||||
while( (extended_scheduler.produce_schedule( rng ) & emit_turn) == 0 )
|
||||
_begin_offset++;
|
||||
assert( _begin_offset == extended_scheduler.size() );
|
||||
|
||||
_end_offset = _begin_offset;
|
||||
while( (extended_scheduler.produce_schedule( rng ) & emit_turn) == 0 )
|
||||
_end_offset++;
|
||||
assert( _end_offset == extended_scheduler.size()-1 );
|
||||
_schedule.resize( extended_scheduler._schedule.size() );
|
||||
std::copy( extended_scheduler._schedule.begin(),
|
||||
extended_scheduler._schedule.end(),
|
||||
_schedule.begin() );
|
||||
return;
|
||||
}
|
||||
|
||||
bool get_slot( OffsetType offset, WitnessID& wit )const
|
||||
{
|
||||
if( offset <= _end_offset )
|
||||
wit = _schedule[ offset ];
|
||||
else
|
||||
wit = _schedule[ _begin_offset +
|
||||
(
|
||||
(offset - _begin_offset) %
|
||||
(_end_offset + 1 - _begin_offset)
|
||||
) ];
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector< WitnessID > _schedule;
|
||||
OffsetType _begin_offset;
|
||||
OffsetType _end_offset;
|
||||
};
|
||||
|
||||
} }
|
||||
128
libraries/chain/include/graphene/chain/witness_scheduler_rng.hpp
Normal file
128
libraries/chain/include/graphene/chain/witness_scheduler_rng.hpp
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <boost/multiprecision/integer.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
/**
|
||||
* Always returns 0. Useful for testing.
|
||||
*/
|
||||
class nullary_rng
|
||||
{
|
||||
public:
|
||||
nullary_rng() {}
|
||||
virtual ~nullary_rng() {}
|
||||
|
||||
template< typename T > T operator()( T max )
|
||||
{ return T(0); }
|
||||
} ;
|
||||
|
||||
/**
|
||||
* The sha256_ctr_rng generates bits using SHA256 in counter (CTR)
|
||||
* mode.
|
||||
*/
|
||||
template< class HashClass, int SeedLength=32 >
|
||||
class hash_ctr_rng
|
||||
{
|
||||
public:
|
||||
hash_ctr_rng( const char* seed, uint64_t counter = 0 )
|
||||
: _counter( counter ), _current_offset( 0 )
|
||||
{
|
||||
memcpy( _seed, seed, SeedLength );
|
||||
_reset_current_value();
|
||||
return;
|
||||
}
|
||||
|
||||
virtual ~hash_ctr_rng() {}
|
||||
|
||||
uint64_t get_bits( uint8_t count )
|
||||
{
|
||||
uint64_t result = 0;
|
||||
uint64_t mask = 1;
|
||||
// grab the requested number of bits
|
||||
while( count > 0 )
|
||||
{
|
||||
result |=
|
||||
(
|
||||
(
|
||||
(
|
||||
_current_value.data()[ (_current_offset >> 3) & 0x1F ]
|
||||
& ( 1 << (_current_offset & 0x07) )
|
||||
)
|
||||
!= 0
|
||||
) ? mask : 0
|
||||
);
|
||||
mask += mask;
|
||||
--count;
|
||||
++_current_offset;
|
||||
if( _current_offset == (_current_value.data_size() << 3) )
|
||||
{
|
||||
_counter++;
|
||||
_current_offset = 0;
|
||||
_reset_current_value();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t operator()( uint64_t bound )
|
||||
{
|
||||
if( bound <= 1 )
|
||||
return 0;
|
||||
#ifdef __GNUC__
|
||||
uint8_t bitcount( 64 - __builtin_clzll( bound ) );
|
||||
#else
|
||||
uint8_t bitcount( 64 - boost::multiprecision::detail::find_msb( bound ) );
|
||||
#endif
|
||||
|
||||
// probability of loop exiting is >= 1/2, so probability of
|
||||
// running N times is bounded above by (1/2)^N
|
||||
while( true )
|
||||
{
|
||||
uint64_t result = get_bits( bitcount );
|
||||
if( result < bound )
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// convenience method which does casting for types other than uint64_t
|
||||
template< typename T > T operator()( T bound )
|
||||
{ return (T) ( (*this)(uint64_t( bound )) ); }
|
||||
|
||||
void _reset_current_value()
|
||||
{
|
||||
// internal implementation detail, called to update
|
||||
// _current_value when _counter changes
|
||||
typename HashClass::encoder enc;
|
||||
enc.write( _seed , SeedLength );
|
||||
enc.write( (char *) &_counter, 8 );
|
||||
_current_value = enc.result();
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t _counter;
|
||||
char _seed[ SeedLength ];
|
||||
HashClass _current_value;
|
||||
uint16_t _current_offset;
|
||||
|
||||
static const int seed_length = SeedLength;
|
||||
} ;
|
||||
|
||||
} }
|
||||
33
libraries/chain/include/graphene/chain/worker_evaluator.hpp
Normal file
33
libraries/chain/include/graphene/chain/worker_evaluator.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/worker_object.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
class worker_create_evaluator : public evaluator<worker_create_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef worker_create_operation operation_type;
|
||||
|
||||
object_id_type do_evaluate( const operation_type& o );
|
||||
object_id_type do_apply( const operation_type& o );
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
199
libraries/chain/include/graphene/chain/worker_object.hpp
Normal file
199
libraries/chain/include/graphene/chain/worker_object.hpp
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
|
||||
#include <graphene/db/flat_index.hpp>
|
||||
|
||||
#include <fc/static_variant.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
class database;
|
||||
|
||||
/**
|
||||
* @defgroup worker_types Implementations of the various worker types in the system
|
||||
*
|
||||
* The system has various worker types, which do different things with the money they are paid. These worker types
|
||||
* and their semantics are specified here.
|
||||
*
|
||||
* All worker types exist as a struct containing the data this worker needs to evaluate, as well as a method
|
||||
* pay_worker, which takes a pay amount and a non-const database reference, and applies the worker's specific pay
|
||||
* semantics to the worker_type struct and/or the database. Furthermore, all worker types have an initializer,
|
||||
* which is a struct containing the data needed to create that kind of worker.
|
||||
*
|
||||
* Each initializer type has a method, init, which takes a non-const database reference, a const reference to the
|
||||
* worker object being created, and a non-const reference to the specific *_worker_type object to initialize. The
|
||||
* init method creates any further objects, and initializes the worker_type object as necessary according to the
|
||||
* semantics of that particular worker type.
|
||||
*
|
||||
* To create a new worker type, define a my_new_worker_type struct with a pay_worker method which updates the
|
||||
* my_new_worker_type object and/or the database. Create a my_new_worker_type::initializer struct with an init
|
||||
* method and any data members necessary to create a new worker of this type. Reflect my_new_worker_type and
|
||||
* my_new_worker_type::initializer into FC's type system, and add them to @ref worker_type and @ref
|
||||
* worker_initializer respectively. Make sure the order of types in @ref worker_type and @ref worker_initializer
|
||||
* remains the same.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief A worker who burns all of his pay
|
||||
*
|
||||
* This worker type burns all pay he receives, paying it back to the network's reserve funds pool.
|
||||
*/
|
||||
struct refund_worker_type
|
||||
{
|
||||
/// Record of how much this worker has burned in his lifetime
|
||||
share_type total_burned;
|
||||
|
||||
void pay_worker(share_type pay, database&);
|
||||
|
||||
struct initializer
|
||||
{
|
||||
void init(database&, const worker_object&, refund_worker_type&)const
|
||||
{}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A worker who sends his pay to a vesting balance
|
||||
*
|
||||
* This worker type takes all of his pay and places it into a vesting balance
|
||||
*/
|
||||
struct vesting_balance_worker_type
|
||||
{
|
||||
/// The balance this worker pays into
|
||||
vesting_balance_id_type balance;
|
||||
|
||||
void pay_worker(share_type pay, database& db);
|
||||
|
||||
struct initializer
|
||||
{
|
||||
initializer(uint16_t vesting_period = 0)
|
||||
: pay_vesting_period_days(vesting_period) {}
|
||||
|
||||
void init(database& db, const worker_object& obj, vesting_balance_worker_type& worker)const;
|
||||
|
||||
uint16_t pay_vesting_period_days;
|
||||
};
|
||||
};
|
||||
///@}
|
||||
|
||||
// The ordering of types in these two static variants MUST be the same.
|
||||
typedef static_variant<
|
||||
refund_worker_type,
|
||||
vesting_balance_worker_type
|
||||
> worker_type;
|
||||
typedef static_variant<
|
||||
refund_worker_type::initializer,
|
||||
vesting_balance_worker_type::initializer
|
||||
> worker_initializer;
|
||||
|
||||
/// @brief A visitor for @ref worker_type which initializes the worker within
|
||||
struct worker_initialize_visitor
|
||||
{
|
||||
private:
|
||||
const worker_object& worker_obj;
|
||||
const worker_initializer& initializer;
|
||||
database& db;
|
||||
|
||||
public:
|
||||
worker_initialize_visitor(const worker_object& worker, const worker_initializer& initializer, database& db)
|
||||
: worker_obj(worker),initializer(initializer),db(db) {}
|
||||
|
||||
typedef void result_type;
|
||||
template<typename WorkerType>
|
||||
void operator()( WorkerType& worker)const
|
||||
{
|
||||
static_assert(worker_type::tag<WorkerType>::value ==
|
||||
worker_initializer::tag<typename WorkerType::initializer>::value,
|
||||
"Tag values for worker_type and worker_initializer do not match! "
|
||||
"Are the types in these static_variants in the same order?");
|
||||
initializer.get<typename WorkerType::initializer>().init(db, worker_obj, worker);
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief A visitor for @ref worker_type which calls pay_worker on the worker within
|
||||
struct worker_pay_visitor
|
||||
{
|
||||
private:
|
||||
share_type pay;
|
||||
database& db;
|
||||
|
||||
public:
|
||||
worker_pay_visitor(share_type pay, database& db)
|
||||
: pay(pay), db(db) {}
|
||||
|
||||
typedef void result_type;
|
||||
template<typename W>
|
||||
void operator()(W& worker)const
|
||||
{
|
||||
worker.pay_worker(pay, db);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Worker object contains the details of a blockchain worker. See @ref workers for details.
|
||||
*/
|
||||
class worker_object : public abstract_object<worker_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = worker_object_type;
|
||||
|
||||
/// ID of the account which owns this worker
|
||||
account_id_type worker_account;
|
||||
/// Time at which this worker begins receiving pay, if elected
|
||||
time_point_sec work_begin_date;
|
||||
/// Time at which this worker will cease to receive pay. Worker will be deleted at this time
|
||||
time_point_sec work_end_date;
|
||||
/// Amount in CORE this worker will be paid each day
|
||||
share_type daily_pay;
|
||||
/// ID of this worker's pay balance
|
||||
worker_type worker;
|
||||
|
||||
/// Voting ID which represents approval of this worker
|
||||
vote_id_type vote_for;
|
||||
/// Voting ID which represents disapproval of this worker
|
||||
vote_id_type vote_against;
|
||||
|
||||
bool is_active(fc::time_point_sec now)const {
|
||||
return now >= work_begin_date && now <= work_end_date;
|
||||
}
|
||||
share_type approving_stake(const vector<uint64_t>& stake_vote_tallies)const {
|
||||
return stake_vote_tallies[vote_for] - stake_vote_tallies[vote_against];
|
||||
}
|
||||
};
|
||||
|
||||
typedef flat_index<worker_object> worker_index;
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT( graphene::chain::refund_worker_type, (total_burned) )
|
||||
FC_REFLECT( graphene::chain::refund_worker_type::initializer, )
|
||||
FC_REFLECT( graphene::chain::vesting_balance_worker_type, (balance) )
|
||||
FC_REFLECT( graphene::chain::vesting_balance_worker_type::initializer, (pay_vesting_period_days) )
|
||||
FC_REFLECT_DERIVED( graphene::chain::worker_object, (graphene::db::object),
|
||||
(worker_account)
|
||||
(work_begin_date)
|
||||
(work_end_date)
|
||||
(daily_pay)
|
||||
(worker)
|
||||
(vote_for)
|
||||
(vote_against)
|
||||
)
|
||||
37
libraries/chain/index.cpp
Normal file
37
libraries/chain/index.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
||||
*
|
||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <fc/io/raw.hpp>
|
||||
#include <graphene/chain/index.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue